@haus-tech/product-import-export-plugin 2.2.0-dev.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/dist/api/plugin.controller.d.ts +8 -0
  2. package/dist/api/plugin.controller.js +49 -0
  3. package/dist/api/product-export.controller.d.ts +14 -0
  4. package/dist/api/product-export.controller.js +117 -0
  5. package/dist/api/product-import.controller.d.ts +11 -0
  6. package/dist/api/product-import.controller.js +62 -0
  7. package/dist/constants.d.ts +2 -0
  8. package/dist/constants.js +5 -0
  9. package/dist/helpers/generate-asset-hash.d.ts +2 -0
  10. package/dist/helpers/generate-asset-hash.js +15 -0
  11. package/dist/helpers/normalize-string.d.ts +1 -0
  12. package/dist/helpers/normalize-string.js +16 -0
  13. package/dist/helpers/remove-update-at-fields.d.ts +5 -0
  14. package/dist/helpers/remove-update-at-fields.js +19 -0
  15. package/dist/index.d.ts +1 -0
  16. package/dist/index.js +17 -0
  17. package/dist/product-import-export.plugin.d.ts +13 -0
  18. package/dist/product-import-export.plugin.js +153 -0
  19. package/dist/providers/import-providers/asset-importer.d.ts +27 -0
  20. package/dist/providers/import-providers/asset-importer.js +127 -0
  21. package/dist/providers/import-providers/import-parser.d.ts +137 -0
  22. package/dist/providers/import-providers/import-parser.js +600 -0
  23. package/dist/providers/import-providers/product-importer.d.ts +47 -0
  24. package/dist/providers/import-providers/product-importer.js +729 -0
  25. package/dist/services/extended-fast-importer.service.d.ts +41 -0
  26. package/dist/services/extended-fast-importer.service.js +418 -0
  27. package/dist/services/product-export.service.d.ts +23 -0
  28. package/dist/services/product-export.service.js +340 -0
  29. package/dist/services/product-import.service.d.ts +21 -0
  30. package/dist/services/product-import.service.js +83 -0
  31. package/dist/types.d.ts +40 -0
  32. package/dist/types.js +2 -0
  33. package/dist/ui/components/export-dialog.component.d.ts +43 -0
  34. package/dist/ui/components/export-dialog.component.html +78 -0
  35. package/dist/ui/components/export-dialog.component.js +108 -0
  36. package/dist/ui/components/export-dialog.component.ts +142 -0
  37. package/dist/ui/components/product-import.component.d.ts +55 -0
  38. package/dist/ui/components/product-import.component.html +76 -0
  39. package/dist/ui/components/product-import.component.js +398 -0
  40. package/dist/ui/components/product-import.component.ts +528 -0
  41. package/dist/ui/product-export.service.d.ts +14 -0
  42. package/dist/ui/product-export.service.js +107 -0
  43. package/dist/ui/product-export.service.ts +107 -0
  44. package/dist/ui/providers.d.ts +2 -0
  45. package/dist/ui/providers.js +49 -0
  46. package/dist/ui/providers.ts +57 -0
  47. package/dist/ui/routes.d.ts +29 -0
  48. package/dist/ui/routes.js +12 -0
  49. package/dist/ui/routes.ts +11 -0
  50. package/dist/ui/translations/en.json +44 -0
  51. package/dist/ui/translations/sv.json +44 -0
  52. package/package.json +30 -0
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.ExportDialogComponent = void 0;
13
+ const core_1 = require("@angular/core");
14
+ const forms_1 = require("@angular/forms");
15
+ const core_2 = require("@vendure/admin-ui/core");
16
+ const lodash_1 = require("lodash");
17
+ let ExportDialogComponent = class ExportDialogComponent {
18
+ fileNameElement;
19
+ resolveWith;
20
+ selection = [];
21
+ fileName = '';
22
+ customFields = [];
23
+ selectedFields = [];
24
+ exportAssetsAs = 'url';
25
+ selectedExportFields = [];
26
+ availableExportFields = [
27
+ 'productId',
28
+ 'name',
29
+ 'slug',
30
+ 'description',
31
+ 'assets',
32
+ 'facets',
33
+ 'optionGroups',
34
+ 'sku',
35
+ 'optionValues',
36
+ 'price',
37
+ 'taxCategory',
38
+ 'stockOnHand',
39
+ 'trackInventory',
40
+ 'variantAssets',
41
+ 'variantFacets',
42
+ ];
43
+ config;
44
+ ngOnInit() {
45
+ this.selectedFields = [...this.customFields];
46
+ if (this.config.defaultExportAssetsAs?.includes(this.config.defaultExportAssetsAs)) {
47
+ this.exportAssetsAs = this.config.defaultExportAssetsAs;
48
+ }
49
+ else {
50
+ this.exportAssetsAs = this.config.exportAssetsAsOptions?.[0] || 'url';
51
+ }
52
+ this.selectedExportFields = (0, lodash_1.uniq)([
53
+ ...(this.config.defaultExportFields || []),
54
+ ...(this.config.requiredExportFields || []),
55
+ ]);
56
+ }
57
+ ngAfterViewInit() {
58
+ if (this.fileNameElement) {
59
+ setTimeout(() => {
60
+ this.fileNameElement.nativeElement.focus();
61
+ }, 0);
62
+ }
63
+ }
64
+ export() {
65
+ this.fileName = this.fileName?.trim();
66
+ this.resolveWith({
67
+ result: true,
68
+ fileName: this.fileName,
69
+ selectedFields: this.selectedFields,
70
+ exportAssetsAs: this.exportAssetsAs,
71
+ selectedExportFields: this.selectedExportFields,
72
+ });
73
+ }
74
+ cancel() {
75
+ this.resolveWith({ result: false });
76
+ }
77
+ toggleFieldSelection(fieldName) {
78
+ const index = this.selectedFields.indexOf(fieldName);
79
+ if (index > -1) {
80
+ this.selectedFields.splice(index, 1);
81
+ }
82
+ else {
83
+ this.selectedFields.push(fieldName);
84
+ }
85
+ }
86
+ toggleExportFieldSelection(fieldName) {
87
+ const index = this.selectedExportFields.indexOf(fieldName);
88
+ if (index > -1) {
89
+ this.selectedExportFields.splice(index, 1);
90
+ }
91
+ else {
92
+ this.selectedExportFields.push(fieldName);
93
+ }
94
+ }
95
+ };
96
+ __decorate([
97
+ (0, core_1.ViewChild)('fileNameInput', { static: false }),
98
+ __metadata("design:type", core_1.ElementRef)
99
+ ], ExportDialogComponent.prototype, "fileNameElement", void 0);
100
+ ExportDialogComponent = __decorate([
101
+ (0, core_1.Component)({
102
+ selector: 'vdr-export-dialog',
103
+ templateUrl: './export-dialog.component.html',
104
+ standalone: true,
105
+ imports: [core_2.SharedModule, forms_1.FormsModule],
106
+ })
107
+ ], ExportDialogComponent);
108
+ exports.ExportDialogComponent = ExportDialogComponent;
@@ -0,0 +1,142 @@
1
+ import { Component, ViewChild, ElementRef, AfterViewInit, OnInit } from '@angular/core'
2
+ import { Dialog } from '@vendure/admin-ui/core'
3
+ import { FormsModule } from '@angular/forms'
4
+ import { SharedModule } from '@vendure/admin-ui/core'
5
+ import { uniq } from 'lodash'
6
+
7
+ type ProductFields =
8
+ | 'productId'
9
+ | 'name'
10
+ | 'slug'
11
+ | 'description'
12
+ | 'assets'
13
+ | 'facets'
14
+ | 'optionGroups'
15
+
16
+ type VariantFields =
17
+ | 'sku'
18
+ | 'optionValues'
19
+ | 'price'
20
+ | 'taxCategory'
21
+ | 'stockOnHand'
22
+ | 'trackInventory'
23
+ | 'variantAssets'
24
+ | 'variantFacets'
25
+
26
+ type ExportFields = Array<ProductFields | VariantFields>
27
+ interface PluginInitOptions {
28
+ defaultFileName?: string
29
+ exportAssetsAsOptions?: Array<'url' | 'json'>
30
+ defaultExportAssetsAs?: 'url' | 'json'
31
+ defaultExportFields?: ExportFields
32
+ requiredExportFields?: ExportFields
33
+ }
34
+
35
+ @Component({
36
+ selector: 'vdr-export-dialog',
37
+ templateUrl: './export-dialog.component.html',
38
+ standalone: true,
39
+ imports: [SharedModule, FormsModule],
40
+ })
41
+ export class ExportDialogComponent
42
+ implements
43
+ Dialog<{
44
+ result: boolean
45
+ fileName?: string
46
+ selectedFields?: string[]
47
+ exportAssetsAs?: 'url' | 'json'
48
+ selectedExportFields?: ExportFields
49
+ }>,
50
+ AfterViewInit,
51
+ OnInit
52
+ {
53
+ @ViewChild('fileNameInput', { static: false }) fileNameElement: ElementRef<HTMLInputElement>
54
+
55
+ resolveWith: (result?: {
56
+ result: boolean
57
+ fileName?: string
58
+ selectedFields?: string[]
59
+ exportAssetsAs?: 'url' | 'json'
60
+ selectedExportFields?: ExportFields
61
+ }) => void
62
+ selection: any[] = []
63
+ fileName: string = ''
64
+ customFields: string[] = []
65
+ selectedFields: string[] = []
66
+ exportAssetsAs: 'url' | 'json' = 'url'
67
+ selectedExportFields: ExportFields = []
68
+ availableExportFields: ExportFields = [
69
+ 'productId',
70
+ 'name',
71
+ 'slug',
72
+ 'description',
73
+ 'assets',
74
+ 'facets',
75
+ 'optionGroups',
76
+ 'sku',
77
+ 'optionValues',
78
+ 'price',
79
+ 'taxCategory',
80
+ 'stockOnHand',
81
+ 'trackInventory',
82
+ 'variantAssets',
83
+ 'variantFacets',
84
+ ]
85
+
86
+ config: PluginInitOptions
87
+
88
+ ngOnInit(): void {
89
+ this.selectedFields = [...this.customFields]
90
+ if (this.config.defaultExportAssetsAs?.includes(this.config.defaultExportAssetsAs)) {
91
+ this.exportAssetsAs = this.config.defaultExportAssetsAs
92
+ } else {
93
+ this.exportAssetsAs = this.config.exportAssetsAsOptions?.[0] || 'url'
94
+ }
95
+
96
+ this.selectedExportFields = uniq([
97
+ ...(this.config.defaultExportFields || []),
98
+ ...(this.config.requiredExportFields || []),
99
+ ])
100
+ }
101
+
102
+ ngAfterViewInit(): void {
103
+ if (this.fileNameElement) {
104
+ setTimeout(() => {
105
+ this.fileNameElement.nativeElement.focus()
106
+ }, 0)
107
+ }
108
+ }
109
+
110
+ export() {
111
+ this.fileName = this.fileName?.trim()
112
+ this.resolveWith({
113
+ result: true,
114
+ fileName: this.fileName,
115
+ selectedFields: this.selectedFields,
116
+ exportAssetsAs: this.exportAssetsAs,
117
+ selectedExportFields: this.selectedExportFields,
118
+ })
119
+ }
120
+
121
+ cancel() {
122
+ this.resolveWith({ result: false })
123
+ }
124
+
125
+ toggleFieldSelection(fieldName: string) {
126
+ const index = this.selectedFields.indexOf(fieldName)
127
+ if (index > -1) {
128
+ this.selectedFields.splice(index, 1)
129
+ } else {
130
+ this.selectedFields.push(fieldName)
131
+ }
132
+ }
133
+
134
+ toggleExportFieldSelection(fieldName: ProductFields | VariantFields) {
135
+ const index = this.selectedExportFields.indexOf(fieldName)
136
+ if (index > -1) {
137
+ this.selectedExportFields.splice(index, 1)
138
+ } else {
139
+ this.selectedExportFields.push(fieldName)
140
+ }
141
+ }
142
+ }
@@ -0,0 +1,55 @@
1
+ import { ElementRef, ChangeDetectorRef, OnInit } from '@angular/core';
2
+ import { NotificationService, LocalStorageService } from '@vendure/admin-ui/core';
3
+ import { TranslateService } from '@ngx-translate/core';
4
+ import { AdminUiConfig } from '@vendure/common/lib/shared-types';
5
+ import { Channel, LanguageCode } from '@vendure/core';
6
+ type ImportOptions = {
7
+ updateProductSlug?: string;
8
+ };
9
+ type ValidateReturnType = {
10
+ isValid: boolean;
11
+ langCodes?: (string | undefined)[];
12
+ clearFile?: boolean;
13
+ };
14
+ export interface PluginInitOptions {
15
+ visibleOptions?: Array<keyof ImportOptions>;
16
+ defaultOptions?: ImportOptions;
17
+ }
18
+ export declare class ProductImportComponent implements OnInit {
19
+ private notificationService;
20
+ private cd;
21
+ private translate;
22
+ private localStorageService;
23
+ serverPath: string;
24
+ validateFile: File | null;
25
+ selectedFile: File | null;
26
+ updateProductSlug: boolean;
27
+ selectedMainLanguage: LanguageCode | undefined;
28
+ availableLanguages: LanguageCode[];
29
+ fileUploadElement: ElementRef<HTMLInputElement>;
30
+ config: PluginInitOptions;
31
+ appConfig: AdminUiConfig;
32
+ currentChannel: Channel;
33
+ constructor(notificationService: NotificationService, cd: ChangeDetectorRef, translate: TranslateService, localStorageService: LocalStorageService);
34
+ ngOnInit(): Promise<void>;
35
+ doValidation(file: File): void;
36
+ onMainLanguageChange(): void;
37
+ onFileSelected(event: Event): void;
38
+ clearFile(): void;
39
+ validateCsvStructure(file: File): Promise<ValidateReturnType>;
40
+ uploadFile(): Promise<void>;
41
+ splitLines(text: string): string[];
42
+ checkifJson(text: string): {
43
+ startsWithJson: boolean;
44
+ endsWithJson: boolean;
45
+ startChar: string;
46
+ endChar: string;
47
+ isJson?: boolean;
48
+ };
49
+ getRequestHeaders(): Record<string, string>;
50
+ checkTranslatabeColumns(lines: string[], columns: string[], header: string[], languageCodes: (string | undefined)[]): {
51
+ errorRows: number[];
52
+ errorColumns: string[];
53
+ };
54
+ }
55
+ export {};
@@ -0,0 +1,76 @@
1
+ <!-- product-import.component.html -->
2
+ <vdr-page-block>
3
+ <vdr-card [title]="'product-import.card.title' | translate">
4
+ <div class="form-grid">
5
+ <vdr-form-field [label]="'product-import.card.description' | translate">
6
+ <input type="file" (change)="onFileSelected($event)" class="file-input" #fileUpload />
7
+
8
+ <div class="file-upload" style="display: flex; align-items: center; gap: 8px">
9
+ <button *ngIf="selectedFile" class="button-small" (click)="fileUpload.click()">
10
+ <clr-icon shape="file"></clr-icon>
11
+ {{ selectedFile?.name }}
12
+ </button>
13
+
14
+ <button class="button primary" *ngIf="!selectedFile" (click)="fileUpload.click()">
15
+ {{ 'product-import.card.button-select' | translate }}
16
+ </button>
17
+ <button
18
+ class="button primary"
19
+ *ngIf="selectedFile"
20
+ (click)="uploadFile()"
21
+ [disabled]="!selectedMainLanguage"
22
+ >
23
+ {{ 'product-import.card.button-upload' | translate }}
24
+ </button>
25
+ </div>
26
+ </vdr-form-field>
27
+ </div>
28
+ <div class="form-grid" *ngIf="selectedFile">
29
+ <div
30
+ class="input-row"
31
+ style="margin-top: 16px"
32
+ *ngIf="config.visibleOptions?.includes('updateProductSlug')"
33
+ >
34
+ <label>
35
+ <input
36
+ type="checkBox"
37
+ name="updateProductSlug"
38
+ value="url"
39
+ [(ngModel)]="updateProductSlug"
40
+ style="width: fit-content"
41
+ />
42
+ {{ 'product-import.card.update-product-slugs' | translate }}
43
+ </label>
44
+ </div>
45
+
46
+ <div class="input-row" style="margin-top: 16px">
47
+ <div>Välj huvudspråk för filen:</div>
48
+ <div *ngFor="let lang of availableLanguages">
49
+ <label>
50
+ <input
51
+ type="radio"
52
+ name="selectedMainLanguage"
53
+ [value]="lang"
54
+ [(ngModel)]="selectedMainLanguage"
55
+ style="width: fit-content"
56
+ (change)="onMainLanguageChange(lang)"
57
+ />
58
+ {{ lang }}
59
+ </label>
60
+ </div>
61
+ </div>
62
+ </div>
63
+ </vdr-card>
64
+ </vdr-page-block>
65
+
66
+ <style>
67
+ .form-grid {
68
+ display: grid;
69
+ grid-template-columns: 1fr 1fr;
70
+ grid-gap: 1rem;
71
+ }
72
+
73
+ .file-input {
74
+ display: none;
75
+ }
76
+ </style>