@postxl/generators 1.13.0 → 1.15.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 (117) hide show
  1. package/dist/backend-authentication/generators/authentication-service.generator.js +1 -1
  2. package/dist/backend-core/backend.generator.js +0 -4
  3. package/dist/backend-core/backend.generator.js.map +1 -1
  4. package/dist/backend-core/modules/backend-module-xlport.generator.js +1 -1
  5. package/dist/backend-excel-io/excel-io.generator.d.ts +19 -0
  6. package/dist/backend-excel-io/excel-io.generator.js +106 -0
  7. package/dist/backend-excel-io/excel-io.generator.js.map +1 -0
  8. package/dist/backend-excel-io/generators/excel-io-service.generator.d.ts +9 -0
  9. package/dist/backend-excel-io/generators/excel-io-service.generator.js +680 -0
  10. package/dist/backend-excel-io/generators/excel-io-service.generator.js.map +1 -0
  11. package/dist/backend-excel-io/index.d.ts +2 -0
  12. package/dist/backend-excel-io/index.js +22 -0
  13. package/dist/backend-excel-io/index.js.map +1 -0
  14. package/dist/backend-excel-io/template/README.md +24 -0
  15. package/dist/backend-excel-io/template/excel-io.controller.ts +195 -0
  16. package/dist/backend-excel-io/template/excel-io.module.ts +17 -0
  17. package/dist/backend-import/generators/detect-delta/detect-delta-functions.generator.js +148 -13
  18. package/dist/backend-import/generators/detect-delta/detect-delta-functions.generator.js.map +1 -1
  19. package/dist/backend-import/generators/filter-error-rows.generator.d.ts +2 -0
  20. package/dist/backend-import/generators/filter-error-rows.generator.js +28 -0
  21. package/dist/backend-import/generators/filter-error-rows.generator.js.map +1 -0
  22. package/dist/backend-import/generators/import-service.generator.js +126 -2
  23. package/dist/backend-import/generators/import-service.generator.js.map +1 -1
  24. package/dist/backend-import/import.generator.js +2 -0
  25. package/dist/backend-import/import.generator.js.map +1 -1
  26. package/dist/backend-repositories/generators/model-repository.generator.js +17 -2
  27. package/dist/backend-repositories/generators/model-repository.generator.js.map +1 -1
  28. package/dist/backend-router-trpc/generators/app-routes.generator.js +5 -0
  29. package/dist/backend-router-trpc/generators/app-routes.generator.js.map +1 -1
  30. package/dist/backend-router-trpc/generators/excel-io-route.generator.d.ts +4 -0
  31. package/dist/backend-router-trpc/generators/excel-io-route.generator.js +35 -0
  32. package/dist/backend-router-trpc/generators/excel-io-route.generator.js.map +1 -0
  33. package/dist/backend-router-trpc/generators/trpc-plugin.generator.js +6 -0
  34. package/dist/backend-router-trpc/generators/trpc-plugin.generator.js.map +1 -1
  35. package/dist/backend-router-trpc/generators/trpc-router-module.generator.js +8 -1
  36. package/dist/backend-router-trpc/generators/trpc-router-module.generator.js.map +1 -1
  37. package/dist/backend-router-trpc/generators/trpc-shared.generator.js +9 -0
  38. package/dist/backend-router-trpc/generators/trpc-shared.generator.js.map +1 -1
  39. package/dist/backend-router-trpc/router-trpc.generator.d.ts +2 -1
  40. package/dist/backend-router-trpc/router-trpc.generator.js +4 -0
  41. package/dist/backend-router-trpc/router-trpc.generator.js.map +1 -1
  42. package/dist/backend-update/model-update-service.generator.js +54 -0
  43. package/dist/backend-update/model-update-service.generator.js.map +1 -1
  44. package/dist/backend-update/update-actions.decoders.d.ts +2 -0
  45. package/dist/backend-update/update-actions.decoders.js +2 -0
  46. package/dist/backend-update/update-actions.decoders.js.map +1 -1
  47. package/dist/backend-update/update.generator.js +6 -0
  48. package/dist/backend-update/update.generator.js.map +1 -1
  49. package/dist/base/base.generator.js +0 -4
  50. package/dist/base/base.generator.js.map +1 -1
  51. package/dist/decoders/datamodel-decoder.generator.js +91 -1
  52. package/dist/decoders/datamodel-decoder.generator.js.map +1 -1
  53. package/dist/decoders/decoders.generator.d.ts +9 -0
  54. package/dist/decoders/decoders.generator.js +15 -0
  55. package/dist/decoders/decoders.generator.js.map +1 -1
  56. package/dist/decoders/discriminated-union.decoder.generator.js +4 -3
  57. package/dist/decoders/discriminated-union.decoder.generator.js.map +1 -1
  58. package/dist/devops/devops.generator.d.ts +5 -1
  59. package/dist/devops/devops.generator.js +5 -4
  60. package/dist/devops/devops.generator.js.map +1 -1
  61. package/dist/devops/generators/docker-compose-yml.generator.d.ts +1 -1
  62. package/dist/devops/generators/docker-compose-yml.generator.js +16 -1
  63. package/dist/devops/generators/docker-compose-yml.generator.js.map +1 -1
  64. package/dist/e2e/template/e2e/specs/example.spec.ts-snapshots/Navigate-to-homepage-and-take-snapshot-1-chromium-linux.png +0 -0
  65. package/dist/frontend-actions/generators/filter-utils.generator.js +1 -1
  66. package/dist/frontend-admin/admin.generator.d.ts +2 -0
  67. package/dist/frontend-admin/admin.generator.js +28 -0
  68. package/dist/frontend-admin/admin.generator.js.map +1 -1
  69. package/dist/frontend-admin/generators/admin-global-actions.generator.js +78 -0
  70. package/dist/frontend-admin/generators/admin-global-actions.generator.js.map +1 -1
  71. package/dist/frontend-admin/generators/admin-overview-page.generator.js +21 -1
  72. package/dist/frontend-admin/generators/admin-overview-page.generator.js.map +1 -1
  73. package/dist/frontend-admin/generators/admin-sidebar.generator.js +20 -0
  74. package/dist/frontend-admin/generators/admin-sidebar.generator.js.map +1 -1
  75. package/dist/frontend-admin/generators/excel-io-page.generator.d.ts +4 -0
  76. package/dist/frontend-admin/generators/excel-io-page.generator.js +258 -0
  77. package/dist/frontend-admin/generators/excel-io-page.generator.js.map +1 -0
  78. package/dist/frontend-admin/generators/import-review-page-result-stage.generator.d.ts +1 -0
  79. package/dist/frontend-admin/generators/import-review-page-result-stage.generator.js +104 -0
  80. package/dist/frontend-admin/generators/import-review-page-result-stage.generator.js.map +1 -0
  81. package/dist/frontend-admin/generators/import-review-page-review-stage.generator.d.ts +1 -0
  82. package/dist/frontend-admin/generators/import-review-page-review-stage.generator.js +1031 -0
  83. package/dist/frontend-admin/generators/import-review-page-review-stage.generator.js.map +1 -0
  84. package/dist/frontend-admin/generators/import-review-page-upload-stage.generator.d.ts +1 -0
  85. package/dist/frontend-admin/generators/import-review-page-upload-stage.generator.js +77 -0
  86. package/dist/frontend-admin/generators/import-review-page-upload-stage.generator.js.map +1 -0
  87. package/dist/frontend-admin/generators/import-review-page.generator.d.ts +7 -0
  88. package/dist/frontend-admin/generators/import-review-page.generator.js +180 -0
  89. package/dist/frontend-admin/generators/import-review-page.generator.js.map +1 -0
  90. package/dist/frontend-admin/generators/model-admin-page.generator.js +60 -56
  91. package/dist/frontend-admin/generators/model-admin-page.generator.js.map +1 -1
  92. package/dist/frontend-admin/utils.js +25 -33
  93. package/dist/frontend-admin/utils.js.map +1 -1
  94. package/dist/frontend-core/frontend.generator.js +1 -2
  95. package/dist/frontend-core/frontend.generator.js.map +1 -1
  96. package/dist/frontend-core/template/src/components/admin/excel-io-actions.tsx +64 -0
  97. package/dist/frontend-core/template/src/components/admin/table-view-panel.tsx +41 -3
  98. package/dist/frontend-core/template/src/hooks/use-excel-io.ts +137 -0
  99. package/dist/frontend-core/template/src/hooks/use-import-review.ts +143 -0
  100. package/dist/frontend-core/template/src/lib/excel-download.ts +28 -0
  101. package/dist/frontend-core/types/hook.d.ts +1 -1
  102. package/dist/frontend-tables/generators/model-table.generator.js +21 -13
  103. package/dist/frontend-tables/generators/model-table.generator.js.map +1 -1
  104. package/dist/frontend-trpc-client/generators/model-hook.generator.js +4 -0
  105. package/dist/frontend-trpc-client/generators/model-hook.generator.js.map +1 -1
  106. package/dist/frontend-trpc-client/trpc-client.generator.d.ts +4 -0
  107. package/dist/frontend-trpc-client/trpc-client.generator.js +1 -0
  108. package/dist/frontend-trpc-client/trpc-client.generator.js.map +1 -1
  109. package/dist/generators.js +2 -0
  110. package/dist/generators.js.map +1 -1
  111. package/dist/index.d.ts +1 -0
  112. package/dist/index.js +5 -2
  113. package/dist/index.js.map +1 -1
  114. package/dist/seed-data/seed-data.generator.d.ts +3 -0
  115. package/dist/seed-data/seed-data.generator.js +45 -1
  116. package/dist/seed-data/seed-data.generator.js.map +1 -1
  117. package/package.json +3 -3
