strapi-plugin-bulk-updater 1.0.1 → 1.2.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 (32) hide show
  1. package/README.md +47 -24
  2. package/dist/_chunks/{BulkUpdater-R78pX-om.mjs → BulkUpdater-BDszahRM.mjs} +657 -159
  3. package/dist/_chunks/BulkUpdater-BDszahRM.mjs.map +1 -0
  4. package/dist/_chunks/{BulkUpdater-CooMo-Hc.js → BulkUpdater-DCrCPKSe.js} +649 -151
  5. package/dist/_chunks/BulkUpdater-DCrCPKSe.js.map +1 -0
  6. package/dist/_chunks/ScopedQuotaSelectInput-ChWrQIBV.mjs +183 -0
  7. package/dist/_chunks/ScopedQuotaSelectInput-ChWrQIBV.mjs.map +1 -0
  8. package/dist/_chunks/ScopedQuotaSelectInput-s4oUMLgK.js +201 -0
  9. package/dist/_chunks/ScopedQuotaSelectInput-s4oUMLgK.js.map +1 -0
  10. package/dist/_chunks/SettingsPage-BRGTrW9H.js +43 -0
  11. package/dist/_chunks/SettingsPage-BRGTrW9H.js.map +1 -0
  12. package/dist/_chunks/SettingsPage-ieu-Out8.mjs +43 -0
  13. package/dist/_chunks/SettingsPage-ieu-Out8.mjs.map +1 -0
  14. package/dist/_chunks/ValidationRulesTab-BGcqM9cN.mjs +598 -0
  15. package/dist/_chunks/ValidationRulesTab-BGcqM9cN.mjs.map +1 -0
  16. package/dist/_chunks/ValidationRulesTab-BoqhoTjo.js +597 -0
  17. package/dist/_chunks/ValidationRulesTab-BoqhoTjo.js.map +1 -0
  18. package/dist/admin/index.js +19 -3
  19. package/dist/admin/index.js.map +1 -1
  20. package/dist/admin/index.mjs +19 -3
  21. package/dist/admin/index.mjs.map +1 -1
  22. package/dist/server/index.js +30795 -318
  23. package/dist/server/index.js.map +1 -1
  24. package/dist/server/index.mjs +30785 -318
  25. package/dist/server/index.mjs.map +1 -1
  26. package/package.json +10 -3
  27. package/dist/_chunks/BulkUpdater-CooMo-Hc.js.map +0 -1
  28. package/dist/_chunks/BulkUpdater-R78pX-om.mjs.map +0 -1
  29. package/dist/_chunks/SettingsPage-C6QyloJe.js +0 -176
  30. package/dist/_chunks/SettingsPage-C6QyloJe.js.map +0 -1
  31. package/dist/_chunks/SettingsPage-Drb7s719.mjs +0 -176
  32. package/dist/_chunks/SettingsPage-Drb7s719.mjs.map +0 -1
