diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..dea8def --- /dev/null +++ b/.prettierignore @@ -0,0 +1,4 @@ +package.json +package-lock.json +dist +node_modules \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..3a97a77 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,13 @@ +{ + "printWidth": 100, + "tabWidth": 2, + "useTabs": false, + "singleQuote": true, + "trailingComma": "all", + "semi": true, + "bracketSpacing": true, + "arrowParens": "always", + "endOfLine": "auto", + "htmlWhitespaceSensitivity": "ignore", + "embeddedLanguageFormatting": "auto" +} diff --git a/README.md b/README.md index 856245c..b04519d 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,7 @@ View your app in AI Studio: https://ai.studio/apps/c9f95229-05dc-4fcb-bfac-ba83f ## Run Locally -**Prerequisites:** Node.js - +**Prerequisites:** Node.js 1. Install dependencies: `npm install` diff --git a/angular.json b/angular.json index add9d39..665d126 100644 --- a/angular.json +++ b/angular.json @@ -3,9 +3,7 @@ "version": 1, "cli": { "packageManager": "npm", - "schematicCollections": [ - "angular-eslint" - ], + "schematicCollections": ["angular-eslint"], "analytics": "169ed763-2250-4e49-a165-52c8e18688e7" }, "newProjectRoot": "projects", @@ -28,9 +26,7 @@ "input": "public" } ], - "styles": [ - "src/styles.css" - ], + "styles": ["src/styles.css"], "server": "src/main.server.ts", "outputMode": "server", "ssr": { @@ -39,6 +35,13 @@ }, "configurations": { "production": { + "outputHashing": "all", + "fileReplacements": [ + { + "replace": "src/environments/environment.ts", + "with": "src/environments/environment.production.ts" + } + ], "budgets": [ { "type": "initial", @@ -50,13 +53,18 @@ "maximumWarning": "4kB", "maximumError": "8kB" } - ], - "outputHashing": "all" + ] }, "development": { "optimization": false, "extractLicenses": false, - "sourceMap": true + "sourceMap": true, + "fileReplacements": [ + { + "replace": "src/environments/environment.ts", + "with": "src/environments/environment.development.ts" + } + ] } }, "defaultConfiguration": "production" @@ -79,10 +87,7 @@ "lint": { "builder": "@angular-eslint/builder:lint", "options": { - "lintFilePatterns": [ - "src/**/*.ts", - "src/**/*.html" - ] + "lintFilePatterns": ["src/**/*.ts", "src/**/*.html"] } } } diff --git a/eslint.config.js b/eslint.config.js index 25955c0..38f180b 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -1,18 +1,23 @@ -// @ts-check +// @ts-nocheck const eslint = require('@eslint/js'); -const {defineConfig} = require('eslint/config'); const tseslint = require('typescript-eslint'); const angular = require('angular-eslint'); +const prettierPlugin = require('eslint-plugin-prettier'); +const prettierConfig = require('eslint-config-prettier'); -module.exports = defineConfig([ +module.exports = tseslint.config( { files: ['**/*.ts'], extends: [ eslint.configs.recommended, - tseslint.configs.recommended, - tseslint.configs.stylistic, - angular.configs.tsRecommended, + ...tseslint.configs.recommended, + ...tseslint.configs.stylistic, + ...angular.configs.tsRecommended, + prettierConfig, ], + plugins: { + prettier: prettierPlugin, + }, processor: angular.processInlineTemplates, rules: { '@angular-eslint/directive-selector': [ @@ -31,14 +36,18 @@ module.exports = defineConfig([ style: 'kebab-case', }, ], + 'prettier/prettier': [ + 'error', + { + endOfLine: 'auto', + }, + ], + '@typescript-eslint/no-explicit-any': 'error', // Forbid usage of 'any' }, }, { files: ['**/*.html'], - extends: [ - angular.configs.templateRecommended, - angular.configs.templateAccessibility, - ], + extends: [...angular.configs.templateRecommended, ...angular.configs.templateAccessibility], rules: {}, - } -]); + }, +); diff --git a/package-lock.json b/package-lock.json index fc596bd..25da62f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -35,8 +35,12 @@ "angular-eslint": "21.1.0", "cross-env": "^10.1.0", "eslint": "^9.39.1", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-prettier": "^5.5.6", "jsdom": "^27.0.0", "postcss": "^8.5.3", + "prettier": "^3.9.6", + "pretty-quick": "^4.2.2", "tailwindcss": "^4.1.12", "typescript": "~5.9.2", "typescript-eslint": "8.47.0", @@ -925,6 +929,7 @@ "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/generator": "^7.29.7", @@ -1329,31 +1334,6 @@ "node": ">=20.19.0" } }, - "node_modules/@emnapi/core": { - "version": "1.11.3", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.3.tgz", - "integrity": "sha512-zLpS5asjEb7lq8jYLq37N6XKaE41DIexlY1rF/z4/tIl3wo13Sqm28fRyfIsKZD+NZ8mM5RoKkpW/rBcuoSZSg==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "@emnapi/wasi-threads": "1.2.3", - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.11.3", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.3.tgz", - "integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@emnapi/wasi-threads": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.3.tgz", @@ -3739,6 +3719,19 @@ "license": "MIT", "optional": true }, + "node_modules/@pkgr/core": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.3.6.tgz", + "integrity": "sha512-SEeaJLb3qBNF/OaXnaR1NmmBbFYk1zC0ZH/52fATcRPLFg/p791YrcyFFy44Bo9sLaGuSuLp5Q6axbb/O+v/RA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/pkgr" + } + }, "node_modules/@protobufjs/aspromise": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", @@ -5149,6 +5142,7 @@ "integrity": "sha512-lJi3PfxVmo0AkEY93ecfN+r8SofEqZNGByvHAI3GBLrvt1Cw6H5k1IM02nSzu0RfUafr2EvFSw0wAsZgubNplQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.47.0", "@typescript-eslint/types": "8.47.0", @@ -6701,7 +6695,6 @@ "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "mdn-data": "2.27.1", "source-map-js": "^1.2.1" @@ -7162,6 +7155,54 @@ } } }, + "node_modules/eslint-config-prettier": { + "version": "10.1.8", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz", + "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "funding": { + "url": "https://opencollective.com/eslint-config-prettier" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.5.6", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.6.tgz", + "integrity": "sha512-ifetmTcxWfz+4qRW3pH/ujdTq2jQIj59AxJMIN26K5avYgU8dxycUETQonWiW+wPrYXA0j3Try0l1CnwVQtDqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prettier-linter-helpers": "^1.0.1", + "synckit": "^0.11.13" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, "node_modules/eslint-scope": { "version": "9.1.2", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", @@ -7509,6 +7550,13 @@ "devOptional": true, "license": "MIT" }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/fast-glob": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", @@ -8892,6 +8940,7 @@ "integrity": "sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "cli-truncate": "^5.0.0", "colorette": "^2.0.20", @@ -9478,6 +9527,16 @@ "integrity": "sha512-8nadJAJjTtqRkmRF36FoJTrywK9nnFmnPwnSMyxaOCU7GDjN9RTMJIxx9De8ErM+vpPhMccr/6fo5WciyQLnMQ==", "license": "MIT" }, + "node_modules/mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/mrmime": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", @@ -10330,6 +10389,84 @@ "node": ">= 0.8.0" } }, + "node_modules/prettier": { + "version": "3.9.6", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.6.tgz", + "integrity": "sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.1.tgz", + "integrity": "sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/pretty-quick": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/pretty-quick/-/pretty-quick-4.2.2.tgz", + "integrity": "sha512-uAh96tBW1SsD34VhhDmWuEmqbpfYc/B3j++5MC/6b3Cb8Ow7NJsvKFhg0eoGu2xXX+o9RkahkTK6sUdd8E7g5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pkgr/core": "^0.2.7", + "ignore": "^7.0.5", + "mri": "^1.2.0", + "picocolors": "^1.1.1", + "picomatch": "^4.0.2", + "tinyexec": "^0.3.2", + "tslib": "^2.8.1" + }, + "bin": { + "pretty-quick": "lib/cli.mjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://opencollective.com/pretty-quick" + }, + "peerDependencies": { + "prettier": "^3.0.0" + } + }, + "node_modules/pretty-quick/node_modules/@pkgr/core": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.10.tgz", + "integrity": "sha512-x6fFWCeak8aCGfqZfe6CXYt5xVjxe9Os1cIPmVRcToInKLjhJkRVXvJ/L3/1KxFkjDQdbZV/YsuLKqa8t/xKpA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/pkgr" + } + }, + "node_modules/pretty-quick/node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, "node_modules/proc-log": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.1.0.tgz", @@ -11202,6 +11339,22 @@ "dev": true, "license": "MIT" }, + "node_modules/synckit": { + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.13.tgz", + "integrity": "sha512-eNRKgb3z66Yp3D2CixVujOUvXLFUTij/zVnV8KRyvFdQwpz7I5DS8UfRkTeLzb64u+dkzDSdelE24izu+zSSUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pkgr/core": "^0.3.6" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/synckit" + } + }, "node_modules/tailwindcss": { "version": "4.3.3", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.3.tgz", diff --git a/package.json b/package.json index cc0e38a..a4cf0d9 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,10 @@ "watch": "ng build --watch --configuration development", "test": "ng test", "lint": "ng lint", + "pretty-quick": "pretty-quick --staged", + "lint:fix": "ng lint --fix", + "format": "prettier --write .", + "format:staged": "pretty-quick --staged", "serve:ssr:app": "node dist/app/server/server.mjs" }, "private": true, @@ -40,8 +44,12 @@ "angular-eslint": "21.1.0", "cross-env": "^10.1.0", "eslint": "^9.39.1", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-prettier": "^5.5.6", "jsdom": "^27.0.0", "postcss": "^8.5.3", + "prettier": "^3.9.6", + "pretty-quick": "^4.2.2", "tailwindcss": "^4.1.12", "typescript": "~5.9.2", "typescript-eslint": "8.47.0", diff --git a/src/app/app.config.server.ts b/src/app/app.config.server.ts index 37c9504..35926e4 100644 --- a/src/app/app.config.server.ts +++ b/src/app/app.config.server.ts @@ -1,7 +1,7 @@ -import {ApplicationConfig, mergeApplicationConfig} from '@angular/core'; -import {provideServerRendering, withRoutes} from '@angular/ssr'; -import {appConfig} from './app.config'; -import {serverRoutes} from './app.routes.server'; +import { ApplicationConfig, mergeApplicationConfig } from '@angular/core'; +import { provideServerRendering, withRoutes } from '@angular/ssr'; +import { appConfig } from './app.config'; +import { serverRoutes } from './app.routes.server'; const serverConfig: ApplicationConfig = { providers: [provideServerRendering(withRoutes(serverRoutes))], diff --git a/src/app/app.config.ts b/src/app/app.config.ts index 7d47338..8c88b3b 100644 --- a/src/app/app.config.ts +++ b/src/app/app.config.ts @@ -1,11 +1,12 @@ -import { - ApplicationConfig, - provideBrowserGlobalErrorListeners, -} from '@angular/core'; -import {provideRouter} from '@angular/router'; - -import {routes} from './app.routes'; +import { ApplicationConfig, provideBrowserGlobalErrorListeners } from '@angular/core'; +import { provideRouter } from '@angular/router'; +import { provideHttpClient, withFetch } from '@angular/common/http'; +import { routes } from './app.routes'; export const appConfig: ApplicationConfig = { - providers: [provideBrowserGlobalErrorListeners(), provideRouter(routes)], + providers: [ + provideHttpClient(withFetch()), + provideBrowserGlobalErrorListeners(), + provideRouter(routes), + ], }; diff --git a/src/app/app.routes.server.ts b/src/app/app.routes.server.ts index 0c6a7ef..15a5c55 100644 --- a/src/app/app.routes.server.ts +++ b/src/app/app.routes.server.ts @@ -9,10 +9,6 @@ export const serverRoutes: ServerRoute[] = [ path: 'catalog/products/:id/view', renderMode: RenderMode.Server, }, - { - path: 'catalog/products/:id/duplicate', - renderMode: RenderMode.Server, - }, { path: 'catalog/products/:id', renderMode: RenderMode.Server, diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts index 500edd7..e7d549a 100644 --- a/src/app/app.routes.ts +++ b/src/app/app.routes.ts @@ -4,74 +4,82 @@ export const routes: Routes = [ { path: '', redirectTo: 'dashboard', - pathMatch: 'full' + pathMatch: 'full', }, { path: 'dashboard', - loadComponent: () => import('./features/dashboard/dashboard').then(m => m.DashboardPageComponent) + loadComponent: () => + import('./features/dashboard/dashboard').then((m) => m.DashboardPageComponent), }, { path: 'catalog/products', - loadComponent: () => import('./features/catalog/products').then(m => m.ProductsPageComponent) + loadComponent: () => + import('./features/catalog/products/products').then((m) => m.ProductsPageComponent), }, { path: 'catalog/products/new', - loadComponent: () => import('./features/catalog/product-form').then(m => m.ProductFormComponent) + loadComponent: () => + import('./features/catalog/product-create/product-create').then((m) => m.ProductCreateComponent), }, { path: 'catalog/products/:id/edit', - loadComponent: () => import('./features/catalog/product-form').then(m => m.ProductFormComponent) + loadComponent: () => + import('./features/catalog/product-workspace/product-workspace').then( + (m) => m.ProductWorkspaceComponent, + ), }, { path: 'catalog/products/:id/view', - loadComponent: () => import('./features/catalog/product-form').then(m => m.ProductFormComponent) - }, - { - path: 'catalog/products/:id/duplicate', - loadComponent: () => import('./features/catalog/product-form').then(m => m.ProductFormComponent) + loadComponent: () => + import('./features/catalog/product-workspace/product-workspace').then( + (m) => m.ProductWorkspaceComponent, + ), }, { path: 'catalog/products/:id', - loadComponent: () => import('./features/catalog/product-form').then(m => m.ProductFormComponent) + loadComponent: () => + import('./features/catalog/product-workspace/product-workspace').then( + (m) => m.ProductWorkspaceComponent, + ), }, { path: 'catalog/:sub', - loadComponent: () => import('./features/placeholder').then(m => m.PlaceholderPageComponent) + loadComponent: () => import('./features/placeholder').then((m) => m.PlaceholderPageComponent), }, { path: 'compatibility/:sub', - loadComponent: () => import('./features/placeholder').then(m => m.PlaceholderPageComponent) + loadComponent: () => import('./features/placeholder').then((m) => m.PlaceholderPageComponent), }, { path: 'vehicles/:sub', - loadComponent: () => import('./features/placeholder').then(m => m.PlaceholderPageComponent) + loadComponent: () => import('./features/placeholder').then((m) => m.PlaceholderPageComponent), }, { path: 'commercial/:sub', - loadComponent: () => import('./features/placeholder').then(m => m.PlaceholderPageComponent) + loadComponent: () => import('./features/placeholder').then((m) => m.PlaceholderPageComponent), }, { path: 'imports', - loadComponent: () => import('./features/placeholder').then(m => m.PlaceholderPageComponent) + loadComponent: () => import('./features/placeholder').then((m) => m.PlaceholderPageComponent), }, { path: 'reports', - loadComponent: () => import('./features/placeholder').then(m => m.PlaceholderPageComponent) + loadComponent: () => import('./features/placeholder').then((m) => m.PlaceholderPageComponent), }, { path: 'notifications', - loadComponent: () => import('./features/placeholder').then(m => m.PlaceholderPageComponent) + loadComponent: () => import('./features/placeholder').then((m) => m.PlaceholderPageComponent), }, { path: 'admin', - loadComponent: () => import('./features/placeholder').then(m => m.PlaceholderPageComponent) + loadComponent: () => import('./features/placeholder').then((m) => m.PlaceholderPageComponent), }, { path: 'help', - loadComponent: () => import('./features/placeholder').then(m => m.PlaceholderPageComponent) + loadComponent: () => import('./features/placeholder').then((m) => m.PlaceholderPageComponent), }, { path: '**', - redirectTo: 'dashboard' - } + redirectTo: 'dashboard', + }, ]; diff --git a/src/app/app.spec.ts b/src/app/app.spec.ts index e69ce7d..75753d6 100644 --- a/src/app/app.spec.ts +++ b/src/app/app.spec.ts @@ -1,5 +1,5 @@ -import {TestBed} from '@angular/core/testing'; -import {App} from './app'; +import { TestBed } from '@angular/core/testing'; +import { App } from './app'; describe('App', () => { beforeEach(async () => { diff --git a/src/app/app.ts b/src/app/app.ts index 8f63dbd..a00c3a7 100644 --- a/src/app/app.ts +++ b/src/app/app.ts @@ -1,5 +1,5 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; -import { AppShellComponent } from './layout/app-shell'; +import { AppShellComponent } from './components/app-shell/app-shell'; @Component({ changeDetection: ChangeDetectionStrategy.OnPush, diff --git a/src/app/layout/app-shell.css b/src/app/components/app-shell/app-shell.css similarity index 100% rename from src/app/layout/app-shell.css rename to src/app/components/app-shell/app-shell.css diff --git a/src/app/layout/app-shell.html b/src/app/components/app-shell/app-shell.html similarity index 75% rename from src/app/layout/app-shell.html rename to src/app/components/app-shell/app-shell.html index ac5a356..d228f20 100644 --- a/src/app/layout/app-shell.html +++ b/src/app/components/app-shell/app-shell.html @@ -1,4 +1,6 @@ -
+ {{ helperText() }} +
+ } + + @if (error()) { +
+
|
-
- {{ col.header }}
-
- |
- }
- @if (hasActions()) {
- Ações | +
+
+ {{ col.header }}
+
+ |
+ } @if (hasActions()) {
+ Ações | }
|---|---|---|---|
|
- |
- }
- @if (hasActions()) {
-
- |
- }
- ||
|
+ |
+ } @if (hasActions()) {
+
+ |
}
- } @else if (data().length === 0) {
- ||
|
- |
- |||
|
+ |
+ |||
|
+ @if (col.type === 'badge' || col.badgeConfig) { @let bg = getBadgeConfig(row, col);
+
- @for (col of columns(); track col.key) {
-
+ } @else { {{ getFormattedValue(row, col) }} }
+
- @if (col.cell) {
- {{ col.cell(row) }}
- } @else {
- {{ row[col.key] }}
- }
- |
+ |
+ } @if (hasActions()) {
+
+
+ @for (act of getVisibleActions(row); track act.id) {
+
}
-
- @if (hasActions()) {
-
- |
- }
-
-
-
-
- |
- {{ message() }} -
-{{ message() }}
{{ description() }}
@if (actionLabel()) { -
{{ message() }}
diff --git a/src/app/design-system/error-state/error-state.ts b/src/app/design-system/error-state/error-state.ts
index ba942cd..dd2269b 100644
--- a/src/app/design-system/error-state/error-state.ts
+++ b/src/app/design-system/error-state/error-state.ts
@@ -8,11 +8,13 @@ import { ButtonComponent } from '../button/button';
imports: [AppIconComponent, ButtonComponent],
changeDetection: ChangeDetectionStrategy.OnPush,
templateUrl: './error-state.html',
- styleUrl: './error-state.css'
+ styleUrl: './error-state.css',
})
export class ErrorStateComponent {
readonly title = input
-
+
- {{ helperText() }}
- {{ helperText() }}
- {{ subtitle() }}
- {{ subtitle() }}
-
+
+ Fornecedor, código, preço de compra, prazo de entrega (lead time), quantidade mínima,
+ preferencial, observações e situação
+
+ Marque as tags ativas para agrupamento e indexação de busca
+
+ Tipo de observação, descrição completa e situação da nota
+ Produto Faturado (Emissão de NFe)
+ Indica se as saídas deste produto geram faturamento comercial e emissão de nota fiscal de venda.
+ {{ getModule('oem').description }}
+ {{ getModule('codigos').description }}
+
+ {{ getModule('equivalentes').description }}
+
+ {{ getModule('compatibilidade').description }}
+
+ Título, identificador URL e descrições técnicas e comerciais
+
+ Unidade de medida, peso bruto e dimensões da embalagem para cálculo de frete
+
+ Códigos de controle e classificações principais do produto no sistema
+ Configurações de exibição do produto nas vitrines e canais de venda
+ As informações abaixo serão utilizadas para criar automaticamente o registro correspondente na tabela de inventário, vinculando o produto ao depósito selecionado.
+ Permitir Backorder (Venda sem Estoque)
+ Define se o produto poderá ser vendido mesmo quando não houver estoque disponível em saldo físico.
+
+ {{ img.name }}
+ {{ img.size }} Nenhuma imagem enviada para este produto.
+
{{ title() }}
@if (subtitle()) {
-
+
+
+
+
+
+
+
+
+ @for (sup of suppliersPaginated(); track sup.id) {
+ Fornecedor
+ Código no Fornecedor
+ Preço Compra
+ Lead Time
+ Qtd. Mínima
+ Preferencial
+ Observações
+ Situação
+ Ações
+
+
+ } @empty {
+
+ {{ sup.supplierName }}
+
+
+ {{ sup.supplierCode }}
+
+
+ R$ {{ sup.purchasePrice.toFixed(2) }}
+
+ {{ sup.leadTimeDays }} dias
+ {{ sup.minQuantity || 1 }} un
+
+ @if (sup.isPreferential) {
+
+ Sim (Preferencial)
+
+ } @else if (!isReadOnly()) {
+
+ } @else {
+ Não
+ }
+
+
+ {{ sup.notes || '-' }}
+
+
+
+
+
+ @if (!isReadOnly()) {
+
+ }
+
+
+
+ }
+
+
+ Nenhum fornecedor cadastrado.
+
+
+
+
+
+
+
+
+
+
+
+
+ @for (note of notesPaginated(); track note.id) {
+ Tipo da Observação
+ Descrição
+ Data Registro
+ Autor
+ Situação
+ Ações
+
+
+ } @empty {
+
+
+ {{ note.type }}
+
+
+ {{ note.description }}
+ {{ note.date }}
+
+ {{ note.author }}
+
+
+
+
+
+ @if (!isReadOnly()) {
+
+ }
+
+
+
+ }
+
+
+ Nenhuma observação cadastrada.
+
+
+
+
+
+
+
+
+
+
+ @for (oem of oemPaginated(); track oem.id) {
+ Fabricante de Referência
+ Código OEM
+ Principal
+ Situação
+ Ações
+
+
+ } @empty {
+ {{ oem.manufacturer }}
+
+ {{ oem.oemCode }}
+
+
+ @if (oem.isPrimary) {
+
+
+
+
+
+
+ @if (!isReadOnly()) {
+
+ }
+
+
+
+ }
+
+
+ Nenhum código OEM cadastrado.
+
+
+
+
+
+
+
+
+
+
+ @for (codeItem of productCodesPaginated(); track codeItem.id) {
+ Tipo do Código
+ Código
+ Situação
+ Ações
+
+
+ } @empty {
+
+ {{ codeItem.type }}
+
+
+ {{ codeItem.code }}
+
+
+
+
+
+ @if (!isReadOnly()) {
+
+ }
+
+
+
+ }
+
+
+ Nenhum código complementar cadastrado.
+
+
+
+
+
+
+
+
+
+
+ @for (eq of equivalentPaginated(); track eq.id) {
+ Produto Equivalente
+ Observação
+ Situação
+ Ações
+
+
+ } @empty {
+
+ {{ eq.productName }}
+
+
+ {{ eq.notes || 'Sem observações' }}
+
+
+
+
+
+ @if (!isReadOnly()) {
+
+ }
+
+
+
+ }
+
+
+ Nenhum produto equivalente vinculado.
+
+
+
+
+
+
+
+
+
+
+ @for (veh of vehiclePaginated(); track veh.id) {
+ Aplicação Veicular (Marca/Modelo/Versão)
+ Motor
+ Anos
+ Observações
+ Situação
+ Ações
+
+
+ } @empty {
+
+ {{ veh.brand }} {{ veh.model }}
+ ({{ veh.version }})
+
+ {{ veh.engine }}
+
+ {{ veh.startYear }} - {{ veh.endYear || 'Atual' }}
+
+ {{ veh.notes || '-' }}
+
+
+
+
+ @if (!isReadOnly()) {
+
+ }
+
+
+
+ }
+
+
+ Nenhuma aplicação veicular vinculada.
+
+
+ Informações Básicas & Descrições
+
+
+ Informações Físicas & Logísticas
+
+
+ Identificação & Classificação
+
+
+ Visibilidade & Destaque
+
+
+
+
+ Galeria de Fotos ({{ mediaImages().length }})
+ Uploads processados assincronamente
+
+
+
+
+ @if (img.isPrimary) {
+
+ {{ productName() || 'Produto sem nome' }} @if (internal_code()) {
+
+ (SKU: {{ internal_code() }})
+
+ }
+
+