@@ -50,6 +50,18 @@ function generateAdminGlobalActions({ context }) {
50
50
  .addImport({
51
51
  from: Generator.toBackendModuleLocation('@app-actions/command-palette-store'),
52
52
  items: [Generator.toFunctionName('useCommandPaletteActions')],
53
+ })
54
+ .addImport({
55
+ from: Generator.toBackendModuleLocation('@lib/config'),
56
+ items: [Generator.toConstantName('APP_CONFIG')],
57
+ })
58
+ .addImport({
59
+ from: Generator.toBackendModuleLocation('@context-providers/auth-context-provider'),
60
+ items: [Generator.toFunctionName('getAuthHeaders')],
61
+ })
62
+ .addImport({
63
+ from: Generator.toBackendModuleLocation('@lib/excel-download'),
64
+ items: [Generator.toFunctionName('downloadBlob'), Generator.toFunctionName('getFilenameFromContentDisposition')],
53
65
  });
54
66
  const { schemas: sortedSchemas, modelsBySchema } = (0, utils_1.groupAndSortModelsBySchema)(context);
55
67
  const createActions = sortedSchemas
@@ -102,7 +114,33 @@ function generateAdminGlobalActions({ context }) {
102
114
  .join(',\n');
103
115
  })
104
116
  .join(',\n');
