@endora-commerce/mod-settings 0.100.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 (127) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +58 -0
  3. package/dist/admin/api/settings-client.d.ts +47 -0
  4. package/dist/admin/api/settings-client.d.ts.map +1 -0
  5. package/dist/admin/api/settings-client.js +41 -0
  6. package/dist/admin/api/settings-client.js.map +1 -0
  7. package/dist/admin/components/ActivationPointerRow.d.ts +21 -0
  8. package/dist/admin/components/ActivationPointerRow.d.ts.map +1 -0
  9. package/dist/admin/components/ActivationPointerRow.js +28 -0
  10. package/dist/admin/components/ActivationPointerRow.js.map +1 -0
  11. package/dist/admin/components/AssetIdSettingInput.d.ts +12 -0
  12. package/dist/admin/components/AssetIdSettingInput.d.ts.map +1 -0
  13. package/dist/admin/components/AssetIdSettingInput.js +10 -0
  14. package/dist/admin/components/AssetIdSettingInput.js.map +1 -0
  15. package/dist/admin/components/ConfigurationReferenceInput.d.ts +39 -0
  16. package/dist/admin/components/ConfigurationReferenceInput.d.ts.map +1 -0
  17. package/dist/admin/components/ConfigurationReferenceInput.js +74 -0
  18. package/dist/admin/components/ConfigurationReferenceInput.js.map +1 -0
  19. package/dist/admin/components/ConflictBanner.d.ts +13 -0
  20. package/dist/admin/components/ConflictBanner.d.ts.map +1 -0
  21. package/dist/admin/components/ConflictBanner.js +12 -0
  22. package/dist/admin/components/ConflictBanner.js.map +1 -0
  23. package/dist/admin/components/ImageSettingInput.d.ts +34 -0
  24. package/dist/admin/components/ImageSettingInput.d.ts.map +1 -0
  25. package/dist/admin/components/ImageSettingInput.js +36 -0
  26. package/dist/admin/components/ImageSettingInput.js.map +1 -0
  27. package/dist/admin/components/QuoteRequestsSettingsTab.d.ts +3 -0
  28. package/dist/admin/components/QuoteRequestsSettingsTab.d.ts.map +1 -0
  29. package/dist/admin/components/QuoteRequestsSettingsTab.js +69 -0
  30. package/dist/admin/components/QuoteRequestsSettingsTab.js.map +1 -0
  31. package/dist/admin/components/SellerCompanyDataInput.d.ts +22 -0
  32. package/dist/admin/components/SellerCompanyDataInput.d.ts.map +1 -0
  33. package/dist/admin/components/SellerCompanyDataInput.js +53 -0
  34. package/dist/admin/components/SellerCompanyDataInput.js.map +1 -0
  35. package/dist/admin/components/SettingRowEditor.d.ts +55 -0
  36. package/dist/admin/components/SettingRowEditor.d.ts.map +1 -0
  37. package/dist/admin/components/SettingRowEditor.js +160 -0
  38. package/dist/admin/components/SettingRowEditor.js.map +1 -0
  39. package/dist/admin/index.d.ts +39 -0
  40. package/dist/admin/index.d.ts.map +1 -0
  41. package/dist/admin/index.js +87 -0
  42. package/dist/admin/index.js.map +1 -0
  43. package/dist/admin/pages/CachePage.d.ts +14 -0
  44. package/dist/admin/pages/CachePage.d.ts.map +1 -0
  45. package/dist/admin/pages/CachePage.js +124 -0
  46. package/dist/admin/pages/CachePage.js.map +1 -0
  47. package/dist/admin/pages/GroupsPage.d.ts +17 -0
  48. package/dist/admin/pages/GroupsPage.d.ts.map +1 -0
  49. package/dist/admin/pages/GroupsPage.js +84 -0
  50. package/dist/admin/pages/GroupsPage.js.map +1 -0
  51. package/dist/admin/pages/SettingsPage.d.ts +20 -0
  52. package/dist/admin/pages/SettingsPage.d.ts.map +1 -0
  53. package/dist/admin/pages/SettingsPage.js +453 -0
  54. package/dist/admin/pages/SettingsPage.js.map +1 -0
  55. package/dist/backend/cli/cache-clear.d.ts +23 -0
  56. package/dist/backend/cli/cache-clear.d.ts.map +1 -0
  57. package/dist/backend/cli/cache-clear.js +37 -0
  58. package/dist/backend/cli/cache-clear.js.map +1 -0
  59. package/dist/backend/index.d.ts +100 -0
  60. package/dist/backend/index.d.ts.map +1 -0
  61. package/dist/backend/index.js +125 -0
  62. package/dist/backend/index.js.map +1 -0
  63. package/dist/backend/routes.admin.d.ts +308 -0
  64. package/dist/backend/routes.admin.d.ts.map +1 -0
  65. package/dist/backend/routes.admin.js +188 -0
  66. package/dist/backend/routes.admin.js.map +1 -0
  67. package/dist/backend/routes.cache.d.ts +20 -0
  68. package/dist/backend/routes.cache.d.ts.map +1 -0
  69. package/dist/backend/routes.cache.js +22 -0
  70. package/dist/backend/routes.cache.js.map +1 -0
  71. package/dist/backend/routes.homepage.d.ts +15 -0
  72. package/dist/backend/routes.homepage.d.ts.map +1 -0
  73. package/dist/backend/routes.homepage.js +20 -0
  74. package/dist/backend/routes.homepage.js.map +1 -0
  75. package/dist/backend/routes.product-card-buttons.d.ts +15 -0
  76. package/dist/backend/routes.product-card-buttons.d.ts.map +1 -0
  77. package/dist/backend/routes.product-card-buttons.js +21 -0
  78. package/dist/backend/routes.product-card-buttons.js.map +1 -0
  79. package/dist/backend/routes.speculation-rules.d.ts +16 -0
  80. package/dist/backend/routes.speculation-rules.d.ts.map +1 -0
  81. package/dist/backend/routes.speculation-rules.js +21 -0
  82. package/dist/backend/routes.speculation-rules.js.map +1 -0
  83. package/dist/backend/routes.storefront.d.ts +15 -0
  84. package/dist/backend/routes.storefront.d.ts.map +1 -0
  85. package/dist/backend/routes.storefront.js +20 -0
  86. package/dist/backend/routes.storefront.js.map +1 -0
  87. package/dist/backend/services/cache-admin.service.d.ts +83 -0
  88. package/dist/backend/services/cache-admin.service.d.ts.map +1 -0
  89. package/dist/backend/services/cache-admin.service.js +148 -0
  90. package/dist/backend/services/cache-admin.service.js.map +1 -0
  91. package/dist/backend/services/homepage-resolver.d.ts +25 -0
  92. package/dist/backend/services/homepage-resolver.d.ts.map +1 -0
  93. package/dist/backend/services/homepage-resolver.js +31 -0
  94. package/dist/backend/services/homepage-resolver.js.map +1 -0
  95. package/dist/backend/services/product-card-buttons-resolver.d.ts +25 -0
  96. package/dist/backend/services/product-card-buttons-resolver.d.ts.map +1 -0
  97. package/dist/backend/services/product-card-buttons-resolver.js +37 -0
  98. package/dist/backend/services/product-card-buttons-resolver.js.map +1 -0
  99. package/dist/backend/services/registered-settings-manifests.d.ts +45 -0
  100. package/dist/backend/services/registered-settings-manifests.d.ts.map +1 -0
  101. package/dist/backend/services/registered-settings-manifests.js +55 -0
  102. package/dist/backend/services/registered-settings-manifests.js.map +1 -0
  103. package/dist/backend/services/setting-write-validators.d.ts +43 -0
  104. package/dist/backend/services/setting-write-validators.d.ts.map +1 -0
  105. package/dist/backend/services/setting-write-validators.js +43 -0
  106. package/dist/backend/services/setting-write-validators.js.map +1 -0
  107. package/dist/backend/services/settings-admin.service.d.ts +206 -0
  108. package/dist/backend/services/settings-admin.service.d.ts.map +1 -0
  109. package/dist/backend/services/settings-admin.service.js +642 -0
  110. package/dist/backend/services/settings-admin.service.js.map +1 -0
  111. package/dist/backend/services/shop-info-resolver.d.ts +15 -0
  112. package/dist/backend/services/shop-info-resolver.d.ts.map +1 -0
  113. package/dist/backend/services/shop-info-resolver.js +44 -0
  114. package/dist/backend/services/shop-info-resolver.js.map +1 -0
  115. package/dist/backend/services/speculation-rules-resolver.d.ts +28 -0
  116. package/dist/backend/services/speculation-rules-resolver.d.ts.map +1 -0
  117. package/dist/backend/services/speculation-rules-resolver.js +39 -0
  118. package/dist/backend/services/speculation-rules-resolver.js.map +1 -0
  119. package/dist/manifest.d.ts +194 -0
  120. package/dist/manifest.d.ts.map +1 -0
  121. package/dist/manifest.js +379 -0
  122. package/dist/manifest.js.map +1 -0
  123. package/docs/settings/index.md +171 -0
  124. package/i18n/en.json +167 -0
  125. package/i18n/pl.json +167 -0
  126. package/package.json +96 -0
  127. package/tailwind.css +14 -0
