@timeax/service-builder 0.2.0 → 0.2.1
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/dist/index.js +736 -301
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -3453,6 +3453,23 @@ function StatusDot({ tone = "default", className }) {
|
|
|
3453
3453
|
|
|
3454
3454
|
// src/builder/service-context.ts
|
|
3455
3455
|
import { createBuilder } from "@timeax/digital-service-engine/core";
|
|
3456
|
+
function createEmptyServiceContextSnapshot(state, props) {
|
|
3457
|
+
const filters = props?.filters ?? [];
|
|
3458
|
+
const tags = filters.map((tag) => ({
|
|
3459
|
+
id: tag.id,
|
|
3460
|
+
label: tag.label,
|
|
3461
|
+
description: describeTag(tag)
|
|
3462
|
+
}));
|
|
3463
|
+
const selectedTag = filters.find((tag) => tag.id === state.selectedTagId) ?? null;
|
|
3464
|
+
return {
|
|
3465
|
+
state,
|
|
3466
|
+
tags,
|
|
3467
|
+
selectedTag,
|
|
3468
|
+
buttonGroups: [],
|
|
3469
|
+
visibleFieldIds: [],
|
|
3470
|
+
usedServiceIds: []
|
|
3471
|
+
};
|
|
3472
|
+
}
|
|
3456
3473
|
function createDefaultServiceContext(props, preferredTagId) {
|
|
3457
3474
|
const tagIds = (props?.filters ?? []).map((tag) => tag.id);
|
|
3458
3475
|
return {
|
|
@@ -3468,43 +3485,37 @@ function sanitizeServiceContext(snapshot, state) {
|
|
|
3468
3485
|
if (selectedButtons.length === state.selectedButtons.length) return state;
|
|
3469
3486
|
return { ...state, selectedButtons };
|
|
3470
3487
|
}
|
|
3471
|
-
function buildServiceContextSnapshot(args) {
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
selectedTag,
|
|
3485
|
-
buttonGroups
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3488
|
+
async function buildServiceContextSnapshot(args) {
|
|
3489
|
+
return new Promise((resolve) => {
|
|
3490
|
+
setTimeout(() => {
|
|
3491
|
+
const props = args.props ?? void 0;
|
|
3492
|
+
const serviceMap = args.services ?? {};
|
|
3493
|
+
const emptySnapshot = createEmptyServiceContextSnapshot(args.state, props);
|
|
3494
|
+
const { tags, selectedTag } = emptySnapshot;
|
|
3495
|
+
if (!props || !selectedTag) {
|
|
3496
|
+
resolve(emptySnapshot);
|
|
3497
|
+
return;
|
|
3498
|
+
}
|
|
3499
|
+
const sandbox = createBuilder({ serviceMap });
|
|
3500
|
+
sandbox.load(props);
|
|
3501
|
+
const visibleFieldIds = sandbox.visibleFields(selectedTag.id, args.state.selectedButtons);
|
|
3502
|
+
const buttonGroups = buildButtonGroups(props.fields ?? [], visibleFieldIds);
|
|
3503
|
+
const usedServiceIds = collectUsedServiceIds({
|
|
3504
|
+
props,
|
|
3505
|
+
tagId: selectedTag.id,
|
|
3506
|
+
visibleFieldIds,
|
|
3507
|
+
selectedButtons: args.state.selectedButtons
|
|
3508
|
+
});
|
|
3509
|
+
resolve({
|
|
3510
|
+
state: args.state,
|
|
3511
|
+
tags,
|
|
3512
|
+
selectedTag,
|
|
3513
|
+
buttonGroups,
|
|
3514
|
+
visibleFieldIds,
|
|
3515
|
+
usedServiceIds
|
|
3516
|
+
});
|
|
3517
|
+
}, 0);
|
|
3499
3518
|
});
|
|
3500
|
-
return {
|
|
3501
|
-
state: args.state,
|
|
3502
|
-
tags,
|
|
3503
|
-
selectedTag,
|
|
3504
|
-
buttonGroups,
|
|
3505
|
-
visibleFieldIds,
|
|
3506
|
-
usedServiceIds
|
|
3507
|
-
};
|
|
3508
3519
|
}
|
|
3509
3520
|
function buildServiceRowVM(args) {
|
|
3510
3521
|
const service = args.services?.[args.summary.id] ?? null;
|
|
@@ -6444,6 +6455,8 @@ function CanvasPanel({
|
|
|
6444
6455
|
const [presentationVersion, setPresentationVersion] = useState8(0);
|
|
6445
6456
|
const lastSyncedSnapshotHashRef = useRef5(initialSnapshotHash);
|
|
6446
6457
|
const guardedEditorRef = useRef5(null);
|
|
6458
|
+
const liveSnapshotRequestRef = useRef5(0);
|
|
6459
|
+
const checksByIdRequestRef = useRef5(0);
|
|
6447
6460
|
const servicesMap = ws.services?.data ?? {};
|
|
6448
6461
|
const errorNodeIds = useMemo9(
|
|
6449
6462
|
() => new Set((errors.merged.validation ?? []).map((row) => row.nodeId).filter(Boolean)),
|
|
@@ -6682,21 +6695,45 @@ function CanvasPanel({
|
|
|
6682
6695
|
}),
|
|
6683
6696
|
[resolvedCurrentTagId, selectedButtons]
|
|
6684
6697
|
);
|
|
6685
|
-
const liveContextSnapshot =
|
|
6686
|
-
|
|
6687
|
-
|
|
6688
|
-
|
|
6689
|
-
|
|
6690
|
-
|
|
6698
|
+
const [liveContextSnapshot, setLiveContextSnapshot] = useState8(() => createEmptyServiceContextSnapshot(liveContextState, canvas.props));
|
|
6699
|
+
useEffect8(() => {
|
|
6700
|
+
const requestId = ++liveSnapshotRequestRef.current;
|
|
6701
|
+
const fallback = createEmptyServiceContextSnapshot(liveContextState, canvas.props);
|
|
6702
|
+
setLiveContextSnapshot(fallback);
|
|
6703
|
+
buildServiceContextSnapshot({ props: canvas.props, services: servicesMap, state: liveContextState }).then((snapshot) => {
|
|
6704
|
+
if (liveSnapshotRequestRef.current !== requestId) return;
|
|
6705
|
+
setLiveContextSnapshot(snapshot);
|
|
6706
|
+
}).catch(() => {
|
|
6707
|
+
if (liveSnapshotRequestRef.current !== requestId) return;
|
|
6708
|
+
setLiveContextSnapshot(fallback);
|
|
6709
|
+
});
|
|
6710
|
+
}, [canvas.props, liveContextState, servicesMap]);
|
|
6711
|
+
const [checksById, setChecksById] = useState8(/* @__PURE__ */ new Map());
|
|
6712
|
+
useEffect8(() => {
|
|
6713
|
+
const requestId = ++checksByIdRequestRef.current;
|
|
6714
|
+
if (!liveContextSnapshot.selectedTag) {
|
|
6715
|
+
setChecksById(/* @__PURE__ */ new Map());
|
|
6716
|
+
return;
|
|
6717
|
+
}
|
|
6691
6718
|
const candidateIds = Object.values(servicesMap).map((service) => service.id);
|
|
6692
|
-
|
|
6693
|
-
|
|
6694
|
-
|
|
6695
|
-
|
|
6696
|
-
|
|
6697
|
-
|
|
6719
|
+
new Promise((resolve) => {
|
|
6720
|
+
setTimeout(() => {
|
|
6721
|
+
const checks = canvas.api.editor.filterServicesForVisibleGroup(candidateIds, {
|
|
6722
|
+
tagId: liveContextSnapshot.selectedTag.id,
|
|
6723
|
+
selectedButtons: liveContextSnapshot.state.selectedButtons,
|
|
6724
|
+
usedServiceIds: liveContextSnapshot.usedServiceIds,
|
|
6725
|
+
effectiveConstraints: liveContextSnapshot.selectedTag.constraints,
|
|
6726
|
+
policies: ws.policies?.policies?.data ?? []
|
|
6727
|
+
});
|
|
6728
|
+
resolve(Array.isArray(checks) ? checks : []);
|
|
6729
|
+
}, 0);
|
|
6730
|
+
}).then((checks) => {
|
|
6731
|
+
if (checksByIdRequestRef.current !== requestId) return;
|
|
6732
|
+
setChecksById(new Map(checks.map((check) => [String(check.id), check])));
|
|
6733
|
+
}).catch(() => {
|
|
6734
|
+
if (checksByIdRequestRef.current !== requestId) return;
|
|
6735
|
+
setChecksById(/* @__PURE__ */ new Map());
|
|
6698
6736
|
});
|
|
6699
|
-
return new Map(checks.map((check) => [String(check.id), check]));
|
|
6700
6737
|
}, [canvas.api.editor, liveContextSnapshot, servicesMap, ws.policies?.policies?.data]);
|
|
6701
6738
|
const serviceContextRows = useMemo9(() => {
|
|
6702
6739
|
return liveContextSnapshot.usedServiceIds.map((id) => {
|
|
@@ -11916,6 +11953,76 @@ function IncludesIconAction({ kind, onClick, disabled, title, icon, className })
|
|
|
11916
11953
|
);
|
|
11917
11954
|
}
|
|
11918
11955
|
|
|
11956
|
+
// src/builder/compatibility-runner.ts
|
|
11957
|
+
var DEFAULT_CHUNK_SIZE = 100;
|
|
11958
|
+
function yieldToMainThread() {
|
|
11959
|
+
return new Promise((resolve) => {
|
|
11960
|
+
setTimeout(() => resolve(), 0);
|
|
11961
|
+
});
|
|
11962
|
+
}
|
|
11963
|
+
async function runCompatibilityChecksIncremental(input) {
|
|
11964
|
+
const { editor, args, cache, cacheKey } = input;
|
|
11965
|
+
const chunkSize = input.chunkSize ?? DEFAULT_CHUNK_SIZE;
|
|
11966
|
+
const candidateKeys = input.candidateIds.map((id) => String(id));
|
|
11967
|
+
const checksById = /* @__PURE__ */ new Map();
|
|
11968
|
+
const missingIds = [];
|
|
11969
|
+
for (let index = 0; index < input.candidateIds.length; index += 1) {
|
|
11970
|
+
const candidateId = input.candidateIds[index];
|
|
11971
|
+
const candidateKey = candidateKeys[index];
|
|
11972
|
+
const entryKey = `${cacheKey}|${candidateKey}`;
|
|
11973
|
+
const cached = cache.get(entryKey);
|
|
11974
|
+
if (cached) {
|
|
11975
|
+
checksById.set(candidateKey, cached);
|
|
11976
|
+
continue;
|
|
11977
|
+
}
|
|
11978
|
+
missingIds.push(candidateId);
|
|
11979
|
+
}
|
|
11980
|
+
if (!missingIds.length) {
|
|
11981
|
+
return candidateKeys.map((id) => checksById.get(id)).filter(Boolean);
|
|
11982
|
+
}
|
|
11983
|
+
for (let start = 0; start < missingIds.length; start += chunkSize) {
|
|
11984
|
+
if (input.shouldAbort?.()) return [];
|
|
11985
|
+
await yieldToMainThread();
|
|
11986
|
+
if (input.shouldAbort?.()) return [];
|
|
11987
|
+
const chunk = missingIds.slice(start, start + chunkSize);
|
|
11988
|
+
const checks = editor.filterServicesForVisibleGroup?.(chunk, args) ?? [];
|
|
11989
|
+
for (const check of checks) {
|
|
11990
|
+
const id = check?.id != null ? String(check.id) : null;
|
|
11991
|
+
if (!id) continue;
|
|
11992
|
+
checksById.set(id, check);
|
|
11993
|
+
cache.set(`${cacheKey}|${id}`, check);
|
|
11994
|
+
}
|
|
11995
|
+
}
|
|
11996
|
+
return candidateKeys.map((id) => checksById.get(id)).filter(Boolean);
|
|
11997
|
+
}
|
|
11998
|
+
function createCompatibilityCacheKey(input) {
|
|
11999
|
+
const selectedButtons = [...input.selectedButtons].sort().join(",");
|
|
12000
|
+
const usedServiceIds = [...input.usedServiceIds].sort().join(",");
|
|
12001
|
+
const primaryRate = input.primaryRate != null ? String(input.primaryRate) : "";
|
|
12002
|
+
const primaryServiceId = input.primaryServiceId ?? "";
|
|
12003
|
+
return [
|
|
12004
|
+
`tag:${input.tagId}`,
|
|
12005
|
+
`buttons:${selectedButtons}`,
|
|
12006
|
+
`used:${usedServiceIds}`,
|
|
12007
|
+
`policies:${input.policiesKey}`,
|
|
12008
|
+
`mode:${input.rateContextMode}`,
|
|
12009
|
+
`source:${input.rateContextSource}`,
|
|
12010
|
+
`rate:${primaryRate}`,
|
|
12011
|
+
`service:${primaryServiceId}`
|
|
12012
|
+
].join("|");
|
|
12013
|
+
}
|
|
12014
|
+
function areServiceContextStatesEqual(left, right) {
|
|
12015
|
+
if (left.selectedTagId !== right.selectedTagId) return false;
|
|
12016
|
+
if (left.strictSafety !== right.strictSafety) return false;
|
|
12017
|
+
if (left.enforcePolicies !== right.enforcePolicies) return false;
|
|
12018
|
+
if (left.selectedButtons.length !== right.selectedButtons.length) return false;
|
|
12019
|
+
const leftSet = new Set(left.selectedButtons);
|
|
12020
|
+
for (const id of right.selectedButtons) {
|
|
12021
|
+
if (!leftSet.has(id)) return false;
|
|
12022
|
+
}
|
|
12023
|
+
return true;
|
|
12024
|
+
}
|
|
12025
|
+
|
|
11919
12026
|
// src/components/service-meta-popover.tsx
|
|
11920
12027
|
import { useEffect as useEffect18, useMemo as useMemo24, useRef as useRef11, useState as useState25 } from "react";
|
|
11921
12028
|
import { FiInfo } from "react-icons/fi";
|
|
@@ -12045,6 +12152,27 @@ function ServiceMetaPopover({
|
|
|
12045
12152
|
] });
|
|
12046
12153
|
}
|
|
12047
12154
|
|
|
12155
|
+
// src/hooks/use-service-catalog-state.ts
|
|
12156
|
+
import { useEffect as useEffect19, useState as useState26 } from "react";
|
|
12157
|
+
function useServiceCatalogState(canvasApi, editor) {
|
|
12158
|
+
const [catalogState, setCatalogState] = useState26(null);
|
|
12159
|
+
useEffect19(() => {
|
|
12160
|
+
const resolveCatalog = (catalog) => catalog ?? editor.getCatalog?.() ?? editor.ensureCatalog?.() ?? null;
|
|
12161
|
+
setCatalogState(resolveCatalog());
|
|
12162
|
+
const offCatalogChange = canvasApi.on("catalog:change", (payload) => {
|
|
12163
|
+
setCatalogState(resolveCatalog(payload?.catalog));
|
|
12164
|
+
});
|
|
12165
|
+
const offCatalogActiveChange = canvasApi.on("catalog:active-change", () => {
|
|
12166
|
+
setCatalogState(resolveCatalog());
|
|
12167
|
+
});
|
|
12168
|
+
return () => {
|
|
12169
|
+
offCatalogChange?.();
|
|
12170
|
+
offCatalogActiveChange?.();
|
|
12171
|
+
};
|
|
12172
|
+
}, [canvasApi, editor]);
|
|
12173
|
+
return catalogState;
|
|
12174
|
+
}
|
|
12175
|
+
|
|
12048
12176
|
// src/panels/right/components/renderif.tsx
|
|
12049
12177
|
import "react";
|
|
12050
12178
|
import { Fragment as Fragment7, jsx as jsx51 } from "react/jsx-runtime";
|
|
@@ -12073,7 +12201,7 @@ function RenderIf({ data, emptyMessage = null, children, when }) {
|
|
|
12073
12201
|
// src/panels/right/partials/global/add-service.tsx
|
|
12074
12202
|
import { useCanvas as useCanvas7, useWorkspace as useWorkspace11 } from "@timeax/digital-service-engine/workspace";
|
|
12075
12203
|
import { InputField as InputField5 } from "@timeax/form-palette";
|
|
12076
|
-
import { useCallback as useCallback18, useEffect as
|
|
12204
|
+
import { useCallback as useCallback18, useEffect as useEffect20, useMemo as useMemo25, useRef as useRef12, useState as useState27 } from "react";
|
|
12077
12205
|
import { BsPlus } from "react-icons/bs";
|
|
12078
12206
|
import { FaFolderOpen } from "react-icons/fa";
|
|
12079
12207
|
import { FiFilter } from "react-icons/fi";
|
|
@@ -12156,13 +12284,22 @@ function AddServicePopover({
|
|
|
12156
12284
|
}) {
|
|
12157
12285
|
const ws = useWorkspace11();
|
|
12158
12286
|
const canvas = useCanvas7();
|
|
12159
|
-
const [open, setOpen] =
|
|
12160
|
-
const [filterOpen, setFilterOpen] =
|
|
12161
|
-
const [query, setQuery] =
|
|
12162
|
-
const [selected, setSelected] =
|
|
12163
|
-
const [contextFilterEnabled, setContextFilterEnabled] =
|
|
12164
|
-
const [
|
|
12287
|
+
const [open, setOpen] = useState27(false);
|
|
12288
|
+
const [filterOpen, setFilterOpen] = useState27(false);
|
|
12289
|
+
const [query, setQuery] = useState27("");
|
|
12290
|
+
const [selected, setSelected] = useState27("");
|
|
12291
|
+
const [contextFilterEnabled, setContextFilterEnabled] = useState27(false);
|
|
12292
|
+
const [rateContextMode, setRateContextMode] = useState27("context");
|
|
12293
|
+
const [rateContextSource, setRateContextSource] = useState27("service");
|
|
12294
|
+
const [manualPrimaryRate, setManualPrimaryRate] = useState27("");
|
|
12295
|
+
const [primaryServiceId, setPrimaryServiceId] = useState27(null);
|
|
12296
|
+
const [compatibleIds, setCompatibleIds] = useState27(null);
|
|
12297
|
+
const compatibleRequestRef = useRef12(0);
|
|
12298
|
+
const compatibleCacheRef = useRef12(/* @__PURE__ */ new Map());
|
|
12299
|
+
const catalogState = useServiceCatalogState(canvas.api, canvas.api.editor);
|
|
12165
12300
|
const policies2 = ws.policies.policies.data ?? [];
|
|
12301
|
+
const policiesKey = useMemo25(() => JSON.stringify(policies2 ?? []), [policies2]);
|
|
12302
|
+
const candidateIds = useMemo25(() => services2.map((service) => service.id), [services2]);
|
|
12166
12303
|
const currentTagId = canvas.api.selection.currentTag?.();
|
|
12167
12304
|
const preferredTagId = currentTagId != null ? String(currentTagId) : canvas.layers.tags[0]?.id != null ? String(canvas.layers.tags[0]?.id) : null;
|
|
12168
12305
|
const selectedButtons = useMemo25(
|
|
@@ -12178,33 +12315,52 @@ function AddServicePopover({
|
|
|
12178
12315
|
}),
|
|
12179
12316
|
[preferredTagId, selectedButtons]
|
|
12180
12317
|
);
|
|
12181
|
-
const liveSnapshot =
|
|
12182
|
-
|
|
12183
|
-
|
|
12184
|
-
|
|
12185
|
-
|
|
12186
|
-
|
|
12187
|
-
|
|
12188
|
-
|
|
12189
|
-
|
|
12190
|
-
|
|
12191
|
-
|
|
12192
|
-
});
|
|
12193
|
-
const offCatalogActiveChange = canvas.api.on("catalog:active-change", () => {
|
|
12194
|
-
const next = editor.getCatalog?.() ?? editor.ensureCatalog?.();
|
|
12195
|
-
setCatalogState(next ?? null);
|
|
12318
|
+
const [liveSnapshot, setLiveSnapshot] = useState27(() => createEmptyServiceContextSnapshot(liveSelectionContext, canvas.props));
|
|
12319
|
+
useEffect20(() => {
|
|
12320
|
+
let active = true;
|
|
12321
|
+
const fallback = createEmptyServiceContextSnapshot(liveSelectionContext, canvas.props);
|
|
12322
|
+
setLiveSnapshot(fallback);
|
|
12323
|
+
buildServiceContextSnapshot({ props: canvas.props, services: servicesMap, state: liveSelectionContext }).then((snapshot) => {
|
|
12324
|
+
if (!active) return;
|
|
12325
|
+
setLiveSnapshot(snapshot);
|
|
12326
|
+
}).catch(() => {
|
|
12327
|
+
if (!active) return;
|
|
12328
|
+
setLiveSnapshot(fallback);
|
|
12196
12329
|
});
|
|
12197
12330
|
return () => {
|
|
12198
|
-
|
|
12199
|
-
offCatalogActiveChange?.();
|
|
12331
|
+
active = false;
|
|
12200
12332
|
};
|
|
12201
|
-
}, [canvas.
|
|
12333
|
+
}, [canvas.props, liveSelectionContext, servicesMap]);
|
|
12202
12334
|
const catalogMode = catalogState?.viewMode === "grouped" ? "catalog" : "all";
|
|
12203
12335
|
const catalogGroups = useMemo25(
|
|
12204
12336
|
() => (catalogState?.nodes ?? []).filter((node) => node.kind === "group").sort((a, b) => (a.order ?? 0) - (b.order ?? 0) || a.label.localeCompare(b.label)),
|
|
12205
12337
|
[catalogState]
|
|
12206
12338
|
);
|
|
12207
12339
|
const selectedCatalogGroupId = catalogGroups.some((node) => node.id === catalogState?.activeNodeId) ? String(catalogState?.activeNodeId) : null;
|
|
12340
|
+
const contextServiceOptions = useMemo25(
|
|
12341
|
+
() => liveSnapshot.usedServiceIds.map((id) => {
|
|
12342
|
+
const service = servicesMap[id];
|
|
12343
|
+
if (!service) return null;
|
|
12344
|
+
return {
|
|
12345
|
+
value: String(service.id),
|
|
12346
|
+
label: `${service.name ?? `Service ${service.id}`}${service.rate != null ? ` (Rate ${service.rate})` : ""}`
|
|
12347
|
+
};
|
|
12348
|
+
}).filter(Boolean),
|
|
12349
|
+
[liveSnapshot.usedServiceIds, servicesMap]
|
|
12350
|
+
);
|
|
12351
|
+
const parsedManualPrimaryRate = useMemo25(() => {
|
|
12352
|
+
const value = Number(manualPrimaryRate.trim());
|
|
12353
|
+
return Number.isFinite(value) ? value : null;
|
|
12354
|
+
}, [manualPrimaryRate]);
|
|
12355
|
+
const hasValidCustomPrimary = useMemo25(() => {
|
|
12356
|
+
if (rateContextMode !== "custom_primary_rate") return true;
|
|
12357
|
+
if (rateContextSource === "manual") return parsedManualPrimaryRate != null;
|
|
12358
|
+
return Boolean(primaryServiceId);
|
|
12359
|
+
}, [parsedManualPrimaryRate, primaryServiceId, rateContextMode, rateContextSource]);
|
|
12360
|
+
useEffect20(() => {
|
|
12361
|
+
if (primaryServiceId && contextServiceOptions.some((option) => option.value === primaryServiceId)) return;
|
|
12362
|
+
setPrimaryServiceId(contextServiceOptions[0]?.value ?? null);
|
|
12363
|
+
}, [contextServiceOptions, primaryServiceId]);
|
|
12208
12364
|
const groupedServiceIds = useMemo25(() => {
|
|
12209
12365
|
const ids = /* @__PURE__ */ new Set();
|
|
12210
12366
|
for (const group of catalogGroups) {
|
|
@@ -12233,28 +12389,73 @@ function AddServicePopover({
|
|
|
12233
12389
|
}
|
|
12234
12390
|
return new Set(selectedGroup.serviceIds.map((id) => String(id)));
|
|
12235
12391
|
}, [catalogGroups, catalogMode, groupedServiceIds, selectedCatalogGroupId, services2]);
|
|
12236
|
-
|
|
12237
|
-
|
|
12238
|
-
if (!liveSnapshot.selectedTag)
|
|
12239
|
-
|
|
12240
|
-
|
|
12241
|
-
|
|
12392
|
+
useEffect20(() => {
|
|
12393
|
+
const requestId = ++compatibleRequestRef.current;
|
|
12394
|
+
if (!contextFilterEnabled || !liveSnapshot.selectedTag) {
|
|
12395
|
+
setCompatibleIds(null);
|
|
12396
|
+
return;
|
|
12397
|
+
}
|
|
12398
|
+
if (!hasValidCustomPrimary) {
|
|
12399
|
+
setCompatibleIds(null);
|
|
12400
|
+
return;
|
|
12401
|
+
}
|
|
12402
|
+
const cacheKey = createCompatibilityCacheKey({
|
|
12403
|
+
tagId: liveSnapshot.selectedTag.id,
|
|
12404
|
+
selectedButtons: liveSnapshot.state.selectedButtons,
|
|
12405
|
+
usedServiceIds: liveSnapshot.usedServiceIds,
|
|
12406
|
+
policiesKey,
|
|
12407
|
+
rateContextMode,
|
|
12408
|
+
rateContextSource,
|
|
12409
|
+
primaryRate: rateContextSource === "manual" ? parsedManualPrimaryRate : null,
|
|
12410
|
+
primaryServiceId: rateContextSource === "service" ? primaryServiceId : null
|
|
12411
|
+
});
|
|
12412
|
+
runCompatibilityChecksIncremental({
|
|
12413
|
+
editor: canvas.api.editor,
|
|
12414
|
+
candidateIds,
|
|
12415
|
+
args: {
|
|
12242
12416
|
tagId: liveSnapshot.selectedTag.id,
|
|
12243
12417
|
selectedButtons: liveSnapshot.state.selectedButtons,
|
|
12244
12418
|
usedServiceIds: liveSnapshot.usedServiceIds,
|
|
12245
12419
|
effectiveConstraints: liveSnapshot.selectedTag.constraints,
|
|
12246
|
-
policies: policies2
|
|
12247
|
-
|
|
12248
|
-
|
|
12249
|
-
|
|
12250
|
-
|
|
12251
|
-
|
|
12252
|
-
|
|
12253
|
-
|
|
12420
|
+
policies: policies2,
|
|
12421
|
+
rateContext: rateContextMode === "custom_primary_rate" ? {
|
|
12422
|
+
mode: "custom_primary_rate",
|
|
12423
|
+
source: rateContextSource,
|
|
12424
|
+
primaryRate: rateContextSource === "manual" ? parsedManualPrimaryRate ?? void 0 : void 0,
|
|
12425
|
+
primaryServiceId: rateContextSource === "service" ? primaryServiceId ?? void 0 : void 0
|
|
12426
|
+
} : { mode: "context" }
|
|
12427
|
+
},
|
|
12428
|
+
cache: compatibleCacheRef.current,
|
|
12429
|
+
cacheKey,
|
|
12430
|
+
shouldAbort: () => compatibleRequestRef.current !== requestId
|
|
12431
|
+
}).then((checks) => {
|
|
12432
|
+
if (compatibleRequestRef.current !== requestId) return;
|
|
12433
|
+
const ids = /* @__PURE__ */ new Set();
|
|
12434
|
+
for (const check of checks) {
|
|
12435
|
+
if (check?.fitsConstraints && check?.passesRate && check?.passesPolicies) {
|
|
12436
|
+
ids.add(String(check.id));
|
|
12437
|
+
}
|
|
12254
12438
|
}
|
|
12255
|
-
|
|
12256
|
-
|
|
12257
|
-
|
|
12439
|
+
setCompatibleIds(ids);
|
|
12440
|
+
}).catch(() => {
|
|
12441
|
+
if (compatibleRequestRef.current !== requestId) return;
|
|
12442
|
+
setCompatibleIds(null);
|
|
12443
|
+
});
|
|
12444
|
+
}, [
|
|
12445
|
+
candidateIds,
|
|
12446
|
+
canvas.api.editor,
|
|
12447
|
+
contextFilterEnabled,
|
|
12448
|
+
hasValidCustomPrimary,
|
|
12449
|
+
liveSnapshot.selectedTag,
|
|
12450
|
+
liveSnapshot.state.selectedButtons,
|
|
12451
|
+
liveSnapshot.usedServiceIds,
|
|
12452
|
+
parsedManualPrimaryRate,
|
|
12453
|
+
policies2,
|
|
12454
|
+
policiesKey,
|
|
12455
|
+
primaryServiceId,
|
|
12456
|
+
rateContextMode,
|
|
12457
|
+
rateContextSource
|
|
12458
|
+
]);
|
|
12258
12459
|
const setCatalogMode = useCallback18(
|
|
12259
12460
|
(mode) => {
|
|
12260
12461
|
const editor = canvas.api.editor;
|
|
@@ -12276,7 +12477,7 @@ function AddServicePopover({
|
|
|
12276
12477
|
service
|
|
12277
12478
|
}));
|
|
12278
12479
|
}, [allowedCatalogIds, compatibleIds, services2, query]);
|
|
12279
|
-
|
|
12480
|
+
useEffect20(() => {
|
|
12280
12481
|
if (selected && !options.some((option) => option.value === selected)) {
|
|
12281
12482
|
setSelected("");
|
|
12282
12483
|
}
|
|
@@ -12306,73 +12507,150 @@ function AddServicePopover({
|
|
|
12306
12507
|
children: /* @__PURE__ */ jsx52(FiFilter, {})
|
|
12307
12508
|
}
|
|
12308
12509
|
) }),
|
|
12309
|
-
/* @__PURE__ */
|
|
12310
|
-
|
|
12311
|
-
|
|
12312
|
-
|
|
12313
|
-
|
|
12314
|
-
|
|
12315
|
-
|
|
12316
|
-
/* @__PURE__ */ jsx52(
|
|
12317
|
-
|
|
12318
|
-
|
|
12319
|
-
|
|
12320
|
-
|
|
12321
|
-
|
|
12322
|
-
|
|
12510
|
+
/* @__PURE__ */ jsx52(
|
|
12511
|
+
PopoverContent,
|
|
12512
|
+
{
|
|
12513
|
+
align: "end",
|
|
12514
|
+
sideOffset: 8,
|
|
12515
|
+
collisionPadding: 12,
|
|
12516
|
+
className: "flex h-[var(--radix-popover-content-available-height)] max-h-[var(--radix-popover-content-available-height)] w-80 flex-col overflow-hidden rounded-xl p-0",
|
|
12517
|
+
children: /* @__PURE__ */ jsx52(ScrollArea, { className: "flex-1 h-full grow ", children: /* @__PURE__ */ jsxs34("div", { className: "space-y-3 p-4", children: [
|
|
12518
|
+
/* @__PURE__ */ jsxs34("div", { children: [
|
|
12519
|
+
/* @__PURE__ */ jsx52("div", { className: "text-sm font-semibold text-slate-900 dark:text-slate-100", children: "Service filters" }),
|
|
12520
|
+
/* @__PURE__ */ jsx52("p", { className: "mt-1 text-xs text-slate-500 dark:text-slate-400", children: "Combine catalog grouping with current context compatibility." })
|
|
12521
|
+
] }),
|
|
12522
|
+
/* @__PURE__ */ jsxs34("div", { className: "space-y-2 rounded-lg border border-slate-200 p-3 dark:border-slate-800", children: [
|
|
12523
|
+
/* @__PURE__ */ jsx52("div", { className: "text-xs font-semibold tracking-[0.16em] text-slate-500 uppercase dark:text-slate-400", children: "Catalog scope" }),
|
|
12524
|
+
/* @__PURE__ */ jsx52(
|
|
12525
|
+
InputField5,
|
|
12323
12526
|
{
|
|
12324
|
-
|
|
12325
|
-
|
|
12326
|
-
|
|
12527
|
+
variant: "radio",
|
|
12528
|
+
value: catalogMode,
|
|
12529
|
+
options: [
|
|
12530
|
+
{ value: "all", label: "All services", description: "Show all services" },
|
|
12531
|
+
{
|
|
12532
|
+
value: "catalog",
|
|
12533
|
+
label: "Catalog group",
|
|
12534
|
+
description: "Show all services in the current catalog group"
|
|
12535
|
+
}
|
|
12536
|
+
],
|
|
12537
|
+
optGroupClassName: "gap-1",
|
|
12538
|
+
onChange: (event) => setCatalogMode(event.value)
|
|
12327
12539
|
}
|
|
12328
|
-
|
|
12329
|
-
|
|
12330
|
-
|
|
12331
|
-
|
|
12332
|
-
|
|
12333
|
-
|
|
12334
|
-
|
|
12335
|
-
|
|
12336
|
-
|
|
12337
|
-
|
|
12338
|
-
|
|
12339
|
-
|
|
12340
|
-
|
|
12341
|
-
|
|
12342
|
-
|
|
12343
|
-
|
|
12344
|
-
|
|
12345
|
-
|
|
12346
|
-
|
|
12347
|
-
|
|
12348
|
-
|
|
12349
|
-
|
|
12350
|
-
|
|
12351
|
-
|
|
12352
|
-
|
|
12353
|
-
|
|
12354
|
-
|
|
12355
|
-
|
|
12356
|
-
|
|
12357
|
-
|
|
12358
|
-
|
|
12359
|
-
|
|
12360
|
-
|
|
12361
|
-
|
|
12362
|
-
|
|
12363
|
-
|
|
12364
|
-
|
|
12365
|
-
|
|
12366
|
-
|
|
12367
|
-
|
|
12368
|
-
|
|
12369
|
-
|
|
12370
|
-
|
|
12371
|
-
|
|
12372
|
-
|
|
12373
|
-
|
|
12374
|
-
|
|
12375
|
-
|
|
12540
|
+
),
|
|
12541
|
+
/* @__PURE__ */ jsx52(
|
|
12542
|
+
InputField5,
|
|
12543
|
+
{
|
|
12544
|
+
variant: "treeselect",
|
|
12545
|
+
placeholder: "Select group",
|
|
12546
|
+
disabled: catalogMode !== "catalog",
|
|
12547
|
+
multiple: false,
|
|
12548
|
+
value: treeValue,
|
|
12549
|
+
triggerClassName: "px-2",
|
|
12550
|
+
options: [{ key: UNGROUPED_TREE_VALUE, label: "Ungrouped" }, ...treeOptions],
|
|
12551
|
+
searchable: true,
|
|
12552
|
+
clearable: true,
|
|
12553
|
+
onChange: (event) => {
|
|
12554
|
+
const next = event.value == null ? null : String(event.value);
|
|
12555
|
+
canvas.api.editor.setActiveCatalogNode?.(
|
|
12556
|
+
next === UNGROUPED_TREE_VALUE || next == null ? void 0 : next
|
|
12557
|
+
);
|
|
12558
|
+
},
|
|
12559
|
+
trailingIcons: [/* @__PURE__ */ jsx52(FaFolderOpen, {})]
|
|
12560
|
+
}
|
|
12561
|
+
),
|
|
12562
|
+
catalogMode === "catalog" ? /* @__PURE__ */ jsxs34("div", { className: "text-xs text-slate-500 dark:text-slate-400", children: [
|
|
12563
|
+
"Showing ",
|
|
12564
|
+
selectedCatalogGroup?.label ?? "Ungrouped",
|
|
12565
|
+
" services."
|
|
12566
|
+
] }) : null
|
|
12567
|
+
] }),
|
|
12568
|
+
/* @__PURE__ */ jsxs34("label", { className: "flex items-start justify-between gap-3 rounded-lg border border-slate-200 p-3 text-sm text-slate-900 dark:border-slate-800 dark:text-slate-100", children: [
|
|
12569
|
+
/* @__PURE__ */ jsxs34("span", { className: "min-w-0", children: [
|
|
12570
|
+
/* @__PURE__ */ jsx52("span", { className: "block font-medium", children: "Current context" }),
|
|
12571
|
+
/* @__PURE__ */ jsx52("span", { className: "mt-1 block text-xs text-slate-500 dark:text-slate-400", children: "Filter services based on the current visible-group context." })
|
|
12572
|
+
] }),
|
|
12573
|
+
/* @__PURE__ */ jsx52(
|
|
12574
|
+
"input",
|
|
12575
|
+
{
|
|
12576
|
+
"aria-label": "Current context",
|
|
12577
|
+
type: "checkbox",
|
|
12578
|
+
checked: contextFilterEnabled,
|
|
12579
|
+
onChange: (event) => setContextFilterEnabled(event.target.checked)
|
|
12580
|
+
}
|
|
12581
|
+
)
|
|
12582
|
+
] }),
|
|
12583
|
+
/* @__PURE__ */ jsxs34("div", { className: "space-y-2 rounded-lg border border-slate-200 p-3 dark:border-slate-800", children: [
|
|
12584
|
+
/* @__PURE__ */ jsx52("div", { className: "text-xs font-semibold tracking-[0.16em] text-slate-500 uppercase dark:text-slate-400", children: "Rate compatibility" }),
|
|
12585
|
+
/* @__PURE__ */ jsx52(
|
|
12586
|
+
InputField5,
|
|
12587
|
+
{
|
|
12588
|
+
variant: "radio",
|
|
12589
|
+
value: rateContextMode,
|
|
12590
|
+
options: [
|
|
12591
|
+
{
|
|
12592
|
+
value: "context",
|
|
12593
|
+
label: "Context coherence",
|
|
12594
|
+
description: "Use active context services for rate coherence."
|
|
12595
|
+
},
|
|
12596
|
+
{
|
|
12597
|
+
value: "custom_primary_rate",
|
|
12598
|
+
label: "Custom primary rate",
|
|
12599
|
+
description: "Use selected service rate or manual rate."
|
|
12600
|
+
}
|
|
12601
|
+
],
|
|
12602
|
+
optGroupClassName: "gap-1",
|
|
12603
|
+
onChange: (event) => setRateContextMode(event.value)
|
|
12604
|
+
}
|
|
12605
|
+
),
|
|
12606
|
+
rateContextMode === "custom_primary_rate" ? /* @__PURE__ */ jsxs34("div", { className: "space-y-2", children: [
|
|
12607
|
+
/* @__PURE__ */ jsx52(
|
|
12608
|
+
InputField5,
|
|
12609
|
+
{
|
|
12610
|
+
variant: "radio",
|
|
12611
|
+
value: rateContextSource,
|
|
12612
|
+
options: [
|
|
12613
|
+
{
|
|
12614
|
+
value: "service",
|
|
12615
|
+
label: "From context service",
|
|
12616
|
+
description: "Use one active context service as primary."
|
|
12617
|
+
},
|
|
12618
|
+
{
|
|
12619
|
+
value: "manual",
|
|
12620
|
+
label: "Manual rate",
|
|
12621
|
+
description: "Enter a custom numeric primary rate."
|
|
12622
|
+
}
|
|
12623
|
+
],
|
|
12624
|
+
optGroupClassName: "gap-1",
|
|
12625
|
+
onChange: (event) => setRateContextSource(event.value)
|
|
12626
|
+
}
|
|
12627
|
+
),
|
|
12628
|
+
rateContextSource === "service" ? /* @__PURE__ */ jsx52(
|
|
12629
|
+
InputField5,
|
|
12630
|
+
{
|
|
12631
|
+
variant: "select",
|
|
12632
|
+
label: "Primary context service",
|
|
12633
|
+
options: contextServiceOptions,
|
|
12634
|
+
value: primaryServiceId ?? void 0,
|
|
12635
|
+
onChange: (event) => setPrimaryServiceId(event.value ? String(event.value) : null),
|
|
12636
|
+
placeholder: "Select service"
|
|
12637
|
+
}
|
|
12638
|
+
) : /* @__PURE__ */ jsx52(
|
|
12639
|
+
InputField5,
|
|
12640
|
+
{
|
|
12641
|
+
variant: "number",
|
|
12642
|
+
label: "Primary rate",
|
|
12643
|
+
value: manualPrimaryRate === "" ? void 0 : Number(manualPrimaryRate),
|
|
12644
|
+
onChange: (event) => setManualPrimaryRate(String(event.value ?? "")),
|
|
12645
|
+
placeholder: "Enter rate"
|
|
12646
|
+
}
|
|
12647
|
+
),
|
|
12648
|
+
!hasValidCustomPrimary ? /* @__PURE__ */ jsx52("p", { className: "text-xs text-amber-700 dark:text-amber-300", children: "Provide a primary service or valid primary rate to apply compatibility filtering." }) : null
|
|
12649
|
+
] }) : null
|
|
12650
|
+
] })
|
|
12651
|
+
] }) })
|
|
12652
|
+
}
|
|
12653
|
+
)
|
|
12376
12654
|
] })
|
|
12377
12655
|
}
|
|
12378
12656
|
),
|
|
@@ -12427,11 +12705,11 @@ var add_service_default = AddService;
|
|
|
12427
12705
|
import { resolveInputDescriptor, useInputs as useInputs2 } from "@timeax/digital-service-engine/react";
|
|
12428
12706
|
import { useCanvas as useCanvas13 } from "@timeax/digital-service-engine/workspace";
|
|
12429
12707
|
import { InputField as InputField12 } from "@timeax/form-palette";
|
|
12430
|
-
import { useEffect as
|
|
12708
|
+
import { useEffect as useEffect21, useMemo as useMemo31, useState as useState31 } from "react";
|
|
12431
12709
|
|
|
12432
12710
|
// src/panels/right/partials/properties/components/descriptor-settings.tsx
|
|
12433
12711
|
import { InputField as InputField6 } from "@timeax/form-palette";
|
|
12434
|
-
import { useMemo as useMemo26, useState as
|
|
12712
|
+
import { useMemo as useMemo26, useState as useState28 } from "react";
|
|
12435
12713
|
|
|
12436
12714
|
// src/panels/right/partials/properties/components/meta.ts
|
|
12437
12715
|
function mergeNodeMeta(meta, patch) {
|
|
@@ -12728,9 +13006,9 @@ function DescriptorPrimitiveField({ schema, value, hasOverride, onSet, onClear,
|
|
|
12728
13006
|
function DescriptorObjectField({ schema, value, hasOverride, onSet, onClear, path, allowClear = true }) {
|
|
12729
13007
|
const objectValue = asRecord(value);
|
|
12730
13008
|
const shapeEntries = useMemo26(() => Object.entries(schema.shape ?? {}), [schema.shape]);
|
|
12731
|
-
const [draftKey, setDraftKey] =
|
|
12732
|
-
const [draftShape, setDraftShape] =
|
|
12733
|
-
const [activeShapes, setActiveShapes] =
|
|
13009
|
+
const [draftKey, setDraftKey] = useState28("");
|
|
13010
|
+
const [draftShape, setDraftShape] = useState28(shapeEntries[0]?.[0] ?? "");
|
|
13011
|
+
const [activeShapes, setActiveShapes] = useState28({});
|
|
12734
13012
|
const orderedEntries = useMemo26(() => getOrderedObjectEntries(schema), [schema]);
|
|
12735
13013
|
const dynamicKeys = Object.keys(objectValue).filter((key) => !hasOwn(schema.fields, key));
|
|
12736
13014
|
const commitObject = (nextObject) => {
|
|
@@ -12888,8 +13166,8 @@ function DescriptorObjectField({ schema, value, hasOverride, onSet, onClear, pat
|
|
|
12888
13166
|
function DescriptorArrayField({ schema, value, hasOverride, onSet, onClear, path, allowClear = true }) {
|
|
12889
13167
|
const arrayValue = asArray(value);
|
|
12890
13168
|
const shapeEntries = useMemo26(() => Object.entries(schema.shape ?? {}), [schema.shape]);
|
|
12891
|
-
const [draftShape, setDraftShape] =
|
|
12892
|
-
const [activeShapes, setActiveShapes] =
|
|
13169
|
+
const [draftShape, setDraftShape] = useState28(shapeEntries[0]?.[0] ?? "");
|
|
13170
|
+
const [activeShapes, setActiveShapes] = useState28({});
|
|
12893
13171
|
const commitArray = (nextArray) => {
|
|
12894
13172
|
if (!nextArray.length) {
|
|
12895
13173
|
onClear(path);
|
|
@@ -13942,15 +14220,15 @@ function ValidationSection({ node }) {
|
|
|
13942
14220
|
import "@timeax/digital-service-engine/core";
|
|
13943
14221
|
import { useCanvas as useCanvas12 } from "@timeax/digital-service-engine/workspace";
|
|
13944
14222
|
import { keyBy } from "lodash";
|
|
13945
|
-
import { useMemo as useMemo30, useState as
|
|
14223
|
+
import { useMemo as useMemo30, useState as useState30 } from "react";
|
|
13946
14224
|
|
|
13947
14225
|
// src/panels/right/partials/properties/components/AddIncludesPopover.tsx
|
|
13948
14226
|
import { InputField as InputField11 } from "@timeax/form-palette";
|
|
13949
|
-
import { useState as
|
|
14227
|
+
import { useState as useState29 } from "react";
|
|
13950
14228
|
import { BsPlus as BsPlus5 } from "react-icons/bs";
|
|
13951
14229
|
import { jsx as jsx58, jsxs as jsxs40 } from "react/jsx-runtime";
|
|
13952
14230
|
function AddIncludesPopover({ open, onOpenChange, onSelect, options }) {
|
|
13953
|
-
const [value, setValue] =
|
|
14231
|
+
const [value, setValue] = useState29();
|
|
13954
14232
|
return /* @__PURE__ */ jsxs40(Popover, { open, onOpenChange, children: [
|
|
13955
14233
|
/* @__PURE__ */ jsx58(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx58(SectionActionTriggerButton, { icon: /* @__PURE__ */ jsx58(BsPlus5, {}), children: "Add" }) }),
|
|
13956
14234
|
/* @__PURE__ */ jsx58(PopoverContent, { children: /* @__PURE__ */ jsxs40("div", { className: "flex flex-col gap-2", children: [
|
|
@@ -13987,7 +14265,7 @@ function AddIncludesPopover({ open, onOpenChange, onSelect, options }) {
|
|
|
13987
14265
|
import { jsx as jsx59, jsxs as jsxs41 } from "react/jsx-runtime";
|
|
13988
14266
|
function IncExcludeSection({ node, mode, capability }) {
|
|
13989
14267
|
const canvas = useCanvas12();
|
|
13990
|
-
const [open, setOpen] =
|
|
14268
|
+
const [open, setOpen] = useState30(false);
|
|
13991
14269
|
const canEdit = capability?.canEdit ?? true;
|
|
13992
14270
|
const helperMessage = capability?.message;
|
|
13993
14271
|
const fields = useMemo30(() => keyBy(canvas.props.fields, "id"), [canvas.props]);
|
|
@@ -14092,19 +14370,19 @@ function FieldProperties({ className, node, kinds, defaultKind }) {
|
|
|
14092
14370
|
const nameValue = node.raw.name ?? "";
|
|
14093
14371
|
const placeholderValue = defaults.placeholder ?? "";
|
|
14094
14372
|
const helpTextValue = defaults.helpText ?? "";
|
|
14095
|
-
const [nameDraft, setNameDraft] =
|
|
14096
|
-
const [placeholderDraft, setPlaceholderDraft] =
|
|
14097
|
-
const [helpTextDraft, setHelpTextDraft] =
|
|
14373
|
+
const [nameDraft, setNameDraft] = useState31(nameValue);
|
|
14374
|
+
const [placeholderDraft, setPlaceholderDraft] = useState31(placeholderValue);
|
|
14375
|
+
const [helpTextDraft, setHelpTextDraft] = useState31(helpTextValue);
|
|
14098
14376
|
const descriptor = useMemo31(() => resolveInputDescriptor(registry, currentType, currentVariant), [currentType, currentVariant, registry]);
|
|
14099
14377
|
const descriptorUi = descriptor?.ui ?? {};
|
|
14100
14378
|
const descriptorKeySet = useMemo31(() => new Set(getDescriptorUiKeys(descriptorUi)), [descriptorUi]);
|
|
14101
|
-
|
|
14379
|
+
useEffect21(() => {
|
|
14102
14380
|
setNameDraft(nameValue);
|
|
14103
14381
|
}, [node.id, nameValue]);
|
|
14104
|
-
|
|
14382
|
+
useEffect21(() => {
|
|
14105
14383
|
setPlaceholderDraft(placeholderValue);
|
|
14106
14384
|
}, [node.id, placeholderValue]);
|
|
14107
|
-
|
|
14385
|
+
useEffect21(() => {
|
|
14108
14386
|
setHelpTextDraft(helpTextValue);
|
|
14109
14387
|
}, [node.id, helpTextValue]);
|
|
14110
14388
|
const fieldTypeOptions = useMemo31(() => {
|
|
@@ -14442,7 +14720,7 @@ import "@timeax/digital-service-engine/core";
|
|
|
14442
14720
|
import { useCanvas as useCanvas15 } from "@timeax/digital-service-engine/workspace";
|
|
14443
14721
|
import { InputField as InputField15 } from "@timeax/form-palette";
|
|
14444
14722
|
import { ArrowUpRight } from "lucide-react";
|
|
14445
|
-
import { useMemo as useMemo32, useState as
|
|
14723
|
+
import { useMemo as useMemo32, useState as useState32 } from "react";
|
|
14446
14724
|
import { TiDelete } from "react-icons/ti";
|
|
14447
14725
|
|
|
14448
14726
|
// src/panels/right/partials/properties/tag/AddConstraintsPopover.tsx
|
|
@@ -14568,7 +14846,7 @@ import { Fragment as Fragment11, jsx as jsx65, jsxs as jsxs47 } from "react/jsx-
|
|
|
14568
14846
|
function TagConstraintsSection({ node }) {
|
|
14569
14847
|
const constraints = Object.keys(node.raw.constraints ?? {});
|
|
14570
14848
|
const canvas = useCanvas15();
|
|
14571
|
-
const [open, setOpen] =
|
|
14849
|
+
const [open, setOpen] = useState32(false);
|
|
14572
14850
|
const allConstraints = useMemo32(() => canvas.api.getConstraints() ?? [], [canvas.props]);
|
|
14573
14851
|
return /* @__PURE__ */ jsx65(Fragment11, { children: /* @__PURE__ */ jsxs47(Section, { children: [
|
|
14574
14852
|
/* @__PURE__ */ jsxs47(Section.Header, { children: [
|
|
@@ -14687,7 +14965,7 @@ function TagProperties({ node, kinds, defaultKind }) {
|
|
|
14687
14965
|
// src/panels/right/tabs/properties.tsx
|
|
14688
14966
|
import { useCanvas as useCanvas16, useWorkspace as useWorkspace12 } from "@timeax/digital-service-engine/workspace";
|
|
14689
14967
|
import { InputField as InputField16 } from "@timeax/form-palette";
|
|
14690
|
-
import { useMemo as useMemo33, useState as
|
|
14968
|
+
import { useMemo as useMemo33, useState as useState33 } from "react";
|
|
14691
14969
|
import { AiOutlineLoading3Quarters } from "react-icons/ai";
|
|
14692
14970
|
import { MdOutlineContentCopy } from "react-icons/md";
|
|
14693
14971
|
import { jsx as jsx69, jsxs as jsxs49 } from "react/jsx-runtime";
|
|
@@ -14703,7 +14981,7 @@ var Properties = ({ kinds = [], defaultKind = "" }) => {
|
|
|
14703
14981
|
if (!canvas.activeId) return { kind: "none" };
|
|
14704
14982
|
return canvas.selector.getNode(canvas.activeId);
|
|
14705
14983
|
}, [canvas.activeId, canvas.props, canvas.selection]);
|
|
14706
|
-
const [copying, setCopying] =
|
|
14984
|
+
const [copying, setCopying] = useState33(false);
|
|
14707
14985
|
const Kind = propertyComponents[node.kind];
|
|
14708
14986
|
if (!Kind) {
|
|
14709
14987
|
return /* @__PURE__ */ jsx69("div", { className: "p-4", children: /* @__PURE__ */ jsx69(EmptyState, { title: "No active node selected", description: "Pick a tag, field, or option from the layers panel or canvas to inspect its core settings." }) });
|
|
@@ -14918,7 +15196,7 @@ var wireframe_tags_widget_default = WireframeTagsWidget;
|
|
|
14918
15196
|
// src/panels/right/tabs/wireframe.tsx
|
|
14919
15197
|
import { useOrderFlow, Wrapper } from "@timeax/digital-service-engine/react";
|
|
14920
15198
|
import { useCanvas as useCanvas17, useWorkspace as useWorkspace13 } from "@timeax/digital-service-engine/workspace";
|
|
14921
|
-
import { useCallback as useCallback19, useMemo as useMemo34, useState as
|
|
15199
|
+
import { useCallback as useCallback19, useMemo as useMemo34, useState as useState34 } from "react";
|
|
14922
15200
|
import { BsChevronDown as BsChevronDown2 } from "react-icons/bs";
|
|
14923
15201
|
import { jsx as jsx71, jsxs as jsxs51 } from "react/jsx-runtime";
|
|
14924
15202
|
var CHECKBOX_SINGLE_EXTRA_PROPS = Object.freeze({ single: true });
|
|
@@ -14946,7 +15224,7 @@ function Wireframe({ kinds: _kinds = [], defaultKind: _defaultKind = "" }) {
|
|
|
14946
15224
|
return void 0;
|
|
14947
15225
|
}
|
|
14948
15226
|
}, [flow.ready, flow.activeTagId, flow.optionSelectionsByFieldId, flow.formValuesByFieldId]);
|
|
14949
|
-
const [isFooterOpen, setIsFooterOpen] =
|
|
15227
|
+
const [isFooterOpen, setIsFooterOpen] = useState34(true);
|
|
14950
15228
|
const footerSummary = useMemo34(() => {
|
|
14951
15229
|
const minText = formatMetricNumber(flow.min);
|
|
14952
15230
|
const maxText = formatMetricNumber(flow.max);
|
|
@@ -15575,13 +15853,13 @@ function FallbackEditorHeader({
|
|
|
15575
15853
|
// src/workspace/fallback-editor/fallback-registrations-panel.tsx
|
|
15576
15854
|
import { useActiveFallbackRegistrations as useActiveFallbackRegistrations3, useEligibleServiceList as useEligibleServiceList2, useFallbackEditor as useFallbackEditor3 } from "@timeax/digital-service-engine/react";
|
|
15577
15855
|
import { Plus, Trash2, X as X2 } from "lucide-react";
|
|
15578
|
-
import { useCallback as useCallback20, useState as
|
|
15856
|
+
import { useCallback as useCallback20, useState as useState36 } from "react";
|
|
15579
15857
|
|
|
15580
15858
|
// src/workspace/fallback-editor/fallback-dialogs.tsx
|
|
15581
15859
|
import { InputField as InputField17 } from "@timeax/form-palette";
|
|
15582
15860
|
import { useActiveFallbackRegistrations as useActiveFallbackRegistrations2, useEligibleServiceList, useFallbackEditor as useFallbackEditor2 } from "@timeax/digital-service-engine/react";
|
|
15583
15861
|
import { Check, Search } from "lucide-react";
|
|
15584
|
-
import { useEffect as
|
|
15862
|
+
import { useEffect as useEffect22, useMemo as useMemo36, useState as useState35 } from "react";
|
|
15585
15863
|
import { jsx as jsx77, jsxs as jsxs56 } from "react/jsx-runtime";
|
|
15586
15864
|
function FallbackAddRegistrationDialog({
|
|
15587
15865
|
open,
|
|
@@ -15590,14 +15868,14 @@ function FallbackAddRegistrationDialog({
|
|
|
15590
15868
|
}) {
|
|
15591
15869
|
const { activeServiceId, serviceProps, snapshot } = useFallbackEditor2();
|
|
15592
15870
|
const registrations = useActiveFallbackRegistrations2();
|
|
15593
|
-
const [scope, setScope] =
|
|
15594
|
-
const [nodeId, setNodeId] =
|
|
15871
|
+
const [scope, setScope] = useState35("global");
|
|
15872
|
+
const [nodeId, setNodeId] = useState35("");
|
|
15595
15873
|
const mode = useMemo36(() => {
|
|
15596
15874
|
if (snapshot) return "snapshot";
|
|
15597
15875
|
if (serviceProps) return "props";
|
|
15598
15876
|
return "none";
|
|
15599
15877
|
}, [snapshot, serviceProps]);
|
|
15600
|
-
|
|
15878
|
+
useEffect22(() => {
|
|
15601
15879
|
if (open) {
|
|
15602
15880
|
setScope("global");
|
|
15603
15881
|
setNodeId("");
|
|
@@ -15655,12 +15933,12 @@ function FallbackAddRegistrationDialog({
|
|
|
15655
15933
|
}
|
|
15656
15934
|
return [];
|
|
15657
15935
|
}, [activeServiceId, mode, serviceProps, snapshot]);
|
|
15658
|
-
|
|
15936
|
+
useEffect22(() => {
|
|
15659
15937
|
if (hasGlobal && scope === "global") {
|
|
15660
15938
|
setScope("node");
|
|
15661
15939
|
}
|
|
15662
15940
|
}, [hasGlobal, scope]);
|
|
15663
|
-
|
|
15941
|
+
useEffect22(() => {
|
|
15664
15942
|
if (!nodeId) return;
|
|
15665
15943
|
if (nodeTargets.some((entry) => entry.id === nodeId)) return;
|
|
15666
15944
|
setNodeId("");
|
|
@@ -15750,11 +16028,11 @@ function FallbackAddCandidatesDialog({
|
|
|
15750
16028
|
}) {
|
|
15751
16029
|
const { eligible, addMany } = useFallbackEditor2();
|
|
15752
16030
|
const eligibleServices = useEligibleServiceList();
|
|
15753
|
-
const [query, setQuery] =
|
|
15754
|
-
const [filterEligibleOnly, setFilterEligibleOnly] =
|
|
15755
|
-
const [selected, setSelected] =
|
|
15756
|
-
const [submitting, setSubmitting] =
|
|
15757
|
-
|
|
16031
|
+
const [query, setQuery] = useState35("");
|
|
16032
|
+
const [filterEligibleOnly, setFilterEligibleOnly] = useState35(true);
|
|
16033
|
+
const [selected, setSelected] = useState35(/* @__PURE__ */ new Set());
|
|
16034
|
+
const [submitting, setSubmitting] = useState35(false);
|
|
16035
|
+
useEffect22(() => {
|
|
15758
16036
|
if (!open) {
|
|
15759
16037
|
setQuery("");
|
|
15760
16038
|
setFilterEligibleOnly(true);
|
|
@@ -15861,7 +16139,7 @@ function VirtualServiceList({
|
|
|
15861
16139
|
rowHeight = 72,
|
|
15862
16140
|
emptyText = "No services found."
|
|
15863
16141
|
}) {
|
|
15864
|
-
const [scrollTop, setScrollTop] =
|
|
16142
|
+
const [scrollTop, setScrollTop] = useState35(0);
|
|
15865
16143
|
const total = items.length;
|
|
15866
16144
|
const visibleCount = Math.ceil(height / rowHeight);
|
|
15867
16145
|
const overscan = 6;
|
|
@@ -15985,10 +16263,10 @@ function FallbackRegistrationsPanel() {
|
|
|
15985
16263
|
const { activeServiceId, remove, clear, check } = useFallbackEditor3();
|
|
15986
16264
|
const registrations = useActiveFallbackRegistrations3();
|
|
15987
16265
|
const eligibleServices = useEligibleServiceList2();
|
|
15988
|
-
const [candidatePickerOpen, setCandidatePickerOpen] =
|
|
15989
|
-
const [candidateContext, setCandidateContext] =
|
|
15990
|
-
const [candidatePrimaryId, setCandidatePrimaryId] =
|
|
15991
|
-
const [registrationDialogOpen, setRegistrationDialogOpen] =
|
|
16266
|
+
const [candidatePickerOpen, setCandidatePickerOpen] = useState36(false);
|
|
16267
|
+
const [candidateContext, setCandidateContext] = useState36(null);
|
|
16268
|
+
const [candidatePrimaryId, setCandidatePrimaryId] = useState36(void 0);
|
|
16269
|
+
const [registrationDialogOpen, setRegistrationDialogOpen] = useState36(false);
|
|
15992
16270
|
const openCandidatePicker = useCallback20((context, primaryId) => {
|
|
15993
16271
|
setCandidateContext(context);
|
|
15994
16272
|
setCandidatePrimaryId(primaryId);
|
|
@@ -16117,12 +16395,12 @@ function FallbackRegistrationsPanel() {
|
|
|
16117
16395
|
import { useFallbackEditor as useFallbackEditor4, usePrimaryServiceList as usePrimaryServiceList2 } from "@timeax/digital-service-engine/react";
|
|
16118
16396
|
import { InputField as InputField18 } from "@timeax/form-palette";
|
|
16119
16397
|
import { Search as Search2 } from "lucide-react";
|
|
16120
|
-
import { useMemo as useMemo37, useState as
|
|
16398
|
+
import { useMemo as useMemo37, useState as useState37 } from "react";
|
|
16121
16399
|
import { jsx as jsx79, jsxs as jsxs58 } from "react/jsx-runtime";
|
|
16122
16400
|
function FallbackServiceSidebar() {
|
|
16123
16401
|
const { activeServiceId, setActiveServiceId, get } = useFallbackEditor4();
|
|
16124
16402
|
const services2 = usePrimaryServiceList2();
|
|
16125
|
-
const [query, setQuery] =
|
|
16403
|
+
const [query, setQuery] = useState37("");
|
|
16126
16404
|
const filtered = useMemo37(() => {
|
|
16127
16405
|
const normalizedQuery = query.trim().toLowerCase();
|
|
16128
16406
|
if (!normalizedQuery) return services2;
|
|
@@ -16182,14 +16460,14 @@ function FallbackServiceSidebar() {
|
|
|
16182
16460
|
// src/workspace/fallback-editor/fallback-settings-panel.tsx
|
|
16183
16461
|
import { useFallbackEditor as useFallbackEditor5 } from "@timeax/digital-service-engine/react";
|
|
16184
16462
|
import { InputField as InputField19 } from "@timeax/form-palette";
|
|
16185
|
-
import { useEffect as
|
|
16463
|
+
import { useEffect as useEffect23, useState as useState38 } from "react";
|
|
16186
16464
|
import { jsx as jsx80, jsxs as jsxs59 } from "react/jsx-runtime";
|
|
16187
16465
|
function FallbackSettingsPanel() {
|
|
16188
16466
|
const { settings, saveSettings, settingsSaving } = useFallbackEditor5();
|
|
16189
|
-
const [draft, setDraft] =
|
|
16190
|
-
const [error, setError] =
|
|
16191
|
-
const [saved, setSaved] =
|
|
16192
|
-
|
|
16467
|
+
const [draft, setDraft] = useState38(settings);
|
|
16468
|
+
const [error, setError] = useState38(null);
|
|
16469
|
+
const [saved, setSaved] = useState38(false);
|
|
16470
|
+
useEffect23(() => {
|
|
16193
16471
|
setDraft(settings);
|
|
16194
16472
|
setSaved(false);
|
|
16195
16473
|
setError(null);
|
|
@@ -16440,7 +16718,7 @@ function NativeFallbackEditorInner({ className }) {
|
|
|
16440
16718
|
// src/workspace/fallback-editor-modal.tsx
|
|
16441
16719
|
import { useCanvas as useCanvas19, useWorkspace as useWorkspace14 } from "@timeax/digital-service-engine/workspace";
|
|
16442
16720
|
import cloneDeep4 from "lodash/cloneDeep";
|
|
16443
|
-
import { createContext as createContext4, useCallback as useCallback21, useContext as useContext4, useEffect as
|
|
16721
|
+
import { createContext as createContext4, useCallback as useCallback21, useContext as useContext4, useEffect as useEffect24, useMemo as useMemo39, useState as useState39 } from "react";
|
|
16444
16722
|
import { createPortal as createPortal4 } from "react-dom";
|
|
16445
16723
|
import { FiX as FiX4 } from "react-icons/fi";
|
|
16446
16724
|
import { jsx as jsx82, jsxs as jsxs61 } from "react/jsx-runtime";
|
|
@@ -16456,9 +16734,9 @@ var FallbackEditorModalContext = createContext4(defaultContextValue2);
|
|
|
16456
16734
|
function FallbackEditorModalProvider({ children }) {
|
|
16457
16735
|
const canvas = useCanvas19();
|
|
16458
16736
|
const ws = useWorkspace14();
|
|
16459
|
-
const [launch, setLaunch] =
|
|
16460
|
-
const [sessionId, setSessionId] =
|
|
16461
|
-
const [surfaceError, setSurfaceError] =
|
|
16737
|
+
const [launch, setLaunch] = useState39(null);
|
|
16738
|
+
const [sessionId, setSessionId] = useState39(0);
|
|
16739
|
+
const [surfaceError, setSurfaceError] = useState39(null);
|
|
16462
16740
|
const close = useCallback21(() => {
|
|
16463
16741
|
setLaunch(null);
|
|
16464
16742
|
setSurfaceError(null);
|
|
@@ -16549,7 +16827,7 @@ function FallbackEditorModalProvider({ children }) {
|
|
|
16549
16827
|
() => canvas.props?.fallbackSettings ?? {},
|
|
16550
16828
|
[canvas.props]
|
|
16551
16829
|
);
|
|
16552
|
-
|
|
16830
|
+
useEffect24(() => {
|
|
16553
16831
|
if (!launch) return;
|
|
16554
16832
|
const onKeyDown = (event) => {
|
|
16555
16833
|
if (event.key === "Escape") close();
|
|
@@ -16621,7 +16899,7 @@ function useFallbackEditorModal() {
|
|
|
16621
16899
|
|
|
16622
16900
|
// src/workspace/bottom-panel/index.tsx
|
|
16623
16901
|
import { useCanvas as useCanvas22, useWorkspace as useWorkspace15 } from "@timeax/digital-service-engine/workspace";
|
|
16624
|
-
import { useCallback as useCallback22, useEffect as
|
|
16902
|
+
import { useCallback as useCallback22, useEffect as useEffect27, useMemo as useMemo41, useRef as useRef14, useState as useState42 } from "react";
|
|
16625
16903
|
import { FiEye as FiEye3, FiEyeOff as FiEyeOff2, FiSearch, FiTerminal as FiTerminal2, FiX as FiX6 } from "react-icons/fi";
|
|
16626
16904
|
import { LuGripHorizontal, LuLayers3 } from "react-icons/lu";
|
|
16627
16905
|
import { MdOutlineSync } from "react-icons/md";
|
|
@@ -17076,7 +17354,7 @@ function LogCard({ row, onRemove }) {
|
|
|
17076
17354
|
|
|
17077
17355
|
// src/workspace/bottom-panel/service-picker-dialog.tsx
|
|
17078
17356
|
import { InputField as InputField20 } from "@timeax/form-palette";
|
|
17079
|
-
import { useEffect as
|
|
17357
|
+
import { useEffect as useEffect25, useMemo as useMemo40, useRef as useRef13, useState as useState40 } from "react";
|
|
17080
17358
|
import { createPortal as createPortal5 } from "react-dom";
|
|
17081
17359
|
|
|
17082
17360
|
// src/workspace/bottom-panel/service-picker.ts
|
|
@@ -17205,15 +17483,15 @@ function ServicePickerDialog({
|
|
|
17205
17483
|
onOpenChange,
|
|
17206
17484
|
onConfirm
|
|
17207
17485
|
}) {
|
|
17208
|
-
const [filters, setFilters] =
|
|
17209
|
-
const [selectedIds, setSelectedIds] =
|
|
17210
|
-
const selectAllRef =
|
|
17211
|
-
|
|
17486
|
+
const [filters, setFilters] = useState40(() => createDefaultServicePickerFilters());
|
|
17487
|
+
const [selectedIds, setSelectedIds] = useState40(/* @__PURE__ */ new Set());
|
|
17488
|
+
const selectAllRef = useRef13(null);
|
|
17489
|
+
useEffect25(() => {
|
|
17212
17490
|
if (!open) return;
|
|
17213
17491
|
setFilters(createDefaultServicePickerFilters());
|
|
17214
17492
|
setSelectedIds(/* @__PURE__ */ new Set());
|
|
17215
17493
|
}, [open]);
|
|
17216
|
-
|
|
17494
|
+
useEffect25(() => {
|
|
17217
17495
|
if (!open) return;
|
|
17218
17496
|
const onKeyDown = (event) => {
|
|
17219
17497
|
if (event.key === "Escape") onOpenChange(false);
|
|
@@ -17246,7 +17524,7 @@ function ServicePickerDialog({
|
|
|
17246
17524
|
const partiallyFilteredSelected = filteredSelectedCount > 0 && filteredSelectedCount < filteredServiceIds.length;
|
|
17247
17525
|
const selectedCount = selectedIds.size;
|
|
17248
17526
|
const canConfirm = selectedCount > 0;
|
|
17249
|
-
|
|
17527
|
+
useEffect25(() => {
|
|
17250
17528
|
if (!selectAllRef.current) return;
|
|
17251
17529
|
selectAllRef.current.indeterminate = partiallyFilteredSelected;
|
|
17252
17530
|
}, [partiallyFilteredSelected]);
|
|
@@ -17560,7 +17838,7 @@ function toPickerSelectOptions(values) {
|
|
|
17560
17838
|
|
|
17561
17839
|
// src/workspace/bottom-panel/services-split-pane.tsx
|
|
17562
17840
|
import { InputField as InputField21 } from "@timeax/form-palette";
|
|
17563
|
-
import { useEffect as
|
|
17841
|
+
import { useEffect as useEffect26, useState as useState41 } from "react";
|
|
17564
17842
|
import { FaFolderOpen as FaFolderOpen2 } from "react-icons/fa";
|
|
17565
17843
|
import { FiEdit2, FiFilter as FiFilter2, FiFolderPlus, FiPlus as FiPlus2, FiTrash2 as FiTrash22 } from "react-icons/fi";
|
|
17566
17844
|
|
|
@@ -17721,7 +17999,7 @@ var UNGROUPED_TREE_VALUE2 = "__catalog_ungrouped__";
|
|
|
17721
17999
|
function ServicesSplitPane(props) {
|
|
17722
18000
|
const emptyTitle = props.mode === "active" ? "No active services yet" : "No services match this view";
|
|
17723
18001
|
const emptyDescription = props.mode === "active" ? "Connect a service to a tag, field, or option and it will appear here with its bindings." : props.mode === "catalog" ? "Select a catalog group or create one to organize source services for faster assignment." : "Try changing the search or toggles to bring more services into view.";
|
|
17724
|
-
const [size, setSize] =
|
|
18002
|
+
const [size, setSize] = useState41(44);
|
|
17725
18003
|
return /* @__PURE__ */ jsx87("div", { className: "min-h-90 p-4", children: /* @__PURE__ */ jsxs65(ResizablePanelGroup, { direction: "horizontal", className: "min-h-90", children: [
|
|
17726
18004
|
/* @__PURE__ */ jsx87(ResizablePanel, { onResize: (s) => setSize(s.inPixels), defaultSize: 44, minSize: 30, children: /* @__PURE__ */ jsxs65("section", { className: "flex h-full min-h-0 flex-col overflow-hidden", style: { "--resizable-width": size + "px" }, children: [
|
|
17727
18005
|
/* @__PURE__ */ jsxs65("div", { className: "space-y-3 border-b border-slate-100 pr-4 dark:border-slate-800", children: [
|
|
@@ -17855,6 +18133,16 @@ function CatalogContextPopover({
|
|
|
17855
18133
|
onOpenChange,
|
|
17856
18134
|
compatibleOnly,
|
|
17857
18135
|
onCompatibleOnlyChange,
|
|
18136
|
+
rateContextMode,
|
|
18137
|
+
onRateContextModeChange,
|
|
18138
|
+
rateContextSource,
|
|
18139
|
+
onRateContextSourceChange,
|
|
18140
|
+
manualPrimaryRate,
|
|
18141
|
+
onManualPrimaryRateChange,
|
|
18142
|
+
primaryServiceId,
|
|
18143
|
+
onPrimaryServiceIdChange,
|
|
18144
|
+
contextServiceOptions,
|
|
18145
|
+
customRateError,
|
|
17858
18146
|
contextLinked,
|
|
17859
18147
|
onContextLinkedChange,
|
|
17860
18148
|
draftContext,
|
|
@@ -17895,6 +18183,66 @@ function CatalogContextPopover({
|
|
|
17895
18183
|
] }),
|
|
17896
18184
|
/* @__PURE__ */ jsx87("input", { type: "checkbox", checked: compatibleOnly, onChange: (event) => onCompatibleOnlyChange(event.target.checked) })
|
|
17897
18185
|
] }),
|
|
18186
|
+
/* @__PURE__ */ jsxs65("div", { className: "space-y-2 rounded-2xl border border-slate-200 bg-slate-50/70 p-3 dark:border-slate-800 dark:bg-slate-900/40", children: [
|
|
18187
|
+
/* @__PURE__ */ jsx87("div", { className: "text-xs font-semibold tracking-[0.16em] text-slate-500 uppercase dark:text-slate-400", children: "Rate compatibility mode" }),
|
|
18188
|
+
/* @__PURE__ */ jsx87(
|
|
18189
|
+
InputField21,
|
|
18190
|
+
{
|
|
18191
|
+
variant: "radio",
|
|
18192
|
+
value: rateContextMode,
|
|
18193
|
+
options: [
|
|
18194
|
+
{
|
|
18195
|
+
value: "context",
|
|
18196
|
+
label: "Context coherence",
|
|
18197
|
+
description: "Use current context services for rate coherence."
|
|
18198
|
+
},
|
|
18199
|
+
{
|
|
18200
|
+
value: "custom_primary_rate",
|
|
18201
|
+
label: "Custom primary rate",
|
|
18202
|
+
description: "Use a chosen service or manual rate as primary."
|
|
18203
|
+
}
|
|
18204
|
+
],
|
|
18205
|
+
optGroupClassName: "gap-1",
|
|
18206
|
+
onChange: (event) => onRateContextModeChange(event.value)
|
|
18207
|
+
}
|
|
18208
|
+
),
|
|
18209
|
+
rateContextMode === "custom_primary_rate" ? /* @__PURE__ */ jsxs65("div", { className: "space-y-2 rounded-xl border border-slate-200 bg-white p-2 dark:border-slate-700 dark:bg-slate-950/40", children: [
|
|
18210
|
+
/* @__PURE__ */ jsx87(
|
|
18211
|
+
InputField21,
|
|
18212
|
+
{
|
|
18213
|
+
variant: "radio",
|
|
18214
|
+
value: rateContextSource,
|
|
18215
|
+
options: [
|
|
18216
|
+
{ value: "service", label: "From context service", description: "Use an active context service rate." },
|
|
18217
|
+
{ value: "manual", label: "Manual rate", description: "Provide a numeric primary rate." }
|
|
18218
|
+
],
|
|
18219
|
+
optGroupClassName: "gap-1",
|
|
18220
|
+
onChange: (event) => onRateContextSourceChange(event.value)
|
|
18221
|
+
}
|
|
18222
|
+
),
|
|
18223
|
+
rateContextSource === "service" ? /* @__PURE__ */ jsx87(
|
|
18224
|
+
InputField21,
|
|
18225
|
+
{
|
|
18226
|
+
variant: "select",
|
|
18227
|
+
label: "Primary context service",
|
|
18228
|
+
options: contextServiceOptions,
|
|
18229
|
+
value: primaryServiceId ?? void 0,
|
|
18230
|
+
onChange: (event) => onPrimaryServiceIdChange(event.value ? String(event.value) : null),
|
|
18231
|
+
placeholder: "Select service"
|
|
18232
|
+
}
|
|
18233
|
+
) : /* @__PURE__ */ jsx87(
|
|
18234
|
+
InputField21,
|
|
18235
|
+
{
|
|
18236
|
+
variant: "number",
|
|
18237
|
+
label: "Primary rate",
|
|
18238
|
+
value: manualPrimaryRate === "" ? void 0 : Number(manualPrimaryRate),
|
|
18239
|
+
onChange: (event) => onManualPrimaryRateChange(String(event.value ?? "")),
|
|
18240
|
+
placeholder: "Enter rate"
|
|
18241
|
+
}
|
|
18242
|
+
),
|
|
18243
|
+
customRateError ? /* @__PURE__ */ jsx87("p", { className: "text-xs text-amber-700 dark:text-amber-300", children: customRateError }) : null
|
|
18244
|
+
] }) : null
|
|
18245
|
+
] }),
|
|
17898
18246
|
/* @__PURE__ */ jsxs65("label", { className: "flex items-start justify-between gap-3 text-sm text-slate-900 dark:text-slate-100", children: [
|
|
17899
18247
|
/* @__PURE__ */ jsxs65("span", { className: "min-w-0", children: [
|
|
17900
18248
|
/* @__PURE__ */ jsx87("span", { className: "block font-medium", children: "Link to current context" }),
|
|
@@ -18103,9 +18451,9 @@ function GroupInputPopoverButton({
|
|
|
18103
18451
|
disabled = false,
|
|
18104
18452
|
onSubmit
|
|
18105
18453
|
}) {
|
|
18106
|
-
const [open, setOpen] =
|
|
18107
|
-
const [value, setValue] =
|
|
18108
|
-
|
|
18454
|
+
const [open, setOpen] = useState41(false);
|
|
18455
|
+
const [value, setValue] = useState41(initialValue);
|
|
18456
|
+
useEffect26(() => {
|
|
18109
18457
|
if (open) setValue(initialValue);
|
|
18110
18458
|
}, [initialValue, open]);
|
|
18111
18459
|
return /* @__PURE__ */ jsxs65(Popover, { open, onOpenChange: setOpen, children: [
|
|
@@ -18170,7 +18518,7 @@ function ConfirmPopoverButton({
|
|
|
18170
18518
|
disabled = false,
|
|
18171
18519
|
onConfirm
|
|
18172
18520
|
}) {
|
|
18173
|
-
const [open, setOpen] =
|
|
18521
|
+
const [open, setOpen] = useState41(false);
|
|
18174
18522
|
return /* @__PURE__ */ jsxs65(Popover, { open, onOpenChange: setOpen, children: [
|
|
18175
18523
|
/* @__PURE__ */ jsx87(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx87(
|
|
18176
18524
|
"button",
|
|
@@ -18261,36 +18609,44 @@ function BottomConsolePanel({ controller, errors, activeServices, allServices, o
|
|
|
18261
18609
|
const policies2 = ws.policies.policies.data ?? [];
|
|
18262
18610
|
const currentTagId = canvas.api.selection.currentTag?.();
|
|
18263
18611
|
const preferredTagId = currentTagId != null ? String(currentTagId) : canvas.layers.tags[0]?.id != null ? String(canvas.layers.tags[0]?.id) : null;
|
|
18264
|
-
const [activeSearch, setActiveSearch] =
|
|
18265
|
-
const [allSearch, setAllSearch] =
|
|
18266
|
-
const [compatibleOnly, setCompatibleOnly] =
|
|
18267
|
-
const [
|
|
18268
|
-
const [
|
|
18269
|
-
const [
|
|
18270
|
-
const [
|
|
18271
|
-
const [
|
|
18272
|
-
const [
|
|
18273
|
-
const [
|
|
18274
|
-
const [
|
|
18275
|
-
const [
|
|
18612
|
+
const [activeSearch, setActiveSearch] = useState42("");
|
|
18613
|
+
const [allSearch, setAllSearch] = useState42("");
|
|
18614
|
+
const [compatibleOnly, setCompatibleOnly] = useState42(false);
|
|
18615
|
+
const [rateContextMode, setRateContextMode] = useState42("context");
|
|
18616
|
+
const [rateContextSource, setRateContextSource] = useState42("service");
|
|
18617
|
+
const [manualPrimaryRate, setManualPrimaryRate] = useState42("");
|
|
18618
|
+
const [primaryServiceId, setPrimaryServiceId] = useState42(null);
|
|
18619
|
+
const [hideActiveServices, setHideActiveServices] = useState42(false);
|
|
18620
|
+
const [hideNonEligibleServices, setHideNonEligibleServices] = useState42(false);
|
|
18621
|
+
const [filterOpen, setFilterOpen] = useState42(false);
|
|
18622
|
+
const [searchOpen, setSearchOpen] = useState42(false);
|
|
18623
|
+
const [contextLinked, setContextLinked] = useState42(false);
|
|
18624
|
+
const [servicePickerOpen, setServicePickerOpen] = useState42(false);
|
|
18625
|
+
const [selectedActiveServiceId, setSelectedActiveServiceId] = useState42(null);
|
|
18626
|
+
const [selectedAllServiceId, setSelectedAllServiceId] = useState42(null);
|
|
18627
|
+
const [catalogContextDraft, setCatalogContextDraft] = useState42(
|
|
18276
18628
|
() => createDefaultServiceContext(canvas.props, preferredTagId)
|
|
18277
18629
|
);
|
|
18278
|
-
const
|
|
18279
|
-
const [panelPosition, setPanelPosition] =
|
|
18280
|
-
const [draggingPanel, setDraggingPanel] =
|
|
18281
|
-
const [consoleSubTab, setConsoleSubTab] =
|
|
18282
|
-
const [consoleScopeFilter, setConsoleScopeFilter] =
|
|
18283
|
-
const [consoleSeverityFilter, setConsoleSeverityFilter] =
|
|
18284
|
-
const [consoleIntroState, setConsoleIntroState] =
|
|
18630
|
+
const catalogState = useServiceCatalogState(canvas.api, canvas.api.editor);
|
|
18631
|
+
const [panelPosition, setPanelPosition] = useState42(() => readStoredPanelPosition());
|
|
18632
|
+
const [draggingPanel, setDraggingPanel] = useState42(false);
|
|
18633
|
+
const [consoleSubTab, setConsoleSubTab] = useState42("validation");
|
|
18634
|
+
const [consoleScopeFilter, setConsoleScopeFilter] = useState42("all");
|
|
18635
|
+
const [consoleSeverityFilter, setConsoleSeverityFilter] = useState42("all");
|
|
18636
|
+
const [consoleIntroState, setConsoleIntroState] = useState42({
|
|
18285
18637
|
validation: { minimized: false, closed: false },
|
|
18286
18638
|
logs: { minimized: false, closed: false },
|
|
18287
18639
|
notices: { minimized: false, closed: false }
|
|
18288
18640
|
});
|
|
18289
|
-
const lastHighlightedIdsRef =
|
|
18290
|
-
const panelContainerRef =
|
|
18291
|
-
const panelRef =
|
|
18292
|
-
const searchInputRef =
|
|
18293
|
-
const dragStartRef =
|
|
18641
|
+
const lastHighlightedIdsRef = useRef14([]);
|
|
18642
|
+
const panelContainerRef = useRef14(null);
|
|
18643
|
+
const panelRef = useRef14(null);
|
|
18644
|
+
const searchInputRef = useRef14(null);
|
|
18645
|
+
const dragStartRef = useRef14(null);
|
|
18646
|
+
const appliedSnapshotRequestRef = useRef14(0);
|
|
18647
|
+
const draftSnapshotRequestRef = useRef14(0);
|
|
18648
|
+
const allChecksByIdRequestRef = useRef14(0);
|
|
18649
|
+
const allChecksCacheRef = useRef14(/* @__PURE__ */ new Map());
|
|
18294
18650
|
const selectedButtons = useMemo41(
|
|
18295
18651
|
() => (canvas.api.selection.selectedButtons?.() ?? []).map((value) => String(value)),
|
|
18296
18652
|
[canvas.api.selection, canvas.selectionInfo.ids, canvas.selectionInfo.optionIds]
|
|
@@ -18305,26 +18661,119 @@ function BottomConsolePanel({ controller, errors, activeServices, allServices, o
|
|
|
18305
18661
|
[preferredTagId, selectedButtons]
|
|
18306
18662
|
);
|
|
18307
18663
|
const effectiveCatalogContext = contextLinked ? liveSelectionContext : catalogContextDraft;
|
|
18308
|
-
const appliedSnapshot =
|
|
18309
|
-
|
|
18310
|
-
|
|
18311
|
-
|
|
18312
|
-
|
|
18313
|
-
()
|
|
18314
|
-
|
|
18664
|
+
const [appliedSnapshot, setAppliedSnapshot] = useState42(() => createEmptyServiceContextSnapshot(effectiveCatalogContext, canvas.props));
|
|
18665
|
+
const [draftSnapshot, setDraftSnapshot] = useState42(() => createEmptyServiceContextSnapshot(catalogContextDraft, canvas.props));
|
|
18666
|
+
useEffect27(() => {
|
|
18667
|
+
const requestId = ++appliedSnapshotRequestRef.current;
|
|
18668
|
+
const fallback = createEmptyServiceContextSnapshot(effectiveCatalogContext, canvas.props);
|
|
18669
|
+
setAppliedSnapshot(fallback);
|
|
18670
|
+
buildServiceContextSnapshot({ props: canvas.props, services: servicesMap, state: effectiveCatalogContext }).then((snapshot) => {
|
|
18671
|
+
if (appliedSnapshotRequestRef.current !== requestId) return;
|
|
18672
|
+
setAppliedSnapshot(snapshot);
|
|
18673
|
+
}).catch(() => {
|
|
18674
|
+
if (appliedSnapshotRequestRef.current !== requestId) return;
|
|
18675
|
+
setAppliedSnapshot(fallback);
|
|
18676
|
+
});
|
|
18677
|
+
}, [canvas.props, effectiveCatalogContext, servicesMap]);
|
|
18678
|
+
useEffect27(() => {
|
|
18679
|
+
const requestId = ++draftSnapshotRequestRef.current;
|
|
18680
|
+
const fallback = createEmptyServiceContextSnapshot(catalogContextDraft, canvas.props);
|
|
18681
|
+
setDraftSnapshot(fallback);
|
|
18682
|
+
buildServiceContextSnapshot({ props: canvas.props, services: servicesMap, state: catalogContextDraft }).then((snapshot) => {
|
|
18683
|
+
if (draftSnapshotRequestRef.current !== requestId) return;
|
|
18684
|
+
setDraftSnapshot(snapshot);
|
|
18685
|
+
}).catch(() => {
|
|
18686
|
+
if (draftSnapshotRequestRef.current !== requestId) return;
|
|
18687
|
+
setDraftSnapshot(fallback);
|
|
18688
|
+
});
|
|
18689
|
+
}, [canvas.props, catalogContextDraft, servicesMap]);
|
|
18690
|
+
const [allChecksById, setAllChecksById] = useState42(/* @__PURE__ */ new Map());
|
|
18691
|
+
const allCandidateIds = useMemo41(() => Object.values(servicesMap).map((service) => service.id), [servicesMap]);
|
|
18692
|
+
const policiesKey = useMemo41(() => JSON.stringify(policies2 ?? []), [policies2]);
|
|
18693
|
+
const contextServiceOptions = useMemo41(
|
|
18694
|
+
() => appliedSnapshot.usedServiceIds.map((id) => {
|
|
18695
|
+
const service = servicesMap[id];
|
|
18696
|
+
if (!service) return null;
|
|
18697
|
+
return {
|
|
18698
|
+
value: String(service.id),
|
|
18699
|
+
label: `${service.name ?? `Service ${service.id}`}${service.rate != null ? ` (Rate ${service.rate})` : ""}`
|
|
18700
|
+
};
|
|
18701
|
+
}).filter(Boolean),
|
|
18702
|
+
[appliedSnapshot.usedServiceIds, servicesMap]
|
|
18315
18703
|
);
|
|
18316
|
-
const
|
|
18317
|
-
|
|
18318
|
-
|
|
18319
|
-
|
|
18704
|
+
const parsedManualPrimaryRate = useMemo41(() => {
|
|
18705
|
+
const value = Number(manualPrimaryRate.trim());
|
|
18706
|
+
return Number.isFinite(value) ? value : null;
|
|
18707
|
+
}, [manualPrimaryRate]);
|
|
18708
|
+
const hasValidCustomPrimary = useMemo41(() => {
|
|
18709
|
+
if (rateContextMode !== "custom_primary_rate") return true;
|
|
18710
|
+
if (rateContextSource === "manual") return parsedManualPrimaryRate != null;
|
|
18711
|
+
return Boolean(primaryServiceId);
|
|
18712
|
+
}, [parsedManualPrimaryRate, primaryServiceId, rateContextMode, rateContextSource]);
|
|
18713
|
+
useEffect27(() => {
|
|
18714
|
+
if (primaryServiceId && contextServiceOptions.some((option) => option.value === primaryServiceId)) return;
|
|
18715
|
+
setPrimaryServiceId(contextServiceOptions[0]?.value ?? null);
|
|
18716
|
+
}, [contextServiceOptions, primaryServiceId]);
|
|
18717
|
+
useEffect27(() => {
|
|
18718
|
+
const requestId = ++allChecksByIdRequestRef.current;
|
|
18719
|
+
if (!appliedSnapshot.selectedTag) {
|
|
18720
|
+
setAllChecksById(/* @__PURE__ */ new Map());
|
|
18721
|
+
return;
|
|
18722
|
+
}
|
|
18723
|
+
if (!hasValidCustomPrimary) {
|
|
18724
|
+
setAllChecksById(/* @__PURE__ */ new Map());
|
|
18725
|
+
return;
|
|
18726
|
+
}
|
|
18727
|
+
const cacheKey = createCompatibilityCacheKey({
|
|
18320
18728
|
tagId: appliedSnapshot.selectedTag.id,
|
|
18321
18729
|
selectedButtons: appliedSnapshot.state.selectedButtons,
|
|
18322
18730
|
usedServiceIds: appliedSnapshot.usedServiceIds,
|
|
18323
|
-
|
|
18324
|
-
|
|
18731
|
+
policiesKey,
|
|
18732
|
+
rateContextMode,
|
|
18733
|
+
rateContextSource,
|
|
18734
|
+
primaryRate: rateContextSource === "manual" ? parsedManualPrimaryRate : null,
|
|
18735
|
+
primaryServiceId: rateContextSource === "service" ? primaryServiceId : null
|
|
18736
|
+
});
|
|
18737
|
+
runCompatibilityChecksIncremental({
|
|
18738
|
+
editor: canvas.api.editor,
|
|
18739
|
+
candidateIds: allCandidateIds,
|
|
18740
|
+
args: {
|
|
18741
|
+
tagId: appliedSnapshot.selectedTag.id,
|
|
18742
|
+
selectedButtons: appliedSnapshot.state.selectedButtons,
|
|
18743
|
+
usedServiceIds: appliedSnapshot.usedServiceIds,
|
|
18744
|
+
effectiveConstraints: appliedSnapshot.selectedTag.constraints,
|
|
18745
|
+
policies: policies2,
|
|
18746
|
+
rateContext: rateContextMode === "custom_primary_rate" ? {
|
|
18747
|
+
mode: "custom_primary_rate",
|
|
18748
|
+
source: rateContextSource,
|
|
18749
|
+
primaryRate: rateContextSource === "manual" ? parsedManualPrimaryRate ?? void 0 : void 0,
|
|
18750
|
+
primaryServiceId: rateContextSource === "service" ? primaryServiceId ?? void 0 : void 0
|
|
18751
|
+
} : { mode: "context" }
|
|
18752
|
+
},
|
|
18753
|
+
cache: allChecksCacheRef.current,
|
|
18754
|
+
cacheKey,
|
|
18755
|
+
shouldAbort: () => allChecksByIdRequestRef.current !== requestId
|
|
18756
|
+
}).then((checks) => {
|
|
18757
|
+
if (allChecksByIdRequestRef.current !== requestId) return;
|
|
18758
|
+
setAllChecksById(new Map(checks.map((check) => [String(check.id), check])));
|
|
18759
|
+
}).catch(() => {
|
|
18760
|
+
if (allChecksByIdRequestRef.current !== requestId) return;
|
|
18761
|
+
setAllChecksById(/* @__PURE__ */ new Map());
|
|
18325
18762
|
});
|
|
18326
|
-
|
|
18327
|
-
|
|
18763
|
+
}, [
|
|
18764
|
+
allCandidateIds,
|
|
18765
|
+
appliedSnapshot.selectedTag,
|
|
18766
|
+
appliedSnapshot.state.selectedButtons,
|
|
18767
|
+
appliedSnapshot.usedServiceIds,
|
|
18768
|
+
canvas.api.editor,
|
|
18769
|
+
hasValidCustomPrimary,
|
|
18770
|
+
parsedManualPrimaryRate,
|
|
18771
|
+
policies2,
|
|
18772
|
+
policiesKey,
|
|
18773
|
+
primaryServiceId,
|
|
18774
|
+
rateContextMode,
|
|
18775
|
+
rateContextSource
|
|
18776
|
+
]);
|
|
18328
18777
|
const hiddenServiceIds = useMemo41(() => {
|
|
18329
18778
|
const ids = new Set(activeServices.map((service) => String(service.id)));
|
|
18330
18779
|
for (const id of appliedSnapshot.usedServiceIds) ids.add(String(id));
|
|
@@ -18356,41 +18805,24 @@ function BottomConsolePanel({ controller, errors, activeServices, allServices, o
|
|
|
18356
18805
|
servicesMap
|
|
18357
18806
|
]
|
|
18358
18807
|
);
|
|
18359
|
-
|
|
18808
|
+
useEffect27(() => {
|
|
18360
18809
|
const next = createDefaultServiceContext(canvas.props, preferredTagId);
|
|
18361
18810
|
setCatalogContextDraft((current) => {
|
|
18362
18811
|
if (contextLinked) return current;
|
|
18363
18812
|
return current.selectedTagId ? current : next;
|
|
18364
18813
|
});
|
|
18365
18814
|
}, [canvas.props, contextLinked, preferredTagId]);
|
|
18366
|
-
|
|
18815
|
+
useEffect27(() => {
|
|
18367
18816
|
if (!contextLinked) return;
|
|
18368
18817
|
setCatalogContextDraft(liveSelectionContext);
|
|
18369
18818
|
}, [contextLinked, liveSelectionContext]);
|
|
18370
|
-
|
|
18819
|
+
useEffect27(() => {
|
|
18371
18820
|
if (contextLinked) return;
|
|
18372
18821
|
const next = sanitizeServiceContext(draftSnapshot, catalogContextDraft);
|
|
18373
|
-
if (
|
|
18822
|
+
if (!areServiceContextStatesEqual(next, catalogContextDraft)) {
|
|
18374
18823
|
setCatalogContextDraft(next);
|
|
18375
18824
|
}
|
|
18376
18825
|
}, [catalogContextDraft, contextLinked, draftSnapshot]);
|
|
18377
|
-
useEffect26(() => {
|
|
18378
|
-
const editor = canvas.api.editor;
|
|
18379
|
-
const ensured = editor.getCatalog?.() ?? editor.ensureCatalog?.();
|
|
18380
|
-
if (ensured) setCatalogState(ensured);
|
|
18381
|
-
const offCatalogChange = canvas.api.on("catalog:change", ({ catalog }) => {
|
|
18382
|
-
const next = catalog ?? editor.getCatalog?.() ?? editor.ensureCatalog?.();
|
|
18383
|
-
setCatalogState(next ?? null);
|
|
18384
|
-
});
|
|
18385
|
-
const offCatalogActiveChange = canvas.api.on("catalog:active-change", () => {
|
|
18386
|
-
const next = editor.getCatalog?.() ?? editor.ensureCatalog?.();
|
|
18387
|
-
setCatalogState(next ?? null);
|
|
18388
|
-
});
|
|
18389
|
-
return () => {
|
|
18390
|
-
offCatalogChange?.();
|
|
18391
|
-
offCatalogActiveChange?.();
|
|
18392
|
-
};
|
|
18393
|
-
}, [canvas.api]);
|
|
18394
18826
|
const catalogPanelMode = catalogState?.viewMode === "grouped" ? "catalog" : "all";
|
|
18395
18827
|
const catalogGroups = useMemo41(
|
|
18396
18828
|
() => (catalogState?.nodes ?? []).filter((node) => node.kind === "group").sort((a, b) => (a.order ?? 0) - (b.order ?? 0) || a.label.localeCompare(b.label)),
|
|
@@ -18420,24 +18852,24 @@ function BottomConsolePanel({ controller, errors, activeServices, allServices, o
|
|
|
18420
18852
|
return ids;
|
|
18421
18853
|
}, [canvas.activeId, canvas.selectionInfo.ids]);
|
|
18422
18854
|
const consoleIssueCount = errors.validation.length + errors.logs.length + notices.length;
|
|
18423
|
-
|
|
18855
|
+
useEffect27(() => {
|
|
18424
18856
|
setSelectedActiveServiceId((current) => ensureSelectedRow(current, activeRows));
|
|
18425
18857
|
}, [activeRows]);
|
|
18426
|
-
|
|
18858
|
+
useEffect27(() => {
|
|
18427
18859
|
if (catalogState?.selectedServiceId == null) return;
|
|
18428
18860
|
setSelectedAllServiceId(String(catalogState.selectedServiceId));
|
|
18429
18861
|
}, [catalogState?.selectedServiceId]);
|
|
18430
|
-
|
|
18862
|
+
useEffect27(() => {
|
|
18431
18863
|
setSelectedAllServiceId((current) => ensureSelectedRow(current, visibleAllRows));
|
|
18432
18864
|
}, [visibleAllRows]);
|
|
18433
|
-
|
|
18865
|
+
useEffect27(() => {
|
|
18434
18866
|
const desiredIds = controller.isOpen && controller.activeTab === "activeServices" && selectedActiveServiceId ? activeRows.find((row) => row.id === selectedActiveServiceId)?.summary.attachedNodeIds ?? [] : [];
|
|
18435
18867
|
if (!sameIds(lastHighlightedIdsRef.current, desiredIds)) {
|
|
18436
18868
|
canvas.api.setHighlighted(desiredIds);
|
|
18437
18869
|
lastHighlightedIdsRef.current = [...desiredIds];
|
|
18438
18870
|
}
|
|
18439
18871
|
}, [activeRows, canvas.api, controller.activeTab, controller.isOpen, selectedActiveServiceId]);
|
|
18440
|
-
|
|
18872
|
+
useEffect27(() => {
|
|
18441
18873
|
return () => {
|
|
18442
18874
|
if (lastHighlightedIdsRef.current.length) {
|
|
18443
18875
|
canvas.api.setHighlighted([]);
|
|
@@ -18445,10 +18877,10 @@ function BottomConsolePanel({ controller, errors, activeServices, allServices, o
|
|
|
18445
18877
|
}
|
|
18446
18878
|
};
|
|
18447
18879
|
}, [canvas.api]);
|
|
18448
|
-
|
|
18880
|
+
useEffect27(() => {
|
|
18449
18881
|
if (searchOpen) searchInputRef.current?.focus();
|
|
18450
18882
|
}, [searchOpen]);
|
|
18451
|
-
|
|
18883
|
+
useEffect27(() => {
|
|
18452
18884
|
setPanelPosition((current) => {
|
|
18453
18885
|
const resolved = resolvePanelPosition(current, panelRef.current, panelContainerRef.current);
|
|
18454
18886
|
persistPanelPosition(resolved);
|
|
@@ -18470,7 +18902,7 @@ function BottomConsolePanel({ controller, errors, activeServices, allServices, o
|
|
|
18470
18902
|
}
|
|
18471
18903
|
event.preventDefault();
|
|
18472
18904
|
};
|
|
18473
|
-
|
|
18905
|
+
useEffect27(() => {
|
|
18474
18906
|
if (!draggingPanel) return;
|
|
18475
18907
|
const onPointerMove = (event) => {
|
|
18476
18908
|
const start = dragStartRef.current;
|
|
@@ -18724,6 +19156,16 @@ function BottomConsolePanel({ controller, errors, activeServices, allServices, o
|
|
|
18724
19156
|
onOpenChange: setFilterOpen,
|
|
18725
19157
|
compatibleOnly,
|
|
18726
19158
|
onCompatibleOnlyChange: setCompatibleOnly,
|
|
19159
|
+
rateContextMode,
|
|
19160
|
+
onRateContextModeChange: setRateContextMode,
|
|
19161
|
+
rateContextSource,
|
|
19162
|
+
onRateContextSourceChange: setRateContextSource,
|
|
19163
|
+
manualPrimaryRate,
|
|
19164
|
+
onManualPrimaryRateChange: setManualPrimaryRate,
|
|
19165
|
+
primaryServiceId,
|
|
19166
|
+
onPrimaryServiceIdChange: setPrimaryServiceId,
|
|
19167
|
+
contextServiceOptions,
|
|
19168
|
+
customRateError: hasValidCustomPrimary ? null : "Provide a primary service or valid primary rate to apply compatibility filtering.",
|
|
18727
19169
|
contextLinked,
|
|
18728
19170
|
onContextLinkedChange: setContextLinked,
|
|
18729
19171
|
draftContext: catalogContextDraft,
|
|
@@ -18953,7 +19395,7 @@ import {
|
|
|
18953
19395
|
useWorkspace as useWorkspace16,
|
|
18954
19396
|
Workspace
|
|
18955
19397
|
} from "@timeax/digital-service-engine/workspace";
|
|
18956
|
-
import { useMemo as useMemo42, useState as
|
|
19398
|
+
import { useMemo as useMemo42, useState as useState43 } from "react";
|
|
18957
19399
|
|
|
18958
19400
|
// backend/memory/create-backend.ts
|
|
18959
19401
|
import { createMemoryWorkspaceBackend } from "@timeax/digital-service-engine/workspace";
|
|
@@ -58367,15 +58809,8 @@ function WorkspaceLayout({ onShare, onPlay, menu, kinds, defaultKind }) {
|
|
|
58367
58809
|
const ws = useWorkspace16();
|
|
58368
58810
|
const errors = useErrors();
|
|
58369
58811
|
const bottomPanel = useBottomConsolePanel();
|
|
58370
|
-
const [draggingServiceId, setDraggingServiceId] =
|
|
58371
|
-
const resolvedKinds = useMemo42(
|
|
58372
|
-
() => Array.from(
|
|
58373
|
-
new Set(
|
|
58374
|
-
(kinds ?? []).map((kind) => String(kind).trim()).filter(Boolean)
|
|
58375
|
-
)
|
|
58376
|
-
),
|
|
58377
|
-
[kinds]
|
|
58378
|
-
);
|
|
58812
|
+
const [draggingServiceId, setDraggingServiceId] = useState43(null);
|
|
58813
|
+
const resolvedKinds = useMemo42(() => Array.from(new Set((kinds ?? []).map((kind) => String(kind).trim()).filter(Boolean))), [kinds]);
|
|
58379
58814
|
const resolvedDefaultKind = useMemo42(() => {
|
|
58380
58815
|
const next = defaultKind?.trim();
|
|
58381
58816
|
if (next) return next;
|