@@ -0,0 +1,183 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import * as React from "react";
3
+ import { Field, SingleSelect, SingleSelectOption, Box, Typography } from "@strapi/design-system";
4
+ import { useForm } from "@strapi/admin/strapi-admin";
5
+ import { useFetchClient } from "@strapi/strapi/admin";
6
+ const DEFAULT_HEADING_ITEMS = [
7
+ { value: "h1", label: "H1 - Main Page Title", maxAllowed: 1 },
8
+ { value: "h2", label: "H2 - Primary Section Heading", maxAllowed: 3 },
9
+ { value: "h3", label: "H3 - Sub-section Heading", maxAllowed: null },
10
+ { value: "h4", label: "H4 - Component Title", maxAllowed: null },
11
+ { value: "h5", label: "H5 - Card / Item Heading", maxAllowed: null },
12
+ { value: "h6", label: "H6 - Minor Heading", maxAllowed: null }
13
+ ];
14
+ function computeCrossComponentUsage(data, targetFieldLeafName, excludePath) {
15
+ const counts = {};
16
+ function traverse(current, currentPath) {
17
+ if (!current || typeof current !== "object") return;
18
+ for (const key of Object.keys(current)) {
19
+ const val = current[key];
20
+ const fullPath = currentPath ? `${currentPath}.${key}` : key;
21
+ if (key === targetFieldLeafName && fullPath !== excludePath && typeof val === "string" && val) {
22
+ counts[val] = (counts[val] || 0) + 1;
23
+ }
24
+ if (typeof val === "object" && val !== null) {
25
+ traverse(val, fullPath);
26
+ }
27
+ }
28
+ }
29
+ traverse(data, "");
30
+ return counts;
31
+ }
32
+ function ScopedQuotaSelectInput({
33
+ name,
34
+ value,
35
+ onChange,
36
+ attribute,
37
+ disabled = false,
38
+ required = false,
39
+ placeholder,
40
+ label,
41
+ hint
42
+ }) {
43
+ const { get } = useFetchClient();
44
+ const formValues = useForm("ScopedQuotaSelectInput", (state) => state.values) || {};
45
+ const fieldLeafName = name.split(".").pop() || name;
46
+ const [activeUiRule, setActiveUiRule] = React.useState(null);
47
+ React.useEffect(() => {
48
+ let isMounted = true;
49
+ get("/bulk-updater/validation-rules").then((res) => {
50
+ if (isMounted && res.data && res.data.success && Array.isArray(res.data.rules)) {
51
+ const matching = res.data.rules.find(
52
+ (r) => r.enabled && r.targetField === fieldLeafName
53
+ );
54
+ if (matching) {
55
+ setActiveUiRule(matching);
56
+ }
57
+ }
58
+ }).catch(() => {
59
+ });
60
+ return () => {
61
+ isMounted = false;
62
+ };
63
+ }, [fieldLeafName]);
64
+ const optionsConfig = attribute?.options || {};
65
+ const items = React.useMemo(() => {
66
+ const rawItems = optionsConfig.items && optionsConfig.items.length > 0 ? optionsConfig.items : activeUiRule?.quotas ? [] : DEFAULT_HEADING_ITEMS;
67
+ const map = /* @__PURE__ */ new Map();
68
+ rawItems.forEach((it) => map.set(it.value.toLowerCase(), { ...it }));
69
+ if (activeUiRule?.quotas) {
70
+ for (const [k, max] of Object.entries(activeUiRule.quotas)) {
71
+ const lowerK = k.toLowerCase();
72
+ if (map.has(lowerK)) {
73
+ const existing = map.get(lowerK);
74
+ map.set(lowerK, {
75
+ ...existing,
76
+ maxAllowed: typeof max === "number" ? max : existing.maxAllowed
77
+ });
78
+ } else {
79
+ const label2 = k.charAt(0).toUpperCase() + k.slice(1);
80
+ map.set(lowerK, {
81
+ value: lowerK,
82
+ label: label2,
83
+ maxAllowed: typeof max === "number" ? max : null
84
+ });
85
+ }
86
+ }
87
+ }
88
+ if (map.size === 0) {
89
+ DEFAULT_HEADING_ITEMS.forEach((it) => map.set(it.value.toLowerCase(), { ...it }));
90
+ }
91
+ return Array.from(map.values());
92
+ }, [optionsConfig.items, activeUiRule]);
93
+ const disabledBehavior = activeUiRule?.exceededAction || optionsConfig.disabledBehavior || "disable";
94
+ const otherUsage = React.useMemo(() => {
95
+ return computeCrossComponentUsage(formValues, fieldLeafName, name);
96
+ }, [formValues, fieldLeafName, name]);
97
+ const processedOptions = React.useMemo(() => {
98
+ return items.map((item) => {
99
+ const usedCount = otherUsage[item.value] || 0;
100
+ const max = item.maxAllowed;
101
+ const isQuotaReached = typeof max === "number" && max > 0 && usedCount >= max;
102
+ const isCurrentValue = value === item.value;
103
+ const isDisabled = isQuotaReached && !isCurrentValue;
104
+ let quotaNotice = "";
105
+ if (typeof max === "number" && max > 0) {
106
+ quotaNotice = `(${usedCount}/${max} used)`;
107
+ }
108
+ return {
109
+ ...item,
110
+ isDisabled,
111
+ quotaNotice,
112
+ isQuotaReached
113
+ };
114
+ }).filter((item) => {
115
+ if (disabledBehavior === "hide" && item.isDisabled) {
116
+ return false;
117
+ }
118
+ return true;
119
+ });
120
+ }, [items, otherUsage, value, disabledBehavior]);
121
+ const exhaustedItems = React.useMemo(() => {
122
+ return items.filter(
123
+ (i) => typeof i.maxAllowed === "number" && i.maxAllowed > 0 && (otherUsage[i.value] || 0) >= i.maxAllowed && value !== i.value
124
+ );
125
+ }, [items, otherUsage, value]);
126
+ const handleChange = (selectedVal) => {
127
+ if (onChange) {
128
+ onChange({ target: { name, value: selectedVal } });
129
+ }
130
+ };
131
+ const displayLabel = label || activeUiRule?.name || fieldLeafName.charAt(0).toUpperCase() + fieldLeafName.slice(1);
132
+ const displayPlaceholder = placeholder || `Select ${displayLabel}...`;
133
+ return /* @__PURE__ */ jsxs(Field.Root, { name, required, children: [
134
+ displayLabel && /* @__PURE__ */ jsx(Field.Label, { children: displayLabel }),
135
+ /* @__PURE__ */ jsx(
136
+ SingleSelect,
137
+ {
138
+ placeholder: displayPlaceholder,
139
+ value: value || "",
140
+ onChange: handleChange,
141
+ disabled,
142
+ children: processedOptions.map((opt) => /* @__PURE__ */ jsxs(
143
+ SingleSelectOption,
144
+ {
145
+ value: opt.value,
146
+ disabled: opt.isDisabled,
147
+ children: [
148
+ opt.label,
149
+ " ",
150
+ opt.quotaNotice && /* @__PURE__ */ jsxs("span", { style: { opacity: 0.65, fontSize: "0.85em", marginLeft: 6 }, children: [
151
+ "[",
152
+ opt.quotaNotice,
153
+ "]"
154
+ ] })
155
+ ]
156
+ },
157
+ opt.value
158
+ ))
159
+ }
160
+ ),
161
+ hint && /* @__PURE__ */ jsx(Field.Hint, { children: hint }),
162
+ exhaustedItems.length > 0 && /* @__PURE__ */ jsx(Box, { paddingTop: 1, children: exhaustedItems.map((item) => /* @__PURE__ */ jsxs(
163
+ Typography,
164
+ {
165
+ variant: "pi",
166
+ textColor: "neutral600",
167
+ style: { display: "block", marginTop: 2 },
168
+ children: [
169
+ "ℹ️ ",
170
+ /* @__PURE__ */ jsx("strong", { children: item.label }),
171
+ " quota reached (Max ",
172
+ item.maxAllowed,
173
+ " per entry)."
174
+ ]
175
+ },
176
+ item.value
177
+ )) })
178
+ ] });
179
+ }
180
+ export {
181
+ ScopedQuotaSelectInput as default
182
+ };
183
+ //# sourceMappingURL=ScopedQuotaSelectInput-ChWrQIBV.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ScopedQuotaSelectInput-ChWrQIBV.mjs","sources":["../../admin/src/components/ScopedQuotaSelectInput.tsx"],"sourcesContent":["import * as React from 'react';\nimport {\n Field,\n SingleSelect,\n SingleSelectOption,\n Box,\n Typography,\n} from '@strapi/design-system';\nimport { useForm } from '@strapi/admin/strapi-admin';\nimport { useFetchClient } from '@strapi/strapi/admin';\n\nexport interface QuotaItem {\n value: string;\n label: string;\n maxAllowed?: number | null; // e.g. 1 for H1, 3 for H2, null for unlimited\n}\n\nexport interface ScopedQuotaSelectProps {\n name: string;\n value?: string | null;\n onChange: (e: { target: { name: string; value: string } }) => void;\n attribute?: {\n type?: string;\n customField?: string;\n options?: {\n scope?: 'entry' | 'zone';\n disabledBehavior?: 'disable' | 'hide';\n items?: QuotaItem[];\n };\n };\n disabled?: boolean;\n required?: boolean;\n placeholder?: string;\n label?: React.ReactNode;\n hint?: React.ReactNode;\n}\n\n// Default fallback options if none configured on the attribute\nconst DEFAULT_HEADING_ITEMS: QuotaItem[] = [\n { value: 'h1', label: 'H1 - Main Page Title', maxAllowed: 1 },\n { value: 'h2', label: 'H2 - Primary Section Heading', maxAllowed: 3 },\n { value: 'h3', label: 'H3 - Sub-section Heading', maxAllowed: null },\n { value: 'h4', label: 'H4 - Component Title', maxAllowed: null },\n { value: 'h5', label: 'H5 - Card / Item Heading', maxAllowed: null },\n { value: 'h6', label: 'H6 - Minor Heading', maxAllowed: null },\n];\n\n/**\n * Recursively traverses the entire form data tree to count occurrences of target field values,\n * excluding the current input's exact field path.\n */\nfunction computeCrossComponentUsage(\n data: any,\n targetFieldLeafName: string,\n excludePath: string\n): Record<string, number> {\n const counts: Record<string, number> = {};\n\n function traverse(current: any, currentPath: string) {\n if (!current || typeof current !== 'object') return;\n\n for (const key of Object.keys(current)) {\n const val = current[key];\n const fullPath = currentPath ? `${currentPath}.${key}` : key;\n\n // Match target leaf name but exclude current field path\n if (key === targetFieldLeafName && fullPath !== excludePath && typeof val === 'string' && val) {\n counts[val] = (counts[val] || 0) + 1;\n }\n\n if (typeof val === 'object' && val !== null) {\n traverse(val, fullPath);\n }\n }\n }\n\n traverse(data, '');\n return counts;\n}\n\nexport default function ScopedQuotaSelectInput({\n name,\n value,\n onChange,\n attribute,\n disabled = false,\n required = false,\n placeholder,\n label,\n hint,\n}: ScopedQuotaSelectProps) {\n const { get } = useFetchClient();\n\n // Subscribe to live Formik/Form values in Strapi v5 Admin Edit View\n const formValues = useForm('ScopedQuotaSelectInput', (state) => state.values) || {};\n\n // Extract the leaf property name (e.g., 'headingLevel' from 'blocks.0.headingLevel')\n const fieldLeafName = name.split('.').pop() || name;\n\n // Active UI-configured rule state\n const [activeUiRule, setActiveUiRule] = React.useState<any>(null);\n\n React.useEffect(() => {\n let isMounted = true;\n get('/bulk-updater/validation-rules')\n .then((res: any) => {\n if (isMounted && res.data && res.data.success && Array.isArray(res.data.rules)) {\n const matching = res.data.rules.find(\n (r: any) => r.enabled && r.targetField === fieldLeafName\n );\n if (matching) {\n setActiveUiRule(matching);\n }\n }\n })\n .catch(() => {\n // Fall back gracefully to schema options on network/auth failure\n });\n return () => {\n isMounted = false;\n };\n }, [fieldLeafName]);\n\n const optionsConfig = attribute?.options || {};\n\n // Dynamically merge items: include items from attribute options, UI rules, or default headings\n const items: QuotaItem[] = React.useMemo(() => {\n const rawItems: QuotaItem[] = optionsConfig.items && optionsConfig.items.length > 0\n ? optionsConfig.items\n : (activeUiRule?.quotas ? [] : DEFAULT_HEADING_ITEMS);\n\n const map = new Map<string, QuotaItem>();\n rawItems.forEach((it) => map.set(it.value.toLowerCase(), { ...it }));\n\n if (activeUiRule?.quotas) {\n for (const [k, max] of Object.entries(activeUiRule.quotas)) {\n const lowerK = k.toLowerCase();\n if (map.has(lowerK)) {\n const existing = map.get(lowerK)!;\n map.set(lowerK, {\n ...existing,\n maxAllowed: typeof max === 'number' ? max : existing.maxAllowed,\n });\n } else {\n // Generate human-friendly label for custom option\n const label = k.charAt(0).toUpperCase() + k.slice(1);\n map.set(lowerK, {\n value: lowerK,\n label,\n maxAllowed: typeof max === 'number' ? max : null,\n });\n }\n }\n }\n\n // If still empty (e.g. newly added custom field with no quotas yet), fallback to default headings\n if (map.size === 0) {\n DEFAULT_HEADING_ITEMS.forEach((it) => map.set(it.value.toLowerCase(), { ...it }));\n }\n\n return Array.from(map.values());\n }, [optionsConfig.items, activeUiRule]);\n\n const disabledBehavior = activeUiRule?.exceededAction || optionsConfig.disabledBehavior || 'disable';\n\n // Compute other components' usage across the entire entry\n const otherUsage = React.useMemo(() => {\n return computeCrossComponentUsage(formValues, fieldLeafName, name);\n }, [formValues, fieldLeafName, name]);\n\n // Compute processed options: evaluate quotas and apply disable or hide rules\n const processedOptions = React.useMemo(() => {\n return items\n .map((item) => {\n const usedCount = otherUsage[item.value] || 0;\n const max = item.maxAllowed;\n\n // Quota is exhausted if other components have already reached maxAllowed\n const isQuotaReached = typeof max === 'number' && max > 0 && usedCount >= max;\n\n // If current field is already holding this value, allow keeping it\n const isCurrentValue = value === item.value;\n const isDisabled = isQuotaReached && !isCurrentValue;\n\n let quotaNotice = '';\n if (typeof max === 'number' && max > 0) {\n quotaNotice = `(${usedCount}/${max} used)`;\n }\n\n return {\n ...item,\n isDisabled,\n quotaNotice,\n isQuotaReached,\n };\n })\n .filter((item) => {\n if (disabledBehavior === 'hide' && item.isDisabled) {\n return false;\n }\n return true;\n });\n }, [items, otherUsage, value, disabledBehavior]);\n\n // Identify options whose quota has been exhausted by other components\n const exhaustedItems = React.useMemo(() => {\n return items.filter(\n (i) =>\n typeof i.maxAllowed === 'number' &&\n i.maxAllowed > 0 &&\n (otherUsage[i.value] || 0) >= i.maxAllowed &&\n value !== i.value\n );\n }, [items, otherUsage, value]);\n\n const handleChange = (selectedVal: string) => {\n if (onChange) {\n onChange({ target: { name, value: selectedVal } });\n }\n };\n\n const displayLabel = label || activeUiRule?.name || (fieldLeafName.charAt(0).toUpperCase() + fieldLeafName.slice(1));\n const displayPlaceholder = placeholder || `Select ${displayLabel}...`;\n\n return (\n <Field.Root name={name} required={required}>\n {displayLabel && <Field.Label>{displayLabel}</Field.Label>}\n <SingleSelect\n placeholder={displayPlaceholder}\n value={value || ''}\n onChange={handleChange}\n disabled={disabled}\n >\n {processedOptions.map((opt) => (\n <SingleSelectOption\n key={opt.value}\n value={opt.value}\n disabled={opt.isDisabled}\n >\n {opt.label}{' '}\n {opt.quotaNotice && (\n <span style={{ opacity: 0.65, fontSize: '0.85em', marginLeft: 6 }}>\n [{opt.quotaNotice}]\n </span>\n )}\n </SingleSelectOption>\n ))}\n </SingleSelect>\n {hint && <Field.Hint>{hint}</Field.Hint>}\n\n {exhaustedItems.length > 0 && (\n <Box paddingTop={1}>\n {exhaustedItems.map((item) => (\n <Typography\n key={item.value}\n variant=\"pi\"\n textColor=\"neutral600\"\n style={{ display: 'block', marginTop: 2 }}\n >\n ℹ️ <strong>{item.label}</strong> quota reached (Max {item.maxAllowed} per entry).\n </Typography>\n ))}\n </Box>\n )}\n </Field.Root>\n );\n}\n"],"names":["label"],"mappings":"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"}
@@ -0,0 +1,201 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const jsxRuntime = require("react/jsx-runtime");
4
+ const React = require("react");
5
+ const designSystem = require("@strapi/design-system");
6
+ const strapiAdmin = require("@strapi/admin/strapi-admin");
7
+ const admin = require("@strapi/strapi/admin");
8
+ function _interopNamespace(e) {
9
+ if (e && e.__esModule) return e;
10
+ const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
11
+ if (e) {
12
+ for (const k in e) {
13
+ if (k !== "default") {
14
+ const d = Object.getOwnPropertyDescriptor(e, k);
15
+ Object.defineProperty(n, k, d.get ? d : {
16
+ enumerable: true,
17
+ get: () => e[k]
18
+ });
19
+ }
20
+ }
21
+ }
22
+ n.default = e;
23
+ return Object.freeze(n);
24
+ }
25
+ const React__namespace = /* @__PURE__ */ _interopNamespace(React);
26
+ const DEFAULT_HEADING_ITEMS = [
27
+ { value: "h1", label: "H1 - Main Page Title", maxAllowed: 1 },
28
+ { value: "h2", label: "H2 - Primary Section Heading", maxAllowed: 3 },
29
+ { value: "h3", label: "H3 - Sub-section Heading", maxAllowed: null },
30
+ { value: "h4", label: "H4 - Component Title", maxAllowed: null },
31
+ { value: "h5", label: "H5 - Card / Item Heading", maxAllowed: null },
32
+ { value: "h6", label: "H6 - Minor Heading", maxAllowed: null }
33
+ ];
34
+ function computeCrossComponentUsage(data, targetFieldLeafName, excludePath) {
35
+ const counts = {};
36
+ function traverse(current, currentPath) {
37
+ if (!current || typeof current !== "object") return;
38
+ for (const key of Object.keys(current)) {
39
+ const val = current[key];
40
+ const fullPath = currentPath ? `${currentPath}.${key}` : key;
41
+ if (key === targetFieldLeafName && fullPath !== excludePath && typeof val === "string" && val) {
42
+ counts[val] = (counts[val] || 0) + 1;
43
+ }
44
+ if (typeof val === "object" && val !== null) {
45
+ traverse(val, fullPath);
46
+ }
47
+ }
48
+ }
49
+ traverse(data, "");
50
+ return counts;
51
+ }
52
+ function ScopedQuotaSelectInput({
53
+ name,
54
+ value,
55
+ onChange,
56
+ attribute,
57
+ disabled = false,
58
+ required = false,
59
+ placeholder,
60
+ label,
61
+ hint
62
+ }) {
63
+ const { get } = admin.useFetchClient();
64
+ const formValues = strapiAdmin.useForm("ScopedQuotaSelectInput", (state) => state.values) || {};
65
+ const fieldLeafName = name.split(".").pop() || name;
66
+ const [activeUiRule, setActiveUiRule] = React__namespace.useState(null);
67
+ React__namespace.useEffect(() => {
68
+ let isMounted = true;
69
+ get("/bulk-updater/validation-rules").then((res) => {
70
+ if (isMounted && res.data && res.data.success && Array.isArray(res.data.rules)) {
71
+ const matching = res.data.rules.find(
72
+ (r) => r.enabled && r.targetField === fieldLeafName
73
+ );
74
+ if (matching) {
75
+ setActiveUiRule(matching);
76
+ }
77
+ }
78
+ }).catch(() => {
79
+ });
80
+ return () => {
81
+ isMounted = false;
82
+ };
83
+ }, [fieldLeafName]);
84
+ const optionsConfig = attribute?.options || {};
85
+ const items = React__namespace.useMemo(() => {
86
+ const rawItems = optionsConfig.items && optionsConfig.items.length > 0 ? optionsConfig.items : activeUiRule?.quotas ? [] : DEFAULT_HEADING_ITEMS;
87
+ const map = /* @__PURE__ */ new Map();
88
+ rawItems.forEach((it) => map.set(it.value.toLowerCase(), { ...it }));
89
+ if (activeUiRule?.quotas) {
90
+ for (const [k, max] of Object.entries(activeUiRule.quotas)) {
91
+ const lowerK = k.toLowerCase();
92
+ if (map.has(lowerK)) {
93
+ const existing = map.get(lowerK);
94
+ map.set(lowerK, {
95
+ ...existing,
96
+ maxAllowed: typeof max === "number" ? max : existing.maxAllowed
97
+ });
98
+ } else {
99
+ const label2 = k.charAt(0).toUpperCase() + k.slice(1);
100
+ map.set(lowerK, {
101
+ value: lowerK,
102
+ label: label2,
103
+ maxAllowed: typeof max === "number" ? max : null
104
+ });
105
+ }
106
+ }
107
+ }
108
+ if (map.size === 0) {
109
+ DEFAULT_HEADING_ITEMS.forEach((it) => map.set(it.value.toLowerCase(), { ...it }));
110
+ }
111
+ return Array.from(map.values());
112
+ }, [optionsConfig.items, activeUiRule]);
113
+ const disabledBehavior = activeUiRule?.exceededAction || optionsConfig.disabledBehavior || "disable";
114
+ const otherUsage = React__namespace.useMemo(() => {
115
+ return computeCrossComponentUsage(formValues, fieldLeafName, name);
116
+ }, [formValues, fieldLeafName, name]);
117
+ const processedOptions = React__namespace.useMemo(() => {
118
+ return items.map((item) => {
119
+ const usedCount = otherUsage[item.value] || 0;
120
+ const max = item.maxAllowed;
121
+ const isQuotaReached = typeof max === "number" && max > 0 && usedCount >= max;
122
+ const isCurrentValue = value === item.value;
123
+ const isDisabled = isQuotaReached && !isCurrentValue;
124
+ let quotaNotice = "";
125
+ if (typeof max === "number" && max > 0) {
126
+ quotaNotice = `(${usedCount}/${max} used)`;
127
+ }
128
+ return {
129
+ ...item,
130
+ isDisabled,
131
+ quotaNotice,
132
+ isQuotaReached
133
+ };
134
+ }).filter((item) => {
135
+ if (disabledBehavior === "hide" && item.isDisabled) {
136
+ return false;
137
+ }
138
+ return true;
139
+ });
140
+ }, [items, otherUsage, value, disabledBehavior]);
141
+ const exhaustedItems = React__namespace.useMemo(() => {
142
+ return items.filter(
143
+ (i) => typeof i.maxAllowed === "number" && i.maxAllowed > 0 && (otherUsage[i.value] || 0) >= i.maxAllowed && value !== i.value
144
+ );
145
+ }, [items, otherUsage, value]);
146
+ const handleChange = (selectedVal) => {
147
+ if (onChange) {
148
+ onChange({ target: { name, value: selectedVal } });
149
+ }
150
+ };
151
+ const displayLabel = label || activeUiRule?.name || fieldLeafName.charAt(0).toUpperCase() + fieldLeafName.slice(1);
152
+ const displayPlaceholder = placeholder || `Select ${displayLabel}...`;
153
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { name, required, children: [
154
+ displayLabel && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: displayLabel }),
155
+ /* @__PURE__ */ jsxRuntime.jsx(
156
+ designSystem.SingleSelect,
157
+ {
158
+ placeholder: displayPlaceholder,
159
+ value: value || "",
160
+ onChange: handleChange,
161
+ disabled,
162
+ children: processedOptions.map((opt) => /* @__PURE__ */ jsxRuntime.jsxs(
163
+ designSystem.SingleSelectOption,
164
+ {
165
+ value: opt.value,
166
+ disabled: opt.isDisabled,
167
+ children: [
168
+ opt.label,
169
+ " ",
170
+ opt.quotaNotice && /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { opacity: 0.65, fontSize: "0.85em", marginLeft: 6 }, children: [
171
+ "[",
172
+ opt.quotaNotice,
173
+ "]"
174
+ ] })
175
+ ]
176
+ },
177
+ opt.value
178
+ ))
179
+ }
180
+ ),
181
+ hint && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Hint, { children: hint }),
182
+ exhaustedItems.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { paddingTop: 1, children: exhaustedItems.map((item) => /* @__PURE__ */ jsxRuntime.jsxs(
183
+ designSystem.Typography,
184
+ {
185
+ variant: "pi",
186
+ textColor: "neutral600",
187
+ style: { display: "block", marginTop: 2 },
188
+ children: [
189
+ "ℹ️ ",
190
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: item.label }),
191
+ " quota reached (Max ",
192
+ item.maxAllowed,
193
+ " per entry)."
194
+ ]
195
+ },
196
+ item.value
197
+ )) })
198
+ ] });
199
+ }
200
+ exports.default = ScopedQuotaSelectInput;
201
+ //# sourceMappingURL=ScopedQuotaSelectInput-s4oUMLgK.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ScopedQuotaSelectInput-s4oUMLgK.js","sources":["../../admin/src/components/ScopedQuotaSelectInput.tsx"],"sourcesContent":["import * as React from 'react';\nimport {\n Field,\n SingleSelect,\n SingleSelectOption,\n Box,\n Typography,\n} from '@strapi/design-system';\nimport { useForm } from '@strapi/admin/strapi-admin';\nimport { useFetchClient } from '@strapi/strapi/admin';\n\nexport interface QuotaItem {\n value: string;\n label: string;\n maxAllowed?: number | null; // e.g. 1 for H1, 3 for H2, null for unlimited\n}\n\nexport interface ScopedQuotaSelectProps {\n name: string;\n value?: string | null;\n onChange: (e: { target: { name: string; value: string } }) => void;\n attribute?: {\n type?: string;\n customField?: string;\n options?: {\n scope?: 'entry' | 'zone';\n disabledBehavior?: 'disable' | 'hide';\n items?: QuotaItem[];\n };\n };\n disabled?: boolean;\n required?: boolean;\n placeholder?: string;\n label?: React.ReactNode;\n hint?: React.ReactNode;\n}\n\n// Default fallback options if none configured on the attribute\nconst DEFAULT_HEADING_ITEMS: QuotaItem[] = [\n { value: 'h1', label: 'H1 - Main Page Title', maxAllowed: 1 },\n { value: 'h2', label: 'H2 - Primary Section Heading', maxAllowed: 3 },\n { value: 'h3', label: 'H3 - Sub-section Heading', maxAllowed: null },\n { value: 'h4', label: 'H4 - Component Title', maxAllowed: null },\n { value: 'h5', label: 'H5 - Card / Item Heading', maxAllowed: null },\n { value: 'h6', label: 'H6 - Minor Heading', maxAllowed: null },\n];\n\n/**\n * Recursively traverses the entire form data tree to count occurrences of target field values,\n * excluding the current input's exact field path.\n */\nfunction computeCrossComponentUsage(\n data: any,\n targetFieldLeafName: string,\n excludePath: string\n): Record<string, number> {\n const counts: Record<string, number> = {};\n\n function traverse(current: any, currentPath: string) {\n if (!current || typeof current !== 'object') return;\n\n for (const key of Object.keys(current)) {\n const val = current[key];\n const fullPath = currentPath ? `${currentPath}.${key}` : key;\n\n // Match target leaf name but exclude current field path\n if (key === targetFieldLeafName && fullPath !== excludePath && typeof val === 'string' && val) {\n counts[val] = (counts[val] || 0) + 1;\n }\n\n if (typeof val === 'object' && val !== null) {\n traverse(val, fullPath);\n }\n }\n }\n\n traverse(data, '');\n return counts;\n}\n\nexport default function ScopedQuotaSelectInput({\n name,\n value,\n onChange,\n attribute,\n disabled = false,\n required = false,\n placeholder,\n label,\n hint,\n}: ScopedQuotaSelectProps) {\n const { get } = useFetchClient();\n\n // Subscribe to live Formik/Form values in Strapi v5 Admin Edit View\n const formValues = useForm('ScopedQuotaSelectInput', (state) => state.values) || {};\n\n // Extract the leaf property name (e.g., 'headingLevel' from 'blocks.0.headingLevel')\n const fieldLeafName = name.split('.').pop() || name;\n\n // Active UI-configured rule state\n const [activeUiRule, setActiveUiRule] = React.useState<any>(null);\n\n React.useEffect(() => {\n let isMounted = true;\n get('/bulk-updater/validation-rules')\n .then((res: any) => {\n if (isMounted && res.data && res.data.success && Array.isArray(res.data.rules)) {\n const matching = res.data.rules.find(\n (r: any) => r.enabled && r.targetField === fieldLeafName\n );\n if (matching) {\n setActiveUiRule(matching);\n }\n }\n })\n .catch(() => {\n // Fall back gracefully to schema options on network/auth failure\n });\n return () => {\n isMounted = false;\n };\n }, [fieldLeafName]);\n\n const optionsConfig = attribute?.options || {};\n\n // Dynamically merge items: include items from attribute options, UI rules, or default headings\n const items: QuotaItem[] = React.useMemo(() => {\n const rawItems: QuotaItem[] = optionsConfig.items && optionsConfig.items.length > 0\n ? optionsConfig.items\n : (activeUiRule?.quotas ? [] : DEFAULT_HEADING_ITEMS);\n\n const map = new Map<string, QuotaItem>();\n rawItems.forEach((it) => map.set(it.value.toLowerCase(), { ...it }));\n\n if (activeUiRule?.quotas) {\n for (const [k, max] of Object.entries(activeUiRule.quotas)) {\n const lowerK = k.toLowerCase();\n if (map.has(lowerK)) {\n const existing = map.get(lowerK)!;\n map.set(lowerK, {\n ...existing,\n maxAllowed: typeof max === 'number' ? max : existing.maxAllowed,\n });\n } else {\n // Generate human-friendly label for custom option\n const label = k.charAt(0).toUpperCase() + k.slice(1);\n map.set(lowerK, {\n value: lowerK,\n label,\n maxAllowed: typeof max === 'number' ? max : null,\n });\n }\n }\n }\n\n // If still empty (e.g. newly added custom field with no quotas yet), fallback to default headings\n if (map.size === 0) {\n DEFAULT_HEADING_ITEMS.forEach((it) => map.set(it.value.toLowerCase(), { ...it }));\n }\n\n return Array.from(map.values());\n }, [optionsConfig.items, activeUiRule]);\n\n const disabledBehavior = activeUiRule?.exceededAction || optionsConfig.disabledBehavior || 'disable';\n\n // Compute other components' usage across the entire entry\n const otherUsage = React.useMemo(() => {\n return computeCrossComponentUsage(formValues, fieldLeafName, name);\n }, [formValues, fieldLeafName, name]);\n\n // Compute processed options: evaluate quotas and apply disable or hide rules\n const processedOptions = React.useMemo(() => {\n return items\n .map((item) => {\n const usedCount = otherUsage[item.value] || 0;\n const max = item.maxAllowed;\n\n // Quota is exhausted if other components have already reached maxAllowed\n const isQuotaReached = typeof max === 'number' && max > 0 && usedCount >= max;\n\n // If current field is already holding this value, allow keeping it\n const isCurrentValue = value === item.value;\n const isDisabled = isQuotaReached && !isCurrentValue;\n\n let quotaNotice = '';\n if (typeof max === 'number' && max > 0) {\n quotaNotice = `(${usedCount}/${max} used)`;\n }\n\n return {\n ...item,\n isDisabled,\n quotaNotice,\n isQuotaReached,\n };\n })\n .filter((item) => {\n if (disabledBehavior === 'hide' && item.isDisabled) {\n return false;\n }\n return true;\n });\n }, [items, otherUsage, value, disabledBehavior]);\n\n // Identify options whose quota has been exhausted by other components\n const exhaustedItems = React.useMemo(() => {\n return items.filter(\n (i) =>\n typeof i.maxAllowed === 'number' &&\n i.maxAllowed > 0 &&\n (otherUsage[i.value] || 0) >= i.maxAllowed &&\n value !== i.value\n );\n }, [items, otherUsage, value]);\n\n const handleChange = (selectedVal: string) => {\n if (onChange) {\n onChange({ target: { name, value: selectedVal } });\n }\n };\n\n const displayLabel = label || activeUiRule?.name || (fieldLeafName.charAt(0).toUpperCase() + fieldLeafName.slice(1));\n const displayPlaceholder = placeholder || `Select ${displayLabel}...`;\n\n return (\n <Field.Root name={name} required={required}>\n {displayLabel && <Field.Label>{displayLabel}</Field.Label>}\n <SingleSelect\n placeholder={displayPlaceholder}\n value={value || ''}\n onChange={handleChange}\n disabled={disabled}\n >\n {processedOptions.map((opt) => (\n <SingleSelectOption\n key={opt.value}\n value={opt.value}\n disabled={opt.isDisabled}\n >\n {opt.label}{' '}\n {opt.quotaNotice && (\n <span style={{ opacity: 0.65, fontSize: '0.85em', marginLeft: 6 }}>\n [{opt.quotaNotice}]\n </span>\n )}\n </SingleSelectOption>\n ))}\n </SingleSelect>\n {hint && <Field.Hint>{hint}</Field.Hint>}\n\n {exhaustedItems.length > 0 && (\n <Box paddingTop={1}>\n {exhaustedItems.map((item) => (\n <Typography\n key={item.value}\n variant=\"pi\"\n textColor=\"neutral600\"\n style={{ display: 'block', marginTop: 2 }}\n >\n ℹ️ <strong>{item.label}</strong> quota reached (Max {item.maxAllowed} per entry).\n </Typography>\n ))}\n </Box>\n )}\n </Field.Root>\n );\n}\n"],"names":["useFetchClient","useForm","React","label","jsxs","Field","jsx","SingleSelect","SingleSelectOption","Box","Typography"],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const jsxRuntime = require("react/jsx-runtime");
4
+ const designSystem = require("@strapi/design-system");
5
+ const icons = require("@strapi/icons");
6
+ const ValidationRulesTab = require("./ValidationRulesTab-BoqhoTjo.js");
7
+ const ALL_FEATURES = [
8
+ "Cross-collection batch attribute & relationship updates",
9
+ "Interactive schema compatibility & target selection",
10
+ "Full regex find & replace with live diff previews",
11
+ "Dynamic cross-component quota validation (UI-configurable)",
12
+ "Enterprise Maker-Checker 4-Eyes approval workflow",
13
+ "Server-enforced off-peak execution maintenance window",
14
+ "3-Tier comprehensive audit logging with one-click reversible rollback",
15
+ "Zero-infra memory caching & pod-level ETag optimization"
16
+ ];
17
+ const SettingsPage = () => {
18
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { padding: 8, background: "neutral100", children: [
19
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", alignItems: "flex-start", gap: 2, marginBottom: 6, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "space-between", width: "100%", children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
20
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", tag: "h1", fontWeight: "bold", children: "Bulk Attribute Updater Settings" }),
21
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", textColor: "neutral600", children: "Configure cross-component validation rules, manage quotas, and view active plugin capabilities." })
22
+ ] }) }) }),
23
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { padding: 6, background: "neutral0", shadow: "filterShadow", hasRadius: true, marginBottom: 6, children: [
24
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", alignItems: "center", marginBottom: 4, children: [
25
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
26
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "delta", tag: "h2", fontWeight: "semiBold", children: "Plugin Status" }),
27
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: "All features are fully unlocked, active, and free under the MIT open-source license." })
28
+ ] }),
29
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { backgroundColor: "success100", textColor: "success700", size: "M", children: "COMMUNITY & ENTERPRISE UNLOCKED" })
30
+ ] }),
31
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { marginTop: 4, children: [
32
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", fontWeight: "bold", textColor: "neutral700", marginBottom: 3, children: "Active Capabilities:" }),
33
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", gap: 2, alignItems: "flex-start", marginTop: 2, children: ALL_FEATURES.map((feat, i) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, alignItems: "center", children: [
34
+ /* @__PURE__ */ jsxRuntime.jsx(icons.Check, { width: "16px", height: "16px", color: "#328048" }),
35
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", children: feat })
36
+ ] }, i)) })
37
+ ] })
38
+ ] }),
39
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 6, children: /* @__PURE__ */ jsxRuntime.jsx(ValidationRulesTab.ValidationRulesTab, {}) })
40
+ ] });
41
+ };
42
+ exports.default = SettingsPage;
43
+ //# sourceMappingURL=SettingsPage-BRGTrW9H.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SettingsPage-BRGTrW9H.js","sources":["../../admin/src/pages/SettingsPage.tsx"],"sourcesContent":["import React from 'react';\nimport {\n Box,\n Flex,\n Typography,\n Badge,\n} from '@strapi/design-system';\nimport { Check } from '@strapi/icons';\nimport ValidationRulesTab from './ValidationRulesTab';\n\nconst ALL_FEATURES = [\n 'Cross-collection batch attribute & relationship updates',\n 'Interactive schema compatibility & target selection',\n 'Full regex find & replace with live diff previews',\n 'Dynamic cross-component quota validation (UI-configurable)',\n 'Enterprise Maker-Checker 4-Eyes approval workflow',\n 'Server-enforced off-peak execution maintenance window',\n '3-Tier comprehensive audit logging with one-click reversible rollback',\n 'Zero-infra memory caching & pod-level ETag optimization',\n];\n\nconst SettingsPage: React.FC = () => {\n return (\n <Box padding={8} background=\"neutral100\">\n <Flex direction=\"column\" alignItems=\"flex-start\" gap={2} marginBottom={6}>\n <Flex justifyContent=\"space-between\" width=\"100%\">\n <Box>\n <Typography variant=\"alpha\" tag=\"h1\" fontWeight=\"bold\">\n Bulk Attribute Updater Settings\n </Typography>\n <Typography variant=\"omega\" textColor=\"neutral600\">\n Configure cross-component validation rules, manage quotas, and view active plugin capabilities.\n </Typography>\n </Box>\n </Flex>\n </Flex>\n\n {/* Plugin Status Card */}\n <Box padding={6} background=\"neutral0\" shadow=\"filterShadow\" hasRadius marginBottom={6}>\n <Flex justifyContent=\"space-between\" alignItems=\"center\" marginBottom={4}>\n <Box>\n <Typography variant=\"delta\" tag=\"h2\" fontWeight=\"semiBold\">\n Plugin Status\n </Typography>\n <Typography variant=\"pi\" textColor=\"neutral600\">\n All features are fully unlocked, active, and free under the MIT open-source license.\n </Typography>\n </Box>\n <Badge backgroundColor=\"success100\" textColor=\"success700\" size=\"M\">\n COMMUNITY & ENTERPRISE UNLOCKED\n </Badge>\n </Flex>\n\n {/* Features Checklist */}\n <Box marginTop={4}>\n <Typography variant=\"pi\" fontWeight=\"bold\" textColor=\"neutral700\" marginBottom={3}>\n Active Capabilities:\n </Typography>\n <Flex direction=\"column\" gap={2} alignItems=\"flex-start\" marginTop={2}>\n {ALL_FEATURES.map((feat, i) => (\n <Flex key={i} gap={2} alignItems=\"center\">\n <Check width=\"16px\" height=\"16px\" color=\"#328048\" />\n <Typography variant=\"omega\">{feat}</Typography>\n </Flex>\n ))}\n </Flex>\n </Box>\n </Box>\n\n {/* Validation Rules Section */}\n <Box marginTop={6}>\n <ValidationRulesTab />\n </Box>\n </Box>\n );\n};\n\nexport default SettingsPage;\n"],"names":["jsxs","Box","jsx","Flex","Typography","Badge","Check","ValidationRulesTab"],"mappings":";;;;;;AAUA,MAAM,eAAe;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,MAAM,eAAyB,MAAM;AACnC,SACEA,2BAAAA,KAACC,aAAAA,KAAA,EAAI,SAAS,GAAG,YAAW,cAC1B,UAAA;AAAA,IAAAC,2BAAAA,IAACC,aAAAA,QAAK,WAAU,UAAS,YAAW,cAAa,KAAK,GAAG,cAAc,GACrE,UAAAD,2BAAAA,IAACC,qBAAK,gBAAe,iBAAgB,OAAM,QACzC,0CAACF,kBAAA,EACC,UAAA;AAAA,MAAAC,2BAAAA,IAACE,aAAAA,cAAW,SAAQ,SAAQ,KAAI,MAAK,YAAW,QAAO,UAAA,kCAAA,CAEvD;AAAA,qCACCA,aAAAA,YAAA,EAAW,SAAQ,SAAQ,WAAU,cAAa,UAAA,kGAAA,CAEnD;AAAA,IAAA,EAAA,CACF,GACF,GACF;AAAA,IAGAJ,2BAAAA,KAACC,aAAAA,KAAA,EAAI,SAAS,GAAG,YAAW,YAAW,QAAO,gBAAe,WAAS,MAAC,cAAc,GACnF,UAAA;AAAA,MAAAD,gCAACG,aAAAA,QAAK,gBAAe,iBAAgB,YAAW,UAAS,cAAc,GACrE,UAAA;AAAA,QAAAH,gCAACC,aAAAA,KAAA,EACC,UAAA;AAAA,UAAAC,2BAAAA,IAACE,aAAAA,cAAW,SAAQ,SAAQ,KAAI,MAAK,YAAW,YAAW,UAAA,gBAAA,CAE3D;AAAA,yCACCA,aAAAA,YAAA,EAAW,SAAQ,MAAK,WAAU,cAAa,UAAA,uFAAA,CAEhD;AAAA,QAAA,GACF;AAAA,QACAF,2BAAAA,IAACG,aAAAA,SAAM,iBAAgB,cAAa,WAAU,cAAa,MAAK,KAAI,UAAA,kCAAA,CAEpE;AAAA,MAAA,GACF;AAAA,MAGAL,2BAAAA,KAACC,aAAAA,KAAA,EAAI,WAAW,GACd,UAAA;AAAA,QAAAC,2BAAAA,IAACE,aAAAA,YAAA,EAAW,SAAQ,MAAK,YAAW,QAAO,WAAU,cAAa,cAAc,GAAG,UAAA,uBAAA,CAEnF;AAAA,QACAF,2BAAAA,IAACC,aAAAA,QAAK,WAAU,UAAS,KAAK,GAAG,YAAW,cAAa,WAAW,GACjE,uBAAa,IAAI,CAAC,MAAM,MACvBH,gCAACG,aAAAA,QAAa,KAAK,GAAG,YAAW,UAC/B,UAAA;AAAA,UAAAD,+BAACI,MAAAA,SAAM,OAAM,QAAO,QAAO,QAAO,OAAM,WAAU;AAAA,UAClDJ,2BAAAA,IAACE,aAAAA,YAAA,EAAW,SAAQ,SAAS,UAAA,KAAA,CAAK;AAAA,QAAA,EAAA,GAFzB,CAGX,CACD,EAAA,CACH;AAAA,MAAA,EAAA,CACF;AAAA,IAAA,GACF;AAAA,mCAGCH,aAAAA,KAAA,EAAI,WAAW,GACd,UAAAC,2BAAAA,IAACK,yCAAmB,EAAA,CACtB;AAAA,EAAA,GACF;AAEJ;;"}
@@ -0,0 +1,43 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import { Box, Flex, Typography, Badge } from "@strapi/design-system";
3
+ import { Check } from "@strapi/icons";
4
+ import { V as ValidationRulesTab } from "./ValidationRulesTab-BGcqM9cN.mjs";
5
+ const ALL_FEATURES = [
6
+ "Cross-collection batch attribute & relationship updates",
7
+ "Interactive schema compatibility & target selection",
8
+ "Full regex find & replace with live diff previews",
9
+ "Dynamic cross-component quota validation (UI-configurable)",
10
+ "Enterprise Maker-Checker 4-Eyes approval workflow",
11
+ "Server-enforced off-peak execution maintenance window",
12
+ "3-Tier comprehensive audit logging with one-click reversible rollback",
13
+ "Zero-infra memory caching & pod-level ETag optimization"
14
+ ];
15
+ const SettingsPage = () => {
16
+ return /* @__PURE__ */ jsxs(Box, { padding: 8, background: "neutral100", children: [
17
+ /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "flex-start", gap: 2, marginBottom: 6, children: /* @__PURE__ */ jsx(Flex, { justifyContent: "space-between", width: "100%", children: /* @__PURE__ */ jsxs(Box, { children: [
18
+ /* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", fontWeight: "bold", children: "Bulk Attribute Updater Settings" }),
19
+ /* @__PURE__ */ jsx(Typography, { variant: "omega", textColor: "neutral600", children: "Configure cross-component validation rules, manage quotas, and view active plugin capabilities." })
20
+ ] }) }) }),
21
+ /* @__PURE__ */ jsxs(Box, { padding: 6, background: "neutral0", shadow: "filterShadow", hasRadius: true, marginBottom: 6, children: [
22
+ /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", marginBottom: 4, children: [
23
+ /* @__PURE__ */ jsxs(Box, { children: [
24
+ /* @__PURE__ */ jsx(Typography, { variant: "delta", tag: "h2", fontWeight: "semiBold", children: "Plugin Status" }),
25
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: "All features are fully unlocked, active, and free under the MIT open-source license." })
26
+ ] }),
27
+ /* @__PURE__ */ jsx(Badge, { backgroundColor: "success100", textColor: "success700", size: "M", children: "COMMUNITY & ENTERPRISE UNLOCKED" })
28
+ ] }),
29
+ /* @__PURE__ */ jsxs(Box, { marginTop: 4, children: [
30
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", textColor: "neutral700", marginBottom: 3, children: "Active Capabilities:" }),
31
+ /* @__PURE__ */ jsx(Flex, { direction: "column", gap: 2, alignItems: "flex-start", marginTop: 2, children: ALL_FEATURES.map((feat, i) => /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", children: [
32
+ /* @__PURE__ */ jsx(Check, { width: "16px", height: "16px", color: "#328048" }),
33
+ /* @__PURE__ */ jsx(Typography, { variant: "omega", children: feat })
34
+ ] }, i)) })
35
+ ] })
36
+ ] }),
37
+ /* @__PURE__ */ jsx(Box, { marginTop: 6, children: /* @__PURE__ */ jsx(ValidationRulesTab, {}) })
38
+ ] });
39
+ };
40
+ export {
41
+ SettingsPage as default
42
+ };
43
+ //# sourceMappingURL=SettingsPage-ieu-Out8.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SettingsPage-ieu-Out8.mjs","sources":["../../admin/src/pages/SettingsPage.tsx"],"sourcesContent":["import React from 'react';\nimport {\n Box,\n Flex,\n Typography,\n Badge,\n} from '@strapi/design-system';\nimport { Check } from '@strapi/icons';\nimport ValidationRulesTab from './ValidationRulesTab';\n\nconst ALL_FEATURES = [\n 'Cross-collection batch attribute & relationship updates',\n 'Interactive schema compatibility & target selection',\n 'Full regex find & replace with live diff previews',\n 'Dynamic cross-component quota validation (UI-configurable)',\n 'Enterprise Maker-Checker 4-Eyes approval workflow',\n 'Server-enforced off-peak execution maintenance window',\n '3-Tier comprehensive audit logging with one-click reversible rollback',\n 'Zero-infra memory caching & pod-level ETag optimization',\n];\n\nconst SettingsPage: React.FC = () => {\n return (\n <Box padding={8} background=\"neutral100\">\n <Flex direction=\"column\" alignItems=\"flex-start\" gap={2} marginBottom={6}>\n <Flex justifyContent=\"space-between\" width=\"100%\">\n <Box>\n <Typography variant=\"alpha\" tag=\"h1\" fontWeight=\"bold\">\n Bulk Attribute Updater Settings\n </Typography>\n <Typography variant=\"omega\" textColor=\"neutral600\">\n Configure cross-component validation rules, manage quotas, and view active plugin capabilities.\n </Typography>\n </Box>\n </Flex>\n </Flex>\n\n {/* Plugin Status Card */}\n <Box padding={6} background=\"neutral0\" shadow=\"filterShadow\" hasRadius marginBottom={6}>\n <Flex justifyContent=\"space-between\" alignItems=\"center\" marginBottom={4}>\n <Box>\n <Typography variant=\"delta\" tag=\"h2\" fontWeight=\"semiBold\">\n Plugin Status\n </Typography>\n <Typography variant=\"pi\" textColor=\"neutral600\">\n All features are fully unlocked, active, and free under the MIT open-source license.\n </Typography>\n </Box>\n <Badge backgroundColor=\"success100\" textColor=\"success700\" size=\"M\">\n COMMUNITY & ENTERPRISE UNLOCKED\n </Badge>\n </Flex>\n\n {/* Features Checklist */}\n <Box marginTop={4}>\n <Typography variant=\"pi\" fontWeight=\"bold\" textColor=\"neutral700\" marginBottom={3}>\n Active Capabilities:\n </Typography>\n <Flex direction=\"column\" gap={2} alignItems=\"flex-start\" marginTop={2}>\n {ALL_FEATURES.map((feat, i) => (\n <Flex key={i} gap={2} alignItems=\"center\">\n <Check width=\"16px\" height=\"16px\" color=\"#328048\" />\n <Typography variant=\"omega\">{feat}</Typography>\n </Flex>\n ))}\n </Flex>\n </Box>\n </Box>\n\n {/* Validation Rules Section */}\n <Box marginTop={6}>\n <ValidationRulesTab />\n </Box>\n </Box>\n );\n};\n\nexport default SettingsPage;\n"],"names":[],"mappings":";;;;AAUA,MAAM,eAAe;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,MAAM,eAAyB,MAAM;AACnC,SACE,qBAAC,KAAA,EAAI,SAAS,GAAG,YAAW,cAC1B,UAAA;AAAA,IAAA,oBAAC,QAAK,WAAU,UAAS,YAAW,cAAa,KAAK,GAAG,cAAc,GACrE,UAAA,oBAAC,QAAK,gBAAe,iBAAgB,OAAM,QACzC,+BAAC,KAAA,EACC,UAAA;AAAA,MAAA,oBAAC,cAAW,SAAQ,SAAQ,KAAI,MAAK,YAAW,QAAO,UAAA,kCAAA,CAEvD;AAAA,0BACC,YAAA,EAAW,SAAQ,SAAQ,WAAU,cAAa,UAAA,kGAAA,CAEnD;AAAA,IAAA,EAAA,CACF,GACF,GACF;AAAA,IAGA,qBAAC,KAAA,EAAI,SAAS,GAAG,YAAW,YAAW,QAAO,gBAAe,WAAS,MAAC,cAAc,GACnF,UAAA;AAAA,MAAA,qBAAC,QAAK,gBAAe,iBAAgB,YAAW,UAAS,cAAc,GACrE,UAAA;AAAA,QAAA,qBAAC,KAAA,EACC,UAAA;AAAA,UAAA,oBAAC,cAAW,SAAQ,SAAQ,KAAI,MAAK,YAAW,YAAW,UAAA,gBAAA,CAE3D;AAAA,8BACC,YAAA,EAAW,SAAQ,MAAK,WAAU,cAAa,UAAA,uFAAA,CAEhD;AAAA,QAAA,GACF;AAAA,QACA,oBAAC,SAAM,iBAAgB,cAAa,WAAU,cAAa,MAAK,KAAI,UAAA,kCAAA,CAEpE;AAAA,MAAA,GACF;AAAA,MAGA,qBAAC,KAAA,EAAI,WAAW,GACd,UAAA;AAAA,QAAA,oBAAC,YAAA,EAAW,SAAQ,MAAK,YAAW,QAAO,WAAU,cAAa,cAAc,GAAG,UAAA,uBAAA,CAEnF;AAAA,QACA,oBAAC,QAAK,WAAU,UAAS,KAAK,GAAG,YAAW,cAAa,WAAW,GACjE,uBAAa,IAAI,CAAC,MAAM,MACvB,qBAAC,QAAa,KAAK,GAAG,YAAW,UAC/B,UAAA;AAAA,UAAA,oBAAC,SAAM,OAAM,QAAO,QAAO,QAAO,OAAM,WAAU;AAAA,UAClD,oBAAC,YAAA,EAAW,SAAQ,SAAS,UAAA,KAAA,CAAK;AAAA,QAAA,EAAA,GAFzB,CAGX,CACD,EAAA,CACH;AAAA,MAAA,EAAA,CACF;AAAA,IAAA,GACF;AAAA,wBAGC,KAAA,EAAI,WAAW,GACd,UAAA,oBAAC,sBAAmB,EAAA,CACtB;AAAA,EAAA,GACF;AAEJ;"}