117
+ const exportActions = sortedSchemas
118
+ .map((schema) => {
119
+ const models = modelsBySchema.get(schema) ?? [];
120
+ return models
121
+ .map((model) => {
122
+ const endpoint = model.route.split('/').findLast(Boolean) ?? model.name.toLowerCase();
123
+ const fallbackFilename = `${endpoint}.xlsx`;
124
+ return `
125
+ command({
126
+ key: 'export-admin-${model.name.toLowerCase()}-excel',
127
+ visibility: 'visible',
128
+ group: 'Export',
129
+ label: 'Export: ${model.userFriendlyName} (Excel)',
130
+ keywords: ['export', 'excel', '${model.name.toLowerCase()}', '${model.userFriendlyName.toLowerCase()}'],
131
+ run: async () => {
132
+ await downloadFromExcelIo('export/${endpoint}', '${fallbackFilename}')
133
+ await waitForNextFrame()
134
+ return { kind: 'close' }
135
+ },
136
+ })
137
+ `;
138
+ })
139
+ .join(',\n');
140
+ })
141
+ .join(',\n');
105
142
  const dynamicActions = [createActions, modelActions].filter((value) => value.trim().length > 0).join(',\n');
143
+ const adminDynamicActions = [exportActions].filter((value) => value.trim().length > 0).join(',\n');
106
144
  return `
107
145
  ${imports.generate()}
108
146
 
@@ -111,6 +149,21 @@ export const useAdminGlobalActions = () => {
111
149
  const { registerGlobalActions } = useCommandPaletteActions()
112
150
 
113
151
  useEffect(() => {
152
+ const downloadFromExcelIo = async (endpoint: string, fallbackFilename: string) => {
153
+ const response = await fetch(\`${'${APP_CONFIG.apiURL}'}/excel-io/${'${endpoint}'}\`, {
154
+ headers: getAuthHeaders(),
155
+ credentials: 'include',
156
+ })
157
+
158
+ if (!response.ok) {
159
+ throw new Error(\`Request failed with status ${'${response.status}'}\`)
160
+ }
161
+
162
+ const blob = await response.blob()
163
+ const filename = getFilenameFromContentDisposition(response.headers.get('Content-Disposition'), fallbackFilename)
164
+ downloadBlob(blob, filename)
165
+ }
166
+
114
167
  const actions = [
115
168
  command({
116
169
  key: 'navigate-admin-overview',
@@ -141,6 +194,31 @@ export const useAdminGlobalActions = () => {
141
194
  return { kind: 'close' }
142
195
  },
143
196
  }),
197
+ command({
198
+ key: 'navigate-admin-excel-io',
199
+ visibility: 'visible',
200
+ group: 'Navigate',
201
+ label: 'Admin: Excel I/O',
202
+ keywords: ['admin', 'import', 'export', 'excel'],
203
+ run: async () => {
204
+ await navigate({ to: '/admin/excel-io' })
205
+ await waitForNextFrame()
206
+ return { kind: 'close' }
207
+ },
208
+ }),
209
+ command({
210
+ key: 'export-admin-all-models-excel',
211
+ visibility: 'visible',
212
+ group: 'Export',
213
+ label: 'Export: All models (Excel)',
214
+ keywords: ['export', 'excel', 'all', 'models'],
215
+ run: async () => {
216
+ await downloadFromExcelIo('export/all', 'all-models.xlsx')
217
+ await waitForNextFrame()
218
+ return { kind: 'close' }
219
+ },
220
+ }),
221
+ ${adminDynamicActions}
144
222
  )
145
223
  }
146
224
 
@@ -1 +1 @@
1
- {"version":3,"file":"admin-global-actions.generator.js","sourceRoot":"","sources":["../../../src/frontend-admin/generators/admin-global-actions.generator.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAKA,gEAqHC;AA1HD,6DAA8C;AAG9C,oCAAqD;AAErD,SAAgB,0BAA0B,CAAC,EAAE,OAAO,EAA8B;IAChF,MAAM,OAAO,GAAG,SAAS,CAAC,eAAe,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,4BAA4B,CAAC,CAAC;SAC/F,SAAS,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,CAAC,SAAS,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC;SACrG,SAAS,CAAC;QACT,IAAI,EAAE,SAAS,CAAC,aAAa,CAAC,wBAAwB,CAAC;QACvD,KAAK,EAAE,CAAC,SAAS,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC;KACjD,CAAC;SACD,SAAS,CAAC;QACT,IAAI,EAAE,SAAS,CAAC,uBAAuB,CAAC,qCAAqC,CAAC;QAC9E,KAAK,EAAE,CAAC,SAAS,CAAC,cAAc,CAAC,SAAS,CAAC,EAAE,SAAS,CAAC,cAAc,CAAC,kBAAkB,CAAC,CAAC;KAC3F,CAAC;SACD,SAAS,CAAC;QACT,IAAI,EAAE,SAAS,CAAC,uBAAuB,CAAC,oCAAoC,CAAC;QAC7E,KAAK,EAAE,CAAC,SAAS,CAAC,cAAc,CAAC,0BAA0B,CAAC,CAAC;KAC9D,CAAC,CAAA;IAEJ,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,GAAG,IAAA,kCAA0B,EAAC,OAAO,CAAC,CAAA;IAEtF,MAAM,aAAa,GAAG,aAAa;SAChC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;QACd,MAAM,MAAM,GAAG,CAAC,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAA;QACtF,OAAO,MAAM;aACV,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;YACb,OAAO;;mCAEkB,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE;;;mCAGxB,KAAK,CAAC,gBAAgB;6CACZ,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,OAAO,KAAK,CAAC,gBAAgB,CAAC,WAAW,EAAE;;;kFAG9B,KAAK,CAAC,IAAI;sGACU,KAAK,CAAC,IAAI;;wCAExE,KAAK,CAAC,KAAK;;;;;WAKxC,CAAA;QACH,CAAC,CAAC;aACD,IAAI,CAAC,KAAK,CAAC,CAAA;IAChB,CAAC,CAAC;SACD,IAAI,CAAC,KAAK,CAAC,CAAA;IAEd,MAAM,YAAY,GAAG,aAAa;SAC/B,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;QACd,MAAM,MAAM,GAAG,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAA;QAC/C,OAAO,MAAM;aACV,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;YACb,OAAO;;qCAEoB,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE;;;+BAG9B,KAAK,CAAC,gBAAgB;qCAChB,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,OAAO,KAAK,CAAC,gBAAgB,CAAC,WAAW,EAAE;;wCAEhE,KAAK,CAAC,KAAK;;;;;WAKxC,CAAA;QACH,CAAC,CAAC;aACD,IAAI,CAAC,KAAK,CAAC,CAAA;IAChB,CAAC,CAAC;SACD,IAAI,CAAC,KAAK,CAAC,CAAA;IAEd,MAAM,cAAc,GAAG,CAAC,aAAa,EAAE,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IAE3G,OAAO;EACP,OAAO,CAAC,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;QAoBZ,cAAc;;;;;;;;;;;;;;;;;;;;;;;CAuBrB,CAAA;AACD,CAAC"}
1
+ {"version":3,"file":"admin-global-actions.generator.js","sourceRoot":"","sources":["../../../src/frontend-admin/generators/admin-global-actions.generator.ts"],"names":[],"mappings":"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"}
@@ -82,7 +82,7 @@ export default function AdminOverviewPage() {
82
82
  </p>
83
83
 
84
84
  ${schemaSections}
85
- {import.meta.env.NEXT_PUBLIC_ALLOW_ADMIN === 'true' && (
85
+ {import.meta.env.VITE_PUBLIC_ALLOW_ADMIN === 'true' && (
86
86
  <section key="Advanced" className="mb-8">
87
87
  <h2 className="text-2xl font-bold mb-4 pb-2 border-b border-gray-200 dark:border-gray-700">
88
88
  Advanced (Dev Only)
@@ -98,6 +98,26 @@ export default function AdminOverviewPage() {
98
98
  Advanced import/export tools for database management
99
99
  </p>
100
100
  </Link>
101
+ <Link
102
+ key="ExcelIo"
103
+ to="/admin/excel-io"
104
+ className="block p-6 bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700 rounded-lg hover:shadow-lg hover:border-blue-500 dark:hover:border-blue-400 transition-all"
105
+ >
106
+ <h3 className="text-lg font-semibold mb-2">Excel I/O</h3>
107
+ <p className="text-sm text-gray-600 dark:text-gray-400">
108
+ Export all or per-model Excel files, and import Excel with delta handling
109
+ </p>
110
+ </Link>
111
+ <Link
112
+ key="ImportReview"
113
+ to="/admin/import-review"
114
+ className="block p-6 bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700 rounded-lg hover:shadow-lg hover:border-blue-500 dark:hover:border-blue-400 transition-all"
115
+ >
116
+ <h3 className="text-lg font-semibold mb-2">Import Review</h3>
117
+ <p className="text-sm text-gray-600 dark:text-gray-400">
118
+ Upload Excel files and review changes before applying them
119
+ </p>
120
+ </Link>
101
121
  </div>
102
122
  </section>
103
123
  )}
@@ -1 +1 @@
1
- {"version":3,"file":"admin-overview-page.generator.js","sourceRoot":"","sources":["../../../src/frontend-admin/generators/admin-overview-page.generator.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAQA,8DAyEC;AAjFD,6DAA8C;AAG9C,oCAAqD;AAErD;;GAEG;AACH,SAAgB,yBAAyB,CAAC,EAAE,OAAO,EAA8B;IAC/E,MAAM,OAAO,GAAG,SAAS,CAAC,eAAe;QACvC,EAAE;SACD,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAA;IAE5D,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,GAAG,IAAA,kCAA0B,EAAC,OAAO,CAAC,CAAA;IAEtF,+BAA+B;IAC/B,MAAM,cAAc,GAAG,aAAa;SACjC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;QACd,MAAM,MAAM,GAAG,cAAc,CAAC,GAAG,CAAC,MAAM,CAAE,CAAA;QAC1C,MAAM,UAAU,GAAG,MAAM;aACtB,GAAG,CACF,CAAC,KAAK,EAAE,EAAE,CAAC;;qBAEA,KAAK,CAAC,IAAI;oBACX,KAAK,CAAC,KAAK;;;2DAG4B,KAAK,CAAC,gBAAgB;+EACF,KAAK,CAAC,gBAAgB,CAAC,WAAW,EAAE;oBAC/F,CACX;aACA,IAAI,CAAC,EAAE,CAAC,CAAA;QAEX,OAAO;wBACW,MAAM;uGACyE,MAAM;;cAE/F,UAAU;;mBAEL,CAAA;IACf,CAAC,CAAC;SACD,IAAI,CAAC,EAAE,CAAC,CAAA;IAEX,OAAO;;EAEP,OAAO,CAAC,QAAQ,EAAE;;;;;;;;;;;UAWV,cAAc;;;;;;;;;;;;;;;;;;;;;;;;CAwBvB,CAAA;AACD,CAAC"}
1
+ {"version":3,"file":"admin-overview-page.generator.js","sourceRoot":"","sources":["../../../src/frontend-admin/generators/admin-overview-page.generator.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAQA,8DA6FC;AArGD,6DAA8C;AAG9C,oCAAqD;AAErD;;GAEG;AACH,SAAgB,yBAAyB,CAAC,EAAE,OAAO,EAA8B;IAC/E,MAAM,OAAO,GAAG,SAAS,CAAC,eAAe;QACvC,EAAE;SACD,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAA;IAE5D,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,GAAG,IAAA,kCAA0B,EAAC,OAAO,CAAC,CAAA;IAEtF,+BAA+B;IAC/B,MAAM,cAAc,GAAG,aAAa;SACjC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;QACd,MAAM,MAAM,GAAG,cAAc,CAAC,GAAG,CAAC,MAAM,CAAE,CAAA;QAC1C,MAAM,UAAU,GAAG,MAAM;aACtB,GAAG,CACF,CAAC,KAAK,EAAE,EAAE,CAAC;;qBAEA,KAAK,CAAC,IAAI;oBACX,KAAK,CAAC,KAAK;;;2DAG4B,KAAK,CAAC,gBAAgB;+EACF,KAAK,CAAC,gBAAgB,CAAC,WAAW,EAAE;oBAC/F,CACX;aACA,IAAI,CAAC,EAAE,CAAC,CAAA;QAEX,OAAO;wBACW,MAAM;uGACyE,MAAM;;cAE/F,UAAU;;mBAEL,CAAA;IACf,CAAC,CAAC;SACD,IAAI,CAAC,EAAE,CAAC,CAAA;IAEX,OAAO;;EAEP,OAAO,CAAC,QAAQ,EAAE;;;;;;;;;;;UAWV,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4CvB,CAAA;AACD,CAAC"}
@@ -184,6 +184,26 @@ export function AdminSidebar({ ...props }: ComponentProps<typeof Sidebar>) {
184
184
  </Link>
185
185
  </SidebarMenuSubButton>
186
186
  </SidebarMenuSubItem>
187
+ <SidebarMenuSubItem key="ExcelIo">
188
+ <SidebarMenuSubButton asChild>
189
+ <Link
190
+ to="/admin/excel-io"
191
+ className="block px-4 py-2 hover:bg-sidebar-accent rounded transition-colors"
192
+ >
193
+ Excel I/O
194
+ </Link>
195
+ </SidebarMenuSubButton>
196
+ </SidebarMenuSubItem>
197
+ <SidebarMenuSubItem key="ImportReview">
198
+ <SidebarMenuSubButton asChild>
199
+ <Link
200
+ to="/admin/import-review"
201
+ className="block px-4 py-2 hover:bg-sidebar-accent rounded transition-colors"
202
+ >
203
+ Import Review
204
+ </Link>
205
+ </SidebarMenuSubButton>
206
+ </SidebarMenuSubItem>
187
207
  </SidebarMenuSub>
188
208
  </SidebarGroupContent>
189
209
  </CollapseContent>
@@ -1 +1 @@
1
- {"version":3,"file":"admin-sidebar.generator.js","sourceRoot":"","sources":["../../../src/frontend-admin/generators/admin-sidebar.generator.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAQA,oDAqKC;AA7KD,6DAA8C;AAG9C,oCAAqD;AAErD;;GAEG;AACH,SAAgB,oBAAoB,CAAC,EAAE,OAAO,EAA8B;IAC1E,MAAM,OAAO,GAAG,SAAS,CAAC,eAAe;QACvC,EAAE;SACD,IAAI,CAAC,SAAS,CAAC,uBAAuB,CAAC,wBAAwB,CAAC,CAAC;SACjE,SAAS,CAAC;QACT,IAAI,EAAE,SAAS,CAAC,aAAa,CAAC,OAAO,CAAC;QACtC,KAAK,EAAE,CAAC,SAAS,CAAC,cAAc,CAAC,gBAAgB,CAAC,CAAC;KACpD,CAAC;SACD,SAAS,CAAC;QACT,IAAI,EAAE,SAAS,CAAC,aAAa,CAAC,cAAc,CAAC;QAC7C,KAAK,EAAE,CAAC,SAAS,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,SAAS,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;KACpF,CAAC,CAAA;IAEJ,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,GAAG,IAAA,kCAA0B,EAAC,OAAO,CAAC,CAAA;IAEtF,+EAA+E;IAC/E,MAAM,UAAU,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,CAAA;IAEtE,6CAA6C;IAC7C,MAAM,sBAAsB,GAAG,CAAC,GAAG,UAAU,EAAE,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,GAAG,WAAW,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAEvG,+CAA+C;IAC/C,MAAM,yBAAyB,GAAG,CAAC,GAAG,UAAU,EAAE,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,GAAG,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAExG,+BAA+B;IAC/B,MAAM,cAAc,GAAG,aAAa;SACjC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;QACd,MAAM,MAAM,GAAG,cAAc,CAAC,GAAG,CAAC,MAAM,CAAE,CAAA;QAC1C,MAAM,UAAU,GAAG,MAAM;aACtB,GAAG,CACF,CAAC,KAAK,EAAE,EAAE,CAAC;uCACkB,KAAK,CAAC,IAAI;;;wBAGzB,KAAK,CAAC,KAAK;;;oBAGf,KAAK,CAAC,gBAAgB;;;;WAI/B,CACF;aACA,IAAI,CAAC,EAAE,CAAC,CAAA;QAEX,MAAM,SAAS,GAAG,MAAM,CAAC,WAAW,EAAE,CAAA;QACtC,OAAO;wCAC2B,SAAS,4BAA4B,SAAS,oCAAoC,SAAS,UAAU,SAAS;;;;;oBAKlI,MAAM;8GACoF,SAAS;;;;;;;;sBAQjG,UAAU;;;;;oBAKZ,CAAA;IAChB,CAAC,CAAC;SACD,IAAI,CAAC,EAAE,CAAC,CAAA;IAEX,OAAO;;;;;;;;;;;;;;;;;;;;EAoBP,OAAO,CAAC,QAAQ,EAAE;;;;;EAKlB,sBAAsB;;;;EAItB,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;UA4BjB,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqCvB,CAAA;AACD,CAAC"}
1
+ {"version":3,"file":"admin-sidebar.generator.js","sourceRoot":"","sources":["../../../src/frontend-admin/generators/admin-sidebar.generator.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAQA,oDAyLC;AAjMD,6DAA8C;AAG9C,oCAAqD;AAErD;;GAEG;AACH,SAAgB,oBAAoB,CAAC,EAAE,OAAO,EAA8B;IAC1E,MAAM,OAAO,GAAG,SAAS,CAAC,eAAe;QACvC,EAAE;SACD,IAAI,CAAC,SAAS,CAAC,uBAAuB,CAAC,wBAAwB,CAAC,CAAC;SACjE,SAAS,CAAC;QACT,IAAI,EAAE,SAAS,CAAC,aAAa,CAAC,OAAO,CAAC;QACtC,KAAK,EAAE,CAAC,SAAS,CAAC,cAAc,CAAC,gBAAgB,CAAC,CAAC;KACpD,CAAC;SACD,SAAS,CAAC;QACT,IAAI,EAAE,SAAS,CAAC,aAAa,CAAC,cAAc,CAAC;QAC7C,KAAK,EAAE,CAAC,SAAS,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,SAAS,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;KACpF,CAAC,CAAA;IAEJ,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,GAAG,IAAA,kCAA0B,EAAC,OAAO,CAAC,CAAA;IAEtF,+EAA+E;IAC/E,MAAM,UAAU,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,CAAA;IAEtE,6CAA6C;IAC7C,MAAM,sBAAsB,GAAG,CAAC,GAAG,UAAU,EAAE,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,GAAG,WAAW,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAEvG,+CAA+C;IAC/C,MAAM,yBAAyB,GAAG,CAAC,GAAG,UAAU,EAAE,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,GAAG,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAExG,+BAA+B;IAC/B,MAAM,cAAc,GAAG,aAAa;SACjC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;QACd,MAAM,MAAM,GAAG,cAAc,CAAC,GAAG,CAAC,MAAM,CAAE,CAAA;QAC1C,MAAM,UAAU,GAAG,MAAM;aACtB,GAAG,CACF,CAAC,KAAK,EAAE,EAAE,CAAC;uCACkB,KAAK,CAAC,IAAI;;;wBAGzB,KAAK,CAAC,KAAK;;;oBAGf,KAAK,CAAC,gBAAgB;;;;WAI/B,CACF;aACA,IAAI,CAAC,EAAE,CAAC,CAAA;QAEX,MAAM,SAAS,GAAG,MAAM,CAAC,WAAW,EAAE,CAAA;QACtC,OAAO;wCAC2B,SAAS,4BAA4B,SAAS,oCAAoC,SAAS,UAAU,SAAS;;;;;oBAKlI,MAAM;8GACoF,SAAS;;;;;;;;sBAQjG,UAAU;;;;;oBAKZ,CAAA;IAChB,CAAC,CAAC;SACD,IAAI,CAAC,EAAE,CAAC,CAAA;IAEX,OAAO;;;;;;;;;;;;;;;;;;;;EAoBP,OAAO,CAAC,QAAQ,EAAE;;;;;EAKlB,sBAAsB;;;;EAItB,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;UA4BjB,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyDvB,CAAA;AACD,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { ContextResult } from '../admin.generator';
2
+ export declare function generateExcelIoPage({ context }: {
3
+ context: ContextResult;
4
+ }): string;
@@ -0,0 +1,258 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.generateExcelIoPage = generateExcelIoPage;
37
+ const Generator = __importStar(require("@postxl/generator"));
38
+ function generateExcelIoPage({ context }) {
39
+ const modelNames = [...context.models.values()]
40
+ .sort((a, b) => a.name.localeCompare(b.name))
41
+ .map((model) => `'${model._conjugated.camelCase}'`)
42
+ .join(',\n ');
43
+ const defaultModel = [...context.models.values()].sort((a, b) => a.name.localeCompare(b.name))[0]?._conjugated.camelCase ?? 'user';
44
+ const imports = Generator.ImportGenerator.from(Generator.toFilePath('./excel-io.page.tsx'))
45
+ .addImport({
46
+ from: Generator.toBackendModuleLocation('@admin/admin-sidebar'),
47
+ items: [Generator.toFunctionName('AdminSidebar')],
48
+ })
49
+ .addImport({ from: Generator.toPackageName('react'), items: [Generator.toFunctionName('useState')] })
50
+ .addImport({
51
+ from: Generator.toBackendModuleLocation('@hooks/use-excel-io'),
52
+ items: [Generator.toFunctionName('useExcelIo')],
53
+ })
54
+ .addImport({
55
+ from: Generator.toPackageName('@postxl/ui-components'),
56
+ items: [
57
+ Generator.toFunctionName('Button'),
58
+ Generator.toFunctionName('Card'),
59
+ Generator.toFunctionName('CardContent'),
60
+ Generator.toFunctionName('CardHeader'),
61
+ Generator.toFunctionName('CardTitle'),
62
+ Generator.toFunctionName('Input'),
63
+ Generator.toFunctionName('Label'),
64
+ Generator.toFunctionName('Select'),
65
+ Generator.toFunctionName('SelectContent'),
66
+ Generator.toFunctionName('SelectItem'),
67
+ Generator.toFunctionName('SelectTrigger'),
68
+ Generator.toFunctionName('SelectValue'),
69
+ Generator.toFunctionName('SidebarInset'),
70
+ Generator.toFunctionName('SidebarProvider'),
71
+ Generator.toFunctionName('Textarea'),
72
+ ],
73
+ });
74
+ return /*tsx*/ `
75
+ ${imports.generate()}
76
+
77
+ const MODELS = [
78
+ ${modelNames}
79
+ ] as const
80
+
81
+ type Status = { type: 'success' | 'error'; message: string }
82
+
83
+ export default function ExcelIoPage() {
84
+ const [selectedModel, setSelectedModel] = useState<(typeof MODELS)[number]>('${defaultModel}')
85
+ const [filtersJson, setFiltersJson] = useState('')
86
+ const [sortJson, setSortJson] = useState('')
87
+ const [status, setStatus] = useState<Record<string, Status | undefined>>({})
88
+
89
+ const {
90
+ isExportingExcel,
91
+ isImportingExcel,
92
+ importInputRef,
93
+ handleExportExcel: exportModelExcel,
94
+ handleImportExcel: importExcelFile,
95
+ openImportDialog,
96
+ } = useExcelIo({ showToasts: false })
97
+
98
+ const setStatusKey = (key: string, value?: Status) => {
99
+ setStatus((prev) => ({ ...prev, [key]: value }))
100
+ }
101
+
102
+ const handleExportAll = async () => {
103
+ const key = 'export-all'
104
+ setStatusKey(key)
105
+
106
+ try {
107
+ await exportModelExcel({ model: undefined })
108
+ setStatusKey(key, { type: 'success', message: 'Export successful' })
109
+ } catch (error) {
110
+ setStatusKey(key, { type: 'error', message: \`Error: ${'${String(error)}'}\` })
111
+ }
112
+ }
113
+
114
+ const handleExportModel = async () => {
115
+ const key = 'export-model'
116
+ setStatusKey(key)
117
+
118
+ try {
119
+ let parsedFilters: Record<string, unknown> = {}
120
+ if (filtersJson.trim().length > 0) {
121
+ parsedFilters = JSON.parse(filtersJson) as Record<string, unknown>
122
+ }
123
+
124
+ let parsedSort: { field: string; direction: 'asc' | 'desc' }[] | undefined
125
+ if (sortJson.trim().length > 0) {
126
+ parsedSort = JSON.parse(sortJson) as { field: string; direction: 'asc' | 'desc' }[]
127
+ }
128
+
129
+ await exportModelExcel({ model: selectedModel, filters: parsedFilters, sort: parsedSort })
130
+ } catch (error) {
131
+ setStatusKey(key, { type: 'error', message: \`Error: ${'${String(error)}'}\` })
132
+ }
133
+ }
134
+
135
+ const triggerImportExcel = async (file: File) => {
136
+ await importExcelFile(file)
137
+ }
138
+
139
+ const statusClass = (value?: Status) => {
140
+ if (!value) {
141
+ return ''
142
+ }
143
+
144
+ return value.type === 'success'
145
+ ? 'text-green-700 border-green-300 bg-green-50 dark:text-green-300 dark:border-green-800 dark:bg-green-950/30'
146
+ : 'text-red-700 border-red-300 bg-red-50 dark:text-red-300 dark:border-red-800 dark:bg-red-950/30'
147
+ }
148
+
149
+ return (
150
+ <SidebarProvider defaultOpen>
151
+ <AdminSidebar />
152
+
153
+ <SidebarInset className="p-4">
154
+ <div className="mx-auto flex w-full max-w-5xl flex-col gap-4">
155
+ <h1 className="text-3xl font-bold">Excel I/O</h1>
156
+ <p className="text-sm text-muted-foreground">Export all data or one model as Excel, and import any Excel file.</p>
157
+
158
+ <Card>
159
+ <CardHeader>
160
+ <CardTitle>Export All Models</CardTitle>
161
+ </CardHeader>
162
+ <CardContent className="space-y-3">
163
+ <Button onClick={() => void handleExportAll()} disabled={isExportingExcel}>
164
+ {isExportingExcel ? 'Exporting...' : 'Export All to Excel'}
165
+ </Button>
166
+ {status['export-all'] && (
167
+ <div className={\`rounded border p-2 text-sm ${"${statusClass(status['export-all'])}"}\`}>{status['export-all']?.message}</div>
168
+ )}
169
+ </CardContent>
170
+ </Card>
171
+
172
+ <Card>
173
+ <CardHeader>
174
+ <CardTitle>Export Single Model</CardTitle>
175
+ </CardHeader>
176
+ <CardContent className="space-y-3">
177
+ <div className="space-y-1">
178
+ <Label htmlFor="model">Model</Label>
179
+ <Select value={selectedModel} onValueChange={(value) => setSelectedModel(value as (typeof MODELS)[number])}>
180
+ <SelectTrigger id="model">
181
+ <SelectValue placeholder="Select model" />
182
+ </SelectTrigger>
183
+ <SelectContent>
184
+ {MODELS.map((model) => (
185
+ <SelectItem key={model} value={model}>
186
+ {model}
187
+ </SelectItem>
188
+ ))}
189
+ </SelectContent>
190
+ </Select>
191
+ </div>
192
+
193
+ <div className="space-y-1">
194
+ <Label htmlFor="filters">Filters JSON (optional)</Label>
195
+ <Textarea
196
+ id="filters"
197
+ value={filtersJson}
198
+ onChange={(event) => setFiltersJson(event.target.value)}
199
+ placeholder='{"globalSearch":"demo"}'
200
+ rows={4}
201
+ />
202
+ </div>
203
+
204
+ <div className="space-y-1">
205
+ <Label htmlFor="sort">Sort JSON (optional)</Label>
206
+ <Textarea
207
+ id="sort"
208
+ value={sortJson}
209
+ onChange={(event) => setSortJson(event.target.value)}
210
+ placeholder='[{"field":"id","direction":"asc"}]'
211
+ rows={4}
212
+ />
213
+ </div>
214
+
215
+ <Button onClick={() => void handleExportModel()} disabled={isExportingExcel}>
216
+ {isExportingExcel ? 'Exporting...' : 'Export Model to Excel'}
217
+ </Button>
218
+
219
+ {status['export-model'] && (
220
+ <div className={\`rounded border p-2 text-sm ${"${statusClass(status['export-model'])}"}\`}>
221
+ {status['export-model']?.message}
222
+ </div>
223
+ )}
224
+ </CardContent>
225
+ </Card>
226
+
227
+ <Card>
228
+ <CardHeader>
229
+ <CardTitle>Import Excel</CardTitle>
230
+ </CardHeader>
231
+ <CardContent className="space-y-3">
232
+ <Label htmlFor="import-file">Upload Excel file</Label>
233
+ <Input
234
+ id="import-file"
235
+ ref={importInputRef}
236
+ type="file"
237
+ accept=".xlsx,.xls"
238
+ disabled={isImportingExcel}
239
+ onChange={(event) => {
240
+ const file = event.target.files?.[0]
241
+ if (file) {
242
+ void triggerImportExcel(file)
243
+ }
244
+ }}
245
+ />
246
+ <Button type="button" variant="outline" onClick={openImportDialog} disabled={isImportingExcel}>
247
+ {isImportingExcel ? 'Importing...' : 'Select & Import Excel'}
248
+ </Button>
249
+ </CardContent>
250
+ </Card>
251
+ </div>
252
+ </SidebarInset>
253
+ </SidebarProvider>
254
+ )
255
+ }
256
+ `;
257
+ }
258
+ //# sourceMappingURL=excel-io-page.generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"excel-io-page.generator.js","sourceRoot":"","sources":["../../../src/frontend-admin/generators/excel-io-page.generator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare function generateImportReviewResultStage(): string;
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateImportReviewResultStage = generateImportReviewResultStage;
4
+ function generateImportReviewResultStage() {
5
+ return `
6
+ function ResultStage({ result, onReset }: Readonly<{ result: ImportExecutionSummary; onReset: () => void }>) {
7
+ return (
8
+ <>
9
+ <Card>
10
+ <CardHeader>
11
+ <CardTitle>Import Complete</CardTitle>
12
+ </CardHeader>
13
+ <CardContent className="space-y-4">
14
+ <div className="grid grid-cols-2 gap-3 sm:grid-cols-3">
15
+ <SummaryCard label="Applied" count={result.totalApplied} variant="success" />
16
+ <SummaryCard label="Skipped" count={result.totalSkipped} variant="warning" />
17
+ <SummaryCard label="Total" count={result.totalApplied + result.totalSkipped} variant="neutral" />
18
+ </div>
19
+ </CardContent>
20
+ </Card>
21
+
22
+ {Object.keys(result.applied).length > 0 && (
23
+ <Card>
24
+ <CardHeader>
25
+ <CardTitle>Applied Changes</CardTitle>
26
+ </CardHeader>
27
+ <CardContent>
28
+ <div className="space-y-2">
29
+ {Object.entries(result.applied).map(([model, counts]) => (
30
+ <div key={model} className="flex items-center gap-2">
31
+ <span className="min-w-32 font-medium">{getModelLabel(model)}</span>
32
+ {counts.created > 0 && (
33
+ <Badge variant="outline" className={TYPE_BADGE_CLASSES.create}>
34
+ {counts.created} created
35
+ </Badge>
36
+ )}
37
+ {counts.updated > 0 && (
38
+ <Badge variant="outline" className={TYPE_BADGE_CLASSES.update}>
39
+ {counts.updated} updated
40
+ </Badge>
41
+ )}
42
+ {counts.deleted > 0 && (
43
+ <Badge variant="outline" className={TYPE_BADGE_CLASSES.delete}>
44
+ {counts.deleted} deleted
45
+ </Badge>
46
+ )}
47
+ </div>
48
+ ))}
49
+ </div>
50
+ </CardContent>
51
+ </Card>
52
+ )}
53
+
54
+ {Object.keys(result.skipped).length > 0 && (
55
+ <Card>
56
+ <CardHeader>
57
+ <CardTitle>Skipped (Errors)</CardTitle>
58
+ </CardHeader>
59
+ <CardContent>
60
+ <div className="space-y-2">
61
+ {Object.entries(result.skipped).map(([model, counts]) => (
62
+ <div key={model} className="flex items-center gap-2">
63
+ <span className="min-w-32 font-medium">{getModelLabel(model)}</span>
64
+ <Badge variant="outline" className={TYPE_BADGE_CLASSES.errors}>
65
+ {counts.errors} errors
66
+ </Badge>
67
+ </div>
68
+ ))}
69
+ </div>
70
+ </CardContent>
71
+ </Card>
72
+ )}
73
+
74
+ <Button onClick={onReset}>Import Another File</Button>
75
+ </>
76
+ )
77
+ }
78
+
79
+ function SummaryCard({
80
+ label,
81
+ count,
82
+ variant,
83
+ }: Readonly<{
84
+ label: string
85
+ count: number
86
+ variant: 'success' | 'warning' | 'neutral'
87
+ }>) {
88
+ const colors = {
89
+ success: 'text-green-700 dark:text-green-400',
90
+ warning: 'text-amber-700 dark:text-amber-400',
91
+ neutral: 'text-muted-foreground',
92
+ }
93
+
94
+ return (
95
+ <div className="rounded border p-3 text-center">
96
+ <div className={"text-2xl font-bold " + colors[variant]}>{count}</div>
97
+ <div className="text-xs text-muted-foreground">{label}</div>
98
+ </div>
99
+ )
100
+ }
101
+
102
+ `;
103
+ }
104
+ //# sourceMappingURL=import-review-page-result-stage.generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"import-review-page-result-stage.generator.js","sourceRoot":"","sources":["../../../src/frontend-admin/generators/import-review-page-result-stage.generator.ts"],"names":[],"mappings":";;AAAA,0EAmGC;AAnGD,SAAgB,+BAA+B;IAC7C,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiGR,CAAA;AACD,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function generateImportReviewReviewStage(): string;