@@ -0,0 +1,22 @@
1
+ import { type ReactNode } from 'react';
2
+ /**
3
+ * Setting code whose JSON value holds the seller's company data. The Settings
4
+ * page renders this with a structured field-by-field editor instead of a raw
5
+ * JSON textarea (the value still round-trips as serialized JSON via the
6
+ * draft text, so the page-level save logic is unchanged).
7
+ */
8
+ export declare const SELLER_COMPANY_DATA_CODE = "invoices.seller.company_data";
9
+ interface Props {
10
+ /** Current value as a serialized JSON string (the setting draft text). */
11
+ value: string;
12
+ /** Emits the next serialized JSON string. */
13
+ onChange: (next: string) => void;
14
+ }
15
+ /**
16
+ * Field-by-field editor for the seller company-data JSON setting. Each input
17
+ * patches its key and the whole object is re-serialized so the existing
18
+ * JSON-typed save path keeps working without changes.
19
+ */
20
+ export declare function SellerCompanyDataInput({ value, onChange }: Props): ReactNode;
21
+ export {};
22
+ //# sourceMappingURL=SellerCompanyDataInput.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SellerCompanyDataInput.d.ts","sourceRoot":"","sources":["../../../src/admin/components/SellerCompanyDataInput.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAIvC;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,iCAAiC,CAAC;AA6BvE,UAAU,KAAK;IACb,0EAA0E;IAC1E,KAAK,EAAE,MAAM,CAAC;IACd,6CAA6C;IAC7C,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,KAAK,GAAG,SAAS,CAmC5E"}
@@ -0,0 +1,53 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import {} from 'react';
3
+ import { Input, Label } from '@endora-commerce/admin-kit/ui';
4
+ import { CountrySelect } from '@endora-commerce/admin-kit/components';
5
+ import { useTranslation } from '@endora-commerce/admin-kit/i18n';
6
+ /**
7
+ * Setting code whose JSON value holds the seller's company data. The Settings
8
+ * page renders this with a structured field-by-field editor instead of a raw
9
+ * JSON textarea (the value still round-trips as serialized JSON via the
10
+ * draft text, so the page-level save logic is unchanged).
11
+ */
12
+ export const SELLER_COMPANY_DATA_CODE = 'invoices.seller.company_data';
13
+ /** Ordered field list mirroring `sellerCompanyDataSchema` in @endora-commerce/contracts. */
14
+ const FIELDS = [
15
+ 'legalName',
16
+ 'addressLine1',
17
+ 'addressLine2',
18
+ 'postalCode',
19
+ 'city',
20
+ 'country',
21
+ 'taxId',
22
+ 'bankName',
23
+ 'bankAccount',
24
+ 'swift',
25
+ 'email',
26
+ 'phone',
27
+ ];
28
+ function parse(text) {
29
+ if (text.trim() === '')
30
+ return {};
31
+ try {
32
+ const obj = JSON.parse(text);
33
+ return obj && typeof obj === 'object' ? obj : {};
34
+ }
35
+ catch {
36
+ return {};
37
+ }
38
+ }
39
+ /**
40
+ * Field-by-field editor for the seller company-data JSON setting. Each input
41
+ * patches its key and the whole object is re-serialized so the existing
42
+ * JSON-typed save path keeps working without changes.
43
+ */
44
+ export function SellerCompanyDataInput({ value, onChange }) {
45
+ const t = useTranslation('settings');
46
+ const obj = parse(value);
47
+ const setField = (field, next) => {
48
+ const updated = { ...obj, [field]: next };
49
+ onChange(JSON.stringify(updated));
50
+ };
51
+ return (_jsx("div", { className: "grid gap-3 md:grid-cols-2", children: FIELDS.map((field) => (_jsxs("div", { className: "space-y-1", children: [_jsx(Label, { htmlFor: `seller-${field}`, className: "text-xs", children: t(`editor.sellerCompanyData.${field}`) }), field === 'country' ? (_jsx(CountrySelect, { id: `seller-${field}`, ariaLabel: t(`editor.sellerCompanyData.${field}`), value: obj[field] ?? null, clearable: true, onChange: (code) => setField(field, code ?? '') })) : (_jsx(Input, { id: `seller-${field}`, value: obj[field] ?? '', onChange: (e) => setField(field, e.target.value) }))] }, field))) }));
52
+ }
53
+ //# sourceMappingURL=SellerCompanyDataInput.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SellerCompanyDataInput.js","sourceRoot":"","sources":["../../../src/admin/components/SellerCompanyDataInput.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAkB,MAAM,OAAO,CAAC;AACvC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,+BAA+B,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,uCAAuC,CAAC;AACtE,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACjE;;;;;GAKG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,8BAA8B,CAAC;AAEvE,4FAA4F;AAC5F,MAAM,MAAM,GAAG;IACb,WAAW;IACX,cAAc;IACd,cAAc;IACd,YAAY;IACZ,MAAM;IACN,SAAS;IACT,OAAO;IACP,UAAU;IACV,aAAa;IACb,OAAO;IACP,OAAO;IACP,OAAO;CACC,CAAC;AAGX,SAAS,KAAK,CAAC,IAAY;IACzB,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE;QAAE,OAAO,EAAE,CAAC;IAClC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC7B,OAAO,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAE,GAA8B,CAAC,CAAC,CAAC,EAAE,CAAC;IAC/E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AASD;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAS;IAC/D,MAAM,CAAC,GAAG,cAAc,CAAC,UAAU,CAAC,CAAC;IACrC,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;IAEzB,MAAM,QAAQ,GAAG,CAAC,KAAY,EAAE,IAAY,EAAQ,EAAE;QACpD,MAAM,OAAO,GAAG,EAAE,GAAG,GAAG,EAAE,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC;QAC1C,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;IACpC,CAAC,CAAC;IAEF,OAAO,CACL,cAAK,SAAS,EAAC,2BAA2B,YACvC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CACrB,eAAiB,SAAS,EAAC,WAAW,aACpC,KAAC,KAAK,IAAC,OAAO,EAAE,UAAU,KAAK,EAAE,EAAE,SAAS,EAAC,SAAS,YACnD,CAAC,CAAC,4BAA4B,KAAK,EAAE,CAAC,GACjC,EACP,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,CACrB,KAAC,aAAa,IACZ,EAAE,EAAE,UAAU,KAAK,EAAE,EACrB,SAAS,EAAE,CAAC,CAAC,4BAA4B,KAAK,EAAE,CAAC,EACjD,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,IAAI,IAAI,EACzB,SAAS,QACT,QAAQ,EAAE,CAAC,IAAI,EAAQ,EAAE,CAAC,QAAQ,CAAC,KAAK,EAAE,IAAI,IAAI,EAAE,CAAC,GACrD,CACH,CAAC,CAAC,CAAC,CACF,KAAC,KAAK,IACJ,EAAE,EAAE,UAAU,KAAK,EAAE,EACrB,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,EACvB,QAAQ,EAAE,CAAC,CAAC,EAAQ,EAAE,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,GACtD,CACH,KAlBO,KAAK,CAmBT,CACP,CAAC,GACE,CACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,55 @@
1
+ import { type ReactNode } from 'react';
2
+ import type { SettingDto } from '@endora-commerce/contracts';
3
+ export interface SettingDraft {
4
+ /** Current text in the input. */
5
+ text: string;
6
+ /** Baseline; the draft is "dirty" when `text !== initialText`. */
7
+ initialText: string;
8
+ }
9
+ interface Props {
10
+ setting: SettingDto;
11
+ draft: SettingDraft;
12
+ /**
13
+ * The channel context the row is being edited under. `null` means
14
+ * the page is in "All channels" mode; otherwise the picked sales-
15
+ * channel code. The row uses this to label per-channel state and to
16
+ * decide whether a row is bound to the default or an explicit override.
17
+ */
18
+ channelContext: string | null;
19
+ isCopied: boolean;
20
+ resetting: boolean;
21
+ /**
22
+ * Feature 073 / FR-033 — the module that owns this setting is not effectively
23
+ * present. The stored value is still shown (off is not uninstall), but every
24
+ * input is disabled and the server refuses the write anyway, so a stale tab
25
+ * cannot save through this row either.
26
+ */
27
+ readOnly?: boolean;
28
+ onChange: (patch: Partial<SettingDraft>) => void;
29
+ onCopyCode: () => void;
30
+ onReset: () => void;
31
+ }
32
+ /**
33
+ * Inline editor for one setting — always in edit mode. The Apply-to scope
34
+ * lives at the page level (a single global channel context); the row only
35
+ * carries the value the user is typing.
36
+ */
37
+ export declare function SettingRowEditor({ setting, draft, channelContext, isCopied, resetting, readOnly, onChange, onCopyCode, onReset, }: Props): ReactNode;
38
+ /**
39
+ * Pick the value displayed in the input for the chosen channel context.
40
+ *
41
+ * Resolution chain mirrors the backend:
42
+ * per-channel override → setting.globalValue → setting.defaultValue
43
+ *
44
+ * "All channels" mode (`channelContext === null`) edits the global tier
45
+ * directly: it shows `globalValue` when the admin has set one, otherwise
46
+ * the manifest default. A specific channel falls back through the chain.
47
+ */
48
+ export declare function deriveDisplayValue(setting: SettingDto, channelContext: string | null): string;
49
+ export type EffectiveSource = 'channel-override' | 'global' | 'default';
50
+ export declare function effectiveSource(setting: SettingDto, channelContext: string | null): EffectiveSource;
51
+ export declare function parseValue(valueType: SettingDto['valueType'], text: string): unknown;
52
+ export declare function computeVersion(setting: SettingDto): string;
53
+ export declare function isDraftDirty(draft: SettingDraft): boolean;
54
+ export {};
55
+ //# sourceMappingURL=SettingRowEditor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SettingRowEditor.d.ts","sourceRoot":"","sources":["../../../src/admin/components/SettingRowEditor.tsx"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AA2B7D,MAAM,WAAW,YAAY;IAC3B,iCAAiC;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,kEAAkE;IAClE,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,UAAU,KAAK;IACb,OAAO,EAAE,UAAU,CAAC;IACpB,KAAK,EAAE,YAAY,CAAC;IACpB;;;;;OAKG;IACH,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,YAAY,CAAC,KAAK,IAAI,CAAC;IACjD,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,OAAO,EACP,KAAK,EACL,cAAc,EACd,QAAQ,EACR,SAAS,EACT,QAAgB,EAChB,QAAQ,EACR,UAAU,EACV,OAAO,GACR,EAAE,KAAK,GAAG,SAAS,CAgMnB;AA+DD;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,UAAU,EACnB,cAAc,EAAE,MAAM,GAAG,IAAI,GAC5B,MAAM,CAQR;AAkBD,MAAM,MAAM,eAAe,GAAG,kBAAkB,GAAG,QAAQ,GAAG,SAAS,CAAC;AAExE,wBAAgB,eAAe,CAC7B,OAAO,EAAE,UAAU,EACnB,cAAc,EAAE,MAAM,GAAG,IAAI,GAC5B,eAAe,CAejB;AAED,wBAAgB,UAAU,CACxB,SAAS,EAAE,UAAU,CAAC,WAAW,CAAC,EAClC,IAAI,EAAE,MAAM,GACX,OAAO,CAuBT;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,UAAU,GAAG,MAAM,CAE1D;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAEzD"}
@@ -0,0 +1,160 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useCallback, } from 'react';
3
+ import { Check, Copy, RotateCcw } from 'lucide-react';
4
+ import { Badge, Button, Input } from '@endora-commerce/admin-kit/ui';
5
+ import { cn } from '@endora-commerce/admin-kit/lib';
6
+ import { useTranslation } from '@endora-commerce/admin-kit/i18n';
7
+ import { ImageSettingInput } from './ImageSettingInput.js';
8
+ import { AssetIdSettingInput } from './AssetIdSettingInput.js';
9
+ import { SellerCompanyDataInput, SELLER_COMPANY_DATA_CODE } from './SellerCompanyDataInput.js';
10
+ import { ConfigurationReferenceInput } from './ConfigurationReferenceInput.js';
11
+ /**
12
+ * String settings that hold an image URL get a file-upload editor (drag-and-drop
13
+ * / file picker via the Assets Library) instead of a plain text input. Matched by
14
+ * convention: a string-typed setting whose code names an image and ends in `_url`.
15
+ */
16
+ function isImageUrlSetting(setting) {
17
+ return (setting.valueType === 'string' &&
18
+ setting.code.includes('image') &&
19
+ setting.code.endsWith('_url'));
20
+ }
21
+ /** String settings that store an Assets Library UUID (e.g. logo_asset_id). */
22
+ function isAssetIdSetting(setting) {
23
+ return setting.valueType === 'string' && setting.code.endsWith('_asset_id');
24
+ }
25
+ /**
26
+ * Inline editor for one setting — always in edit mode. The Apply-to scope
27
+ * lives at the page level (a single global channel context); the row only
28
+ * carries the value the user is typing.
29
+ */
30
+ export function SettingRowEditor({ setting, draft, channelContext, isCopied, resetting, readOnly = false, onChange, onCopyCode, onReset, }) {
31
+ const t = useTranslation('settings');
32
+ const isDirty = isDraftDirty(draft);
33
+ const isSecret = setting.valueType === 'secret';
34
+ const overrideCount = setting.valuesByChannel.length;
35
+ const source = effectiveSource(setting, channelContext);
36
+ // Secret settings are redacted server-side (value === null); presence is
37
+ // signalled through the isSet flags instead (feature 043, FR-021).
38
+ const hasGlobalOverride = isSecret
39
+ ? setting.globalValueIsSet === true
40
+ : setting.globalValue !== null && setting.globalValue !== undefined;
41
+ const setText = useCallback((next) => {
42
+ if (readOnly)
43
+ return;
44
+ onChange({ text: next });
45
+ }, [onChange, readOnly]);
46
+ return (_jsxs("div", { className: cn('space-y-2 rounded-md border px-4 py-3 transition-colors', isDirty && 'border-amber-300 bg-amber-50/40', readOnly && 'bg-muted/40 opacity-70'), children: [_jsxs("div", { className: "flex items-start justify-between gap-2", children: [_jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("span", { className: "text-sm font-medium", children: setting.name }), _jsx("button", { type: "button", onClick: onCopyCode, title: isCopied
47
+ ? t('actions.copyCode.copied')
48
+ : `${t('actions.copyCode.label')}: ${setting.code}`, "aria-label": `${t('actions.copyCode.label')}: ${setting.code}`, className: cn('rounded p-1 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground', isCopied && 'text-emerald-600 hover:text-emerald-600'), children: isCopied ? (_jsx(Check, { className: "h-3.5 w-3.5" })) : (_jsx(Copy, { className: "h-3.5 w-3.5" })) }), _jsx(Badge, { variant: "outline", className: "font-mono text-[10px] text-muted-foreground", children: setting.valueType }), channelContext === null && hasGlobalOverride && (_jsx(Badge, { variant: "secondary", className: "text-[10px]", children: t('context.globalOverrideSet') })), channelContext === null && !hasGlobalOverride && (_jsx(Badge, { variant: "outline", className: "text-[10px] text-muted-foreground", children: t('context.usingDefault') })), channelContext !== null && source === 'channel-override' && (_jsx(Badge, { variant: "secondary", className: "text-[10px]", children: t('context.channelOverridePresent') })), channelContext !== null && source === 'global' && (_jsx(Badge, { variant: "outline", className: "text-[10px] text-muted-foreground", children: t('context.inheritsGlobal') })), channelContext !== null && source === 'default' && (_jsx(Badge, { variant: "outline", className: "text-[10px] text-muted-foreground", children: t('context.usingDefault') })), isDirty && (_jsx(Badge, { variant: "secondary", className: "bg-amber-100 text-amber-900 hover:bg-amber-100", children: t('editor.dirty') })), readOnly && (_jsx(Badge, { variant: "outline", className: "text-[10px] text-muted-foreground", children: t('editor.readOnly') }))] }), setting.description ? (_jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: setting.description })) : null, readOnly ? (_jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: t('editor.readOnlyReason') })) : null] }), _jsxs(Button, { type: "button", variant: "ghost", size: "sm", onClick: onReset, disabled: readOnly ||
49
+ resetting ||
50
+ (channelContext === null && !hasGlobalOverride) ||
51
+ (channelContext !== null && source !== 'channel-override'), title: t('actions.resetToDefault'), className: "shrink-0", children: [_jsx(RotateCcw, { className: "mr-1 h-3.5 w-3.5" }), t('actions.reset')] })] }), _jsx("fieldset", { disabled: readOnly, className: "contents", children: setting.enumOptions && setting.enumOptions.length > 0 ? (_jsx("select", { className: "w-full rounded-md border bg-background px-3 py-2 text-sm", value: draft.text, onChange: (e) => setText(e.target.value), disabled: readOnly, children: setting.enumOptions.map((opt) => (_jsx("option", { value: opt, children: opt }, opt))) })) : setting.code === SELLER_COMPANY_DATA_CODE ? (_jsx(SellerCompanyDataInput, { value: draft.text, onChange: setText })) : isAssetIdSetting(setting) ? (_jsx(AssetIdSettingInput, { value: draft.text, onChange: setText })) : isImageUrlSetting(setting) ? (_jsx(ImageSettingInput, { value: draft.text, onChange: setText })) : setting.valueType === 'credential_ref' ? (_jsx(ConfigurationReferenceInput, { configurationType: setting.configurationType, value: draft.text, onChange: setText })) : isSecret ? (_jsx(Input, { type: "password", autoComplete: "new-password", value: draft.text, onChange: (e) => setText(e.target.value), disabled: readOnly, placeholder: hasGlobalOverride || setting.valuesByChannel.some((v) => v.isSet)
52
+ ? t('editor.placeholder.secretSet')
53
+ : t('editor.placeholder.secretUnset') })) : (renderInput(setting.valueType, draft.text, setText, t, readOnly)) }), _jsxs("div", { className: "flex flex-wrap items-center gap-x-3 text-xs text-muted-foreground", children: [isSecret ? (
54
+ // No value previews for secrets — only the set / not-set fact.
55
+ _jsx("span", { children: hasGlobalOverride ? t('editor.secretIsSet') : t('editor.secretNotSet') })) : (_jsxs(_Fragment, { children: [_jsxs("span", { children: [t('editor.defaultPrefix'), " ", _jsx("code", { className: "font-mono", children: formatPreview(setting.defaultValue) })] }), hasGlobalOverride && (_jsxs(_Fragment, { children: [_jsx("span", { children: "\u00B7" }), _jsxs("span", { children: [t('editor.globalPrefix'), " ", _jsx("code", { className: "font-mono", children: formatPreview(setting.globalValue) })] })] }))] })), _jsx("span", { children: "\u00B7" }), _jsx("span", { children: t('editor.perChannelOverrides', { count: overrideCount }) })] })] }));
56
+ }
57
+ function formatPreview(value) {
58
+ if (value === null || value === undefined)
59
+ return '∅';
60
+ if (typeof value === 'string')
61
+ return value === '' ? '""' : value;
62
+ try {
63
+ return JSON.stringify(value);
64
+ }
65
+ catch {
66
+ return String(value);
67
+ }
68
+ }
69
+ function renderInput(valueType, value, setValue, t, readOnly) {
70
+ if (valueType === 'boolean') {
71
+ return (_jsxs("select", { className: "w-full rounded-md border bg-background px-3 py-2 text-sm", value: value, onChange: (e) => setValue(e.target.value), disabled: readOnly, children: [_jsx("option", { value: "true", children: "true" }), _jsx("option", { value: "false", children: "false" })] }));
72
+ }
73
+ if (valueType === 'json') {
74
+ return (_jsx("textarea", { className: "min-h-[96px] w-full rounded-md border bg-background px-3 py-2 font-mono text-sm", value: value, onChange: (e) => setValue(e.target.value), disabled: readOnly, placeholder: t('editor.placeholder.json') }));
75
+ }
76
+ if (valueType === 'string_list') {
77
+ return (_jsx(Input, { value: value, onChange: (e) => setValue(e.target.value), disabled: readOnly, placeholder: t('editor.placeholder.stringList') }));
78
+ }
79
+ return (_jsx(Input, { type: valueType === 'number' ? 'number' : 'text', value: value, onChange: (e) => setValue(e.target.value), disabled: readOnly }));
80
+ }
81
+ /**
82
+ * Pick the value displayed in the input for the chosen channel context.
83
+ *
84
+ * Resolution chain mirrors the backend:
85
+ * per-channel override → setting.globalValue → setting.defaultValue
86
+ *
87
+ * "All channels" mode (`channelContext === null`) edits the global tier
88
+ * directly: it shows `globalValue` when the admin has set one, otherwise
89
+ * the manifest default. A specific channel falls back through the chain.
90
+ */
91
+ export function deriveDisplayValue(setting, channelContext) {
92
+ // Secrets never round-trip back into the input — the server redacts the
93
+ // value, and the editor is write-only ("enter a new value to replace").
94
+ if (setting.valueType === 'secret')
95
+ return '';
96
+ const v = resolveEffective(setting, channelContext);
97
+ if (v === null || v === undefined)
98
+ return '';
99
+ if (typeof v === 'string')
100
+ return v;
101
+ return JSON.stringify(v);
102
+ }
103
+ function resolveEffective(setting, channelContext) {
104
+ if (channelContext !== null) {
105
+ const override = setting.valuesByChannel.find((entry) => entry.salesChannelCode === channelContext);
106
+ if (override)
107
+ return override.value;
108
+ }
109
+ if (setting.globalValue !== null && setting.globalValue !== undefined) {
110
+ return setting.globalValue;
111
+ }
112
+ return setting.defaultValue;
113
+ }
114
+ export function effectiveSource(setting, channelContext) {
115
+ const isSecret = setting.valueType === 'secret';
116
+ if (channelContext !== null) {
117
+ const entry = setting.valuesByChannel.find((e) => e.salesChannelCode === channelContext);
118
+ if (entry && (!isSecret || entry.isSet === true))
119
+ return 'channel-override';
120
+ }
121
+ if (isSecret) {
122
+ return setting.globalValueIsSet === true ? 'global' : 'default';
123
+ }
124
+ if (setting.globalValue !== null && setting.globalValue !== undefined) {
125
+ return 'global';
126
+ }
127
+ return 'default';
128
+ }
129
+ export function parseValue(valueType, text) {
130
+ switch (valueType) {
131
+ case 'string':
132
+ case 'secret':
133
+ // Feature 058 — a credential_ref value is the referenced configuration code.
134
+ case 'credential_ref':
135
+ return text;
136
+ case 'number':
137
+ return Number(text);
138
+ case 'boolean':
139
+ return text === 'true';
140
+ case 'string_list':
141
+ return text
142
+ .split(',')
143
+ .map((s) => s.trim())
144
+ .filter(Boolean);
145
+ case 'json':
146
+ try {
147
+ return JSON.parse(text);
148
+ }
149
+ catch {
150
+ return text;
151
+ }
152
+ }
153
+ }
154
+ export function computeVersion(setting) {
155
+ return setting.version;
156
+ }
157
+ export function isDraftDirty(draft) {
158
+ return draft.text !== draft.initialText;
159
+ }
160
+ //# sourceMappingURL=SettingRowEditor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SettingRowEditor.js","sourceRoot":"","sources":["../../../src/admin/components/SettingRowEditor.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * `settings`' admin surface — three routes and three sidebar entries, declared
3
+ * by the module that owns them (feature 091, Phase 4, batch 10;
4
+ * `specs/091-module-owned-admin-surfaces/contracts/admin-contribution.md`).
5
+ *
6
+ * **Three routes, not four, and the fourth is the point of this batch's
7
+ * pairing.** `check:admin-registrations` attributed `/settings/pwa` here
8
+ * because `App.tsx` imported `PwaPage` out of this module's surface directory,
9
+ * and batch 6 recorded the consequence in as many words: the sidebar row moved
10
+ * to `pwa` while the route stayed host-declared, so an operator who switched
11
+ * `pwa` off still reached the screen and met the module's own 503 field by
12
+ * field — *"unchanged by this batch and closes when `settings` moves"*. This is
13
+ * that batch. `PwaPage`, `PushAudienceRuleBuilder` and `pwa-client.ts` are
14
+ * `@endora-commerce/mod-pwa`'s now, and the route is declared beside the nav
15
+ * entry that advertises it, gated on `pwa`'s presence rather than on this
16
+ * module's.
17
+ *
18
+ * **The one reach this module still owed is paid, and both of its endpoints
19
+ * are in this batch.** `ConfigurationReferenceInput` — the editor for the
20
+ * `credential_ref` setting value type — imported `credentials`' admin API
21
+ * client and its `ConfigurationPreviewModal`. P6 took the client half; the
22
+ * component half takes D-191's `./admin-ui` exit, decided by
23
+ * `admin-component-contribution.md` Z1 from the signature rather than from
24
+ * taste. The reach stays **counted** (Z11) and its ledger key is re-keyed
25
+ * rather than retired: a supported spelling is not an uncounted one.
26
+ *
27
+ * **`nonDeactivatable`, so the operator axis is the platform's** (`plan.md`
28
+ * Ruling 2). Every module's configuration resolves through this one, its own
29
+ * activation control included, so a manifest that let an operator switch it off
30
+ * would be a switch with nothing left to switch it back. The permission axis is
31
+ * what it still has and is what the off-state test drives; the missing axis is
32
+ * read off the manifest rather than skipped.
33
+ *
34
+ * **This entry exports data and nothing else** (R2); every component is a
35
+ * dynamic-import factory (R6).
36
+ */
37
+ import type { AdminContributions } from '@endora-commerce/admin-kit/contributions';
38
+ export declare const contributions: AdminContributions;
39
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/admin/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0CAA0C,CAAC;AA2BnF,eAAO,MAAM,aAAa,EAAE,kBA+D3B,CAAC"}
@@ -0,0 +1,87 @@
1
+ /** The module's landing route: the grouped settings screen. */
2
+ const ROUTE_PATH = '/settings';
3
+ /**
4
+ * The code that opens the settings screens.
5
+ *
6
+ * `GET /api/v1/admin/settings` and `GET /api/v1/admin/settings/groups` are both
7
+ * `requireAdmin('settings:read')`, and this module's `open-settings` palette
8
+ * action declares the same code — the pair
9
+ * `check:action-route-permissions` holds to each other.
10
+ */
11
+ const READ_PERMISSION = 'settings:read';
12
+ /**
13
+ * The code the cache screen enforces.
14
+ *
15
+ * `POST /api/v1/admin/settings/cache/clear` and its siblings are
16
+ * `requireAdmin('settings:write')`: the screen is a set of destructive buttons
17
+ * and nothing else, so an operator holding only the read code would open a page
18
+ * on which every control refuses. The codes are opaque strings, so the read
19
+ * code does not satisfy this gate — which is the whole reason the sidebar row
20
+ * carried the write code by hand before this conversion.
21
+ */
22
+ const WRITE_PERMISSION = 'settings:write';
23
+ export const contributions = {
24
+ routes: [
25
+ {
26
+ path: ROUTE_PATH,
27
+ component: () => import('./pages/SettingsPage.js'),
28
+ requiredPermission: READ_PERMISSION,
29
+ index: true,
30
+ },
31
+ {
32
+ path: `${ROUTE_PATH}/groups`,
33
+ component: () => import('./pages/GroupsPage.js'),
34
+ requiredPermission: READ_PERMISSION,
35
+ },
36
+ {
37
+ path: `${ROUTE_PATH}/cache`,
38
+ component: () => import('./pages/CachePage.js'),
39
+ requiredPermission: WRITE_PERMISSION,
40
+ },
41
+ ],
42
+ nav: [
43
+ {
44
+ to: ROUTE_PATH,
45
+ // Module-relative (R8), resolved in this module's own namespace out of
46
+ // `packages/modules/settings/i18n/`. These were `appShell.nav.settings`,
47
+ // `appShell.nav.settingGroups` and `appShell.nav.cache` in the shared
48
+ // `_i18n` bundle, three of the four shared files a module author had to
49
+ // edit.
50
+ labelKey: 'nav.settings.label',
51
+ // The glyphs `AppShell.tsx` rendered by hand, both already on
52
+ // `KnownIconNameSchema` — this module's `open-settings` action names
53
+ // `Settings` too.
54
+ icon: 'Settings',
55
+ section: 'system',
56
+ // The hand-written positions in *System* times a hundred, which is batch
57
+ // four's convention: `/settings`, `/settings/groups` and
58
+ // `/settings/cache` were the tenth, eleventh and twelfth rows, between
59
+ // `/credentials` (900, this batch) and `/settings/pwa` (1400, batch six).
60
+ // *System* still holds host-declared entries (`/platform/modules`,
61
+ // `/catalog/bulk-operations`), so `composeNav` appends every registry row
62
+ // after both whatever the weight says; what the weight can still do is
63
+ // keep the converted rows in the order the operator already had.
64
+ weight: 1000,
65
+ requiredPermission: READ_PERMISSION,
66
+ },
67
+ {
68
+ to: `${ROUTE_PATH}/groups`,
69
+ labelKey: 'nav.settingGroups.label',
70
+ icon: 'Settings',
71
+ section: 'system',
72
+ weight: 1100,
73
+ requiredPermission: READ_PERMISSION,
74
+ },
75
+ {
76
+ to: `${ROUTE_PATH}/cache`,
77
+ labelKey: 'nav.cache.label',
78
+ icon: 'Eraser',
79
+ section: 'system',
80
+ weight: 1200,
81
+ // The write code, which is what the hand-written row carried and what the
82
+ // route above enforces: this screen is destructive from the first click.
83
+ requiredPermission: WRITE_PERMISSION,
84
+ },
85
+ ],
86
+ };
87
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/admin/index.ts"],"names":[],"mappings":"AAsCA,+DAA+D;AAC/D,MAAM,UAAU,GAAG,WAAW,CAAC;AAE/B;;;;;;;GAOG;AACH,MAAM,eAAe,GAAG,eAAe,CAAC;AAExC;;;;;;;;;GASG;AACH,MAAM,gBAAgB,GAAG,gBAAgB,CAAC;AAE1C,MAAM,CAAC,MAAM,aAAa,GAAuB;IAC/C,MAAM,EAAE;QACN;YACE,IAAI,EAAE,UAAU;YAChB,SAAS,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,yBAAyB,CAAC;YAClD,kBAAkB,EAAE,eAAe;YACnC,KAAK,EAAE,IAAI;SACZ;QACD;YACE,IAAI,EAAE,GAAG,UAAU,SAAS;YAC5B,SAAS,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,uBAAuB,CAAC;YAChD,kBAAkB,EAAE,eAAe;SACpC;QACD;YACE,IAAI,EAAE,GAAG,UAAU,QAAQ;YAC3B,SAAS,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,sBAAsB,CAAC;YAC/C,kBAAkB,EAAE,gBAAgB;SACrC;KACF;IACD,GAAG,EAAE;QACH;YACE,EAAE,EAAE,UAAU;YACd,uEAAuE;YACvE,yEAAyE;YACzE,sEAAsE;YACtE,wEAAwE;YACxE,QAAQ;YACR,QAAQ,EAAE,oBAAoB;YAC9B,8DAA8D;YAC9D,qEAAqE;YACrE,kBAAkB;YAClB,IAAI,EAAE,UAAU;YAChB,OAAO,EAAE,QAAQ;YACjB,yEAAyE;YACzE,yDAAyD;YACzD,uEAAuE;YACvE,0EAA0E;YAC1E,mEAAmE;YACnE,0EAA0E;YAC1E,uEAAuE;YACvE,iEAAiE;YACjE,MAAM,EAAE,IAAI;YACZ,kBAAkB,EAAE,eAAe;SACpC;QACD;YACE,EAAE,EAAE,GAAG,UAAU,SAAS;YAC1B,QAAQ,EAAE,yBAAyB;YACnC,IAAI,EAAE,UAAU;YAChB,OAAO,EAAE,QAAQ;YACjB,MAAM,EAAE,IAAI;YACZ,kBAAkB,EAAE,eAAe;SACpC;QACD;YACE,EAAE,EAAE,GAAG,UAAU,QAAQ;YACzB,QAAQ,EAAE,iBAAiB;YAC3B,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,QAAQ;YACjB,MAAM,EAAE,IAAI;YACZ,0EAA0E;YAC1E,yEAAyE;YACzE,kBAAkB,EAAE,gBAAgB;SACrC;KACF;CACF,CAAC"}
@@ -0,0 +1,14 @@
1
+ import { type ReactNode } from 'react';
2
+ /**
3
+ * Cache maintenance page — lets an operator flush selected Redis cache
4
+ * namespaces so freshly-published content / changed settings appear without
5
+ * waiting for TTL expiry. Backed by `/api/v1/admin/cache/*` (settings:write).
6
+ */
7
+ export declare function CachePage(): ReactNode;
8
+ /**
9
+ * The registry loads a route component through a dynamic-import factory and
10
+ * reads its default export (feature 091, FR-013). The named export stays: it is
11
+ * the spelling this module's own code and its tests use.
12
+ */
13
+ export default CachePage;
14
+ //# sourceMappingURL=CachePage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CachePage.d.ts","sourceRoot":"","sources":["../../../src/admin/pages/CachePage.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA6C,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAQlF;;;;GAIG;AACH,wBAAgB,SAAS,IAAI,SAAS,CA0NrC;AAED;;;;GAIG;AACH,eAAe,SAAS,CAAC"}
@@ -0,0 +1,124 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useCallback, useEffect, useMemo, useState } from 'react';
3
+ import { Eraser, Languages, RefreshCw, Search } from 'lucide-react';
4
+ import { ApiError } from '@endora-commerce/admin-kit/lib';
5
+ import { Alert, AlertDescription, Button, Card, CardContent, Checkbox, PageHeader } from '@endora-commerce/admin-kit/ui';
6
+ import { reloadBundles, useTranslation } from '@endora-commerce/admin-kit/i18n';
7
+ import { settingsClient } from '../api/settings-client.js';
8
+ /**
9
+ * Cache maintenance page — lets an operator flush selected Redis cache
10
+ * namespaces so freshly-published content / changed settings appear without
11
+ * waiting for TTL expiry. Backed by `/api/v1/admin/cache/*` (settings:write).
12
+ */
13
+ export function CachePage() {
14
+ const t = useTranslation('settings');
15
+ const [namespaces, setNamespaces] = useState([]);
16
+ const [cacheEnabled, setCacheEnabled] = useState(true);
17
+ const [selected, setSelected] = useState(new Set());
18
+ const [loading, setLoading] = useState(true);
19
+ const [busy, setBusy] = useState(false);
20
+ const [error, setError] = useState(null);
21
+ const [result, setResult] = useState(null);
22
+ // Prefer a localised label/description for a known namespace, fall back to
23
+ // the backend-provided English default for any namespace the bundle hasn't
24
+ // caught up with yet.
25
+ const nsLabel = useCallback((ns) => {
26
+ const key = `cache.namespace.${ns.key}.label`;
27
+ const localised = t(key);
28
+ return localised === key ? ns.label : localised;
29
+ }, [t]);
30
+ const nsDescription = useCallback((ns) => {
31
+ const key = `cache.namespace.${ns.key}.description`;
32
+ const localised = t(key);
33
+ return localised === key ? ns.description : localised;
34
+ }, [t]);
35
+ const load = useCallback(async () => {
36
+ setLoading(true);
37
+ setError(null);
38
+ try {
39
+ const res = await settingsClient.listCacheNamespaces();
40
+ setNamespaces(res.data);
41
+ setCacheEnabled(res.cacheEnabled);
42
+ }
43
+ catch (err) {
44
+ setError(err instanceof ApiError ? err.message : t('cache.error.load'));
45
+ }
46
+ finally {
47
+ setLoading(false);
48
+ }
49
+ }, [t]);
50
+ useEffect(() => {
51
+ void load();
52
+ }, [load]);
53
+ const allSelected = useMemo(() => namespaces.length > 0 && selected.size === namespaces.length, [namespaces, selected]);
54
+ const toggle = (key) => {
55
+ setSelected((prev) => {
56
+ const next = new Set(prev);
57
+ if (next.has(key))
58
+ next.delete(key);
59
+ else
60
+ next.add(key);
61
+ return next;
62
+ });
63
+ };
64
+ const toggleAll = () => {
65
+ setSelected((prev) => prev.size === namespaces.length ? new Set() : new Set(namespaces.map((n) => n.key)));
66
+ };
67
+ const reindexSearch = async () => {
68
+ setBusy(true);
69
+ setError(null);
70
+ setResult(null);
71
+ try {
72
+ const res = await settingsClient.reindexSearch();
73
+ setResult(t('search.reindex.done', {
74
+ channels: res.channelsReindexed,
75
+ documents: res.documentCount,
76
+ }));
77
+ }
78
+ catch (err) {
79
+ setError(err instanceof ApiError ? err.message : t('search.reindex.error'));
80
+ }
81
+ finally {
82
+ setBusy(false);
83
+ }
84
+ };
85
+ const reloadTranslations = async () => {
86
+ setBusy(true);
87
+ setError(null);
88
+ setResult(null);
89
+ try {
90
+ const res = await reloadBundles();
91
+ setResult(t('cache.i18n.done', { installed: res.installed }));
92
+ // Refresh so the TranslationProvider refetches the new admin bundles.
93
+ window.setTimeout(() => window.location.reload(), 800);
94
+ }
95
+ catch (err) {
96
+ setError(err instanceof ApiError ? err.message : t('cache.i18n.error'));
97
+ setBusy(false);
98
+ }
99
+ };
100
+ const clear = async (which) => {
101
+ setBusy(true);
102
+ setError(null);
103
+ setResult(null);
104
+ try {
105
+ const res = await settingsClient.clearCache({ namespaces: which });
106
+ setResult(t('cache.cleared', { count: res.data.totalDeletedKeys }));
107
+ setSelected(new Set());
108
+ }
109
+ catch (err) {
110
+ setError(err instanceof ApiError ? err.message : t('cache.error.clear'));
111
+ }
112
+ finally {
113
+ setBusy(false);
114
+ }
115
+ };
116
+ return (_jsxs("div", { className: "space-y-6", children: [_jsx(PageHeader, { title: t('cache.page.title'), description: t('cache.page.description') }), error ? (_jsx(Alert, { variant: "destructive", children: _jsx(AlertDescription, { children: error }) })) : null, result ? (_jsx(Alert, { children: _jsx(AlertDescription, { children: result }) })) : null, !cacheEnabled ? (_jsx(Alert, { children: _jsx(AlertDescription, { children: t('cache.disabled') }) })) : null, _jsx(Card, { children: _jsx(CardContent, { className: "space-y-1 p-4", children: loading ? (_jsx("p", { className: "py-6 text-sm text-muted-foreground", children: t('cache.loading') })) : (_jsxs(_Fragment, { children: [_jsxs("label", { className: "flex items-center gap-3 border-b border-border pb-3", children: [_jsx(Checkbox, { checked: allSelected, onChange: toggleAll, "aria-label": t('cache.selectAll') }), _jsx("span", { className: "text-sm font-medium", children: t('cache.selectAll') })] }), namespaces.map((ns) => (_jsxs("label", { className: "flex items-start gap-3 rounded-md px-1 py-2 hover:bg-muted/50", children: [_jsx(Checkbox, { className: "mt-1", checked: selected.has(ns.key), onChange: () => toggle(ns.key), "aria-label": nsLabel(ns) }), _jsxs("span", { className: "flex flex-col", children: [_jsx("span", { className: "text-sm font-medium", children: nsLabel(ns) }), _jsx("span", { className: "text-xs text-muted-foreground", children: nsDescription(ns) })] })] }, ns.key)))] })) }) }), _jsxs("div", { className: "flex flex-wrap gap-3", children: [_jsxs(Button, { onClick: () => clear([...selected]), disabled: busy || selected.size === 0, children: [_jsx(Eraser, { className: "mr-2 h-4 w-4" }), t('cache.clearSelected')] }), _jsxs(Button, { variant: "outline", onClick: () => clear('all'), disabled: busy, children: [_jsx(Eraser, { className: "mr-2 h-4 w-4" }), t('cache.clearAll')] }), _jsxs(Button, { variant: "ghost", onClick: () => void load(), disabled: busy || loading, children: [_jsx(RefreshCw, { className: "mr-2 h-4 w-4" }), t('cache.refresh')] })] }), _jsx(Card, { children: _jsxs(CardContent, { className: "space-y-3 p-4", children: [_jsxs("div", { children: [_jsx("h2", { className: "text-sm font-medium", children: t('search.reindex.title') }), _jsx("p", { className: "text-xs text-muted-foreground", children: t('search.reindex.description') })] }), _jsxs(Button, { variant: "outline", onClick: () => void reindexSearch(), disabled: busy, children: [_jsx(Search, { className: "mr-2 h-4 w-4" }), t('search.reindex.button')] })] }) }), _jsx(Card, { children: _jsxs(CardContent, { className: "space-y-3 p-4", children: [_jsxs("div", { children: [_jsx("h2", { className: "text-sm font-medium", children: t('cache.i18n.title') }), _jsx("p", { className: "text-xs text-muted-foreground", children: t('cache.i18n.description') })] }), _jsxs(Button, { variant: "outline", onClick: () => void reloadTranslations(), disabled: busy, children: [_jsx(Languages, { className: "mr-2 h-4 w-4" }), t('cache.i18n.button')] })] }) })] }));
117
+ }
118
+ /**
119
+ * The registry loads a route component through a dynamic-import factory and
120
+ * reads its default export (feature 091, FR-013). The named export stays: it is
121
+ * the spelling this module's own code and its tests use.
122
+ */
123
+ export default CachePage;
124
+ //# sourceMappingURL=CachePage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CachePage.js","sourceRoot":"","sources":["../../../src/admin/pages/CachePage.tsx"],"names":[],"mappings":"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"}