@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.
- package/LICENSE +21 -0
- package/README.md +58 -0
- package/dist/admin/api/settings-client.d.ts +47 -0
- package/dist/admin/api/settings-client.d.ts.map +1 -0
- package/dist/admin/api/settings-client.js +41 -0
- package/dist/admin/api/settings-client.js.map +1 -0
- package/dist/admin/components/ActivationPointerRow.d.ts +21 -0
- package/dist/admin/components/ActivationPointerRow.d.ts.map +1 -0
- package/dist/admin/components/ActivationPointerRow.js +28 -0
- package/dist/admin/components/ActivationPointerRow.js.map +1 -0
- package/dist/admin/components/AssetIdSettingInput.d.ts +12 -0
- package/dist/admin/components/AssetIdSettingInput.d.ts.map +1 -0
- package/dist/admin/components/AssetIdSettingInput.js +10 -0
- package/dist/admin/components/AssetIdSettingInput.js.map +1 -0
- package/dist/admin/components/ConfigurationReferenceInput.d.ts +39 -0
- package/dist/admin/components/ConfigurationReferenceInput.d.ts.map +1 -0
- package/dist/admin/components/ConfigurationReferenceInput.js +74 -0
- package/dist/admin/components/ConfigurationReferenceInput.js.map +1 -0
- package/dist/admin/components/ConflictBanner.d.ts +13 -0
- package/dist/admin/components/ConflictBanner.d.ts.map +1 -0
- package/dist/admin/components/ConflictBanner.js +12 -0
- package/dist/admin/components/ConflictBanner.js.map +1 -0
- package/dist/admin/components/ImageSettingInput.d.ts +34 -0
- package/dist/admin/components/ImageSettingInput.d.ts.map +1 -0
- package/dist/admin/components/ImageSettingInput.js +36 -0
- package/dist/admin/components/ImageSettingInput.js.map +1 -0
- package/dist/admin/components/QuoteRequestsSettingsTab.d.ts +3 -0
- package/dist/admin/components/QuoteRequestsSettingsTab.d.ts.map +1 -0
- package/dist/admin/components/QuoteRequestsSettingsTab.js +69 -0
- package/dist/admin/components/QuoteRequestsSettingsTab.js.map +1 -0
- package/dist/admin/components/SellerCompanyDataInput.d.ts +22 -0
- package/dist/admin/components/SellerCompanyDataInput.d.ts.map +1 -0
- package/dist/admin/components/SellerCompanyDataInput.js +53 -0
- package/dist/admin/components/SellerCompanyDataInput.js.map +1 -0
- package/dist/admin/components/SettingRowEditor.d.ts +55 -0
- package/dist/admin/components/SettingRowEditor.d.ts.map +1 -0
- package/dist/admin/components/SettingRowEditor.js +160 -0
- package/dist/admin/components/SettingRowEditor.js.map +1 -0
- package/dist/admin/index.d.ts +39 -0
- package/dist/admin/index.d.ts.map +1 -0
- package/dist/admin/index.js +87 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/admin/pages/CachePage.d.ts +14 -0
- package/dist/admin/pages/CachePage.d.ts.map +1 -0
- package/dist/admin/pages/CachePage.js +124 -0
- package/dist/admin/pages/CachePage.js.map +1 -0
- package/dist/admin/pages/GroupsPage.d.ts +17 -0
- package/dist/admin/pages/GroupsPage.d.ts.map +1 -0
- package/dist/admin/pages/GroupsPage.js +84 -0
- package/dist/admin/pages/GroupsPage.js.map +1 -0
- package/dist/admin/pages/SettingsPage.d.ts +20 -0
- package/dist/admin/pages/SettingsPage.d.ts.map +1 -0
- package/dist/admin/pages/SettingsPage.js +453 -0
- package/dist/admin/pages/SettingsPage.js.map +1 -0
- package/dist/backend/cli/cache-clear.d.ts +23 -0
- package/dist/backend/cli/cache-clear.d.ts.map +1 -0
- package/dist/backend/cli/cache-clear.js +37 -0
- package/dist/backend/cli/cache-clear.js.map +1 -0
- package/dist/backend/index.d.ts +100 -0
- package/dist/backend/index.d.ts.map +1 -0
- package/dist/backend/index.js +125 -0
- package/dist/backend/index.js.map +1 -0
- package/dist/backend/routes.admin.d.ts +308 -0
- package/dist/backend/routes.admin.d.ts.map +1 -0
- package/dist/backend/routes.admin.js +188 -0
- package/dist/backend/routes.admin.js.map +1 -0
- package/dist/backend/routes.cache.d.ts +20 -0
- package/dist/backend/routes.cache.d.ts.map +1 -0
- package/dist/backend/routes.cache.js +22 -0
- package/dist/backend/routes.cache.js.map +1 -0
- package/dist/backend/routes.homepage.d.ts +15 -0
- package/dist/backend/routes.homepage.d.ts.map +1 -0
- package/dist/backend/routes.homepage.js +20 -0
- package/dist/backend/routes.homepage.js.map +1 -0
- package/dist/backend/routes.product-card-buttons.d.ts +15 -0
- package/dist/backend/routes.product-card-buttons.d.ts.map +1 -0
- package/dist/backend/routes.product-card-buttons.js +21 -0
- package/dist/backend/routes.product-card-buttons.js.map +1 -0
- package/dist/backend/routes.speculation-rules.d.ts +16 -0
- package/dist/backend/routes.speculation-rules.d.ts.map +1 -0
- package/dist/backend/routes.speculation-rules.js +21 -0
- package/dist/backend/routes.speculation-rules.js.map +1 -0
- package/dist/backend/routes.storefront.d.ts +15 -0
- package/dist/backend/routes.storefront.d.ts.map +1 -0
- package/dist/backend/routes.storefront.js +20 -0
- package/dist/backend/routes.storefront.js.map +1 -0
- package/dist/backend/services/cache-admin.service.d.ts +83 -0
- package/dist/backend/services/cache-admin.service.d.ts.map +1 -0
- package/dist/backend/services/cache-admin.service.js +148 -0
- package/dist/backend/services/cache-admin.service.js.map +1 -0
- package/dist/backend/services/homepage-resolver.d.ts +25 -0
- package/dist/backend/services/homepage-resolver.d.ts.map +1 -0
- package/dist/backend/services/homepage-resolver.js +31 -0
- package/dist/backend/services/homepage-resolver.js.map +1 -0
- package/dist/backend/services/product-card-buttons-resolver.d.ts +25 -0
- package/dist/backend/services/product-card-buttons-resolver.d.ts.map +1 -0
- package/dist/backend/services/product-card-buttons-resolver.js +37 -0
- package/dist/backend/services/product-card-buttons-resolver.js.map +1 -0
- package/dist/backend/services/registered-settings-manifests.d.ts +45 -0
- package/dist/backend/services/registered-settings-manifests.d.ts.map +1 -0
- package/dist/backend/services/registered-settings-manifests.js +55 -0
- package/dist/backend/services/registered-settings-manifests.js.map +1 -0
- package/dist/backend/services/setting-write-validators.d.ts +43 -0
- package/dist/backend/services/setting-write-validators.d.ts.map +1 -0
- package/dist/backend/services/setting-write-validators.js +43 -0
- package/dist/backend/services/setting-write-validators.js.map +1 -0
- package/dist/backend/services/settings-admin.service.d.ts +206 -0
- package/dist/backend/services/settings-admin.service.d.ts.map +1 -0
- package/dist/backend/services/settings-admin.service.js +642 -0
- package/dist/backend/services/settings-admin.service.js.map +1 -0
- package/dist/backend/services/shop-info-resolver.d.ts +15 -0
- package/dist/backend/services/shop-info-resolver.d.ts.map +1 -0
- package/dist/backend/services/shop-info-resolver.js +44 -0
- package/dist/backend/services/shop-info-resolver.js.map +1 -0
- package/dist/backend/services/speculation-rules-resolver.d.ts +28 -0
- package/dist/backend/services/speculation-rules-resolver.d.ts.map +1 -0
- package/dist/backend/services/speculation-rules-resolver.js +39 -0
- package/dist/backend/services/speculation-rules-resolver.js.map +1 -0
- package/dist/manifest.d.ts +194 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +379 -0
- package/dist/manifest.js.map +1 -0
- package/docs/settings/index.md +171 -0
- package/i18n/en.json +167 -0
- package/i18n/pl.json +167 -0
- package/package.json +96 -0
- 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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"}
|