hs-uix 2.1.0 → 2.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.
- package/README.md +3 -1
- package/common-components.d.ts +319 -68
- package/dist/calendar.js +397 -119
- package/dist/calendar.mjs +399 -119
- package/dist/common-components.js +3546 -88
- package/dist/common-components.mjs +3530 -84
- package/dist/datatable.js +108 -18
- package/dist/datatable.mjs +108 -18
- package/dist/experimental.js +2876 -0
- package/dist/experimental.mjs +2883 -0
- package/dist/feed.js +267 -38
- package/dist/feed.mjs +260 -37
- package/dist/filter.js +1379 -0
- package/dist/filter.mjs +1334 -0
- package/dist/form.js +222 -26
- package/dist/form.mjs +227 -27
- package/dist/index.js +3255 -353
- package/dist/index.mjs +3199 -344
- package/dist/kanban.js +282 -62
- package/dist/kanban.mjs +273 -61
- package/dist/safe.js +9207 -0
- package/dist/safe.mjs +9298 -0
- package/dist/utils.js +491 -75
- package/dist/utils.mjs +491 -75
- package/experimental.d.ts +1 -0
- package/filter.d.ts +1 -0
- package/index.d.ts +45 -3
- package/package.json +19 -1
- package/safe.d.ts +1 -0
- package/src/calendar/README.md +76 -5
- package/src/calendar/index.d.ts +108 -1
- package/src/common-components/README.md +140 -1
- package/src/datatable/README.md +0 -2
- package/src/experimental/README.md +126 -0
- package/src/experimental/index.d.ts +346 -0
- package/src/feed/README.md +69 -0
- package/src/feed/index.d.ts +103 -0
- package/src/filter/README.md +148 -0
- package/src/filter/index.d.ts +221 -0
- package/src/form/README.md +132 -4
- package/src/form/index.d.ts +82 -1
- package/src/kanban/README.md +119 -6
- package/src/kanban/index.d.ts +153 -2
- package/src/safe/README.md +108 -0
- package/src/safe/index.d.ts +158 -0
- package/src/utils/README.md +39 -0
- package/src/wizard/README.md +158 -0
- package/src/wizard/index.d.ts +138 -0
- package/utils.d.ts +17 -0
package/dist/index.js
CHANGED
|
@@ -36,9 +36,19 @@ __export(src_exports, {
|
|
|
36
36
|
CrmDataTable: () => CrmDataTable,
|
|
37
37
|
CrmKanban: () => CrmKanban,
|
|
38
38
|
CrmLookupSelect: () => CrmLookupSelect,
|
|
39
|
+
CrmRecordPicker: () => CrmRecordPicker,
|
|
40
|
+
DATE_FILTER_OPERATORS: () => DATE_FILTER_OPERATORS,
|
|
41
|
+
DATE_RANGE_CUSTOM_VALUE: () => DATE_RANGE_CUSTOM_VALUE,
|
|
42
|
+
DATE_ROLLING_UNIT_OPTIONS: () => DATE_ROLLING_UNIT_OPTIONS,
|
|
43
|
+
DEFAULT_FEED_TYPE_PRESETS: () => DEFAULT_FEED_TYPE_PRESETS,
|
|
39
44
|
DEFAULT_SVG_FONT_WEIGHT: () => DEFAULT_SVG_FONT_WEIGHT,
|
|
40
45
|
DataTable: () => DataTable,
|
|
46
|
+
DateRangePicker: () => DateRangePicker,
|
|
47
|
+
EMPTY_STATE_IMAGES: () => EMPTY_STATE_IMAGES,
|
|
48
|
+
EMPTY_STATE_IMAGE_ALIASES: () => EMPTY_STATE_IMAGE_ALIASES,
|
|
49
|
+
FILTER_OPERATORS: () => FILTER_OPERATORS,
|
|
41
50
|
Feed: () => Feed,
|
|
51
|
+
FilterBuilder: () => FilterBuilder,
|
|
42
52
|
FormBuilder: () => FormBuilder,
|
|
43
53
|
HS_DATE_DIRECTION_LABELS: () => HS_DATE_DIRECTION_LABELS,
|
|
44
54
|
HS_DATE_PRESETS: () => HS_DATE_PRESETS,
|
|
@@ -57,21 +67,61 @@ __export(src_exports, {
|
|
|
57
67
|
HS_TEXT_COLOR: () => HS_TEXT_COLOR,
|
|
58
68
|
ICONS: () => ICONS,
|
|
59
69
|
ICON_NAMES: () => ICON_NAMES,
|
|
70
|
+
ICON_NAME_ALIASES: () => ICON_NAME_ALIASES2,
|
|
60
71
|
Icon: () => Icon,
|
|
61
72
|
Kanban: () => Kanban,
|
|
62
73
|
KanbanCardActions: () => KanbanCardActions,
|
|
63
74
|
KeyValueList: () => KeyValueList,
|
|
75
|
+
NATIVE_ICON_NAMES: () => NATIVE_ICON_NAMES,
|
|
64
76
|
NATIVE_ICON_NAME_LIST: () => NATIVE_ICON_NAME_LIST,
|
|
77
|
+
SAFE_ARRAY_PROPS: () => SAFE_ARRAY_PROPS,
|
|
78
|
+
SAFE_DERIVE_PROPS: () => SAFE_DERIVE_PROPS,
|
|
79
|
+
SKELETON_FILL: () => SKELETON_FILL,
|
|
65
80
|
SPINNERS: () => SPINNERS,
|
|
66
81
|
SPINNER_NAMES: () => SPINNER_NAMES,
|
|
82
|
+
SafeAvatarStack: () => SafeAvatarStack,
|
|
83
|
+
SafeCalendar: () => SafeCalendar,
|
|
84
|
+
SafeCrmDataTable: () => SafeCrmDataTable,
|
|
85
|
+
SafeCrmKanban: () => SafeCrmKanban,
|
|
86
|
+
SafeDataTable: () => SafeDataTable,
|
|
87
|
+
SafeEmptyState: () => SafeEmptyState,
|
|
88
|
+
SafeFeed: () => SafeFeed,
|
|
89
|
+
SafeFormBuilder: () => SafeFormBuilder,
|
|
90
|
+
SafeIcon: () => SafeIcon,
|
|
91
|
+
SafeKanban: () => SafeKanban,
|
|
92
|
+
SafeKeyValueList: () => SafeKeyValueList,
|
|
93
|
+
SafeMultiSelect: () => SafeMultiSelect,
|
|
94
|
+
SafePopover: () => SafePopover,
|
|
95
|
+
SafeSelect: () => SafeSelect,
|
|
96
|
+
SafeStatisticsTrend: () => SafeStatisticsTrend,
|
|
97
|
+
SafeStepIndicator: () => SafeStepIndicator,
|
|
98
|
+
SafeToggleGroup: () => SafeToggleGroup,
|
|
67
99
|
SectionHeader: () => SectionHeader,
|
|
68
100
|
Spinner: () => Spinner,
|
|
69
101
|
StyledText: () => StyledText,
|
|
102
|
+
TREND_DIRECTIONS: () => TREND_DIRECTIONS,
|
|
103
|
+
TREND_DIRECTION_ALIASES: () => TREND_DIRECTION_ALIASES,
|
|
104
|
+
UNASSIGNED_LANE_KEY: () => UNASSIGNED_LANE_KEY,
|
|
105
|
+
addFilter: () => addFilter,
|
|
106
|
+
applyPatches: () => applyPatches,
|
|
107
|
+
applyTypePreset: () => applyTypePreset,
|
|
70
108
|
buildCrmSearchConfig: () => buildCrmSearchConfig,
|
|
71
109
|
buildOptions: () => buildOptions,
|
|
110
|
+
changeConditionOperator: () => changeConditionOperator,
|
|
111
|
+
changeConditionProperty: () => changeConditionProperty,
|
|
112
|
+
compareHsDateValues: () => compareHsDateValues,
|
|
113
|
+
computeStageCounts: () => computeStageCounts,
|
|
114
|
+
conditionToCrmFilter: () => conditionToCrmFilter,
|
|
115
|
+
countConditions: () => countConditions,
|
|
116
|
+
createCondition: () => createCondition,
|
|
117
|
+
createGroup: () => createGroup,
|
|
72
118
|
createStatusTagSortComparator: () => createStatusTagSortComparator,
|
|
73
119
|
crmSearchResultToOption: () => crmSearchResultToOption,
|
|
120
|
+
evaluateWip: () => evaluateWip,
|
|
121
|
+
fieldsFromHubSpotProperties: () => fieldsFromHubSpotProperties,
|
|
122
|
+
findNewlyExceededWip: () => findNewlyExceededWip,
|
|
74
123
|
findOptionLabel: () => findOptionLabel2,
|
|
124
|
+
flushBuffer: () => flushBuffer,
|
|
75
125
|
formatCurrency: () => formatCurrency,
|
|
76
126
|
formatCurrencyCompact: () => formatCurrencyCompact,
|
|
77
127
|
formatDate: () => formatDate,
|
|
@@ -79,7 +129,14 @@ __export(src_exports, {
|
|
|
79
129
|
formatPercentage: () => formatPercentage,
|
|
80
130
|
getAutoStatusTagVariant: () => getAutoStatusTagVariant,
|
|
81
131
|
getAutoTagVariant: () => getAutoTagVariant,
|
|
132
|
+
getLaneKey: () => getLaneKey,
|
|
133
|
+
getNodeAtPath: () => getNodeAtPath,
|
|
134
|
+
getOperatorOptions: () => getOperatorOptions,
|
|
82
135
|
gridToBraille: () => gridToBraille,
|
|
136
|
+
isConditionNode: () => isConditionNode,
|
|
137
|
+
isGroupNode: () => isGroupNode,
|
|
138
|
+
isValidDateRange: () => isValidDateRange,
|
|
139
|
+
lookupTypePreset: () => lookupTypePreset,
|
|
83
140
|
makeAvatarStackDataUri: () => makeAvatarStackDataUri,
|
|
84
141
|
makeCrmSearchMultiSelectField: () => makeCrmSearchMultiSelectField,
|
|
85
142
|
makeCrmSearchSelectField: () => makeCrmSearchSelectField,
|
|
@@ -88,12 +145,30 @@ __export(src_exports, {
|
|
|
88
145
|
makeStyledTextDataUri: () => makeStyledTextDataUri,
|
|
89
146
|
normalizeCrmSearchRecord: () => normalizeCrmSearchRecord,
|
|
90
147
|
normalizeCrmSearchRows: () => normalizeCrmSearchRows,
|
|
148
|
+
operatorExpectsHighValue: () => operatorExpectsHighValue,
|
|
149
|
+
operatorExpectsValue: () => operatorExpectsValue,
|
|
150
|
+
operatorExpectsValues: () => operatorExpectsValues,
|
|
151
|
+
orderLaneKeys: () => orderLaneKeys,
|
|
152
|
+
partitionLanes: () => partitionLanes,
|
|
153
|
+
partitionNewItems: () => partitionNewItems,
|
|
154
|
+
presetToRange: () => presetToRange,
|
|
155
|
+
removeFilter: () => removeFilter,
|
|
156
|
+
resetSafeWarnings: () => resetSafeWarnings,
|
|
91
157
|
resolveCrmObjectType: () => resolveCrmObjectType,
|
|
158
|
+
resolveLaneLabel: () => resolveLaneLabel,
|
|
159
|
+
resolveWipLimit: () => resolveWipLimit,
|
|
92
160
|
sumBy: () => sumBy,
|
|
93
161
|
svgToIconEntry: () => svgToIconEntry,
|
|
162
|
+
toCrmSearchFilterGroups: () => toCrmSearchFilterGroups,
|
|
163
|
+
toHsDateValue: () => toHsDateValue,
|
|
164
|
+
toTimestampMs: () => toTimestampMs,
|
|
165
|
+
updateFilter: () => updateFilter,
|
|
94
166
|
useCrmSearchDataSource: () => useCrmSearchDataSource,
|
|
95
167
|
useCrmSearchOptions: () => useCrmSearchOptions,
|
|
96
|
-
useFormPrefill: () => useFormPrefill
|
|
168
|
+
useFormPrefill: () => useFormPrefill,
|
|
169
|
+
validateTree: () => validateTree,
|
|
170
|
+
warnOnce: () => warnOnce,
|
|
171
|
+
withSafeArrayProps: () => withSafeArrayProps
|
|
97
172
|
});
|
|
98
173
|
module.exports = __toCommonJS(src_exports);
|
|
99
174
|
|
|
@@ -356,6 +431,7 @@ var HS_TEXT_COLOR = "#33475b";
|
|
|
356
431
|
var HS_SUBTLE_BG = "#F5F8FA";
|
|
357
432
|
var HS_MUTED_TEXT = "#7C98B6";
|
|
358
433
|
var HS_NEUTRAL_CHIP = "#CBD6E2";
|
|
434
|
+
var SKELETON_FILL = "#DFE3EB";
|
|
359
435
|
var HS_TAG_SUBTLE_BORDER = "#7C98B6";
|
|
360
436
|
var HS_TAG_TEXT_COLOR = HS_TEXT_COLOR;
|
|
361
437
|
var HS_TAG_FONT_SIZE = 12;
|
|
@@ -618,7 +694,7 @@ var GENERATED_ICONS = {
|
|
|
618
694
|
"ZoomOut": { "viewBox": "0 0 32 32", "paths": ["M14.42 26.75c2.85 0 5.47-.97 7.56-2.6l-.03.02 5.28 5.34a1.619 1.619 0 0 0 2.76-1.15c0-.45-.18-.85-.47-1.14l-5.33-5.33c1.59-2.06 2.55-4.68 2.55-7.52C26.74 7.54 21.2 2 14.37 2S2 7.55 2 14.38s5.54 12.37 12.37 12.37h.05m0-21.55c5.06 0 9.16 4.1 9.16 9.16s-4.1 9.16-9.16 9.16-9.16-4.1-9.16-9.16c.01-5.05 4.11-9.14 9.16-9.15Zm-4.31 10.78h8.62c.89 0 1.62-.72 1.62-1.62s-.72-1.62-1.62-1.62h-8.62c-.89 0-1.62.72-1.62 1.62s.72 1.62 1.62 1.62"] }
|
|
619
695
|
};
|
|
620
696
|
|
|
621
|
-
// src/common-components/
|
|
697
|
+
// src/common-components/nativeIconNames.js
|
|
622
698
|
var NATIVE_ICON_NAMES = /* @__PURE__ */ new Set([
|
|
623
699
|
"add",
|
|
624
700
|
"appointment",
|
|
@@ -630,12 +706,12 @@ var NATIVE_ICON_NAMES = /* @__PURE__ */ new Set([
|
|
|
630
706
|
"block",
|
|
631
707
|
"book",
|
|
632
708
|
"bulb",
|
|
709
|
+
"callTranscript",
|
|
633
710
|
"calling",
|
|
634
711
|
"callingHangup",
|
|
635
712
|
"callingMade",
|
|
636
713
|
"callingMissed",
|
|
637
714
|
"callingVoicemail",
|
|
638
|
-
"callTranscript",
|
|
639
715
|
"campaigns",
|
|
640
716
|
"cap",
|
|
641
717
|
"checkCircle",
|
|
@@ -664,13 +740,13 @@ var NATIVE_ICON_NAMES = /* @__PURE__ */ new Set([
|
|
|
664
740
|
"enroll",
|
|
665
741
|
"exclamation",
|
|
666
742
|
"exclamationCircle",
|
|
667
|
-
"facebook",
|
|
668
743
|
"faceHappy",
|
|
669
744
|
"faceHappyFilled",
|
|
670
745
|
"faceNeutral",
|
|
671
746
|
"faceNeutralFilled",
|
|
672
747
|
"faceSad",
|
|
673
748
|
"faceSadFilled",
|
|
749
|
+
"facebook",
|
|
674
750
|
"favoriteHollow",
|
|
675
751
|
"file",
|
|
676
752
|
"filledXCircleIcon",
|
|
@@ -811,6 +887,8 @@ var NATIVE_ICON_NAMES = /* @__PURE__ */ new Set([
|
|
|
811
887
|
"zoomIn",
|
|
812
888
|
"zoomOut"
|
|
813
889
|
]);
|
|
890
|
+
|
|
891
|
+
// src/common-components/Icon.js
|
|
814
892
|
var NATIVE_COLORS = /* @__PURE__ */ new Set(["inherit", "alert", "warning", "success"]);
|
|
815
893
|
var NATIVE_SIZE_TOKENS = {
|
|
816
894
|
sm: "sm",
|
|
@@ -1052,6 +1130,7 @@ var CollectionFilterControl = ({
|
|
|
1052
1130
|
{ key: name, direction: "row", align: "center", gap: "xs" },
|
|
1053
1131
|
h3(import_ui_extensions5.DateInput, {
|
|
1054
1132
|
name: `${controlName}-from`,
|
|
1133
|
+
label: filter.fromLabel ?? labels.dateFrom,
|
|
1055
1134
|
placeholder: filter.fromLabel ?? labels.dateFrom,
|
|
1056
1135
|
format: "medium",
|
|
1057
1136
|
value: rangeValue.from ?? null,
|
|
@@ -1060,6 +1139,7 @@ var CollectionFilterControl = ({
|
|
|
1060
1139
|
h3(Icon, { name: "right", size: "sm" }),
|
|
1061
1140
|
h3(import_ui_extensions5.DateInput, {
|
|
1062
1141
|
name: `${controlName}-to`,
|
|
1142
|
+
label: filter.toLabel ?? labels.dateTo,
|
|
1063
1143
|
placeholder: filter.toLabel ?? labels.dateTo,
|
|
1064
1144
|
format: "medium",
|
|
1065
1145
|
value: rangeValue.to ?? null,
|
|
@@ -1198,6 +1278,45 @@ var editValidationError = (result) => {
|
|
|
1198
1278
|
return typeof result === "string" ? result : "Invalid value";
|
|
1199
1279
|
};
|
|
1200
1280
|
|
|
1281
|
+
// src/datatable/rowExpansion.js
|
|
1282
|
+
var extractRowId = (row, rowIdField = "id", fallback = void 0) => {
|
|
1283
|
+
const id = row == null ? void 0 : row[rowIdField];
|
|
1284
|
+
return id != null ? id : fallback;
|
|
1285
|
+
};
|
|
1286
|
+
var normalizeExpandedIds = (ids) => {
|
|
1287
|
+
if (ids == null) return /* @__PURE__ */ new Set();
|
|
1288
|
+
const list = ids instanceof Set ? [...ids] : Array.isArray(ids) ? ids : [ids];
|
|
1289
|
+
return new Set(list.filter((id) => id != null));
|
|
1290
|
+
};
|
|
1291
|
+
var expandRowId = (expandedIds, rowId, expandSingle = false) => {
|
|
1292
|
+
if (rowId == null) return expandedIds;
|
|
1293
|
+
if (expandSingle) return /* @__PURE__ */ new Set([rowId]);
|
|
1294
|
+
const next = new Set(expandedIds);
|
|
1295
|
+
next.add(rowId);
|
|
1296
|
+
return next;
|
|
1297
|
+
};
|
|
1298
|
+
var collapseRowId = (expandedIds, rowId) => {
|
|
1299
|
+
if (rowId == null || !expandedIds.has(rowId)) return expandedIds;
|
|
1300
|
+
const next = new Set(expandedIds);
|
|
1301
|
+
next.delete(rowId);
|
|
1302
|
+
return next;
|
|
1303
|
+
};
|
|
1304
|
+
var toggleExpandedId = (expandedIds, rowId, expandSingle = false) => {
|
|
1305
|
+
if (rowId == null) return expandedIds;
|
|
1306
|
+
return expandedIds.has(rowId) ? collapseRowId(expandedIds, rowId) : expandRowId(expandedIds, rowId, expandSingle);
|
|
1307
|
+
};
|
|
1308
|
+
var withDetailRows = (items, expandedIds, rowIdField = "id") => {
|
|
1309
|
+
if (!expandedIds || expandedIds.size === 0) return items;
|
|
1310
|
+
const out = [];
|
|
1311
|
+
items.forEach((item) => {
|
|
1312
|
+
out.push(item);
|
|
1313
|
+
if (item.type === "data" && expandedIds.has(extractRowId(item.row, rowIdField))) {
|
|
1314
|
+
out.push({ type: "detail", row: item.row });
|
|
1315
|
+
}
|
|
1316
|
+
});
|
|
1317
|
+
return out;
|
|
1318
|
+
};
|
|
1319
|
+
|
|
1201
1320
|
// src/datatable/DataTable.jsx
|
|
1202
1321
|
var import_ui_extensions7 = require("@hubspot/ui-extensions");
|
|
1203
1322
|
var NARROW_EDIT_TYPES = /* @__PURE__ */ new Set(["checkbox", "toggle"]);
|
|
@@ -1409,6 +1528,21 @@ var DataTable = ({
|
|
|
1409
1528
|
hideRowActionsWhenSelectionActive = false,
|
|
1410
1529
|
// hide row action column while selected-row action bar is visible
|
|
1411
1530
|
// -----------------------------------------------------------------------
|
|
1531
|
+
// Row expansion (detail rows)
|
|
1532
|
+
// -----------------------------------------------------------------------
|
|
1533
|
+
renderExpandedRow,
|
|
1534
|
+
// (row) => ReactNode — providing this enables the feature
|
|
1535
|
+
expandedRowIds: externalExpandedRowIds,
|
|
1536
|
+
// controlled — array of expanded row IDs
|
|
1537
|
+
defaultExpandedRowIds,
|
|
1538
|
+
// uncontrolled — initially expanded row IDs
|
|
1539
|
+
onExpandedRowsChange,
|
|
1540
|
+
// (expandedRowIds[]) => void
|
|
1541
|
+
expandOn = "icon",
|
|
1542
|
+
// "icon" (chevron toggle column) | "row" (click row content)
|
|
1543
|
+
expandSingle = false,
|
|
1544
|
+
// accordion mode — expanding a row collapses the others
|
|
1545
|
+
// -----------------------------------------------------------------------
|
|
1412
1546
|
// Inline editing
|
|
1413
1547
|
// -----------------------------------------------------------------------
|
|
1414
1548
|
editMode,
|
|
@@ -1653,6 +1787,25 @@ var DataTable = ({
|
|
|
1653
1787
|
});
|
|
1654
1788
|
return rows;
|
|
1655
1789
|
}, [groupedData, paginatedRows, expandedGroups]);
|
|
1790
|
+
const expandable = typeof renderExpandedRow === "function";
|
|
1791
|
+
const showExpandColumn = expandable && expandOn === "icon";
|
|
1792
|
+
const [internalExpandedRowIds, setInternalExpandedRowIds] = (0, import_react7.useState)(
|
|
1793
|
+
() => normalizeExpandedIds(defaultExpandedRowIds)
|
|
1794
|
+
);
|
|
1795
|
+
const expandedRowIds = (0, import_react7.useMemo)(
|
|
1796
|
+
() => externalExpandedRowIds != null ? normalizeExpandedIds(externalExpandedRowIds) : internalExpandedRowIds,
|
|
1797
|
+
[externalExpandedRowIds, internalExpandedRowIds]
|
|
1798
|
+
);
|
|
1799
|
+
const toggleRowExpanded = (0, import_react7.useCallback)((rowId) => {
|
|
1800
|
+
if (rowId == null) return;
|
|
1801
|
+
const next = toggleExpandedId(expandedRowIds, rowId, expandSingle);
|
|
1802
|
+
if (externalExpandedRowIds == null) setInternalExpandedRowIds(next);
|
|
1803
|
+
if (onExpandedRowsChange) onExpandedRowsChange([...next]);
|
|
1804
|
+
}, [expandedRowIds, expandSingle, externalExpandedRowIds, onExpandedRowsChange]);
|
|
1805
|
+
const renderedRows = (0, import_react7.useMemo)(() => {
|
|
1806
|
+
if (!expandable) return displayRows;
|
|
1807
|
+
return withDetailRows(displayRows, expandedRowIds, rowIdField);
|
|
1808
|
+
}, [expandable, displayRows, expandedRowIds, rowIdField]);
|
|
1656
1809
|
const footerData = serverSide ? data : filteredData;
|
|
1657
1810
|
const activeChips = (0, import_react7.useMemo)(
|
|
1658
1811
|
() => buildActiveFilterChips(filters, filterValues),
|
|
@@ -1804,6 +1957,7 @@ var DataTable = ({
|
|
|
1804
1957
|
const type = col.editType || "text";
|
|
1805
1958
|
const rowId = row[rowIdField];
|
|
1806
1959
|
const fieldName = `edit-${rowId}-${col.field}`;
|
|
1960
|
+
const inputLabel = typeof col.label === "string" ? col.label : col.field;
|
|
1807
1961
|
const commit = (val) => commitEdit(row, col.field, val);
|
|
1808
1962
|
const exitEdit = () => {
|
|
1809
1963
|
if (editError) return;
|
|
@@ -1844,15 +1998,15 @@ var DataTable = ({
|
|
|
1844
1998
|
case "multiselect":
|
|
1845
1999
|
return /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.MultiSelect, { ...extra, name: fieldName, label: "", value: editValue || [], onChange: commit, options: resolveEditOptions(col, data) });
|
|
1846
2000
|
case "date":
|
|
1847
|
-
return /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.DateInput, { ...extra, name: fieldName, label:
|
|
2001
|
+
return /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.DateInput, { ...extra, name: fieldName, label: inputLabel, value: editValue, onChange: commit });
|
|
1848
2002
|
case "time":
|
|
1849
|
-
return /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.TimeInput, { ...extra, name: fieldName, label:
|
|
2003
|
+
return /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.TimeInput, { ...extra, name: fieldName, label: inputLabel, value: editValue, onChange: commit });
|
|
1850
2004
|
case "datetime":
|
|
1851
|
-
return /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.Flex, { direction: "row", align: "center", gap: "xs", wrap: "nowrap" }, /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.DateInput, { ...extra, name: `${fieldName}-date`, label:
|
|
2005
|
+
return /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.Flex, { direction: "row", align: "center", gap: "xs", wrap: "nowrap" }, /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.DateInput, { ...extra, name: `${fieldName}-date`, label: `${inputLabel} date`, value: editValue == null ? void 0 : editValue.date, onChange: (val) => {
|
|
1852
2006
|
const next = { ...editValue, date: val };
|
|
1853
2007
|
handleInput(next);
|
|
1854
2008
|
commitEdit(row, col.field, next, { keepEditing: true });
|
|
1855
|
-
}, onBlur: maybeExitDatetimeEdit }), /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.TimeInput, { ...extra.timeProps || {}, name: `${fieldName}-time`, label:
|
|
2009
|
+
}, onBlur: maybeExitDatetimeEdit }), /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.TimeInput, { ...extra.timeProps || {}, name: `${fieldName}-time`, label: `${inputLabel} time`, value: editValue == null ? void 0 : editValue.time, onChange: (val) => {
|
|
1856
2010
|
const next = { ...editValue, time: val };
|
|
1857
2011
|
handleInput(next);
|
|
1858
2012
|
commitEdit(row, col.field, next, { keepEditing: true });
|
|
@@ -1866,7 +2020,8 @@ var DataTable = ({
|
|
|
1866
2020
|
}
|
|
1867
2021
|
};
|
|
1868
2022
|
const resolvedEditMode = editMode || (columns.some((col) => col.editable) ? "discrete" : null);
|
|
1869
|
-
const useColumnRendering = selectable || !!resolvedEditMode || editingRowId != null || showRowActionsColumn || !renderRow;
|
|
2023
|
+
const useColumnRendering = selectable || !!resolvedEditMode || editingRowId != null || showRowActionsColumn || expandable || !renderRow;
|
|
2024
|
+
const totalColumnCount = columns.length + (selectable ? 1 : 0) + (showExpandColumn ? 1 : 0) + (showRowActionsColumn ? 1 : 0);
|
|
1870
2025
|
const autoWidths = (0, import_react7.useMemo)(
|
|
1871
2026
|
() => autoWidth ? computeAutoWidths(columns, data) : {},
|
|
1872
2027
|
[columns, data, autoWidth]
|
|
@@ -1885,6 +2040,7 @@ var DataTable = ({
|
|
|
1885
2040
|
const type = col.editType || "text";
|
|
1886
2041
|
const rowId = row[rowIdField];
|
|
1887
2042
|
const fieldName = `inline-${rowId}-${col.field}`;
|
|
2043
|
+
const inputLabel = typeof col.label === "string" ? col.label : col.field;
|
|
1888
2044
|
const cellKey = `${rowId}-${col.field}`;
|
|
1889
2045
|
const value = row[col.field];
|
|
1890
2046
|
const validate = col.editValidate;
|
|
@@ -1933,13 +2089,13 @@ var DataTable = ({
|
|
|
1933
2089
|
case "multiselect":
|
|
1934
2090
|
return /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.MultiSelect, { ...extra, name: fieldName, label: "", value: value || [], onChange: fire, options: resolveEditOptions(col, data) });
|
|
1935
2091
|
case "date":
|
|
1936
|
-
return /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.DateInput, { ...extra, name: fieldName, label:
|
|
2092
|
+
return /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.DateInput, { ...extra, name: fieldName, label: inputLabel, value, onChange: fire });
|
|
1937
2093
|
case "time":
|
|
1938
|
-
return /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.TimeInput, { ...extra, name: fieldName, label:
|
|
2094
|
+
return /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.TimeInput, { ...extra, name: fieldName, label: inputLabel, value, onChange: fire });
|
|
1939
2095
|
case "datetime":
|
|
1940
|
-
return /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.Flex, { direction: "row", align: "center", gap: "xs", wrap: "nowrap" }, /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.DateInput, { ...extra, name: `${fieldName}-date`, label:
|
|
2096
|
+
return /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.Flex, { direction: "row", align: "center", gap: "xs", wrap: "nowrap" }, /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.DateInput, { ...extra, name: `${fieldName}-date`, label: `${inputLabel} date`, value: value == null ? void 0 : value.date, onChange: (val) => {
|
|
1941
2097
|
fire({ ...value, date: val });
|
|
1942
|
-
} }), /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.TimeInput, { ...extra.timeProps || {}, name: `${fieldName}-time`, label:
|
|
2098
|
+
} }), /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.TimeInput, { ...extra.timeProps || {}, name: `${fieldName}-time`, label: `${inputLabel} time`, value: value == null ? void 0 : value.time, onChange: (val) => {
|
|
1943
2099
|
fire({ ...value, time: val });
|
|
1944
2100
|
} }));
|
|
1945
2101
|
case "toggle":
|
|
@@ -2093,7 +2249,7 @@ var DataTable = ({
|
|
|
2093
2249
|
checked: allVisibleSelected,
|
|
2094
2250
|
onChange: handleSelectAll
|
|
2095
2251
|
}
|
|
2096
|
-
)), columns.map((col) => {
|
|
2252
|
+
)), showExpandColumn && /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.TableHeader, { width: "min" }), columns.map((col) => {
|
|
2097
2253
|
const headerAlign = resolvedEditMode === "inline" && col.editable ? void 0 : col.align;
|
|
2098
2254
|
return /* @__PURE__ */ import_react7.default.createElement(
|
|
2099
2255
|
import_ui_extensions7.TableHeader,
|
|
@@ -2107,8 +2263,8 @@ var DataTable = ({
|
|
|
2107
2263
|
col.description ? /* @__PURE__ */ import_react7.default.createElement(import_react7.default.Fragment, null, col.label, "\xA0", /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.Link, { inline: true, variant: "dark", overlay: /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.Tooltip, null, col.description) }, /* @__PURE__ */ import_react7.default.createElement(Icon, { name: "info", screenReaderText: typeof col.description === "string" ? col.description : void 0 }))) : col.label
|
|
2108
2264
|
);
|
|
2109
2265
|
}), showRowActionsColumn && /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.TableHeader, { width: "min" }))),
|
|
2110
|
-
/* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.TableBody, null,
|
|
2111
|
-
(item, idx) => item.type === "group-header" ? /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.TableRow, { key: `group-${item.group.key}` }, selectable && /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.TableCell, { width: "min" }), columns.map((col, colIdx) => {
|
|
2266
|
+
/* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.TableBody, null, renderedRows.map(
|
|
2267
|
+
(item, idx) => item.type === "group-header" ? /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.TableRow, { key: `group-${item.group.key}` }, selectable && /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.TableCell, { width: "min" }), showExpandColumn && /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.TableCell, { width: "min" }), columns.map((col, colIdx) => {
|
|
2112
2268
|
var _a, _b, _c;
|
|
2113
2269
|
return /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.TableCell, { key: col.field, width: getCellWidth(col), align: colIdx === 0 ? void 0 : col.align }, colIdx === 0 ? /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.Flex, { direction: "row", align: "center", gap: "xs", wrap: "nowrap" }, /* @__PURE__ */ import_react7.default.createElement(
|
|
2114
2270
|
Icon,
|
|
@@ -2125,7 +2281,7 @@ var DataTable = ({
|
|
|
2125
2281
|
},
|
|
2126
2282
|
/* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.Text, { format: { fontWeight: "demibold" } }, item.group.label)
|
|
2127
2283
|
)) : ((_a = groupBy.aggregations) == null ? void 0 : _a[col.field]) ? groupBy.aggregations[col.field](item.group.rows, item.group.key) : ((_c = (_b = groupBy.groupValues) == null ? void 0 : _b[item.group.key]) == null ? void 0 : _c[col.field]) ?? "");
|
|
2128
|
-
}), showRowActionsColumn && /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.TableCell, { width: "min" })) : useColumnRendering ? /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.TableRow, { key: item.row[rowIdField] ?? idx }, selectable && /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.TableCell, { width: "min" }, /* @__PURE__ */ import_react7.default.createElement(
|
|
2284
|
+
}), showRowActionsColumn && /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.TableCell, { width: "min" })) : item.type === "detail" ? /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.TableRow, { key: `detail-${item.row[rowIdField] ?? idx}` }, /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.TableCell, { colSpan: totalColumnCount }, renderExpandedRow(item.row))) : useColumnRendering ? /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.TableRow, { key: item.row[rowIdField] ?? idx }, selectable && /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.TableCell, { width: "min" }, /* @__PURE__ */ import_react7.default.createElement(
|
|
2129
2285
|
import_ui_extensions7.Checkbox,
|
|
2130
2286
|
{
|
|
2131
2287
|
name: `select-${item.row[rowIdField]}`,
|
|
@@ -2133,13 +2289,22 @@ var DataTable = ({
|
|
|
2133
2289
|
checked: selectedIds.has(item.row[rowIdField]),
|
|
2134
2290
|
onChange: (checked) => handleSelectRow(item.row[rowIdField], checked)
|
|
2135
2291
|
}
|
|
2292
|
+
)), showExpandColumn && /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.TableCell, { width: "min" }, /* @__PURE__ */ import_react7.default.createElement(
|
|
2293
|
+
Icon,
|
|
2294
|
+
{
|
|
2295
|
+
name: expandedRowIds.has(item.row[rowIdField]) ? "upCarat" : "downCarat",
|
|
2296
|
+
onClick: () => toggleRowExpanded(item.row[rowIdField]),
|
|
2297
|
+
screenReaderText: expandedRowIds.has(item.row[rowIdField]) ? "Collapse row" : "Expand row"
|
|
2298
|
+
}
|
|
2136
2299
|
)), columns.map((col) => {
|
|
2137
2300
|
const rowId = item.row[rowIdField];
|
|
2138
2301
|
const isDiscreteEditing = resolvedEditMode === "discrete" && (editingCell == null ? void 0 : editingCell.rowId) === rowId && (editingCell == null ? void 0 : editingCell.field) === col.field;
|
|
2139
2302
|
const isRowEditing = editingRowId != null && rowId === editingRowId && col.editable;
|
|
2140
2303
|
const isShowingInput = isDiscreteEditing || isRowEditing || resolvedEditMode === "inline" && col.editable;
|
|
2141
2304
|
const cellAlign = isShowingInput ? void 0 : col.align;
|
|
2142
|
-
|
|
2305
|
+
const cellContent = renderCellContent(item.row, col);
|
|
2306
|
+
const wrapInRowToggle = expandable && expandOn === "row" && !col.editable && !isShowingInput;
|
|
2307
|
+
return /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.TableCell, { key: col.field, width: isDiscreteEditing || isRowEditing ? "auto" : getCellWidth(col), align: cellAlign }, wrapInRowToggle ? /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.Link, { variant: "dark", onClick: () => toggleRowExpanded(rowId) }, cellContent) : cellContent);
|
|
2143
2308
|
}), showRowActionsColumn && /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.TableCell, { width: "min" }, /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.Flex, { direction: "row", align: "center", gap: "xs", wrap: "nowrap" }, (() => {
|
|
2144
2309
|
const resolvedRowActions = typeof rowActions === "function" ? rowActions(item.row) : rowActions;
|
|
2145
2310
|
const actions = Array.isArray(resolvedRowActions) ? resolvedRowActions : [];
|
|
@@ -2156,13 +2321,14 @@ var DataTable = ({
|
|
|
2156
2321
|
));
|
|
2157
2322
|
})()))) : renderRow(item.row)
|
|
2158
2323
|
)),
|
|
2159
|
-
(footer || columns.some((col) => col.footer)) && /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.TableFooter, null, typeof footer === "function" ? footer(footerData) : /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.TableRow, null, selectable && /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.TableHeader, { width: "min" }), columns.map((col) => {
|
|
2324
|
+
(footer || columns.some((col) => col.footer)) && /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.TableFooter, null, typeof footer === "function" ? footer(footerData) : /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.TableRow, null, selectable && /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.TableHeader, { width: "min" }), showExpandColumn && /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.TableHeader, { width: "min" }), columns.map((col) => {
|
|
2160
2325
|
const footerDef = col.footer;
|
|
2161
2326
|
const content = typeof footerDef === "function" ? footerDef(footerData) : footerDef || "";
|
|
2162
2327
|
return /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.TableHeader, { key: col.field, align: col.align }, content);
|
|
2163
2328
|
}), showRowActionsColumn && /* @__PURE__ */ import_react7.default.createElement(import_ui_extensions7.TableHeader, { width: "min" })))
|
|
2164
2329
|
));
|
|
2165
2330
|
};
|
|
2331
|
+
DataTable.displayName = "DataTable";
|
|
2166
2332
|
|
|
2167
2333
|
// src/form/FormBuilder.jsx
|
|
2168
2334
|
var import_react8 = __toESM(require("react"));
|
|
@@ -2489,8 +2655,25 @@ var resolveDependentCascade = ({ name, value, fields, values, getEmptyValueForFi
|
|
|
2489
2655
|
return { newValues, changedDependents };
|
|
2490
2656
|
};
|
|
2491
2657
|
|
|
2658
|
+
// src/form/formDirty.js
|
|
2659
|
+
var isFormDirty = (values, initialValues) => !deepEqual(values || {}, initialValues || {});
|
|
2660
|
+
var getDirtyFields = (values, initialValues) => {
|
|
2661
|
+
const current = values || {};
|
|
2662
|
+
const baseline = initialValues || {};
|
|
2663
|
+
const names = [...Object.keys(current)];
|
|
2664
|
+
for (const name of Object.keys(baseline)) {
|
|
2665
|
+
if (!Object.prototype.hasOwnProperty.call(current, name)) names.push(name);
|
|
2666
|
+
}
|
|
2667
|
+
return names.filter((name) => !deepEqual(current[name], baseline[name]));
|
|
2668
|
+
};
|
|
2669
|
+
|
|
2492
2670
|
// src/form/FormBuilder.jsx
|
|
2493
2671
|
var getRepeaterErrorKey = (fieldName, rowIdx, subFieldName) => `${fieldName}[${rowIdx}].${subFieldName}`;
|
|
2672
|
+
var withFieldLoadingSpinner = (element, loading) => {
|
|
2673
|
+
if (!loading) return element;
|
|
2674
|
+
return /* @__PURE__ */ import_react8.default.createElement(import_ui_extensions8.Flex, { direction: "row", gap: "xs", align: "end" }, /* @__PURE__ */ import_react8.default.createElement(import_ui_extensions8.Box, { flex: 1 }, element), /* @__PURE__ */ import_react8.default.createElement(import_ui_extensions8.LoadingSpinner, { size: "xs", layout: "inline" }));
|
|
2675
|
+
};
|
|
2676
|
+
var formBuilderInstanceCounter = 0;
|
|
2494
2677
|
var fieldSetHasErrors = (errors, fields) => {
|
|
2495
2678
|
if (!errors || !fields || fields.length === 0) return false;
|
|
2496
2679
|
const names = new Set(fields.map((field) => field.name));
|
|
@@ -2590,8 +2773,10 @@ var FormBuilder = (0, import_react8.forwardRef)(function FormBuilder2(props, ref
|
|
|
2590
2773
|
// controlled loading state
|
|
2591
2774
|
disabled = false,
|
|
2592
2775
|
// disable entire form
|
|
2593
|
-
renderButtons: renderButtonsProp
|
|
2776
|
+
renderButtons: renderButtonsProp,
|
|
2594
2777
|
// custom action row renderer
|
|
2778
|
+
confirmDiscard
|
|
2779
|
+
// true | { title, message, confirmLabel, cancelLabel } — confirm before the built-in Cancel discards dirty changes
|
|
2595
2780
|
} = props;
|
|
2596
2781
|
const {
|
|
2597
2782
|
columns = 1,
|
|
@@ -2710,6 +2895,7 @@ var FormBuilder = (0, import_react8.forwardRef)(function FormBuilder2(props, ref
|
|
|
2710
2895
|
"readOnly",
|
|
2711
2896
|
"alwaysEditable",
|
|
2712
2897
|
"disabled",
|
|
2898
|
+
"loading",
|
|
2713
2899
|
"defaultValue",
|
|
2714
2900
|
"fieldProps",
|
|
2715
2901
|
"colSpan",
|
|
@@ -2966,7 +3152,7 @@ var FormBuilder = (0, import_react8.forwardRef)(function FormBuilder2(props, ref
|
|
|
2966
3152
|
syncDirtyBaseline(values);
|
|
2967
3153
|
}, [values, syncDirtyBaseline]);
|
|
2968
3154
|
const isDirty = (0, import_react8.useMemo)(() => {
|
|
2969
|
-
return
|
|
3155
|
+
return isFormDirty(formValues, initialSnapshot.current);
|
|
2970
3156
|
}, [formValues]);
|
|
2971
3157
|
const prevDirtyRef = (0, import_react8.useRef)(false);
|
|
2972
3158
|
(0, import_react8.useEffect)(() => {
|
|
@@ -2975,6 +3161,27 @@ var FormBuilder = (0, import_react8.forwardRef)(function FormBuilder2(props, ref
|
|
|
2975
3161
|
if (onDirtyChange) onDirtyChange(isDirty);
|
|
2976
3162
|
}
|
|
2977
3163
|
}, [isDirty, onDirtyChange]);
|
|
3164
|
+
let hostActions = null;
|
|
3165
|
+
try {
|
|
3166
|
+
hostActions = (0, import_ui_extensions8.useExtensionActions)();
|
|
3167
|
+
} catch (err) {
|
|
3168
|
+
hostActions = null;
|
|
3169
|
+
}
|
|
3170
|
+
const discardModalIdRef = (0, import_react8.useRef)(null);
|
|
3171
|
+
if (discardModalIdRef.current === null) {
|
|
3172
|
+
formBuilderInstanceCounter += 1;
|
|
3173
|
+
discardModalIdRef.current = `hs-uix-form-discard-${formBuilderInstanceCounter}`;
|
|
3174
|
+
}
|
|
3175
|
+
const discardConfig = confirmDiscard ? confirmDiscard === true ? {} : confirmDiscard : null;
|
|
3176
|
+
const discardTitle = discardConfig && discardConfig.title || "Discard changes?";
|
|
3177
|
+
const discardMessage = discardConfig && discardConfig.message || "You have unsaved changes. If you discard now, they will be lost.";
|
|
3178
|
+
const discardConfirmLabel = discardConfig && discardConfig.confirmLabel || "Discard changes";
|
|
3179
|
+
const discardCancelLabel = discardConfig && discardConfig.cancelLabel || "Keep editing";
|
|
3180
|
+
const closeDiscardModal = (0, import_react8.useCallback)(() => {
|
|
3181
|
+
if (hostActions && typeof hostActions.closeOverlay === "function") {
|
|
3182
|
+
hostActions.closeOverlay(discardModalIdRef.current);
|
|
3183
|
+
}
|
|
3184
|
+
}, [hostActions]);
|
|
2978
3185
|
const autoSaveTimerRef = (0, import_react8.useRef)(null);
|
|
2979
3186
|
const autoSaveRef = (0, import_react8.useRef)(autoSave);
|
|
2980
3187
|
autoSaveRef.current = autoSave;
|
|
@@ -3613,6 +3820,7 @@ var FormBuilder = (0, import_react8.forwardRef)(function FormBuilder2(props, ref
|
|
|
3613
3820
|
},
|
|
3614
3821
|
getValues: () => formValues,
|
|
3615
3822
|
isDirty: () => isDirty,
|
|
3823
|
+
getDirtyFields: () => getDirtyFields(formValuesRef.current, initialSnapshot.current),
|
|
3616
3824
|
setFieldValue: (name, value) => handleFieldChange(name, value),
|
|
3617
3825
|
setFieldError: (name, message) => updateErrors({ [name]: message }),
|
|
3618
3826
|
setErrors: (errors) => {
|
|
@@ -3632,7 +3840,8 @@ var FormBuilder = (0, import_react8.forwardRef)(function FormBuilder2(props, ref
|
|
|
3632
3840
|
const isRequired = showRequiredIndicator && resolveRequired(field, formValues);
|
|
3633
3841
|
const fieldFormReadOnly = field.alwaysEditable ? false : formReadOnly;
|
|
3634
3842
|
const isReadOnly = field.readOnly || fieldFormReadOnly;
|
|
3635
|
-
const
|
|
3843
|
+
const isFieldLoading = !!field.loading;
|
|
3844
|
+
const isDisabled = disabled || resolveDisabled(field, formValues) || fieldFormReadOnly || isFieldLoading;
|
|
3636
3845
|
const fieldOnChange = field.debounce ? (v) => handleDebouncedFieldChange(field.name, v) : (v) => handleFieldChange(field.name, v);
|
|
3637
3846
|
if (field.type === "display" || field.type === "slot") {
|
|
3638
3847
|
if (field.render) {
|
|
@@ -3816,7 +4025,7 @@ var FormBuilder = (0, import_react8.forwardRef)(function FormBuilder2(props, ref
|
|
|
3816
4025
|
disabled: isDisabled,
|
|
3817
4026
|
error: hasError,
|
|
3818
4027
|
validationMessage: renderFieldError ? void 0 : fieldError || void 0,
|
|
3819
|
-
...
|
|
4028
|
+
...validatingFields[field.name] ? { loading: true } : {},
|
|
3820
4029
|
...field.fieldProps || {}
|
|
3821
4030
|
};
|
|
3822
4031
|
const options = resolveOptions(field, formValues);
|
|
@@ -3974,25 +4183,31 @@ var FormBuilder = (0, import_react8.forwardRef)(function FormBuilder2(props, ref
|
|
|
3974
4183
|
)));
|
|
3975
4184
|
}
|
|
3976
4185
|
case "select":
|
|
3977
|
-
return
|
|
3978
|
-
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
|
|
4186
|
+
return withFieldLoadingSpinner(
|
|
4187
|
+
/* @__PURE__ */ import_react8.default.createElement(
|
|
4188
|
+
import_ui_extensions8.Select,
|
|
4189
|
+
{
|
|
4190
|
+
...commonProps,
|
|
4191
|
+
value: fieldValue,
|
|
4192
|
+
options,
|
|
4193
|
+
variant: field.variant,
|
|
4194
|
+
onChange: fieldOnChange
|
|
4195
|
+
}
|
|
4196
|
+
),
|
|
4197
|
+
isFieldLoading
|
|
3986
4198
|
);
|
|
3987
4199
|
case "multiselect":
|
|
3988
|
-
return
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
4200
|
+
return withFieldLoadingSpinner(
|
|
4201
|
+
/* @__PURE__ */ import_react8.default.createElement(
|
|
4202
|
+
import_ui_extensions8.MultiSelect,
|
|
4203
|
+
{
|
|
4204
|
+
...commonProps,
|
|
4205
|
+
value: fieldValue || [],
|
|
4206
|
+
options,
|
|
4207
|
+
onChange: fieldOnChange
|
|
4208
|
+
}
|
|
4209
|
+
),
|
|
4210
|
+
isFieldLoading
|
|
3996
4211
|
);
|
|
3997
4212
|
case "toggle":
|
|
3998
4213
|
return /* @__PURE__ */ import_react8.default.createElement(
|
|
@@ -4513,6 +4728,30 @@ var FormBuilder = (0, import_react8.forwardRef)(function FormBuilder2(props, ref
|
|
|
4513
4728
|
if (layout) return renderExplicitLayout();
|
|
4514
4729
|
return renderFieldSubset(visibleFields);
|
|
4515
4730
|
};
|
|
4731
|
+
const renderCancelButton = () => {
|
|
4732
|
+
if (discardConfig && isDirty) {
|
|
4733
|
+
return /* @__PURE__ */ import_react8.default.createElement(
|
|
4734
|
+
import_ui_extensions8.Button,
|
|
4735
|
+
{
|
|
4736
|
+
variant: "secondary",
|
|
4737
|
+
disabled,
|
|
4738
|
+
overlay: /* @__PURE__ */ import_react8.default.createElement(import_ui_extensions8.Modal, { id: discardModalIdRef.current, title: discardTitle, width: "small" }, /* @__PURE__ */ import_react8.default.createElement(import_ui_extensions8.ModalBody, null, /* @__PURE__ */ import_react8.default.createElement(import_ui_extensions8.Text, null, discardMessage)), /* @__PURE__ */ import_react8.default.createElement(import_ui_extensions8.ModalFooter, null, /* @__PURE__ */ import_react8.default.createElement(import_ui_extensions8.Button, { variant: "secondary", onClick: closeDiscardModal }, discardCancelLabel), /* @__PURE__ */ import_react8.default.createElement(
|
|
4739
|
+
import_ui_extensions8.Button,
|
|
4740
|
+
{
|
|
4741
|
+
variant: "destructive",
|
|
4742
|
+
onClick: () => {
|
|
4743
|
+
closeDiscardModal();
|
|
4744
|
+
if (onCancel) onCancel();
|
|
4745
|
+
}
|
|
4746
|
+
},
|
|
4747
|
+
discardConfirmLabel
|
|
4748
|
+
)))
|
|
4749
|
+
},
|
|
4750
|
+
cancelButtonLabel
|
|
4751
|
+
);
|
|
4752
|
+
}
|
|
4753
|
+
return /* @__PURE__ */ import_react8.default.createElement(import_ui_extensions8.Button, { variant: "secondary", onClick: onCancel, disabled }, cancelButtonLabel);
|
|
4754
|
+
};
|
|
4516
4755
|
const renderButtons = () => {
|
|
4517
4756
|
if (submitPosition === "none" || formReadOnly) return null;
|
|
4518
4757
|
const isLastStep = !isMultiStep || currentStep === steps.length - 1;
|
|
@@ -4526,6 +4765,7 @@ var FormBuilder = (0, import_react8.forwardRef)(function FormBuilder2(props, ref
|
|
|
4526
4765
|
totalSteps: isMultiStep ? steps.length : 1,
|
|
4527
4766
|
disabled,
|
|
4528
4767
|
loading: isLoading,
|
|
4768
|
+
isDirty,
|
|
4529
4769
|
labels: {
|
|
4530
4770
|
submit: submitButtonLabel,
|
|
4531
4771
|
cancel: cancelButtonLabel,
|
|
@@ -4541,7 +4781,7 @@ var FormBuilder = (0, import_react8.forwardRef)(function FormBuilder2(props, ref
|
|
|
4541
4781
|
return renderButtonsProp(buttonContext);
|
|
4542
4782
|
}
|
|
4543
4783
|
if (isMultiStep) {
|
|
4544
|
-
return /* @__PURE__ */ import_react8.default.createElement(import_ui_extensions8.Flex, { direction: "row", justify: "between", align: "center" }, !isFirstStep ? /* @__PURE__ */ import_react8.default.createElement(import_ui_extensions8.Button, { variant: "secondary", onClick: handleBack, disabled }, backButtonLabel) : showCancel ?
|
|
4784
|
+
return /* @__PURE__ */ import_react8.default.createElement(import_ui_extensions8.Flex, { direction: "row", justify: "between", align: "center" }, !isFirstStep ? /* @__PURE__ */ import_react8.default.createElement(import_ui_extensions8.Button, { variant: "secondary", onClick: handleBack, disabled }, backButtonLabel) : showCancel ? renderCancelButton() : /* @__PURE__ */ import_react8.default.createElement(import_ui_extensions8.Text, null, " "), /* @__PURE__ */ import_react8.default.createElement(import_ui_extensions8.Inline, { gap: "small" }, /* @__PURE__ */ import_react8.default.createElement(import_ui_extensions8.Text, { variant: "microcopy" }, "Step ", currentStep + 1, " of ", steps.length), isLastStep ? /* @__PURE__ */ import_react8.default.createElement(
|
|
4545
4785
|
import_ui_extensions8.LoadingButton,
|
|
4546
4786
|
{
|
|
4547
4787
|
variant: submitVariant,
|
|
@@ -4552,7 +4792,7 @@ var FormBuilder = (0, import_react8.forwardRef)(function FormBuilder2(props, ref
|
|
|
4552
4792
|
submitButtonLabel
|
|
4553
4793
|
) : /* @__PURE__ */ import_react8.default.createElement(import_ui_extensions8.Button, { variant: "primary", onClick: handleNext, disabled }, nextButtonLabel)));
|
|
4554
4794
|
}
|
|
4555
|
-
return /* @__PURE__ */ import_react8.default.createElement(import_ui_extensions8.Flex, { direction: "row", justify: singleStepJustify, gap: "sm" }, showCancel &&
|
|
4795
|
+
return /* @__PURE__ */ import_react8.default.createElement(import_ui_extensions8.Flex, { direction: "row", justify: singleStepJustify, gap: "sm" }, showCancel && renderCancelButton(), /* @__PURE__ */ import_react8.default.createElement(
|
|
4556
4796
|
import_ui_extensions8.LoadingButton,
|
|
4557
4797
|
{
|
|
4558
4798
|
variant: submitVariant,
|
|
@@ -4592,10 +4832,231 @@ var FormBuilder = (0, import_react8.forwardRef)(function FormBuilder2(props, ref
|
|
|
4592
4832
|
formContent
|
|
4593
4833
|
);
|
|
4594
4834
|
});
|
|
4835
|
+
FormBuilder.displayName = "FormBuilder";
|
|
4836
|
+
|
|
4837
|
+
// src/form/hubspotSchema.js
|
|
4838
|
+
var coerceBool = (value) => value === true || value === "true" || value === "Yes" || value === "yes" || value === "1";
|
|
4839
|
+
var coerceNumber = (value) => {
|
|
4840
|
+
if (value === null || value === void 0 || value === "") return void 0;
|
|
4841
|
+
if (typeof value === "number") return value;
|
|
4842
|
+
const parsed = Number(value);
|
|
4843
|
+
return Number.isNaN(parsed) ? void 0 : parsed;
|
|
4844
|
+
};
|
|
4845
|
+
var mapPropertyOptions = (options) => {
|
|
4846
|
+
if (!Array.isArray(options)) return void 0;
|
|
4847
|
+
const mapped = options.filter((opt) => opt && opt.hidden !== true).map((opt) => {
|
|
4848
|
+
const result = { label: opt.label != null ? opt.label : String(opt.value), value: opt.value };
|
|
4849
|
+
if (opt.description != null && opt.description !== "") result.description = opt.description;
|
|
4850
|
+
return result;
|
|
4851
|
+
});
|
|
4852
|
+
return mapped;
|
|
4853
|
+
};
|
|
4854
|
+
var resolveFieldType = (property) => {
|
|
4855
|
+
const { type, fieldType } = property;
|
|
4856
|
+
if (type === "datetime") return "datetime";
|
|
4857
|
+
if (type === "date" || fieldType === "date") return "date";
|
|
4858
|
+
switch (fieldType) {
|
|
4859
|
+
case "select":
|
|
4860
|
+
return "select";
|
|
4861
|
+
// FormBuilder's radio rendering is the "radioGroup" type (native
|
|
4862
|
+
// ToggleGroup with toggleType="radioButtonList").
|
|
4863
|
+
case "radio":
|
|
4864
|
+
return "radioGroup";
|
|
4865
|
+
// HubSpot "checkbox" = multiple checkboxes over an enumeration → multiselect.
|
|
4866
|
+
case "checkbox":
|
|
4867
|
+
return "multiselect";
|
|
4868
|
+
case "booleancheckbox":
|
|
4869
|
+
return "toggle";
|
|
4870
|
+
case "number":
|
|
4871
|
+
return "number";
|
|
4872
|
+
case "textarea":
|
|
4873
|
+
return "textarea";
|
|
4874
|
+
case "text":
|
|
4875
|
+
case "phonenumber":
|
|
4876
|
+
return "text";
|
|
4877
|
+
default:
|
|
4878
|
+
break;
|
|
4879
|
+
}
|
|
4880
|
+
switch (type) {
|
|
4881
|
+
case "enumeration":
|
|
4882
|
+
return "select";
|
|
4883
|
+
case "number":
|
|
4884
|
+
return "number";
|
|
4885
|
+
case "bool":
|
|
4886
|
+
return "toggle";
|
|
4887
|
+
default:
|
|
4888
|
+
return "text";
|
|
4889
|
+
}
|
|
4890
|
+
};
|
|
4891
|
+
var isPropertyReadOnly = (property) => property.calculated === true || property.modificationMetadata && property.modificationMetadata.readOnlyValue === true;
|
|
4892
|
+
var resolveRequiredOverride = (requiredOverrides, name) => {
|
|
4893
|
+
if (!requiredOverrides) return void 0;
|
|
4894
|
+
if (Array.isArray(requiredOverrides)) {
|
|
4895
|
+
return requiredOverrides.includes(name) ? true : void 0;
|
|
4896
|
+
}
|
|
4897
|
+
if (Object.prototype.hasOwnProperty.call(requiredOverrides, name)) {
|
|
4898
|
+
return !!requiredOverrides[name];
|
|
4899
|
+
}
|
|
4900
|
+
return void 0;
|
|
4901
|
+
};
|
|
4902
|
+
var fieldsFromHubSpotProperties = (properties, options = {}) => {
|
|
4903
|
+
if (!Array.isArray(properties)) return [];
|
|
4904
|
+
const {
|
|
4905
|
+
include,
|
|
4906
|
+
exclude,
|
|
4907
|
+
overrides,
|
|
4908
|
+
requiredOverrides,
|
|
4909
|
+
includeDescriptions = false
|
|
4910
|
+
} = options;
|
|
4911
|
+
const includeSet = Array.isArray(include) ? new Set(include) : null;
|
|
4912
|
+
const excludeSet = Array.isArray(exclude) ? new Set(exclude) : null;
|
|
4913
|
+
let selected = properties.filter((property) => {
|
|
4914
|
+
if (!property || !property.name) return false;
|
|
4915
|
+
if (includeSet && !includeSet.has(property.name)) return false;
|
|
4916
|
+
if (excludeSet && excludeSet.has(property.name)) return false;
|
|
4917
|
+
if (property.hidden === true && !includeSet) return false;
|
|
4918
|
+
return true;
|
|
4919
|
+
});
|
|
4920
|
+
if (includeSet) {
|
|
4921
|
+
const order = new Map(include.map((name, idx) => [name, idx]));
|
|
4922
|
+
selected = [...selected].sort((a, b) => order.get(a.name) - order.get(b.name));
|
|
4923
|
+
}
|
|
4924
|
+
return selected.map((property) => {
|
|
4925
|
+
const type = resolveFieldType(property);
|
|
4926
|
+
const field = {
|
|
4927
|
+
name: property.name,
|
|
4928
|
+
type,
|
|
4929
|
+
label: property.label || property.name
|
|
4930
|
+
};
|
|
4931
|
+
if (includeDescriptions && property.description) {
|
|
4932
|
+
field.description = property.description;
|
|
4933
|
+
}
|
|
4934
|
+
if (type === "select" || type === "multiselect" || type === "radioGroup") {
|
|
4935
|
+
field.options = mapPropertyOptions(property.options) || [];
|
|
4936
|
+
}
|
|
4937
|
+
if (type === "toggle") {
|
|
4938
|
+
field.transformIn = coerceBool;
|
|
4939
|
+
field.transformOut = (value) => !!value;
|
|
4940
|
+
}
|
|
4941
|
+
if (type === "number") {
|
|
4942
|
+
field.transformIn = coerceNumber;
|
|
4943
|
+
}
|
|
4944
|
+
if (isPropertyReadOnly(property)) {
|
|
4945
|
+
field.readOnly = true;
|
|
4946
|
+
}
|
|
4947
|
+
const required = resolveRequiredOverride(requiredOverrides, property.name);
|
|
4948
|
+
if (required !== void 0) field.required = required;
|
|
4949
|
+
const override = overrides && overrides[property.name];
|
|
4950
|
+
return override ? { ...field, ...override } : field;
|
|
4951
|
+
});
|
|
4952
|
+
};
|
|
4595
4953
|
|
|
4596
4954
|
// src/kanban/Kanban.jsx
|
|
4597
4955
|
var import_react11 = __toESM(require("react"));
|
|
4598
4956
|
|
|
4957
|
+
// src/kanban/kanbanLanes.js
|
|
4958
|
+
var UNASSIGNED_LANE_KEY = "__unassigned";
|
|
4959
|
+
var UNKNOWN_STAGE_KEY = "__unknown";
|
|
4960
|
+
var getLaneKey = (row, swimlaneBy) => {
|
|
4961
|
+
const raw = typeof swimlaneBy === "function" ? swimlaneBy(row) : row == null ? void 0 : row[swimlaneBy];
|
|
4962
|
+
if (raw == null || raw === "") return UNASSIGNED_LANE_KEY;
|
|
4963
|
+
return String(raw);
|
|
4964
|
+
};
|
|
4965
|
+
var orderLaneKeys = (seenKeys, swimlaneOrder) => {
|
|
4966
|
+
const seen = Array.isArray(seenKeys) ? seenKeys : [];
|
|
4967
|
+
if (!Array.isArray(swimlaneOrder) || swimlaneOrder.length === 0) return [...seen];
|
|
4968
|
+
const explicit = [];
|
|
4969
|
+
for (const key of swimlaneOrder) {
|
|
4970
|
+
const normalized = String(key);
|
|
4971
|
+
if (!explicit.includes(normalized)) explicit.push(normalized);
|
|
4972
|
+
}
|
|
4973
|
+
const rest = seen.filter((key) => !explicit.includes(key));
|
|
4974
|
+
return [...explicit, ...rest];
|
|
4975
|
+
};
|
|
4976
|
+
var partitionLanes = (rows, { swimlaneBy, swimlaneOrder } = {}) => {
|
|
4977
|
+
const rowsByLane = {};
|
|
4978
|
+
const firstSeen = [];
|
|
4979
|
+
for (const row of rows || []) {
|
|
4980
|
+
const key = getLaneKey(row, swimlaneBy);
|
|
4981
|
+
if (!rowsByLane[key]) {
|
|
4982
|
+
rowsByLane[key] = [];
|
|
4983
|
+
firstSeen.push(key);
|
|
4984
|
+
}
|
|
4985
|
+
rowsByLane[key].push(row);
|
|
4986
|
+
}
|
|
4987
|
+
const laneKeys = orderLaneKeys(firstSeen, swimlaneOrder);
|
|
4988
|
+
for (const key of laneKeys) {
|
|
4989
|
+
if (!rowsByLane[key]) rowsByLane[key] = [];
|
|
4990
|
+
}
|
|
4991
|
+
return { laneKeys, rowsByLane };
|
|
4992
|
+
};
|
|
4993
|
+
var resolveLaneLabel = (laneKey, swimlaneLabels, rows, unassignedLabel) => {
|
|
4994
|
+
if (typeof swimlaneLabels === "function") {
|
|
4995
|
+
const out = swimlaneLabels(laneKey, rows || []);
|
|
4996
|
+
if (out != null) return out;
|
|
4997
|
+
} else if (swimlaneLabels && typeof swimlaneLabels === "object") {
|
|
4998
|
+
const out = swimlaneLabels[laneKey];
|
|
4999
|
+
if (out != null) return out;
|
|
5000
|
+
}
|
|
5001
|
+
if (laneKey === UNASSIGNED_LANE_KEY) return unassignedLabel || "Unassigned";
|
|
5002
|
+
return String(laneKey);
|
|
5003
|
+
};
|
|
5004
|
+
var bucketRowsByStage = (rows, stages, getStage) => {
|
|
5005
|
+
const map = {};
|
|
5006
|
+
for (const stage of stages || []) map[stage.value] = [];
|
|
5007
|
+
for (const row of rows || []) {
|
|
5008
|
+
const key = getStage(row);
|
|
5009
|
+
if (map[key]) {
|
|
5010
|
+
map[key].push(row);
|
|
5011
|
+
} else if ((stages || []).length > 0) {
|
|
5012
|
+
if (!map[UNKNOWN_STAGE_KEY]) map[UNKNOWN_STAGE_KEY] = [];
|
|
5013
|
+
map[UNKNOWN_STAGE_KEY].push(row);
|
|
5014
|
+
}
|
|
5015
|
+
}
|
|
5016
|
+
return map;
|
|
5017
|
+
};
|
|
5018
|
+
var sortBuckets = (buckets, comparator) => {
|
|
5019
|
+
if (!comparator) return buckets;
|
|
5020
|
+
const out = {};
|
|
5021
|
+
for (const key of Object.keys(buckets || {})) {
|
|
5022
|
+
out[key] = [...buckets[key]].sort(comparator);
|
|
5023
|
+
}
|
|
5024
|
+
return out;
|
|
5025
|
+
};
|
|
5026
|
+
var resolveWipLimit = (stage, wipLimits) => {
|
|
5027
|
+
const override = wipLimits ? wipLimits[stage == null ? void 0 : stage.value] : void 0;
|
|
5028
|
+
const limit = override != null ? override : stage == null ? void 0 : stage.wipLimit;
|
|
5029
|
+
if (typeof limit !== "number" || !Number.isFinite(limit) || limit < 0) return null;
|
|
5030
|
+
return limit;
|
|
5031
|
+
};
|
|
5032
|
+
var computeStageCounts = (stages, buckets, stageMeta) => {
|
|
5033
|
+
const counts = {};
|
|
5034
|
+
for (const stage of stages || []) {
|
|
5035
|
+
const meta = stageMeta ? stageMeta[stage.value] : void 0;
|
|
5036
|
+
counts[stage.value] = meta && meta.totalCount != null ? meta.totalCount : ((buckets == null ? void 0 : buckets[stage.value]) || []).length;
|
|
5037
|
+
}
|
|
5038
|
+
return counts;
|
|
5039
|
+
};
|
|
5040
|
+
var evaluateWip = (stages, counts, wipLimits) => {
|
|
5041
|
+
const out = {};
|
|
5042
|
+
for (const stage of stages || []) {
|
|
5043
|
+
const limit = resolveWipLimit(stage, wipLimits);
|
|
5044
|
+
const count = (counts == null ? void 0 : counts[stage.value]) || 0;
|
|
5045
|
+
out[stage.value] = { count, limit, exceeded: limit != null && count > limit };
|
|
5046
|
+
}
|
|
5047
|
+
return out;
|
|
5048
|
+
};
|
|
5049
|
+
var findNewlyExceededWip = (prev, next) => {
|
|
5050
|
+
const events = [];
|
|
5051
|
+
for (const stageId of Object.keys(next || {})) {
|
|
5052
|
+
const entry = next[stageId];
|
|
5053
|
+
if (!entry || !entry.exceeded) continue;
|
|
5054
|
+
if (prev && prev[stageId] && prev[stageId].exceeded) continue;
|
|
5055
|
+
events.push({ stageId, count: entry.count, limit: entry.limit });
|
|
5056
|
+
}
|
|
5057
|
+
return events;
|
|
5058
|
+
};
|
|
5059
|
+
|
|
4599
5060
|
// src/common-components/CollectionSortSelect.js
|
|
4600
5061
|
var import_react9 = __toESM(require("react"));
|
|
4601
5062
|
var import_ui_extensions9 = require("@hubspot/ui-extensions");
|
|
@@ -4867,7 +5328,7 @@ var StyledText = ({
|
|
|
4867
5328
|
const nativeVariant = NATIVE_TAG_VARIANT_ALIASES[background == null ? void 0 : background.variant] ?? (background == null ? void 0 : background.variant) ?? "default";
|
|
4868
5329
|
return import_react10.default.createElement(import_ui_extensions10.Tag, { variant: nativeVariant }, resolvedText);
|
|
4869
5330
|
}
|
|
4870
|
-
const { src, width: w, height:
|
|
5331
|
+
const { src, width: w, height: h7 } = makeStyledTextDataUri(resolvedText, {
|
|
4871
5332
|
variant,
|
|
4872
5333
|
format,
|
|
4873
5334
|
orientation,
|
|
@@ -4883,7 +5344,7 @@ var StyledText = ({
|
|
|
4883
5344
|
return import_react10.default.createElement(import_ui_extensions10.Image, {
|
|
4884
5345
|
src,
|
|
4885
5346
|
width: w,
|
|
4886
|
-
height:
|
|
5347
|
+
height: h7,
|
|
4887
5348
|
alt: alt ?? String(resolvedText)
|
|
4888
5349
|
});
|
|
4889
5350
|
};
|
|
@@ -4923,6 +5384,12 @@ var DEFAULT_LABELS3 = {
|
|
|
4923
5384
|
errorTitle: "Something went wrong.",
|
|
4924
5385
|
errorMessage: "An error occurred while loading data.",
|
|
4925
5386
|
cardCount: (n) => String(n),
|
|
5387
|
+
// "5 / 4" — count vs WIP limit in the stage header. The slash format is the
|
|
5388
|
+
// standard kanban convention; override for tighter ("5/4") or verbose forms.
|
|
5389
|
+
wipCount: (count, limit) => `${count} / ${limit}`,
|
|
5390
|
+
overWip: "Over WIP",
|
|
5391
|
+
laneCount: (n) => String(n),
|
|
5392
|
+
unassignedLane: "Unassigned",
|
|
4926
5393
|
moveTo: "Move",
|
|
4927
5394
|
clearAll: "Clear all",
|
|
4928
5395
|
selectAll: (count, label) => `Select all ${count} ${label}`,
|
|
@@ -5149,10 +5616,14 @@ var KanbanColumn = ({
|
|
|
5149
5616
|
onToggleCollapsed,
|
|
5150
5617
|
columnFooter,
|
|
5151
5618
|
countDisplay,
|
|
5619
|
+
wip,
|
|
5620
|
+
compactEmpty,
|
|
5152
5621
|
labels,
|
|
5153
5622
|
children
|
|
5154
5623
|
}) => {
|
|
5155
|
-
const
|
|
5624
|
+
const hasWipLimit = wip != null && wip.limit != null;
|
|
5625
|
+
const countLabel = hasWipLimit ? labels.wipCount(wip.count, wip.limit) : labels.cardCount(totalCount != null ? totalCount : bucketCount);
|
|
5626
|
+
const overWipNode = wip && wip.exceeded ? /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.StatusTag, { variant: "warning" }, labels.overWip) : null;
|
|
5156
5627
|
const countNode = countDisplay === "text" ? /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Text, { format: { fontWeight: "demibold" } }, countLabel) : countDisplay === "none" ? null : /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Tag, { variant: "default" }, countLabel);
|
|
5157
5628
|
if (collapsed) {
|
|
5158
5629
|
const rotated = makeRotatedLabelDataUri(stage.label);
|
|
@@ -5185,8 +5656,11 @@ var KanbanColumn = ({
|
|
|
5185
5656
|
}
|
|
5186
5657
|
) : null));
|
|
5187
5658
|
}
|
|
5659
|
+
if (compactEmpty && !loading && rows.length === 0 && bucketCount === 0) {
|
|
5660
|
+
return /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Tile, { compact: true }, /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Flex, { direction: "row", align: "center", justify: "between", gap: "xs" }, /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Text, { variant: "microcopy", format: { fontWeight: "demibold" } }, stage.shortLabel || stage.label), /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Text, { variant: "microcopy", format: { italic: true } }, labels.emptyColumn)));
|
|
5661
|
+
}
|
|
5188
5662
|
const footerContent = stage.footer ? stage.footer(rows) : columnFooter ? columnFooter(rows, stage) : null;
|
|
5189
|
-
return /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Tile, { compact: true }, /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Flex, { direction: "column", gap: "xs" }, /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Flex, { direction: "row", align: "center", justify: "between", gap: "xs" }, /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Flex, { direction: "row", align: "center", gap: "xs" }, /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Text, { format: { fontWeight: "demibold" } }, stage.shortLabel || stage.label), countNode, loading ? /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.LoadingSpinner, { size: "xs" }) : null), /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Button, { variant: "transparent", size: "sm", onClick: onToggleCollapsed, tooltip: "Collapse" }, /* @__PURE__ */ import_react11.default.createElement(Icon, { name: "left", size: "sm", screenReaderText: `Collapse ${stage.label}` }))), footerContent ? /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Text, { variant: "microcopy" }, footerContent) : null, /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Divider, null), children, error ? /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Alert, { variant: "danger", title: labels.errorTitle }, /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Flex, { direction: "row", gap: "xs", align: "center" }, /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Text, { variant: "microcopy" }, error), onLoadMore ? /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Button, { variant: "transparent", size: "xs", onClick: () => onLoadMore(stage.value) }, labels.retryLoadMore) : null)) : null, !error && hasMore && onLoadMore && !loading && bucketCount > 0 ? /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Flex, { direction: "row", justify: "center" }, /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Link, { onClick: () => onLoadMore(stage.value) }, labels.loadMore(bucketCount, totalCount))) : null, !error && loading && hasMore ? /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.LoadingSpinner, { size: "sm", layout: "centered", label: labels.loadingMore }) : null, !error && !hasMore && bucketCount > rows.length ? /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Flex, { direction: "row", justify: "center" }, /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Link, { onClick: onToggleExpanded }, expanded ? labels.showLess : labels.showMore(rows.length, bucketCount))) : null, rows.length === 0 && bucketCount === 0 && !loading ? /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Text, { variant: "microcopy", format: { italic: true } }, labels.emptyColumn) : null));
|
|
5663
|
+
return /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Tile, { compact: true }, /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Flex, { direction: "column", gap: "xs" }, /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Flex, { direction: "row", align: "center", justify: "between", gap: "xs" }, /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Flex, { direction: "row", align: "center", gap: "xs" }, /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Text, { format: { fontWeight: "demibold" } }, stage.shortLabel || stage.label), countNode, overWipNode, loading ? /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.LoadingSpinner, { size: "xs" }) : null), /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Button, { variant: "transparent", size: "sm", onClick: onToggleCollapsed, tooltip: "Collapse" }, /* @__PURE__ */ import_react11.default.createElement(Icon, { name: "left", size: "sm", screenReaderText: `Collapse ${stage.label}` }))), footerContent ? /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Text, { variant: "microcopy" }, footerContent) : null, /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Divider, null), children, error ? /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Alert, { variant: "danger", title: labels.errorTitle }, /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Flex, { direction: "row", gap: "xs", align: "center" }, /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Text, { variant: "microcopy" }, error), onLoadMore ? /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Button, { variant: "transparent", size: "xs", onClick: () => onLoadMore(stage.value) }, labels.retryLoadMore) : null)) : null, !error && hasMore && onLoadMore && !loading && bucketCount > 0 ? /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Flex, { direction: "row", justify: "center" }, /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Link, { onClick: () => onLoadMore(stage.value) }, labels.loadMore(bucketCount, totalCount))) : null, !error && loading && hasMore ? /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.LoadingSpinner, { size: "sm", layout: "centered", label: labels.loadingMore }) : null, !error && !hasMore && bucketCount > rows.length ? /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Flex, { direction: "row", justify: "center" }, /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Link, { onClick: onToggleExpanded }, expanded ? labels.showLess : labels.showMore(rows.length, bucketCount))) : null, rows.length === 0 && bucketCount === 0 && !loading ? /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Text, { variant: "microcopy", format: { italic: true } }, labels.emptyColumn) : null));
|
|
5190
5664
|
};
|
|
5191
5665
|
var renderMetricsPanel = (metrics) => {
|
|
5192
5666
|
if (!metrics) return null;
|
|
@@ -5225,14 +5699,14 @@ var KanbanToolbar = ({
|
|
|
5225
5699
|
sortOptions,
|
|
5226
5700
|
sortValue,
|
|
5227
5701
|
onSortChange,
|
|
5228
|
-
|
|
5229
|
-
|
|
5702
|
+
showMetricsButton,
|
|
5703
|
+
metricsPanel,
|
|
5230
5704
|
onToggleMetrics,
|
|
5231
5705
|
labels,
|
|
5232
5706
|
toolbarLeftFlex,
|
|
5233
5707
|
toolbarRightFlex
|
|
5234
5708
|
}) => {
|
|
5235
|
-
const rightControls = (sortOptions == null ? void 0 : sortOptions.length) > 0 ||
|
|
5709
|
+
const rightControls = (sortOptions == null ? void 0 : sortOptions.length) > 0 || showMetricsButton ? /* @__PURE__ */ import_react11.default.createElement(import_react11.default.Fragment, null, sortOptions && sortOptions.length > 0 ? /* @__PURE__ */ import_react11.default.createElement(
|
|
5236
5710
|
CollectionSortSelect,
|
|
5237
5711
|
{
|
|
5238
5712
|
name: "kanban-sort",
|
|
@@ -5241,7 +5715,7 @@ var KanbanToolbar = ({
|
|
|
5241
5715
|
options: sortOptions,
|
|
5242
5716
|
onChange: onSortChange
|
|
5243
5717
|
}
|
|
5244
|
-
) : null,
|
|
5718
|
+
) : null, showMetricsButton ? /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Button, { variant: "secondary", size: "small", onClick: onToggleMetrics }, /* @__PURE__ */ import_react11.default.createElement(Icon, { name: "gauge", size: "sm" }), " ", labels.metricsButton) : null) : null;
|
|
5245
5719
|
return /* @__PURE__ */ import_react11.default.createElement(
|
|
5246
5720
|
CollectionToolbar,
|
|
5247
5721
|
{
|
|
@@ -5268,7 +5742,7 @@ var KanbanToolbar = ({
|
|
|
5268
5742
|
onRemove: onFilterRemove
|
|
5269
5743
|
},
|
|
5270
5744
|
right: rightControls,
|
|
5271
|
-
footer:
|
|
5745
|
+
footer: metricsPanel,
|
|
5272
5746
|
labels,
|
|
5273
5747
|
leftFlex: toolbarLeftFlex,
|
|
5274
5748
|
rightFlex: toolbarRightFlex
|
|
@@ -5320,6 +5794,18 @@ var Kanban = ({
|
|
|
5320
5794
|
// --- Per-stage pagination ---
|
|
5321
5795
|
stageMeta,
|
|
5322
5796
|
onLoadMore,
|
|
5797
|
+
// --- WIP limits ---
|
|
5798
|
+
wipLimits,
|
|
5799
|
+
onWipExceeded,
|
|
5800
|
+
// --- Swimlanes ---
|
|
5801
|
+
swimlaneBy,
|
|
5802
|
+
swimlaneLabels,
|
|
5803
|
+
swimlaneOrder,
|
|
5804
|
+
collapseLanes = true,
|
|
5805
|
+
collapsedLanes,
|
|
5806
|
+
defaultCollapsedLanes,
|
|
5807
|
+
onCollapsedLanesChange,
|
|
5808
|
+
metricsPerLane = false,
|
|
5323
5809
|
// --- Selection ---
|
|
5324
5810
|
selectable = false,
|
|
5325
5811
|
selectedIds,
|
|
@@ -5384,6 +5870,9 @@ var Kanban = ({
|
|
|
5384
5870
|
const [internalFilters, setInternalFilters] = (0, import_react11.useState)(() => getEmptyFilterValues(filters));
|
|
5385
5871
|
const [internalSort, setInternalSort] = (0, import_react11.useState)(defaultSort || (((_a = sortOptions == null ? void 0 : sortOptions[0]) == null ? void 0 : _a.value) ?? ""));
|
|
5386
5872
|
const [internalCollapsed, setInternalCollapsed] = (0, import_react11.useState)([]);
|
|
5873
|
+
const [internalCollapsedLanes, setInternalCollapsedLanes] = (0, import_react11.useState)(
|
|
5874
|
+
() => defaultCollapsedLanes || []
|
|
5875
|
+
);
|
|
5387
5876
|
const [internalExpanded, setInternalExpanded] = (0, import_react11.useState)([]);
|
|
5388
5877
|
const [internalSelection, setInternalSelection] = (0, import_react11.useState)([]);
|
|
5389
5878
|
const [internalShowMetrics, setInternalShowMetrics] = (0, import_react11.useState)(false);
|
|
@@ -5400,6 +5889,7 @@ var Kanban = ({
|
|
|
5400
5889
|
const resolvedFilters = filterValues != null ? filterValues : internalFilters;
|
|
5401
5890
|
const resolvedSort = sort != null ? sort : internalSort;
|
|
5402
5891
|
const resolvedCollapsed = collapsedStages != null ? collapsedStages : internalCollapsed;
|
|
5892
|
+
const resolvedCollapsedLanes = collapsedLanes != null ? collapsedLanes : internalCollapsedLanes;
|
|
5403
5893
|
const resolvedExpanded = expandedStages != null ? expandedStages : internalExpanded;
|
|
5404
5894
|
const resolvedSelection = selectedIds != null ? selectedIds : internalSelection;
|
|
5405
5895
|
const searchEnabled = showSearch && Array.isArray(searchFields) && searchFields.length > 0;
|
|
@@ -5416,9 +5906,10 @@ var Kanban = ({
|
|
|
5416
5906
|
search: overrides.search != null ? overrides.search : resolvedSearch,
|
|
5417
5907
|
filters: overrides.filters != null ? overrides.filters : resolvedFilters,
|
|
5418
5908
|
sort: overrides.sort != null ? overrides.sort : resolvedSort || null,
|
|
5419
|
-
collapsedStages: overrides.collapsedStages != null ? overrides.collapsedStages : resolvedCollapsed
|
|
5909
|
+
collapsedStages: overrides.collapsedStages != null ? overrides.collapsedStages : resolvedCollapsed,
|
|
5910
|
+
collapsedLanes: overrides.collapsedLanes != null ? overrides.collapsedLanes : resolvedCollapsedLanes
|
|
5420
5911
|
});
|
|
5421
|
-
}, [onParamsChange, resolvedCollapsed, resolvedFilters, resolvedSearch, resolvedSort]);
|
|
5912
|
+
}, [onParamsChange, resolvedCollapsed, resolvedCollapsedLanes, resolvedFilters, resolvedSearch, resolvedSort]);
|
|
5422
5913
|
const lastAppliedSearchRef = (0, import_react11.useRef)(searchValue != null ? searchValue : "");
|
|
5423
5914
|
(0, import_react11.useEffect)(() => {
|
|
5424
5915
|
if (searchValue == null) return;
|
|
@@ -5477,6 +5968,15 @@ var Kanban = ({
|
|
|
5477
5968
|
},
|
|
5478
5969
|
[fireParamsChange, resolvedCollapsed, collapsedStages, onCollapsedStagesChange]
|
|
5479
5970
|
);
|
|
5971
|
+
const handleLaneCollapsed = (0, import_react11.useCallback)(
|
|
5972
|
+
(laneKey) => {
|
|
5973
|
+
const next = resolvedCollapsedLanes.includes(laneKey) ? resolvedCollapsedLanes.filter((k) => k !== laneKey) : [...resolvedCollapsedLanes, laneKey];
|
|
5974
|
+
if (onCollapsedLanesChange) onCollapsedLanesChange(next);
|
|
5975
|
+
if (collapsedLanes == null) setInternalCollapsedLanes(next);
|
|
5976
|
+
fireParamsChange({ collapsedLanes: next });
|
|
5977
|
+
},
|
|
5978
|
+
[fireParamsChange, resolvedCollapsedLanes, collapsedLanes, onCollapsedLanesChange]
|
|
5979
|
+
);
|
|
5480
5980
|
const handleExpanded = (0, import_react11.useCallback)(
|
|
5481
5981
|
(stageValue) => {
|
|
5482
5982
|
const next = resolvedExpanded.includes(stageValue) ? resolvedExpanded.filter((v) => v !== stageValue) : [...resolvedExpanded, stageValue];
|
|
@@ -5545,33 +6045,45 @@ var Kanban = ({
|
|
|
5545
6045
|
}
|
|
5546
6046
|
return result;
|
|
5547
6047
|
}, [data, resolvedSearch, resolvedFilters, filters, searchEnabled, searchFields, fuzzySearch, fuzzyOptions]);
|
|
5548
|
-
const buckets = (0, import_react11.useMemo)(
|
|
5549
|
-
|
|
5550
|
-
|
|
5551
|
-
|
|
5552
|
-
const key = getStageFor(row);
|
|
5553
|
-
if (map[key]) {
|
|
5554
|
-
map[key].push(row);
|
|
5555
|
-
} else if (stages.length > 0) {
|
|
5556
|
-
if (!map.__unknown) map.__unknown = [];
|
|
5557
|
-
map.__unknown.push(row);
|
|
5558
|
-
}
|
|
5559
|
-
}
|
|
5560
|
-
return map;
|
|
5561
|
-
}, [filteredData, stages, getStageFor]);
|
|
6048
|
+
const buckets = (0, import_react11.useMemo)(
|
|
6049
|
+
() => bucketRowsByStage(filteredData, stages, getStageFor),
|
|
6050
|
+
[filteredData, stages, getStageFor]
|
|
6051
|
+
);
|
|
5562
6052
|
const sortComparator = (0, import_react11.useMemo)(() => {
|
|
5563
6053
|
if (!sortOptions || !resolvedSort) return null;
|
|
5564
6054
|
const opt = sortOptions.find((s) => s.value === resolvedSort);
|
|
5565
6055
|
return (opt == null ? void 0 : opt.comparator) || null;
|
|
5566
6056
|
}, [sortOptions, resolvedSort]);
|
|
5567
|
-
const sortedBuckets = (0, import_react11.useMemo)(() =>
|
|
5568
|
-
|
|
6057
|
+
const sortedBuckets = (0, import_react11.useMemo)(() => sortBuckets(buckets, sortComparator), [buckets, sortComparator]);
|
|
6058
|
+
const hasLanes = swimlaneBy != null;
|
|
6059
|
+
const laneData = (0, import_react11.useMemo)(() => {
|
|
6060
|
+
if (!hasLanes) return null;
|
|
6061
|
+
return partitionLanes(filteredData, { swimlaneBy, swimlaneOrder });
|
|
6062
|
+
}, [hasLanes, filteredData, swimlaneBy, swimlaneOrder]);
|
|
6063
|
+
const laneBuckets = (0, import_react11.useMemo)(() => {
|
|
6064
|
+
if (!laneData) return null;
|
|
5569
6065
|
const out = {};
|
|
5570
|
-
for (const
|
|
5571
|
-
out[
|
|
6066
|
+
for (const laneKey of laneData.laneKeys) {
|
|
6067
|
+
out[laneKey] = sortBuckets(
|
|
6068
|
+
bucketRowsByStage(laneData.rowsByLane[laneKey] || [], stages, getStageFor),
|
|
6069
|
+
sortComparator
|
|
6070
|
+
);
|
|
5572
6071
|
}
|
|
5573
6072
|
return out;
|
|
5574
|
-
}, [
|
|
6073
|
+
}, [laneData, stages, getStageFor, sortComparator]);
|
|
6074
|
+
const wipByStage = (0, import_react11.useMemo)(
|
|
6075
|
+
() => evaluateWip(stages, computeStageCounts(stages, buckets, stageMeta), wipLimits),
|
|
6076
|
+
[stages, buckets, stageMeta, wipLimits]
|
|
6077
|
+
);
|
|
6078
|
+
const prevWipRef = (0, import_react11.useRef)({});
|
|
6079
|
+
(0, import_react11.useEffect)(() => {
|
|
6080
|
+
const newlyExceeded = findNewlyExceededWip(prevWipRef.current, wipByStage);
|
|
6081
|
+
prevWipRef.current = wipByStage;
|
|
6082
|
+
if (!onWipExceeded) return;
|
|
6083
|
+
for (const event of newlyExceeded) {
|
|
6084
|
+
onWipExceeded(event.stageId, event.count, event.limit);
|
|
6085
|
+
}
|
|
6086
|
+
}, [wipByStage, onWipExceeded]);
|
|
5575
6087
|
const activeChips = (0, import_react11.useMemo)(
|
|
5576
6088
|
() => buildActiveFilterChips(filters, resolvedFilters),
|
|
5577
6089
|
[filters, resolvedFilters]
|
|
@@ -5698,6 +6210,52 @@ var Kanban = ({
|
|
|
5698
6210
|
selectionActions: selectionActions || [],
|
|
5699
6211
|
labels
|
|
5700
6212
|
};
|
|
6213
|
+
const metricsProvided = metrics != null && (!Array.isArray(metrics) || metrics.length > 0);
|
|
6214
|
+
const perLaneMetricsActive = hasLanes && metricsPerLane && typeof metrics === "function";
|
|
6215
|
+
const globalMetricsContent = metricsProvided && !perLaneMetricsActive ? typeof metrics === "function" ? metrics(filteredData, null) : metrics : null;
|
|
6216
|
+
const renderStageColumns = (bucketMap, laneKey) => {
|
|
6217
|
+
const inLane = laneKey != null;
|
|
6218
|
+
return /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Flex, { direction: "row", gap: "sm", wrap: "nowrap" }, stages.map((stage) => {
|
|
6219
|
+
const stageRows = bucketMap[stage.value] || [];
|
|
6220
|
+
const meta = inLane ? void 0 : stageMeta == null ? void 0 : stageMeta[stage.value];
|
|
6221
|
+
const isExpanded = resolvedExpanded.includes(stage.value);
|
|
6222
|
+
const clamp = isExpanded ? maxCardsExpanded : maxCardsPerColumn;
|
|
6223
|
+
const visibleRows = stageRows.slice(0, clamp);
|
|
6224
|
+
const isCollapsed = resolvedCollapsed.includes(stage.value);
|
|
6225
|
+
const stageWip = wipByStage[stage.value];
|
|
6226
|
+
const wip = inLane ? (stageWip == null ? void 0 : stageWip.exceeded) ? { count: stageWip.count, limit: null, exceeded: true } : null : stageWip;
|
|
6227
|
+
return /* @__PURE__ */ import_react11.default.createElement(
|
|
6228
|
+
import_ui_extensions11.AutoGrid,
|
|
6229
|
+
{
|
|
6230
|
+
key: inLane ? `${laneKey}::${stage.value}` : stage.value,
|
|
6231
|
+
columnWidth: isCollapsed ? 72 : effectiveColumnWidth
|
|
6232
|
+
},
|
|
6233
|
+
/* @__PURE__ */ import_react11.default.createElement(
|
|
6234
|
+
KanbanColumn,
|
|
6235
|
+
{
|
|
6236
|
+
stage,
|
|
6237
|
+
rows: visibleRows,
|
|
6238
|
+
bucketCount: stageRows.length,
|
|
6239
|
+
totalCount: meta == null ? void 0 : meta.totalCount,
|
|
6240
|
+
hasMore: meta == null ? void 0 : meta.hasMore,
|
|
6241
|
+
loading: meta == null ? void 0 : meta.loading,
|
|
6242
|
+
error: meta == null ? void 0 : meta.error,
|
|
6243
|
+
onLoadMore: inLane ? void 0 : onLoadMore,
|
|
6244
|
+
expanded: isExpanded,
|
|
6245
|
+
onToggleExpanded: () => handleExpanded(stage.value),
|
|
6246
|
+
collapsed: isCollapsed,
|
|
6247
|
+
onToggleCollapsed: () => handleCollapsed(stage.value),
|
|
6248
|
+
columnFooter,
|
|
6249
|
+
countDisplay,
|
|
6250
|
+
wip,
|
|
6251
|
+
compactEmpty: inLane,
|
|
6252
|
+
labels
|
|
6253
|
+
},
|
|
6254
|
+
visibleRows.map((row) => renderCardNode(row, stage))
|
|
6255
|
+
)
|
|
6256
|
+
);
|
|
6257
|
+
}));
|
|
6258
|
+
};
|
|
5701
6259
|
const mainContent = error ? renderErrorState ? renderErrorState({
|
|
5702
6260
|
error,
|
|
5703
6261
|
title: labels.errorTitle,
|
|
@@ -5709,35 +6267,32 @@ var Kanban = ({
|
|
|
5709
6267
|
) : filteredData.length === 0 ? renderEmptyState ? renderEmptyState({
|
|
5710
6268
|
title: labels.emptyTitle,
|
|
5711
6269
|
message: labels.emptyMessage
|
|
5712
|
-
}) : /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Tile, null, /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Flex, { direction: "column", align: "center", justify: "center" }, /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.EmptyState, { title: labels.emptyTitle, layout: "vertical" }, /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Text, null, labels.emptyMessage)))) : /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Flex, { direction: "
|
|
5713
|
-
const
|
|
5714
|
-
const
|
|
5715
|
-
const
|
|
5716
|
-
const
|
|
5717
|
-
const
|
|
5718
|
-
const
|
|
5719
|
-
|
|
5720
|
-
|
|
6270
|
+
}) : /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Tile, null, /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Flex, { direction: "column", align: "center", justify: "center" }, /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.EmptyState, { title: labels.emptyTitle, layout: "vertical" }, /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Text, null, labels.emptyMessage)))) : hasLanes ? /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Flex, { direction: "column", gap: "md" }, ((laneData == null ? void 0 : laneData.laneKeys) || []).map((laneKey, laneIndex) => {
|
|
6271
|
+
const laneRows = laneData.rowsByLane[laneKey] || [];
|
|
6272
|
+
const laneLabel = resolveLaneLabel(laneKey, swimlaneLabels, laneRows, labels.unassignedLane);
|
|
6273
|
+
const laneLabelText = typeof laneLabel === "string" ? laneLabel : String(laneKey);
|
|
6274
|
+
const isLaneCollapsed = collapseLanes && resolvedCollapsedLanes.includes(laneKey);
|
|
6275
|
+
const laneCountLabel = labels.laneCount(laneRows.length);
|
|
6276
|
+
const laneCountNode = countDisplay === "none" ? null : countDisplay === "text" ? /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Text, { format: { fontWeight: "demibold" } }, laneCountLabel) : /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Tag, { variant: "default" }, laneCountLabel);
|
|
6277
|
+
const laneMetricsNode = !isLaneCollapsed && perLaneMetricsActive && resolvedShowMetrics ? renderMetricsPanel(metrics(laneRows, laneKey)) : null;
|
|
6278
|
+
return /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Flex, { key: laneKey, direction: "column", gap: "xs" }, laneIndex > 0 ? /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Divider, null) : null, /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Flex, { direction: "row", align: "center", gap: "xs" }, collapseLanes ? /* @__PURE__ */ import_react11.default.createElement(
|
|
6279
|
+
import_ui_extensions11.Button,
|
|
5721
6280
|
{
|
|
5722
|
-
|
|
5723
|
-
|
|
5724
|
-
|
|
5725
|
-
|
|
5726
|
-
hasMore: meta == null ? void 0 : meta.hasMore,
|
|
5727
|
-
loading: meta == null ? void 0 : meta.loading,
|
|
5728
|
-
error: meta == null ? void 0 : meta.error,
|
|
5729
|
-
onLoadMore,
|
|
5730
|
-
expanded: isExpanded,
|
|
5731
|
-
onToggleExpanded: () => handleExpanded(stage.value),
|
|
5732
|
-
collapsed: isCollapsed,
|
|
5733
|
-
onToggleCollapsed: () => handleCollapsed(stage.value),
|
|
5734
|
-
columnFooter,
|
|
5735
|
-
countDisplay,
|
|
5736
|
-
labels
|
|
6281
|
+
variant: "transparent",
|
|
6282
|
+
size: "sm",
|
|
6283
|
+
onClick: () => handleLaneCollapsed(laneKey),
|
|
6284
|
+
tooltip: isLaneCollapsed ? `Expand ${laneLabelText}` : `Collapse ${laneLabelText}`
|
|
5737
6285
|
},
|
|
5738
|
-
|
|
5739
|
-
|
|
5740
|
-
|
|
6286
|
+
/* @__PURE__ */ import_react11.default.createElement(
|
|
6287
|
+
Icon,
|
|
6288
|
+
{
|
|
6289
|
+
name: isLaneCollapsed ? "right" : "down",
|
|
6290
|
+
size: "sm",
|
|
6291
|
+
screenReaderText: isLaneCollapsed ? `Expand ${laneLabelText}` : `Collapse ${laneLabelText}`
|
|
6292
|
+
}
|
|
6293
|
+
)
|
|
6294
|
+
) : null, /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Text, { format: { fontWeight: "demibold" } }, laneLabel), laneCountNode), laneMetricsNode, !isLaneCollapsed ? renderStageColumns((laneBuckets == null ? void 0 : laneBuckets[laneKey]) || {}, laneKey) : null);
|
|
6295
|
+
})) : renderStageColumns(sortedBuckets, null);
|
|
5741
6296
|
const resolvedShowClearFiltersButton = showClearFiltersButton ?? showFilterBadges;
|
|
5742
6297
|
return /* @__PURE__ */ import_react11.default.createElement(import_ui_extensions11.Flex, { direction: "column", gap: "sm" }, /* @__PURE__ */ import_react11.default.createElement(
|
|
5743
6298
|
KanbanToolbar,
|
|
@@ -5757,8 +6312,8 @@ var Kanban = ({
|
|
|
5757
6312
|
sortOptions,
|
|
5758
6313
|
sortValue: resolvedSort,
|
|
5759
6314
|
onSortChange: handleSort,
|
|
5760
|
-
|
|
5761
|
-
|
|
6315
|
+
showMetricsButton: metricsProvided,
|
|
6316
|
+
metricsPanel: resolvedShowMetrics && globalMetricsContent ? renderMetricsPanel(globalMetricsContent) : null,
|
|
5762
6317
|
onToggleMetrics: toggleMetrics,
|
|
5763
6318
|
labels,
|
|
5764
6319
|
toolbarLeftFlex,
|
|
@@ -5766,6 +6321,7 @@ var Kanban = ({
|
|
|
5766
6321
|
}
|
|
5767
6322
|
), showSelectionBar && selectable && selectedCount > 0 ? renderSelectionBar ? renderSelectionBar(selectionBarProps) : /* @__PURE__ */ import_react11.default.createElement(DefaultSelectionBar, { ...selectionBarProps }) : null, mainContent);
|
|
5768
6323
|
};
|
|
6324
|
+
Kanban.displayName = "Kanban";
|
|
5769
6325
|
|
|
5770
6326
|
// src/kanban/KanbanCardActions.jsx
|
|
5771
6327
|
var import_react12 = __toESM(require("react"));
|
|
@@ -5967,6 +6523,110 @@ var AvatarStack = ({
|
|
|
5967
6523
|
});
|
|
5968
6524
|
};
|
|
5969
6525
|
|
|
6526
|
+
// src/feed/feedLiveBuffer.js
|
|
6527
|
+
var isDateValueObject2 = (v) => v != null && typeof v === "object" && typeof v.year === "number" && typeof v.month === "number" && typeof v.date === "number";
|
|
6528
|
+
var toTimestampMs = (value) => {
|
|
6529
|
+
if (value == null || value === "") return null;
|
|
6530
|
+
if (value instanceof Date) {
|
|
6531
|
+
const time2 = value.getTime();
|
|
6532
|
+
return Number.isNaN(time2) ? null : time2;
|
|
6533
|
+
}
|
|
6534
|
+
if (typeof value === "number") return Number.isFinite(value) ? value : null;
|
|
6535
|
+
if (isDateValueObject2(value)) {
|
|
6536
|
+
return new Date(value.year, value.month, value.date, value.hour || 0, value.minute || 0).getTime();
|
|
6537
|
+
}
|
|
6538
|
+
const parsed = new Date(value);
|
|
6539
|
+
const time = parsed.getTime();
|
|
6540
|
+
return Number.isNaN(time) ? null : time;
|
|
6541
|
+
};
|
|
6542
|
+
var defaultGetId = (item, index) => (item == null ? void 0 : item.id) ?? (item == null ? void 0 : item.key) ?? index;
|
|
6543
|
+
var partitionNewItems = (prevNewestTs, items, getTs, options = {}) => {
|
|
6544
|
+
const { knownIds = null, getId = defaultGetId } = options;
|
|
6545
|
+
const safeItems = Array.isArray(items) ? items : [];
|
|
6546
|
+
const firstLoad = prevNewestTs == null;
|
|
6547
|
+
const visible = [];
|
|
6548
|
+
const visibleIds = [];
|
|
6549
|
+
const buffered = [];
|
|
6550
|
+
const bufferedIds = [];
|
|
6551
|
+
let newestTs = typeof prevNewestTs === "number" ? prevNewestTs : null;
|
|
6552
|
+
safeItems.forEach((item, index) => {
|
|
6553
|
+
const id = getId(item, index);
|
|
6554
|
+
const ts = toTimestampMs(typeof getTs === "function" ? getTs(item) : void 0);
|
|
6555
|
+
const isKnown = knownIds != null && id !== void 0 && knownIds.has(id);
|
|
6556
|
+
const isNewArrival = !firstLoad && !isKnown && ts != null && ts > prevNewestTs;
|
|
6557
|
+
if (isNewArrival) {
|
|
6558
|
+
buffered.push(item);
|
|
6559
|
+
bufferedIds.push(id);
|
|
6560
|
+
return;
|
|
6561
|
+
}
|
|
6562
|
+
visible.push(item);
|
|
6563
|
+
visibleIds.push(id);
|
|
6564
|
+
if (ts != null && (newestTs == null || ts > newestTs)) newestTs = ts;
|
|
6565
|
+
});
|
|
6566
|
+
return { visible, buffered, visibleIds, bufferedIds, newestTs };
|
|
6567
|
+
};
|
|
6568
|
+
var flushBuffer = (visible, buffered, getTs) => {
|
|
6569
|
+
const safeVisible = Array.isArray(visible) ? visible : [];
|
|
6570
|
+
const safeBuffered = Array.isArray(buffered) ? buffered : [];
|
|
6571
|
+
const items = [...safeBuffered, ...safeVisible];
|
|
6572
|
+
let newestTs = null;
|
|
6573
|
+
items.forEach((item) => {
|
|
6574
|
+
const ts = toTimestampMs(typeof getTs === "function" ? getTs(item) : void 0);
|
|
6575
|
+
if (ts != null && (newestTs == null || ts > newestTs)) newestTs = ts;
|
|
6576
|
+
});
|
|
6577
|
+
return { items, flushed: safeBuffered, newestTs };
|
|
6578
|
+
};
|
|
6579
|
+
|
|
6580
|
+
// src/feed/feedTypePresets.js
|
|
6581
|
+
var hasValue = (value) => value != null && value !== false && value !== "";
|
|
6582
|
+
var DEFAULT_FEED_TYPE_PRESETS = {
|
|
6583
|
+
call: { icon: "calling", label: "Call" },
|
|
6584
|
+
email: { icon: "email", label: "Email" },
|
|
6585
|
+
incoming_email: { icon: "inbox", label: "Incoming email" },
|
|
6586
|
+
forwarded_email: { icon: "forward", label: "Forwarded email" },
|
|
6587
|
+
meeting: { icon: "appointment", label: "Meeting" },
|
|
6588
|
+
note: { icon: "comment", label: "Note" },
|
|
6589
|
+
task: { icon: "tasks", label: "Task" },
|
|
6590
|
+
sms: { icon: "messages", label: "SMS" },
|
|
6591
|
+
whatsapp: { icon: "messages", label: "WhatsApp" },
|
|
6592
|
+
linkedin_message: { icon: "linkedin", label: "LinkedIn message" },
|
|
6593
|
+
postal_mail: { icon: "send", label: "Postal mail" },
|
|
6594
|
+
conversation: { icon: "questionAnswer", label: "Conversation" }
|
|
6595
|
+
};
|
|
6596
|
+
var lookupTypePreset = (type, presets) => {
|
|
6597
|
+
if (!presets || typeof presets !== "object") return null;
|
|
6598
|
+
if (type == null || type === "") return null;
|
|
6599
|
+
if (Object.prototype.hasOwnProperty.call(presets, type)) return presets[type];
|
|
6600
|
+
const lower = String(type).toLowerCase();
|
|
6601
|
+
if (Object.prototype.hasOwnProperty.call(presets, lower)) return presets[lower];
|
|
6602
|
+
const snake = lower.replace(/[\s-]+/g, "_");
|
|
6603
|
+
if (Object.prototype.hasOwnProperty.call(presets, snake)) return presets[snake];
|
|
6604
|
+
return null;
|
|
6605
|
+
};
|
|
6606
|
+
var applyTypePreset = (item, typePresets) => {
|
|
6607
|
+
if (item == null || typeof item !== "object") return item;
|
|
6608
|
+
const preset = lookupTypePreset(item.type, typePresets);
|
|
6609
|
+
if (!preset || typeof preset !== "object") return item;
|
|
6610
|
+
let next = null;
|
|
6611
|
+
const fill = (key, value) => {
|
|
6612
|
+
if (next === null) next = { ...item };
|
|
6613
|
+
next[key] = value;
|
|
6614
|
+
};
|
|
6615
|
+
if (!hasValue(item.icon) && !hasValue(item.iconName) && hasValue(preset.icon)) {
|
|
6616
|
+
fill("iconName", preset.icon);
|
|
6617
|
+
}
|
|
6618
|
+
if (!hasValue(item.iconColor) && hasValue(preset.color)) {
|
|
6619
|
+
fill("iconColor", preset.color);
|
|
6620
|
+
}
|
|
6621
|
+
if (!hasValue(item.typeLabel) && hasValue(preset.label)) {
|
|
6622
|
+
fill("typeLabel", preset.label);
|
|
6623
|
+
}
|
|
6624
|
+
if (item.statusVariant == null && item.outcomeVariant == null && item.severityVariant == null && hasValue(preset.statusVariant)) {
|
|
6625
|
+
fill("statusVariant", preset.statusVariant);
|
|
6626
|
+
}
|
|
6627
|
+
return next ?? item;
|
|
6628
|
+
};
|
|
6629
|
+
|
|
5970
6630
|
// src/feed/Feed.jsx
|
|
5971
6631
|
var DEFAULT_LABELS4 = {
|
|
5972
6632
|
search: "Search activity...",
|
|
@@ -5980,6 +6640,8 @@ var DEFAULT_LABELS4 = {
|
|
|
5980
6640
|
loadingMessage: "This should only take a moment.",
|
|
5981
6641
|
loadingMore: "Loading...",
|
|
5982
6642
|
loadMore: "View more",
|
|
6643
|
+
newItems: (count) => count === 1 ? "Show 1 new item" : `Show ${count} new items`,
|
|
6644
|
+
newItemTag: "New",
|
|
5983
6645
|
collapseAll: "Collapse all",
|
|
5984
6646
|
expandAll: "Expand all",
|
|
5985
6647
|
emptyTitle: "No activity yet",
|
|
@@ -5992,7 +6654,15 @@ var DEFAULT_LABELS4 = {
|
|
|
5992
6654
|
var DEFAULT_RECORD_LABEL = { singular: "item", plural: "items" };
|
|
5993
6655
|
var DEFAULT_SEARCH_FIELDS = ["title", "subject", "body", "description", "content", "preview", "type", "typeLabel", "actorName", "author"];
|
|
5994
6656
|
var DEFAULT_PAGE_SIZE = 5;
|
|
5995
|
-
var
|
|
6657
|
+
var EMPTY_ITEMS = [];
|
|
6658
|
+
var INITIAL_LIVE_STATE = {
|
|
6659
|
+
source: null,
|
|
6660
|
+
watermark: null,
|
|
6661
|
+
bufferedKeys: EMPTY_ITEMS,
|
|
6662
|
+
knownKeys: EMPTY_ITEMS,
|
|
6663
|
+
newKeys: EMPTY_ITEMS
|
|
6664
|
+
};
|
|
6665
|
+
var hasValue2 = (value) => value != null && value !== false && value !== "";
|
|
5996
6666
|
var keepWordsTogether = (value) => typeof value === "string" ? value.replace(/\s+/g, "\xA0") : value;
|
|
5997
6667
|
var getItemKey = (item, index, getKey) => {
|
|
5998
6668
|
if (typeof getKey === "function") return getKey(item, index);
|
|
@@ -6019,11 +6689,11 @@ var pickHeaderActions = (item) => item == null ? void 0 : item.headerActions;
|
|
|
6019
6689
|
var itemHasExpandableContent = (item, fields) => {
|
|
6020
6690
|
if ((item == null ? void 0 : item.collapsible) === false) return false;
|
|
6021
6691
|
if ((item == null ? void 0 : item.collapsible) === true) return true;
|
|
6022
|
-
if (
|
|
6023
|
-
if (
|
|
6024
|
-
if (
|
|
6025
|
-
if (
|
|
6026
|
-
if (
|
|
6692
|
+
if (hasValue2(pickBody(item))) return true;
|
|
6693
|
+
if (hasValue2(pickActor(item))) return true;
|
|
6694
|
+
if (hasValue2(item == null ? void 0 : item.actions)) return true;
|
|
6695
|
+
if (hasValue2(item == null ? void 0 : item.footer)) return true;
|
|
6696
|
+
if (hasValue2(item == null ? void 0 : item.meta) || hasValue2(item == null ? void 0 : item.metadata)) return true;
|
|
6027
6697
|
if (Array.isArray(fields)) {
|
|
6028
6698
|
if (fields.some((f) => ["body", "footer"].includes(f.placement ?? "body"))) return true;
|
|
6029
6699
|
}
|
|
@@ -6105,7 +6775,7 @@ var getRecordLabel = (recordLabel, count) => {
|
|
|
6105
6775
|
var FeedActorAvatar = ({ item, avatarSize }) => {
|
|
6106
6776
|
const actor = pickActor(item);
|
|
6107
6777
|
const avatar = (item == null ? void 0 : item.avatar) ?? pickActorAvatar(actor);
|
|
6108
|
-
if (!
|
|
6778
|
+
if (!hasValue2(avatar)) return null;
|
|
6109
6779
|
return /* @__PURE__ */ import_react14.default.createElement(
|
|
6110
6780
|
AvatarStack,
|
|
6111
6781
|
{
|
|
@@ -6117,10 +6787,10 @@ var FeedActorAvatar = ({ item, avatarSize }) => {
|
|
|
6117
6787
|
);
|
|
6118
6788
|
};
|
|
6119
6789
|
var FeedTypeIcon = ({ item, iconSize }) => {
|
|
6120
|
-
if (
|
|
6790
|
+
if (hasValue2(item == null ? void 0 : item.icon) && typeof item.icon !== "string") return item.icon;
|
|
6121
6791
|
const iconName = typeof (item == null ? void 0 : item.icon) === "string" ? item.icon : item == null ? void 0 : item.iconName;
|
|
6122
|
-
if (!
|
|
6123
|
-
return /* @__PURE__ */ import_react14.default.createElement(Icon, { name: iconName, size: iconSize, purpose: "decorative" });
|
|
6792
|
+
if (!hasValue2(iconName)) return null;
|
|
6793
|
+
return /* @__PURE__ */ import_react14.default.createElement(Icon, { name: iconName, size: iconSize, color: item == null ? void 0 : item.iconColor, purpose: "decorative" });
|
|
6124
6794
|
};
|
|
6125
6795
|
var FeedActions = ({ actions }) => {
|
|
6126
6796
|
if (!Array.isArray(actions) || actions.length === 0) return actions || null;
|
|
@@ -6143,7 +6813,7 @@ var FeedField = ({ field, item, index }) => {
|
|
|
6143
6813
|
if (field.visible && !field.visible(item)) return null;
|
|
6144
6814
|
const value = getValue(item, field.field);
|
|
6145
6815
|
const rendered = field.render ? field.render(value, item, index) : value;
|
|
6146
|
-
if (!
|
|
6816
|
+
if (!hasValue2(rendered)) return null;
|
|
6147
6817
|
if (field.href) {
|
|
6148
6818
|
const href = typeof field.href === "function" ? field.href(item) : field.href;
|
|
6149
6819
|
return /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Link, { href }, rendered);
|
|
@@ -6180,7 +6850,7 @@ var renderPlacedFields = ({ fields, placement, item, index, inline = false }) =>
|
|
|
6180
6850
|
return /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Flex, { direction: "column", gap: "xs" }, nodes);
|
|
6181
6851
|
};
|
|
6182
6852
|
var renderHeaderActions = (headerActions) => {
|
|
6183
|
-
if (!
|
|
6853
|
+
if (!hasValue2(headerActions)) return null;
|
|
6184
6854
|
if (!Array.isArray(headerActions)) return headerActions;
|
|
6185
6855
|
return /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Inline, { gap: "sm", align: "center" }, headerActions.filter(Boolean).map((action, index) => /* @__PURE__ */ import_react14.default.createElement(
|
|
6186
6856
|
import_ui_extensions14.Link,
|
|
@@ -6202,6 +6872,8 @@ var DefaultFeedItem = ({
|
|
|
6202
6872
|
collapsible,
|
|
6203
6873
|
expanded,
|
|
6204
6874
|
onToggleExpanded,
|
|
6875
|
+
isNew,
|
|
6876
|
+
newItemTagLabel,
|
|
6205
6877
|
renderActor,
|
|
6206
6878
|
renderTimestamp,
|
|
6207
6879
|
renderMeta,
|
|
@@ -6221,7 +6893,7 @@ var DefaultFeedItem = ({
|
|
|
6221
6893
|
const body = pickBody(item);
|
|
6222
6894
|
const avatar = /* @__PURE__ */ import_react14.default.createElement(FeedActorAvatar, { item, avatarSize });
|
|
6223
6895
|
const typeIcon = /* @__PURE__ */ import_react14.default.createElement(FeedTypeIcon, { item, iconSize });
|
|
6224
|
-
const hasAvatarNode =
|
|
6896
|
+
const hasAvatarNode = hasValue2(item == null ? void 0 : item.avatar) || hasValue2(pickActorAvatar(rawActor));
|
|
6225
6897
|
const titleFields = fieldsForPlacement(fields, "title");
|
|
6226
6898
|
const titleField = titleFields.length > 0 ? /* @__PURE__ */ import_react14.default.createElement(FeedField, { field: titleFields[0], item, index }) : null;
|
|
6227
6899
|
const subtitleFields = renderPlacedFields({ fields, placement: "subtitle", item, index, inline: true });
|
|
@@ -6229,8 +6901,8 @@ var DefaultFeedItem = ({
|
|
|
6229
6901
|
const bodyFields = renderPlacedFields({ fields, placement: "body", item, index });
|
|
6230
6902
|
const footerFields = renderPlacedFields({ fields, placement: "footer", item, index, inline: true });
|
|
6231
6903
|
const titleContent = titleField ?? (item == null ? void 0 : item.title) ?? (item == null ? void 0 : item.subject);
|
|
6232
|
-
const title =
|
|
6233
|
-
const titleText =
|
|
6904
|
+
const title = hasValue2(item == null ? void 0 : item.href) ? /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Link, { href: item.href }, titleContent) : titleContent;
|
|
6905
|
+
const titleText = hasValue2(title) ? /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Text, { format: { fontWeight: "demibold" }, truncate: true }, title) : null;
|
|
6234
6906
|
const headerLeft = /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Flex, { direction: "row", align: "center", gap: "xs", wrap: "nowrap" }, collapsible ? /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Box, { flex: "none", alignSelf: "center" }, /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Link, { variant: "dark", onClick: onToggleExpanded }, /* @__PURE__ */ import_react14.default.createElement(
|
|
6235
6907
|
Icon,
|
|
6236
6908
|
{
|
|
@@ -6238,10 +6910,10 @@ var DefaultFeedItem = ({
|
|
|
6238
6910
|
size: "md",
|
|
6239
6911
|
screenReaderText: expanded ? "Collapse" : "Expand"
|
|
6240
6912
|
}
|
|
6241
|
-
))) : null, typeIcon, titleText);
|
|
6242
|
-
const headerRight =
|
|
6913
|
+
))) : null, typeIcon, titleText, isNew ? /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Box, { flex: "none" }, /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Tag, { variant: "info" }, newItemTagLabel ?? "New")) : null);
|
|
6914
|
+
const headerRight = hasValue2(headerActions) || hasValue2(timestamp) || hasValue2(type) ? /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Inline, { gap: "sm", align: "center" }, renderHeaderActions(headerActions), hasValue2(type) && /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Text, { variant: "microcopy" }, type), hasValue2(timestamp) && /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Text, { variant: "microcopy" }, formatTimestamp(timestamp))) : null;
|
|
6243
6915
|
const showBody = !collapsible || expanded;
|
|
6244
|
-
return /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Flex, { direction: "column", gap: compact ? "xs" : "sm" }, /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Flex, { direction: "row", justify: "between", align: "center", gap: "sm", wrap: "nowrap" }, /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Box, { flex: 1 }, headerLeft), headerRight), showBody ? /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Flex, { direction: "column", gap: compact ? "xs" : "sm" }, (hasAvatarNode ||
|
|
6916
|
+
return /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Flex, { direction: "column", gap: compact ? "xs" : "sm" }, /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Flex, { direction: "row", justify: "between", align: "center", gap: "sm", wrap: "nowrap" }, /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Box, { flex: 1 }, headerLeft), headerRight), showBody ? /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Flex, { direction: "column", gap: compact ? "xs" : "sm" }, (hasAvatarNode || hasValue2(actor) || hasValue2(subtitleFields) || hasValue2(status)) && /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Flex, { direction: "row", align: "center", gap: "xs", wrap: "wrap" }, hasAvatarNode ? avatar : null, hasValue2(actor) && /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Text, { variant: "microcopy" }, actor), subtitleFields, hasValue2(status) && /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.StatusTag, { variant: statusVariant, hollow: true }, status)), hasValue2(body) && /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Text, null, body), bodyFields, Array.isArray(meta) ? meta.length > 0 ? /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.List, { variant: "inline-divided" }, meta) : metaFields : hasValue2(meta) ? /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Inline, { gap: "xs" }, meta) : metaFields ? metaFields : null, hasValue2(actions) && /* @__PURE__ */ import_react14.default.createElement(FeedActions, { actions }), (hasValue2(footer) || hasValue2(footerFields)) && /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Inline, { gap: "xs", align: "center" }, footerFields, footer)) : null);
|
|
6245
6917
|
};
|
|
6246
6918
|
var applyTab = (items, activeTab, tabField) => {
|
|
6247
6919
|
if (!activeTab || activeTab === "all") return items;
|
|
@@ -6465,10 +7137,19 @@ var Feed = ({
|
|
|
6465
7137
|
collapsedIds,
|
|
6466
7138
|
onCollapsedIdsChange,
|
|
6467
7139
|
showCollapseToggle = true,
|
|
6468
|
-
alignToolbarWithGroups = "auto"
|
|
7140
|
+
alignToolbarWithGroups = "auto",
|
|
7141
|
+
newItemsBehavior = "immediate",
|
|
7142
|
+
onNewItemsFlush,
|
|
7143
|
+
highlightNew = false,
|
|
7144
|
+
typePresets
|
|
6469
7145
|
}) => {
|
|
6470
|
-
const labels = { ...DEFAULT_LABELS4, ...labelOverrides || {} };
|
|
6471
|
-
const safeItems = Array.isArray(items) ? items :
|
|
7146
|
+
const labels = (0, import_react14.useMemo)(() => ({ ...DEFAULT_LABELS4, ...labelOverrides || {} }), [labelOverrides]);
|
|
7147
|
+
const safeItems = Array.isArray(items) ? items : EMPTY_ITEMS;
|
|
7148
|
+
const resolvedTypePresets = typePresets === true ? DEFAULT_FEED_TYPE_PRESETS : typePresets;
|
|
7149
|
+
const presetItems = (0, import_react14.useMemo)(
|
|
7150
|
+
() => resolvedTypePresets ? safeItems.map((item) => applyTypePreset(item, resolvedTypePresets)) : safeItems,
|
|
7151
|
+
[safeItems, resolvedTypePresets]
|
|
7152
|
+
);
|
|
6472
7153
|
const [internalTab, setInternalTab] = (0, import_react14.useState)(tabValue ?? defaultTab ?? "all");
|
|
6473
7154
|
const [internalSearch, setInternalSearch] = (0, import_react14.useState)(searchValue ?? "");
|
|
6474
7155
|
const [internalFilters, setInternalFilters] = (0, import_react14.useState)(filterValues ?? defaultFilterValues);
|
|
@@ -6481,6 +7162,47 @@ var Feed = ({
|
|
|
6481
7162
|
return [];
|
|
6482
7163
|
};
|
|
6483
7164
|
const [internalCollapsedIds, setInternalCollapsedIds] = (0, import_react14.useState)(computeInitialCollapsed);
|
|
7165
|
+
const bufferNewItems = newItemsBehavior === "pill";
|
|
7166
|
+
const highlightMs = typeof highlightNew === "number" && highlightNew > 0 ? highlightNew : 0;
|
|
7167
|
+
const trackNewItems = bufferNewItems || highlightMs > 0;
|
|
7168
|
+
const [liveState, setLiveState] = (0, import_react14.useState)(INITIAL_LIVE_STATE);
|
|
7169
|
+
const liveKeyOf = (item, index) => getItemKey(item, index, getKey);
|
|
7170
|
+
if (trackNewItems && liveState.source !== presetItems) {
|
|
7171
|
+
const firstLoad = liveState.source === null;
|
|
7172
|
+
const partition = partitionNewItems(liveState.watermark, presetItems, pickTimestamp, {
|
|
7173
|
+
knownIds: new Set(liveState.knownKeys),
|
|
7174
|
+
getId: liveKeyOf
|
|
7175
|
+
});
|
|
7176
|
+
const now = Date.now();
|
|
7177
|
+
const keptNewKeys = highlightMs > 0 ? liveState.newKeys.filter((entry) => now - entry.at < highlightMs) : EMPTY_ITEMS;
|
|
7178
|
+
if (bufferNewItems) {
|
|
7179
|
+
setLiveState({
|
|
7180
|
+
source: presetItems,
|
|
7181
|
+
watermark: partition.newestTs,
|
|
7182
|
+
bufferedKeys: partition.bufferedIds,
|
|
7183
|
+
knownKeys: partition.visibleIds,
|
|
7184
|
+
newKeys: keptNewKeys
|
|
7185
|
+
});
|
|
7186
|
+
} else {
|
|
7187
|
+
const { newestTs } = flushBuffer(partition.visible, partition.buffered, pickTimestamp);
|
|
7188
|
+
setLiveState({
|
|
7189
|
+
source: presetItems,
|
|
7190
|
+
watermark: newestTs ?? partition.newestTs,
|
|
7191
|
+
bufferedKeys: EMPTY_ITEMS,
|
|
7192
|
+
knownKeys: [...partition.visibleIds, ...partition.bufferedIds],
|
|
7193
|
+
newKeys: highlightMs > 0 && !firstLoad ? [...keptNewKeys, ...partition.bufferedIds.map((key) => ({ key, at: now }))] : keptNewKeys
|
|
7194
|
+
});
|
|
7195
|
+
}
|
|
7196
|
+
}
|
|
7197
|
+
const bufferedKeySet = (0, import_react14.useMemo)(() => new Set(liveState.bufferedKeys), [liveState.bufferedKeys]);
|
|
7198
|
+
const newKeySet = (0, import_react14.useMemo)(
|
|
7199
|
+
() => new Set(liveState.newKeys.map((entry) => entry.key)),
|
|
7200
|
+
[liveState.newKeys]
|
|
7201
|
+
);
|
|
7202
|
+
const sourceItems = (0, import_react14.useMemo)(() => {
|
|
7203
|
+
if (!bufferNewItems || bufferedKeySet.size === 0) return presetItems;
|
|
7204
|
+
return presetItems.filter((item, index) => !bufferedKeySet.has(getItemKey(item, index, getKey)));
|
|
7205
|
+
}, [presetItems, bufferNewItems, bufferedKeySet, getKey]);
|
|
6484
7206
|
const activeTab = tabValue !== void 0 ? tabValue : internalTab;
|
|
6485
7207
|
const activeSearch = searchValue !== void 0 ? searchValue : internalSearch;
|
|
6486
7208
|
const activeFilters = filterValues !== void 0 ? filterValues : internalFilters;
|
|
@@ -6503,6 +7225,17 @@ var Feed = ({
|
|
|
6503
7225
|
(0, import_react14.useEffect)(() => {
|
|
6504
7226
|
if (Array.isArray(collapsedIds)) setInternalCollapsedIds(collapsedIds);
|
|
6505
7227
|
}, [collapsedIds]);
|
|
7228
|
+
(0, import_react14.useEffect)(() => {
|
|
7229
|
+
if (!highlightMs || liveState.newKeys.length === 0) return void 0;
|
|
7230
|
+
const earliestAt = Math.min(...liveState.newKeys.map((entry) => entry.at));
|
|
7231
|
+
const timer = setTimeout(() => {
|
|
7232
|
+
setLiveState((prev) => ({
|
|
7233
|
+
...prev,
|
|
7234
|
+
newKeys: prev.newKeys.filter((entry) => Date.now() - entry.at < highlightMs)
|
|
7235
|
+
}));
|
|
7236
|
+
}, Math.max(16, earliestAt + highlightMs - Date.now()));
|
|
7237
|
+
return () => clearTimeout(timer);
|
|
7238
|
+
}, [highlightMs, liveState.newKeys]);
|
|
6506
7239
|
const emitParamsChange = (next) => {
|
|
6507
7240
|
if (typeof onParamsChange === "function") {
|
|
6508
7241
|
onParamsChange({ tab: activeTab, search: activeSearch, filters: activeFilters, sort: activeSort, ...next });
|
|
@@ -6556,13 +7289,40 @@ var Feed = ({
|
|
|
6556
7289
|
setCollapsedIds(collapsibleKeys);
|
|
6557
7290
|
};
|
|
6558
7291
|
const handleExpandAll = () => setCollapsedIds([]);
|
|
7292
|
+
const handleFlushNewItems = () => {
|
|
7293
|
+
const flushedItems = [];
|
|
7294
|
+
const flushedKeys = [];
|
|
7295
|
+
const keptItems = [];
|
|
7296
|
+
presetItems.forEach((item, index) => {
|
|
7297
|
+
const key = getItemKey(item, index, getKey);
|
|
7298
|
+
if (bufferedKeySet.has(key)) {
|
|
7299
|
+
flushedItems.push(item);
|
|
7300
|
+
flushedKeys.push(key);
|
|
7301
|
+
} else {
|
|
7302
|
+
keptItems.push(item);
|
|
7303
|
+
}
|
|
7304
|
+
});
|
|
7305
|
+
const { newestTs } = flushBuffer(keptItems, flushedItems, pickTimestamp);
|
|
7306
|
+
const now = Date.now();
|
|
7307
|
+
setLiveState((prev) => ({
|
|
7308
|
+
source: presetItems,
|
|
7309
|
+
watermark: newestTs ?? prev.watermark,
|
|
7310
|
+
bufferedKeys: EMPTY_ITEMS,
|
|
7311
|
+
knownKeys: presetItems.map((item, index) => getItemKey(item, index, getKey)),
|
|
7312
|
+
newKeys: highlightMs > 0 ? [
|
|
7313
|
+
...prev.newKeys.filter((entry) => now - entry.at < highlightMs),
|
|
7314
|
+
...flushedKeys.map((key) => ({ key, at: now }))
|
|
7315
|
+
] : prev.newKeys
|
|
7316
|
+
}));
|
|
7317
|
+
onNewItemsFlush == null ? void 0 : onNewItemsFlush(flushedItems);
|
|
7318
|
+
};
|
|
6559
7319
|
const processedItems = (0, import_react14.useMemo)(() => {
|
|
6560
|
-
if (serverSide) return
|
|
6561
|
-
const tabbed = applyTab(
|
|
7320
|
+
if (serverSide) return sourceItems;
|
|
7321
|
+
const tabbed = applyTab(sourceItems, activeTab, tabField);
|
|
6562
7322
|
const searched = applySearch(tabbed, activeSearch, searchFields);
|
|
6563
7323
|
const filtered = applyFilters(searched, filters, activeFilters);
|
|
6564
7324
|
return applySort(filtered, activeSort, sortOptions);
|
|
6565
|
-
}, [
|
|
7325
|
+
}, [sourceItems, activeTab, tabField, activeSearch, searchFields, filters, activeFilters, activeSort, sortOptions, serverSide]);
|
|
6566
7326
|
const visibleItems = (0, import_react14.useMemo)(
|
|
6567
7327
|
() => processedItems.slice(0, Math.max(0, resolvedMaxItems)),
|
|
6568
7328
|
[processedItems, resolvedMaxItems]
|
|
@@ -6589,8 +7349,8 @@ var Feed = ({
|
|
|
6589
7349
|
const canViewMore = visibleItems.length < processedItems.length;
|
|
6590
7350
|
const shouldShowExternalLoadMore = hasMore && onLoadMore;
|
|
6591
7351
|
const normalizedTabs = (0, import_react14.useMemo)(
|
|
6592
|
-
() => normalizeTabs(tabs,
|
|
6593
|
-
[tabs,
|
|
7352
|
+
() => normalizeTabs(tabs, presetItems, tabField, labels),
|
|
7353
|
+
[tabs, presetItems, tabField, labels]
|
|
6594
7354
|
);
|
|
6595
7355
|
const resolvedShowTabs = showTabs ?? normalizedTabs.length > 1;
|
|
6596
7356
|
const sortControl = Array.isArray(sortOptions) && sortOptions.length > 0 ? /* @__PURE__ */ import_react14.default.createElement(
|
|
@@ -6605,7 +7365,7 @@ var Feed = ({
|
|
|
6605
7365
|
) : null;
|
|
6606
7366
|
const countControl = showItemCount ? /* @__PURE__ */ import_react14.default.createElement(CollectionCount, { text: itemCountLabel }) : null;
|
|
6607
7367
|
const toolbarRight = sortControl || countControl ? /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Inline, { gap: "sm", align: "center" }, sortControl, countControl) : null;
|
|
6608
|
-
const firstGroupHasLabel = groups.length > 0 &&
|
|
7368
|
+
const firstGroupHasLabel = groups.length > 0 && hasValue2(groups[0].label);
|
|
6609
7369
|
const hasLeftToolbarControls = resolvedShowSearch || Array.isArray(filters) && filters.length > 0 || activeChips.length > 0;
|
|
6610
7370
|
const alignControlsWithFirstGroup = !renderToolbar && showToolbar && !loading && !error && processedItems.length > 0 && !hasLeftToolbarControls && !!toolbarRight && firstGroupHasLabel && (alignToolbarWithGroups === true || alignToolbarWithGroups === "auto" && (groupByDate || !!groupBy));
|
|
6611
7371
|
const toolbarNode = renderToolbar ? renderToolbar({
|
|
@@ -6655,15 +7415,21 @@ var Feed = ({
|
|
|
6655
7415
|
return activeCollapsedIds.includes(getItemKey(item, i >= 0 ? i : idx, getKey));
|
|
6656
7416
|
});
|
|
6657
7417
|
const collapseToggle = showCollapseToggle && collapsibleVisibleItems.length > 1 && !loading && !error ? /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Link, { onClick: allCollapsed ? handleExpandAll : handleCollapseAll }, keepWordsTogether(allCollapsed ? labels.expandAll : labels.collapseAll)) : null;
|
|
6658
|
-
if (
|
|
6659
|
-
const headerBody = /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Flex, { direction: "column", gap: "xs" },
|
|
6660
|
-
const headerRight =
|
|
7418
|
+
if (hasValue2(title) || hasValue2(description) || hasValue2(actions) || hasValue2(children) || collapseToggle) {
|
|
7419
|
+
const headerBody = /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Flex, { direction: "column", gap: "xs" }, hasValue2(title) && /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Text, { format: { fontWeight: "demibold" } }, title), hasValue2(description) && /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Text, null, description), children);
|
|
7420
|
+
const headerRight = hasValue2(actions) || collapseToggle ? /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Inline, { gap: "sm", align: "center" }, actions, collapseToggle) : null;
|
|
6661
7421
|
content.push(
|
|
6662
7422
|
/* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Flex, { key: "header", direction: "row", justify: "between", align: "start", gap: "sm" }, headerBody, headerRight)
|
|
6663
7423
|
);
|
|
6664
7424
|
}
|
|
6665
7425
|
const bodyContent = [];
|
|
6666
7426
|
if (toolbarNode) bodyContent.push(/* @__PURE__ */ import_react14.default.createElement(import_react14.default.Fragment, { key: "toolbar" }, toolbarNode));
|
|
7427
|
+
const pendingNewCount = bufferNewItems ? liveState.bufferedKeys.length : 0;
|
|
7428
|
+
if (pendingNewCount > 0 && !loading && !error) {
|
|
7429
|
+
bodyContent.push(
|
|
7430
|
+
/* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Flex, { key: "new-items-pill", direction: "row", justify: "center" }, /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Button, { variant: "secondary", size: "small", onClick: handleFlushNewItems }, typeof labels.newItems === "function" ? labels.newItems(pendingNewCount) : labels.newItems))
|
|
7431
|
+
);
|
|
7432
|
+
}
|
|
6667
7433
|
if (loading) {
|
|
6668
7434
|
bodyContent.push(
|
|
6669
7435
|
renderLoadingState ? renderLoadingState({ label: labels.loading }) : (
|
|
@@ -6680,14 +7446,14 @@ var Feed = ({
|
|
|
6680
7446
|
message: labels.errorMessage
|
|
6681
7447
|
}) : /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Alert, { key: "error", variant: "danger", title: typeof error === "string" ? error : labels.errorTitle }, /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Text, null, labels.errorMessage))
|
|
6682
7448
|
);
|
|
6683
|
-
} else if (processedItems.length === 0) {
|
|
7449
|
+
} else if (processedItems.length === 0 && pendingNewCount === 0) {
|
|
6684
7450
|
bodyContent.push(
|
|
6685
7451
|
renderEmptyState ? renderEmptyState({ title: labels.emptyTitle, message: labels.emptyMessage }) : /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Tile, { key: "empty" }, /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Flex, { direction: "column", align: "center", justify: "center" }, /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.EmptyState, { title: labels.emptyTitle, layout: "vertical" }, /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Text, null, labels.emptyMessage))))
|
|
6686
7452
|
);
|
|
6687
7453
|
} else {
|
|
6688
7454
|
bodyContent.push(
|
|
6689
|
-
/* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Flex, { key: "items", direction: "column", gap: compact ? "xs" : gap }, groups.map((group, groupIndex) => /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Flex, { key: group.key, direction: "column", gap: compact ? "xs" : gap },
|
|
6690
|
-
const globalIndex =
|
|
7455
|
+
/* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Flex, { key: "items", direction: "column", gap: compact ? "xs" : gap }, groups.map((group, groupIndex) => /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Flex, { key: group.key, direction: "column", gap: compact ? "xs" : gap }, hasValue2(group.label) && (alignControlsWithFirstGroup && groupIndex === 0 ? /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Flex, { direction: "row", justify: "between", align: "center", gap: "sm" }, /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Text, { format: { fontWeight: "demibold" } }, group.label), toolbarRight) : /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Text, { format: { fontWeight: "demibold" } }, group.label)), group.items.map((item, index) => {
|
|
7456
|
+
const globalIndex = presetItems.indexOf(item);
|
|
6691
7457
|
const itemIndex = globalIndex >= 0 ? globalIndex : index;
|
|
6692
7458
|
const key = getItemKey(item, itemIndex, getKey);
|
|
6693
7459
|
const node = renderItem ? renderItem(item, itemIndex) : /* @__PURE__ */ import_react14.default.createElement(
|
|
@@ -6702,6 +7468,8 @@ var Feed = ({
|
|
|
6702
7468
|
collapsible: collapsible !== false && itemHasExpandableContent(item, fields),
|
|
6703
7469
|
expanded: !activeCollapsedIds.includes(key),
|
|
6704
7470
|
onToggleExpanded: () => toggleItemExpanded(key),
|
|
7471
|
+
isNew: highlightMs > 0 && newKeySet.has(key),
|
|
7472
|
+
newItemTagLabel: labels.newItemTag,
|
|
6705
7473
|
renderActor,
|
|
6706
7474
|
renderTimestamp,
|
|
6707
7475
|
renderMeta,
|
|
@@ -6748,6 +7516,7 @@ var Feed = ({
|
|
|
6748
7516
|
if (container === "card" || container === "tile") return /* @__PURE__ */ import_react14.default.createElement(import_ui_extensions14.Tile, { compact: true }, feed);
|
|
6749
7517
|
return feed;
|
|
6750
7518
|
};
|
|
7519
|
+
Feed.displayName = "Feed";
|
|
6751
7520
|
|
|
6752
7521
|
// src/calendar/Calendar.jsx
|
|
6753
7522
|
var import_react15 = __toESM(require("react"));
|
|
@@ -6756,7 +7525,7 @@ var import_experimental = require("@hubspot/ui-extensions/experimental");
|
|
|
6756
7525
|
|
|
6757
7526
|
// src/calendar/dateUtils.js
|
|
6758
7527
|
var MS_PER_DAY = 864e5;
|
|
6759
|
-
var
|
|
7528
|
+
var isDateValueObject3 = (v) => v != null && typeof v === "object" && typeof v.year === "number" && typeof v.month === "number" && typeof v.date === "number";
|
|
6760
7529
|
var fromEpoch = (ms) => {
|
|
6761
7530
|
const d = new Date(ms);
|
|
6762
7531
|
if (Number.isNaN(d.getTime())) return null;
|
|
@@ -6766,7 +7535,7 @@ var fromEpoch = (ms) => {
|
|
|
6766
7535
|
var toDate2 = (value) => {
|
|
6767
7536
|
if (value == null || value === "") return null;
|
|
6768
7537
|
if (value instanceof Date) return Number.isNaN(value.getTime()) ? null : value;
|
|
6769
|
-
if (
|
|
7538
|
+
if (isDateValueObject3(value)) {
|
|
6770
7539
|
return new Date(
|
|
6771
7540
|
value.year,
|
|
6772
7541
|
value.month,
|
|
@@ -6861,7 +7630,7 @@ var buildHours = (startHour = 8, endHour = 20) => {
|
|
|
6861
7630
|
let e = Math.max(0, Math.min(23, Math.round(endHour)));
|
|
6862
7631
|
if (s > e) [s, e] = [e, s];
|
|
6863
7632
|
const hours = [];
|
|
6864
|
-
for (let
|
|
7633
|
+
for (let h7 = s; h7 <= e; h7 += 1) hours.push(h7);
|
|
6865
7634
|
return hours;
|
|
6866
7635
|
};
|
|
6867
7636
|
var WEEKDAY_LONG = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
|
|
@@ -6957,21 +7726,6 @@ var formatTimeZoneLabel = (tz, atDate = /* @__PURE__ */ new Date()) => {
|
|
|
6957
7726
|
|
|
6958
7727
|
// src/calendar/svgChips.js
|
|
6959
7728
|
var toDataUri = (svg) => `data:image/svg+xml,${encodeURIComponent(svg)}`;
|
|
6960
|
-
var escapeXml = (s) => String(s == null ? "" : s).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
6961
|
-
var truncateLabel = (value, max) => {
|
|
6962
|
-
const s = String(value == null ? "" : value);
|
|
6963
|
-
if (!max || s.length <= max) return s;
|
|
6964
|
-
return s.slice(0, Math.max(1, max - 1)).trimEnd() + "\u2026";
|
|
6965
|
-
};
|
|
6966
|
-
var CHIP_PALETTE = {
|
|
6967
|
-
default: { fill: "#7FD1DE", text: HS_TEXT_COLOR },
|
|
6968
|
-
info: { fill: "#00A4BD", text: "#FFFFFF" },
|
|
6969
|
-
success: { fill: "#00BDA5", text: "#FFFFFF" },
|
|
6970
|
-
warning: { fill: "#F5C26B", text: HS_TEXT_COLOR },
|
|
6971
|
-
error: { fill: "#F2545B", text: "#FFFFFF" },
|
|
6972
|
-
danger: { fill: "#F2545B", text: "#FFFFFF" }
|
|
6973
|
-
// StatusTag spells red "danger"; accept both
|
|
6974
|
-
};
|
|
6975
7729
|
var DOT_FILL = {
|
|
6976
7730
|
default: "#7C98B6",
|
|
6977
7731
|
info: "#00A4BD",
|
|
@@ -6986,31 +7740,177 @@ var makeDotDataUri = (variant = "default", size = 8) => {
|
|
|
6986
7740
|
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="0 0 ${size} ${size}"><circle cx="${r}" cy="${r}" r="${r}" fill="${fill}" /></svg>`;
|
|
6987
7741
|
return { src: toDataUri(svg), width: size, height: size };
|
|
6988
7742
|
};
|
|
6989
|
-
var makeEventChipDataUri = (opts) => {
|
|
6990
|
-
const { label, width, height = 24, variant = "default" } = opts;
|
|
6991
|
-
const palette = CHIP_PALETTE[variant] || CHIP_PALETTE.default;
|
|
6992
|
-
const accentX = 5;
|
|
6993
|
-
const accentW = 3;
|
|
6994
|
-
const textX = accentX + accentW + 6;
|
|
6995
|
-
const rightPad = 8;
|
|
6996
|
-
const maxChars = Math.max(1, Math.floor((width - textX - rightPad) / 6));
|
|
6997
|
-
const text = truncateLabel(label, maxChars);
|
|
6998
|
-
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}"><rect x="0.5" y="0.5" width="${width - 1}" height="${height - 1}" rx="4" ry="4" fill="#FFFFFF" stroke="#CBD6E2" stroke-width="1" /><rect x="${accentX}" y="5" width="${accentW}" height="${height - 10}" rx="1.5" ry="1.5" fill="${palette.fill}" /><text x="${textX}" y="${height / 2}" font-family='${HS_FONT_FAMILY}' font-size="12" font-weight="500" fill="${HS_TEXT_COLOR}" text-anchor="start" dominant-baseline="central">${escapeXml(text)}</text></svg>`;
|
|
6999
|
-
return { src: toDataUri(svg), width, height };
|
|
7000
|
-
};
|
|
7001
|
-
var makeMoreDataUri = (opts) => {
|
|
7002
|
-
const { label, width, height = 24 } = opts;
|
|
7003
|
-
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}"><text x="3" y="${height / 2}" font-family='${HS_FONT_FAMILY}' font-size="13" font-weight="700" fill="#0091AE" text-anchor="start" dominant-baseline="central">${escapeXml(label)}</text></svg>`;
|
|
7004
|
-
return { src: toDataUri(svg), width, height };
|
|
7005
|
-
};
|
|
7006
7743
|
var makeSpacerDataUri = (height = 24, width = 4) => {
|
|
7007
7744
|
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}"><rect x="0" y="0" width="${width}" height="${height}" fill="#FFFFFF" fill-opacity="0" /></svg>`;
|
|
7008
7745
|
return { src: toDataUri(svg), width, height };
|
|
7009
7746
|
};
|
|
7010
7747
|
|
|
7748
|
+
// src/calendar/rescheduleUtils.js
|
|
7749
|
+
var shiftDate = (date, shift) => {
|
|
7750
|
+
const d = toDate2(date);
|
|
7751
|
+
if (!d) return null;
|
|
7752
|
+
if (!shift || typeof shift !== "object") return new Date(d);
|
|
7753
|
+
const days = (shift.days || 0) + (shift.weeks || 0) * 7;
|
|
7754
|
+
let next = days ? addDays(d, days) : new Date(d);
|
|
7755
|
+
const ms = (shift.hours || 0) * 36e5 + (shift.minutes || 0) * 6e4;
|
|
7756
|
+
if (ms) next = new Date(next.getTime() + ms);
|
|
7757
|
+
return next;
|
|
7758
|
+
};
|
|
7759
|
+
var shiftEvent = (range, shift) => {
|
|
7760
|
+
const start = toDate2(range && range.start);
|
|
7761
|
+
if (!start) return null;
|
|
7762
|
+
const end = toDate2(range && range.end) || start;
|
|
7763
|
+
return { start: shiftDate(start, shift), end: shiftDate(end, shift) };
|
|
7764
|
+
};
|
|
7765
|
+
var calendarDayDelta = (a, b) => Math.round((startOfDay(b).getTime() - startOfDay(a).getTime()) / MS_PER_DAY);
|
|
7766
|
+
var msIntoDay = (d) => ((d.getHours() * 60 + d.getMinutes()) * 60 + d.getSeconds()) * 1e3 + d.getMilliseconds();
|
|
7767
|
+
var rescheduleToStart = (range, newStart) => {
|
|
7768
|
+
const start = toDate2(range && range.start);
|
|
7769
|
+
const target = toDate2(newStart);
|
|
7770
|
+
if (!start || !target) return null;
|
|
7771
|
+
const end = toDate2(range && range.end) || start;
|
|
7772
|
+
const dayDelta = calendarDayDelta(start, target);
|
|
7773
|
+
const timeDelta = msIntoDay(target) - msIntoDay(start);
|
|
7774
|
+
const endOnDay = addDays(end, dayDelta);
|
|
7775
|
+
if (!timeDelta) return { start: target, end: endOnDay };
|
|
7776
|
+
return {
|
|
7777
|
+
start: target,
|
|
7778
|
+
end: new Date(
|
|
7779
|
+
endOnDay.getFullYear(),
|
|
7780
|
+
endOnDay.getMonth(),
|
|
7781
|
+
endOnDay.getDate(),
|
|
7782
|
+
0,
|
|
7783
|
+
0,
|
|
7784
|
+
0,
|
|
7785
|
+
msIntoDay(endOnDay) + timeDelta
|
|
7786
|
+
)
|
|
7787
|
+
};
|
|
7788
|
+
};
|
|
7789
|
+
var applyDatePick = (start, value) => {
|
|
7790
|
+
if (!isDateValueObject3(value)) return null;
|
|
7791
|
+
const s = toDate2(start);
|
|
7792
|
+
return new Date(
|
|
7793
|
+
value.year,
|
|
7794
|
+
value.month,
|
|
7795
|
+
value.date,
|
|
7796
|
+
s ? s.getHours() : 0,
|
|
7797
|
+
s ? s.getMinutes() : 0,
|
|
7798
|
+
s ? s.getSeconds() : 0,
|
|
7799
|
+
s ? s.getMilliseconds() : 0
|
|
7800
|
+
);
|
|
7801
|
+
};
|
|
7802
|
+
var DEFAULT_RESCHEDULE_PRESETS = [
|
|
7803
|
+
{ label: "+1 hour", shift: { hours: 1 } },
|
|
7804
|
+
{ label: "+1 day", shift: { days: 1 } },
|
|
7805
|
+
{ label: "Next week", shift: { weeks: 1 } }
|
|
7806
|
+
];
|
|
7807
|
+
var normalizeRescheduleOptions = (options) => {
|
|
7808
|
+
if (!options) return [];
|
|
7809
|
+
if (options === true) return DEFAULT_RESCHEDULE_PRESETS;
|
|
7810
|
+
if (!Array.isArray(options)) return [];
|
|
7811
|
+
const out = [];
|
|
7812
|
+
for (const opt of options) {
|
|
7813
|
+
if (typeof opt === "function") {
|
|
7814
|
+
out.push({ label: opt.label || opt.name || "Reschedule", getStart: opt });
|
|
7815
|
+
} else if (opt && typeof opt === "object" && opt.label != null) {
|
|
7816
|
+
if (typeof opt.shift === "function") {
|
|
7817
|
+
out.push({ label: opt.label, getStart: opt.shift });
|
|
7818
|
+
} else if (typeof opt.getStart === "function") {
|
|
7819
|
+
out.push({ label: opt.label, getStart: opt.getStart });
|
|
7820
|
+
} else if (opt.shift && typeof opt.shift === "object") {
|
|
7821
|
+
out.push({ label: opt.label, shift: opt.shift });
|
|
7822
|
+
}
|
|
7823
|
+
}
|
|
7824
|
+
}
|
|
7825
|
+
return out;
|
|
7826
|
+
};
|
|
7827
|
+
var resolveRescheduleTarget = (range, option, fnArg) => {
|
|
7828
|
+
if (!range || !toDate2(range.start) || !option) return null;
|
|
7829
|
+
if (typeof option.getStart === "function") {
|
|
7830
|
+
const next = toDate2(option.getStart(fnArg !== void 0 ? fnArg : range));
|
|
7831
|
+
return next ? rescheduleToStart(range, next) : null;
|
|
7832
|
+
}
|
|
7833
|
+
if (option.shift && typeof option.shift === "object") {
|
|
7834
|
+
return shiftEvent(range, option.shift);
|
|
7835
|
+
}
|
|
7836
|
+
return null;
|
|
7837
|
+
};
|
|
7838
|
+
|
|
7839
|
+
// src/calendar/resourceLanes.js
|
|
7840
|
+
var resolveResourceId = (record, spec) => {
|
|
7841
|
+
if (record == null || spec == null) return null;
|
|
7842
|
+
const value = typeof spec === "function" ? spec(record) : record[spec];
|
|
7843
|
+
if (value == null || value === "") return null;
|
|
7844
|
+
return value;
|
|
7845
|
+
};
|
|
7846
|
+
var buildResourceLanes = (events, options = {}) => {
|
|
7847
|
+
const {
|
|
7848
|
+
resources,
|
|
7849
|
+
resourceLabels,
|
|
7850
|
+
getId,
|
|
7851
|
+
showUnassignedLane = true,
|
|
7852
|
+
unassignedLabel = "Unassigned"
|
|
7853
|
+
} = options;
|
|
7854
|
+
const labelFor = (id) => {
|
|
7855
|
+
if (resourceLabels && resourceLabels[id] != null) return resourceLabels[id];
|
|
7856
|
+
return String(id);
|
|
7857
|
+
};
|
|
7858
|
+
const lanes = [];
|
|
7859
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
7860
|
+
const addLane = (id, label, declared) => {
|
|
7861
|
+
const key = String(id);
|
|
7862
|
+
if (byKey.has(key)) return byKey.get(key);
|
|
7863
|
+
const lane = { id, key, label, events: [], unassigned: false, declared };
|
|
7864
|
+
byKey.set(key, lane);
|
|
7865
|
+
lanes.push(lane);
|
|
7866
|
+
return lane;
|
|
7867
|
+
};
|
|
7868
|
+
(resources || []).forEach((resource) => {
|
|
7869
|
+
if (resource == null) return;
|
|
7870
|
+
if (typeof resource === "object") {
|
|
7871
|
+
addLane(resource.id, resource.label != null ? resource.label : labelFor(resource.id), true);
|
|
7872
|
+
} else {
|
|
7873
|
+
addLane(resource, labelFor(resource), true);
|
|
7874
|
+
}
|
|
7875
|
+
});
|
|
7876
|
+
const unassigned = {
|
|
7877
|
+
id: null,
|
|
7878
|
+
key: "__unassigned__",
|
|
7879
|
+
label: unassignedLabel,
|
|
7880
|
+
events: [],
|
|
7881
|
+
unassigned: true,
|
|
7882
|
+
declared: false
|
|
7883
|
+
};
|
|
7884
|
+
(events || []).forEach((event) => {
|
|
7885
|
+
const id = getId ? getId(event) : null;
|
|
7886
|
+
if (id == null || id === "") {
|
|
7887
|
+
unassigned.events.push(event);
|
|
7888
|
+
return;
|
|
7889
|
+
}
|
|
7890
|
+
const lane = byKey.get(String(id)) || addLane(id, labelFor(id), false);
|
|
7891
|
+
lane.events.push(event);
|
|
7892
|
+
});
|
|
7893
|
+
if (showUnassignedLane && unassigned.events.length > 0) lanes.push(unassigned);
|
|
7894
|
+
return lanes;
|
|
7895
|
+
};
|
|
7896
|
+
var eventsIntersectingRange = (events, rangeStart, rangeEnd) => {
|
|
7897
|
+
const rs = rangeStart.getTime();
|
|
7898
|
+
const re = rangeEnd.getTime();
|
|
7899
|
+
return (events || []).filter((event) => {
|
|
7900
|
+
if (!event || !event.start) return false;
|
|
7901
|
+
const es = event.start.getTime();
|
|
7902
|
+
const ee = (event.end || event.start).getTime();
|
|
7903
|
+
return es <= re && ee >= rs;
|
|
7904
|
+
});
|
|
7905
|
+
};
|
|
7906
|
+
var laneEventsForDay = (events, day) => eventsIntersectingRange(events, startOfDay(day), endOfDay(day)).sort(
|
|
7907
|
+
(a, b) => a.start.getTime() - b.start.getTime()
|
|
7908
|
+
);
|
|
7909
|
+
|
|
7011
7910
|
// src/calendar/Calendar.jsx
|
|
7012
7911
|
var DEFAULT_MAX_EVENTS_PER_DAY = 3;
|
|
7013
7912
|
var ALL_VIEWS = ["month", "week", "day", "agenda"];
|
|
7913
|
+
var ALL_VIEWS_WITH_RESOURCE = ["month", "week", "day", "resource", "agenda"];
|
|
7014
7914
|
var DEFAULT_DAY_START_HOUR = 8;
|
|
7015
7915
|
var DEFAULT_DAY_END_HOUR = 20;
|
|
7016
7916
|
var DEFAULT_TIME_ZONES = [
|
|
@@ -7046,7 +7946,8 @@ var VIEW_LABELS = {
|
|
|
7046
7946
|
month: "Month",
|
|
7047
7947
|
week: "Week",
|
|
7048
7948
|
day: "Day",
|
|
7049
|
-
agenda: "Agenda"
|
|
7949
|
+
agenda: "Agenda",
|
|
7950
|
+
resource: "Resource"
|
|
7050
7951
|
};
|
|
7051
7952
|
var DEFAULT_LABELS5 = {
|
|
7052
7953
|
today: "Today",
|
|
@@ -7063,7 +7964,11 @@ var DEFAULT_LABELS5 = {
|
|
|
7063
7964
|
errorMessage: "An error occurred while loading events.",
|
|
7064
7965
|
dayDetailTitle: (label) => label,
|
|
7065
7966
|
open: "Open",
|
|
7066
|
-
allDay: "All day"
|
|
7967
|
+
allDay: "All day",
|
|
7968
|
+
reschedule: "Reschedule",
|
|
7969
|
+
pickDate: "Pick date",
|
|
7970
|
+
unassigned: "Unassigned",
|
|
7971
|
+
resource: "Resource"
|
|
7067
7972
|
};
|
|
7068
7973
|
var DEFAULT_EVENT_FIELDS = {
|
|
7069
7974
|
id: "id",
|
|
@@ -7098,11 +8003,30 @@ var STATUS_VARIANT = {
|
|
|
7098
8003
|
error: "danger",
|
|
7099
8004
|
danger: "danger"
|
|
7100
8005
|
};
|
|
8006
|
+
var TAG_VARIANT = {
|
|
8007
|
+
default: "default",
|
|
8008
|
+
info: "info",
|
|
8009
|
+
success: "success",
|
|
8010
|
+
warning: "warning",
|
|
8011
|
+
error: "error",
|
|
8012
|
+
danger: "error"
|
|
8013
|
+
};
|
|
8014
|
+
var MONTH_EVENT_STYLES = /* @__PURE__ */ new Set(["statusTag", "tag"]);
|
|
8015
|
+
var monthLabelMaxChars = (style) => {
|
|
8016
|
+
const overhead = style === "tag" ? 34 : 46;
|
|
8017
|
+
return Math.max(6, Math.floor((MONTH_COL_WIDTH - overhead) / 6.6));
|
|
8018
|
+
};
|
|
8019
|
+
var truncateMonthLabel = (value, max) => {
|
|
8020
|
+
const s = String(value == null ? "" : value);
|
|
8021
|
+
if (!max || s.length <= max) return s;
|
|
8022
|
+
return s.slice(0, max).trimEnd();
|
|
8023
|
+
};
|
|
7101
8024
|
var MONTH_COL_WIDTH = 160;
|
|
7102
8025
|
var TIMEGRID_DAY_COL = 150;
|
|
7103
8026
|
var TIMEGRID_DAY_COL_SINGLE = 560;
|
|
8027
|
+
var RESOURCE_LABEL_COL_WIDTH = "min";
|
|
7104
8028
|
var HOUR_SLOT_HEIGHT = 64;
|
|
7105
|
-
var EventDetail = ({ event, labels }) => {
|
|
8029
|
+
var EventDetail = ({ event, labels, reschedule, idSuffix = "" }) => {
|
|
7106
8030
|
const { start, end, title, subtitle, href } = event;
|
|
7107
8031
|
let when = "";
|
|
7108
8032
|
if (start) {
|
|
@@ -7116,11 +8040,27 @@ var EventDetail = ({ event, labels }) => {
|
|
|
7116
8040
|
when = `${formatDayTitle(start)} \u2013 ${formatDayTitle(end)}`;
|
|
7117
8041
|
}
|
|
7118
8042
|
}
|
|
7119
|
-
return /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Flex, { direction: "column", gap: "xs" }, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Text, { format: { fontWeight: "demibold" } }, title || "--"), when ? /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Text, { variant: "microcopy" }, when) : null, subtitle ? /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Text,
|
|
8043
|
+
return /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Flex, { direction: "column", gap: "xs" }, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Text, { format: { fontWeight: "demibold" }, truncate: true }, title || "--"), when ? /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Text, { variant: "microcopy", truncate: true }, when) : null, subtitle ? /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Text, { truncate: true }, subtitle) : null, href ? /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Link, { href: href.url, external: href.external }, labels.open) : null, reschedule ? /* @__PURE__ */ import_react15.default.createElement(import_react15.default.Fragment, null, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Divider, null), /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Text, { variant: "microcopy", format: { fontWeight: "demibold" } }, labels.reschedule), reschedule.options.length > 0 ? /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Flex, { direction: "row", gap: "xs", wrap: "wrap" }, reschedule.options.map((option, i) => /* @__PURE__ */ import_react15.default.createElement(
|
|
8044
|
+
import_ui_extensions15.Button,
|
|
8045
|
+
{
|
|
8046
|
+
key: `${option.label}-${i}`,
|
|
8047
|
+
size: "xs",
|
|
8048
|
+
variant: "secondary",
|
|
8049
|
+
onClick: () => reschedule.onPreset(event, option)
|
|
8050
|
+
},
|
|
8051
|
+
option.label
|
|
8052
|
+
))) : null, /* @__PURE__ */ import_react15.default.createElement(
|
|
8053
|
+
import_ui_extensions15.DateInput,
|
|
8054
|
+
{
|
|
8055
|
+
name: `cal-resched-${event.key}${idSuffix}`,
|
|
8056
|
+
label: labels.pickDate,
|
|
8057
|
+
onChange: (value) => reschedule.onPick(event, value)
|
|
8058
|
+
}
|
|
8059
|
+
)) : null);
|
|
7120
8060
|
};
|
|
7121
|
-
var buildOverlay = (event, mode, renderEventDetail, labels, idSuffix = "") => {
|
|
8061
|
+
var buildOverlay = (event, mode, renderEventDetail, labels, idSuffix = "", reschedule = null) => {
|
|
7122
8062
|
if (mode === "none") return void 0;
|
|
7123
|
-
const body = renderEventDetail ? renderEventDetail(event) : /* @__PURE__ */ import_react15.default.createElement(EventDetail, { event, labels });
|
|
8063
|
+
const body = renderEventDetail ? renderEventDetail(event) : /* @__PURE__ */ import_react15.default.createElement(EventDetail, { event, labels, reschedule, idSuffix });
|
|
7124
8064
|
const id = `cal-evt-${event.key}${idSuffix}`;
|
|
7125
8065
|
if (mode === "modal") {
|
|
7126
8066
|
return /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Modal, { id, title: event.title || labels.open, width: "small" }, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.ModalBody, null, body));
|
|
@@ -7128,46 +8068,34 @@ var buildOverlay = (event, mode, renderEventDetail, labels, idSuffix = "") => {
|
|
|
7128
8068
|
if (mode === "panel") {
|
|
7129
8069
|
return /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Panel, { id, title: event.title || labels.open, width: "small", variant: "modal" }, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.PanelBody, null, body));
|
|
7130
8070
|
}
|
|
7131
|
-
return /* @__PURE__ */ import_react15.default.createElement(import_experimental.Popover, { id, placement: "bottom" }, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Tile, { compact: true }, body));
|
|
8071
|
+
return /* @__PURE__ */ import_react15.default.createElement(import_experimental.Popover, { id, placement: "bottom", variant: "longform" }, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Tile, { compact: true }, body));
|
|
7132
8072
|
};
|
|
7133
|
-
var AgendaEventRow = ({ event, day, overlayMode, renderEventDetail, onEventClick, labels }) => {
|
|
8073
|
+
var AgendaEventRow = ({ event, day, overlayMode, renderEventDetail, onEventClick, labels, reschedule }) => {
|
|
7134
8074
|
const variant = VALID_VARIANTS.has(event.color) ? event.color : "default";
|
|
7135
|
-
const overlay = buildOverlay(event, overlayMode, renderEventDetail, labels, day ? `-ag${day.getTime()}` : "");
|
|
8075
|
+
const overlay = buildOverlay(event, overlayMode, renderEventDetail, labels, day ? `-ag${day.getTime()}` : "", reschedule);
|
|
7136
8076
|
const handleClick = onEventClick ? () => onEventClick(event.raw, event) : void 0;
|
|
7137
8077
|
const timeLabel = isAllDayEvent(event) ? labels.allDay : formatTime(event.start);
|
|
7138
8078
|
return /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Flex, { direction: "row", align: "center", gap: "sm" }, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Box, { flex: 2 }, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Flex, { direction: "row", align: "center" }, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Text, { variant: "microcopy", format: { fontWeight: "demibold" } }, timeLabel))), /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Box, { flex: 11 }, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Flex, { direction: "row", align: "center", gap: "xs" }, /* @__PURE__ */ import_react15.default.createElement(ColorDot, { variant }), /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Text, { truncate: true }, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Link, { overlay, onClick: handleClick }, event.title || "--")))), event.subtitle ? /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Box, { flex: 4 }, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Flex, { direction: "row", align: "center" }, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Text, { variant: "microcopy", truncate: true }, event.subtitle))) : null);
|
|
7139
8079
|
};
|
|
7140
|
-
var
|
|
7141
|
-
var
|
|
7142
|
-
var MonthChip = ({ event, day, overlayMode, renderEventDetail, onEventClick, labels }) => {
|
|
8080
|
+
var MONTH_SLOT_HEIGHT = 24;
|
|
8081
|
+
var MonthChip = ({ event, day, overlayMode, renderEventDetail, onEventClick, labels, monthEventStyle, monthEventMaxChars, reschedule, idScope = "" }) => {
|
|
7143
8082
|
const isStartDay = !day || !event.start || isSameDay(event.start, day);
|
|
7144
|
-
const overlay = buildOverlay(event, overlayMode, renderEventDetail, labels, day ? `-m${day.getTime()}` : "");
|
|
8083
|
+
const overlay = buildOverlay(event, overlayMode, renderEventDetail, labels, day ? `-m${idScope}${day.getTime()}` : "", reschedule);
|
|
7145
8084
|
const handleClick = onEventClick ? () => onEventClick(event.raw, event) : void 0;
|
|
7146
8085
|
const variant = VALID_VARIANTS.has(event.color) ? event.color : "default";
|
|
7147
8086
|
const startHasTime = event.start && (event.start.getHours() !== 0 || event.start.getMinutes() !== 0);
|
|
7148
8087
|
const time = isStartDay && startHasTime ? `${formatTime(event.start)} ` : "";
|
|
7149
8088
|
const prefix = isStartDay ? "" : "\u2192 ";
|
|
7150
|
-
const
|
|
7151
|
-
|
|
7152
|
-
|
|
7153
|
-
|
|
7154
|
-
|
|
7155
|
-
});
|
|
7156
|
-
return /* @__PURE__ */ import_react15.default.createElement(
|
|
7157
|
-
import_ui_extensions15.Image,
|
|
7158
|
-
{
|
|
7159
|
-
src: chip.src,
|
|
7160
|
-
width: chip.width,
|
|
7161
|
-
height: chip.height,
|
|
7162
|
-
alt: event.title || "",
|
|
7163
|
-
overlay,
|
|
7164
|
-
onClick: handleClick
|
|
7165
|
-
}
|
|
7166
|
-
);
|
|
8089
|
+
const maxChars = monthEventMaxChars != null ? monthEventMaxChars : monthLabelMaxChars(monthEventStyle);
|
|
8090
|
+
const label = truncateMonthLabel(`${prefix}${time}${event.title || "--"}`, maxChars);
|
|
8091
|
+
if (monthEventStyle === "tag") {
|
|
8092
|
+
return /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Tag, { variant: TAG_VARIANT[variant] || "default", overlay, onClick: handleClick }, label);
|
|
8093
|
+
}
|
|
8094
|
+
return /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Link, { overlay, onClick: handleClick }, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.StatusTag, { variant: STATUS_VARIANT[variant] || "default" }, label));
|
|
7167
8095
|
};
|
|
7168
|
-
var DayListItem = ({ event, day, overlayMode, renderEventDetail, onEventClick, labels }) => {
|
|
8096
|
+
var DayListItem = ({ event, day, overlayMode, renderEventDetail, onEventClick, labels, reschedule, idScope = "" }) => {
|
|
7169
8097
|
const handleClick = onEventClick ? () => onEventClick(event.raw, event) : void 0;
|
|
7170
|
-
const overlay = buildOverlay(event, overlayMode, renderEventDetail, labels, day ? `-more${day.getTime()}` : "-more");
|
|
8098
|
+
const overlay = buildOverlay(event, overlayMode, renderEventDetail, labels, day ? `-more${idScope}${day.getTime()}` : "-more", reschedule);
|
|
7171
8099
|
const href = event.href;
|
|
7172
8100
|
return /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Button, { variant: "transparent", size: "sm", href: href ? href.url : void 0, overlay, onClick: handleClick }, event.title || "--");
|
|
7173
8101
|
};
|
|
@@ -7232,11 +8160,45 @@ var Toolbar = ({
|
|
|
7232
8160
|
}
|
|
7233
8161
|
));
|
|
7234
8162
|
};
|
|
7235
|
-
var
|
|
7236
|
-
|
|
7237
|
-
|
|
7238
|
-
|
|
7239
|
-
|
|
8163
|
+
var DayChipStack = ({ day, events, maxEventsPerDay, chipProps, labels, idScope = "" }) => {
|
|
8164
|
+
const slotSpacer = makeSpacerDataUri(MONTH_SLOT_HEIGHT, 1);
|
|
8165
|
+
const shown = events.slice(0, maxEventsPerDay);
|
|
8166
|
+
const hasOverflow = events.length > maxEventsPerDay;
|
|
8167
|
+
const heightSpacer = /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Image, { src: slotSpacer.src, width: slotSpacer.width, height: slotSpacer.height, alt: "" });
|
|
8168
|
+
const slotRow = (key, content) => /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Flex, { key, direction: "row", align: "center", gap: "flush" }, heightSpacer, content);
|
|
8169
|
+
const slots = [];
|
|
8170
|
+
for (let i = 0; i < maxEventsPerDay; i++) {
|
|
8171
|
+
if (i < shown.length) {
|
|
8172
|
+
slots.push(slotRow(shown[i].key, /* @__PURE__ */ import_react15.default.createElement(MonthChip, { event: shown[i], day, idScope, ...chipProps })));
|
|
8173
|
+
} else {
|
|
8174
|
+
slots.push(/* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Image, { key: `sp-${i}`, src: slotSpacer.src, width: slotSpacer.width, height: slotSpacer.height, alt: "" }));
|
|
8175
|
+
}
|
|
8176
|
+
}
|
|
8177
|
+
if (hasOverflow) {
|
|
8178
|
+
slots.push(
|
|
8179
|
+
slotRow(
|
|
8180
|
+
"more",
|
|
8181
|
+
/* @__PURE__ */ import_react15.default.createElement(
|
|
8182
|
+
import_ui_extensions15.Link,
|
|
8183
|
+
{
|
|
8184
|
+
overlay: /* @__PURE__ */ import_react15.default.createElement(import_experimental.Popover, { id: `cal-day-${idScope}${day.getTime()}`, placement: "top", variant: "longform" }, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Tile, { compact: true }, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Flex, { direction: "column", gap: "sm" }, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Flex, { direction: "row", justify: "center", align: "center", gap: "xs" }, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Text, { format: { fontWeight: "bold" } }, String(events.length)), /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Text, { format: { fontWeight: "demibold" } }, labels.onThisDate)), /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Divider, null), events.map((event, i) => /* @__PURE__ */ import_react15.default.createElement(import_react15.default.Fragment, { key: event.key }, /* @__PURE__ */ import_react15.default.createElement(DayListItem, { event, day, idScope, ...chipProps }), i < events.length - 1 ? /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Divider, null) : null)))))
|
|
8185
|
+
},
|
|
8186
|
+
labels.more(events.length - maxEventsPerDay)
|
|
8187
|
+
)
|
|
8188
|
+
)
|
|
8189
|
+
);
|
|
8190
|
+
} else {
|
|
8191
|
+
slots.push(
|
|
8192
|
+
/* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Image, { key: "more-sp", src: slotSpacer.src, width: slotSpacer.width, height: slotSpacer.height, alt: "" })
|
|
8193
|
+
);
|
|
8194
|
+
}
|
|
8195
|
+
return /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Flex, { direction: "column", gap: "xs" }, slots);
|
|
8196
|
+
};
|
|
8197
|
+
var MonthView = ({
|
|
8198
|
+
refDate,
|
|
8199
|
+
now,
|
|
8200
|
+
weekStartsOn,
|
|
8201
|
+
hideWeekends,
|
|
7240
8202
|
weeks,
|
|
7241
8203
|
eventsForDay,
|
|
7242
8204
|
maxEventsPerDay,
|
|
@@ -7246,51 +8208,23 @@ var MonthView = ({
|
|
|
7246
8208
|
}) => {
|
|
7247
8209
|
const headers = weekdayLabels(weekStartsOn, hideWeekends, true);
|
|
7248
8210
|
const today = now || /* @__PURE__ */ new Date();
|
|
7249
|
-
const spacer24 = makeSpacerDataUri(MONTH_CHIP_HEIGHT, MONTH_COL_WIDTH);
|
|
7250
8211
|
const renderCell = (day) => {
|
|
7251
8212
|
const dayEvents = eventsForDay(day);
|
|
7252
8213
|
const inMonth = isSameMonth(day, refDate);
|
|
7253
8214
|
const isToday = isSameDay(day, today);
|
|
7254
8215
|
if (renderDayCell) return renderDayCell(day, dayEvents);
|
|
7255
|
-
|
|
7256
|
-
|
|
7257
|
-
|
|
7258
|
-
|
|
7259
|
-
|
|
7260
|
-
|
|
7261
|
-
|
|
7262
|
-
|
|
7263
|
-
/* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Image, { key: `sp-${i}`, src: spacer24.src, width: spacer24.width, height: spacer24.height, alt: "" })
|
|
7264
|
-
);
|
|
8216
|
+
return /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.AutoGrid, { columnWidth: MONTH_COL_WIDTH, gap: "flush" }, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Flex, { direction: "column", gap: "xs" }, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Flex, { direction: "row", align: "center", gap: "xs" }, isToday ? /* @__PURE__ */ import_react15.default.createElement(ColorDot, { variant: "info" }) : null, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Text, { variant: "microcopy", format: { fontWeight: inMonth ? "demibold" : "regular" } }, String(day.getDate()))), /* @__PURE__ */ import_react15.default.createElement(
|
|
8217
|
+
DayChipStack,
|
|
8218
|
+
{
|
|
8219
|
+
day,
|
|
8220
|
+
events: dayEvents,
|
|
8221
|
+
maxEventsPerDay,
|
|
8222
|
+
chipProps,
|
|
8223
|
+
labels
|
|
7265
8224
|
}
|
|
7266
|
-
|
|
7267
|
-
if (hasOverflow) {
|
|
7268
|
-
const more = makeMoreDataUri({
|
|
7269
|
-
label: labels.more(dayEvents.length - maxEventsPerDay),
|
|
7270
|
-
width: MONTH_COL_WIDTH,
|
|
7271
|
-
height: MONTH_CHIP_HEIGHT
|
|
7272
|
-
});
|
|
7273
|
-
slots.push(
|
|
7274
|
-
/* @__PURE__ */ import_react15.default.createElement(
|
|
7275
|
-
import_ui_extensions15.Image,
|
|
7276
|
-
{
|
|
7277
|
-
key: "more",
|
|
7278
|
-
src: more.src,
|
|
7279
|
-
width: more.width,
|
|
7280
|
-
height: more.height,
|
|
7281
|
-
alt: labels.more(dayEvents.length - maxEventsPerDay),
|
|
7282
|
-
overlay: /* @__PURE__ */ import_react15.default.createElement(import_experimental.Popover, { id: `cal-day-${day.getTime()}`, placement: "top", variant: "longform" }, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Tile, { compact: true }, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Flex, { direction: "column", gap: "sm" }, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Flex, { direction: "row", align: "center", gap: "sm" }, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Heading, null, String(dayEvents.length)), /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Text, { format: { fontWeight: "demibold" } }, labels.onThisDate)), /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Divider, null), dayEvents.map((event, i) => /* @__PURE__ */ import_react15.default.createElement(import_react15.default.Fragment, { key: event.key }, /* @__PURE__ */ import_react15.default.createElement(DayListItem, { event, day, ...chipProps }), i < dayEvents.length - 1 ? /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Divider, null) : null)))))
|
|
7283
|
-
}
|
|
7284
|
-
)
|
|
7285
|
-
);
|
|
7286
|
-
} else {
|
|
7287
|
-
slots.push(
|
|
7288
|
-
/* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Image, { key: "more-sp", src: spacer24.src, width: spacer24.width, height: spacer24.height, alt: "" })
|
|
7289
|
-
);
|
|
7290
|
-
}
|
|
7291
|
-
return /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Flex, { direction: "column", gap: "xs" }, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Flex, { direction: "row", align: "center", gap: "xs" }, isToday ? /* @__PURE__ */ import_react15.default.createElement(ColorDot, { variant: "info" }) : null, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Text, { variant: "microcopy", format: { fontWeight: inMonth ? "demibold" : "regular" } }, String(day.getDate()))), slots);
|
|
8225
|
+
)));
|
|
7292
8226
|
};
|
|
7293
|
-
return /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Table, { bordered: true, flush: true }, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.TableHead, null, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.TableRow, null, headers.map((
|
|
8227
|
+
return /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Table, { bordered: true, flush: true }, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.TableHead, null, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.TableRow, null, headers.map((h7) => /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.TableHeader, { key: h7, width: "min", align: "center" }, h7.toUpperCase())))), /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.TableBody, null, weeks.map((week, wi) => {
|
|
7294
8228
|
const days = hideWeekends ? week.filter((d) => d.getDay() !== 0 && d.getDay() !== 6) : week;
|
|
7295
8229
|
return /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.TableRow, { key: wi }, days.map((day) => /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.TableCell, { key: day.getTime(), width: "min" }, renderCell(day))));
|
|
7296
8230
|
})));
|
|
@@ -7310,13 +8244,40 @@ var AgendaView = ({ rangeStart, rangeEnd, eventsForDay, chipProps, labels, rende
|
|
|
7310
8244
|
}
|
|
7311
8245
|
return /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Flex, { direction: "column", gap: "lg" }, days.map(({ day, events }) => /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Flex, { key: day.getTime(), direction: "column", gap: "sm" }, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Flex, { direction: "row", justify: "between", align: "end" }, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Text, { format: { fontWeight: "demibold" } }, formatDayTitle(day)), /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Text, { variant: "microcopy" }, `${events.length} ${events.length === 1 ? "event" : "events"}`)), /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Divider, null), events.map((event) => /* @__PURE__ */ import_react15.default.createElement(AgendaEventRow, { key: event.key, event, day, ...chipProps })))));
|
|
7312
8246
|
};
|
|
8247
|
+
var ResourceView = ({ days, now, lanes, maxEventsPerDay, chipProps, labels, renderEmptyState }) => {
|
|
8248
|
+
const today = now || /* @__PURE__ */ new Date();
|
|
8249
|
+
if (!lanes || lanes.length === 0) {
|
|
8250
|
+
if (renderEmptyState) return renderEmptyState({});
|
|
8251
|
+
return /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.EmptyState, { title: labels.noEventsTitle }, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Text, null, labels.noEventsMessage));
|
|
8252
|
+
}
|
|
8253
|
+
const rangeStart = startOfDay(days[0]);
|
|
8254
|
+
const rangeEnd = endOfDay(days[days.length - 1]);
|
|
8255
|
+
return /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Table, { bordered: true, flush: true }, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.TableHead, null, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.TableRow, null, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.TableHeader, { width: RESOURCE_LABEL_COL_WIDTH }, String(labels.resource).toUpperCase()), days.map((day) => {
|
|
8256
|
+
const isToday = isSameDay(day, today);
|
|
8257
|
+
const label = `${formatWeekdayShort(day)} ${formatMonthShort(day)} ${day.getDate()}`;
|
|
8258
|
+
return /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.TableHeader, { key: day.getTime(), width: "min", align: "center" }, isToday ? `${label} \xB7 Today` : label);
|
|
8259
|
+
}))), /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.TableBody, null, lanes.map((lane, laneIndex) => {
|
|
8260
|
+
const visible = eventsIntersectingRange(lane.events, rangeStart, rangeEnd);
|
|
8261
|
+
return /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.TableRow, { key: lane.key }, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.TableCell, { width: RESOURCE_LABEL_COL_WIDTH }, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Flex, { direction: "column", gap: "flush" }, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Text, { format: { fontWeight: "demibold" } }, lane.label), /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Text, { variant: "microcopy" }, `${visible.length} ${visible.length === 1 ? "event" : "events"}`))), days.map((day) => /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.TableCell, { key: day.getTime(), width: "min" }, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.AutoGrid, { columnWidth: MONTH_COL_WIDTH, gap: "flush" }, /* @__PURE__ */ import_react15.default.createElement(
|
|
8262
|
+
DayChipStack,
|
|
8263
|
+
{
|
|
8264
|
+
day,
|
|
8265
|
+
events: laneEventsForDay(visible, day),
|
|
8266
|
+
maxEventsPerDay,
|
|
8267
|
+
chipProps,
|
|
8268
|
+
labels,
|
|
8269
|
+
idScope: `r${laneIndex}-`
|
|
8270
|
+
}
|
|
8271
|
+
)))));
|
|
8272
|
+
})));
|
|
8273
|
+
};
|
|
7313
8274
|
var formatTimedDuration = (start, end) => {
|
|
7314
8275
|
const mins = Math.max(0, Math.round(((end || start).getTime() - start.getTime()) / 6e4));
|
|
7315
|
-
const
|
|
8276
|
+
const h7 = Math.floor(mins / 60);
|
|
7316
8277
|
const m = mins % 60;
|
|
7317
|
-
if (
|
|
7318
|
-
if (m === 0) return `${
|
|
7319
|
-
return `${
|
|
8278
|
+
if (h7 === 0) return `${m} min`;
|
|
8279
|
+
if (m === 0) return `${h7} hr`;
|
|
8280
|
+
return `${h7} hr ${m} min`;
|
|
7320
8281
|
};
|
|
7321
8282
|
var hourSpan = (event) => {
|
|
7322
8283
|
const start = event.start;
|
|
@@ -7331,6 +8292,7 @@ var TimeGridView = ({ days, now, hours, dayStartHour, dayEndHour, eventsForDay,
|
|
|
7331
8292
|
const today = now || /* @__PURE__ */ new Date();
|
|
7332
8293
|
const centerDays = days.length === 1;
|
|
7333
8294
|
const dayColWidth = days.length === 1 ? TIMEGRID_DAY_COL_SINGLE : TIMEGRID_DAY_COL;
|
|
8295
|
+
const weekTitleMaxChars = Math.max(6, Math.floor((TIMEGRID_DAY_COL - 46) / 6.6));
|
|
7334
8296
|
const todayInView = days.some((d) => isSameDay(d, today));
|
|
7335
8297
|
const nowHour = today.getHours();
|
|
7336
8298
|
const dayData = days.map((day) => {
|
|
@@ -7356,7 +8318,8 @@ var TimeGridView = ({ days, now, hours, dayStartHour, dayEndHour, eventsForDay,
|
|
|
7356
8318
|
chipProps.overlayMode,
|
|
7357
8319
|
chipProps.renderEventDetail,
|
|
7358
8320
|
chipProps.labels,
|
|
7359
|
-
`-tg${mode}${hour}-${dayMs}
|
|
8321
|
+
`-tg${mode}${hour}-${dayMs}`,
|
|
8322
|
+
chipProps.reschedule
|
|
7360
8323
|
);
|
|
7361
8324
|
const handleClick = chipProps.onEventClick ? () => chipProps.onEventClick(e.raw, e) : void 0;
|
|
7362
8325
|
const variant = VALID_VARIANTS.has(e.color) ? e.color : "default";
|
|
@@ -7375,10 +8338,10 @@ var TimeGridView = ({ days, now, hours, dayStartHour, dayEndHour, eventsForDay,
|
|
|
7375
8338
|
} else if (mode === "cont") {
|
|
7376
8339
|
sub = `\u2191 cont. through ${endLabel}`;
|
|
7377
8340
|
}
|
|
7378
|
-
|
|
8341
|
+
const titleLabel = centerDays ? e.title || "--" : truncateMonthLabel(e.title || "--", weekTitleMaxChars);
|
|
8342
|
+
return /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Flex, { key: `${e.key}-${mode}-${hour}`, direction: "column", gap: "flush" }, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Link, { overlay, onClick: handleClick }, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.StatusTag, { variant: STATUS_VARIANT[variant] || "default" }, titleLabel)), sub ? /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Text, { variant: "microcopy" }, sub) : null);
|
|
7379
8343
|
};
|
|
7380
|
-
const
|
|
7381
|
-
const dayCell = (key, content) => /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.TableCell, { key, width: centerDays ? "max" : "min", align: "left" }, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Flex, { direction: "column", gap: "xs" }, content, centerDays ? null : /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Image, { src: daySpacer.src, width: daySpacer.width, height: daySpacer.height, alt: "" })));
|
|
8344
|
+
const dayCell = (key, content) => /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.TableCell, { key, width: centerDays ? "max" : "min", align: "left" }, centerDays ? /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Flex, { direction: "column", gap: "xs" }, content) : /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.AutoGrid, { columnWidth: dayColWidth, gap: "flush" }, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Flex, { direction: "column", gap: "xs" }, content)));
|
|
7382
8345
|
const slotSpacer = makeSpacerDataUri(HOUR_SLOT_HEIGHT, 1);
|
|
7383
8346
|
const emptyCell = null;
|
|
7384
8347
|
return /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Table, { bordered: true, flush: true, density: "compact" }, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.TableHead, null, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.TableRow, null, /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.TableHeader, { width: "min" }, "TIME"), dayData.map(({ day }) => {
|
|
@@ -7434,9 +8397,21 @@ var Calendar = (props) => {
|
|
|
7434
8397
|
weekStartsOn = 0,
|
|
7435
8398
|
hideWeekends = false,
|
|
7436
8399
|
maxEventsPerDay = DEFAULT_MAX_EVENTS_PER_DAY,
|
|
8400
|
+
// month-grid event token style: "statusTag" (dot + text, default) | "tag" (pill)
|
|
8401
|
+
monthEventStyle = "statusTag",
|
|
8402
|
+
// max characters for a month-cell label before "…" (default derived per style)
|
|
8403
|
+
monthEventMaxChars,
|
|
7437
8404
|
// time grid (week / day)
|
|
7438
8405
|
dayStartHour = DEFAULT_DAY_START_HOUR,
|
|
7439
8406
|
dayEndHour = DEFAULT_DAY_END_HOUR,
|
|
8407
|
+
// resource / lane view (rows = resources, columns = the focused week's days)
|
|
8408
|
+
resources,
|
|
8409
|
+
resourceField,
|
|
8410
|
+
resourceLabels,
|
|
8411
|
+
showUnassignedLane = true,
|
|
8412
|
+
// drag-free reschedule (presets + date picker in the event-detail overlay)
|
|
8413
|
+
rescheduleOptions,
|
|
8414
|
+
onEventReschedule,
|
|
7440
8415
|
// timezone
|
|
7441
8416
|
timeZone: controlledTimeZone,
|
|
7442
8417
|
defaultTimeZone,
|
|
@@ -7475,10 +8450,12 @@ var Calendar = (props) => {
|
|
|
7475
8450
|
const fields = (0, import_react15.useMemo)(() => ({ ...DEFAULT_EVENT_FIELDS, ...eventFields || {} }), [eventFields]);
|
|
7476
8451
|
const [internalView, setInternalView] = (0, import_react15.useState)(defaultView);
|
|
7477
8452
|
const view = controlledView != null ? controlledView : internalView;
|
|
8453
|
+
const resourceEnabled = resources && resources.length > 0 || resourceField != null;
|
|
7478
8454
|
const enabledViews = (0, import_react15.useMemo)(() => {
|
|
7479
|
-
const
|
|
7480
|
-
|
|
7481
|
-
|
|
8455
|
+
const all = resourceEnabled ? ALL_VIEWS_WITH_RESOURCE : ALL_VIEWS;
|
|
8456
|
+
const base = viewsProp && viewsProp.length > 0 ? viewsProp : all;
|
|
8457
|
+
return base.filter((v) => all.includes(v));
|
|
8458
|
+
}, [viewsProp, resourceEnabled]);
|
|
7482
8459
|
const setView = (0, import_react15.useCallback)(
|
|
7483
8460
|
(next) => {
|
|
7484
8461
|
if (controlledView == null) setInternalView(next);
|
|
@@ -7503,7 +8480,9 @@ var Calendar = (props) => {
|
|
|
7503
8480
|
const focusedDate = (controlledFocusedDate != null ? toDate2(controlledFocusedDate) : internalDate) || startOfDay(nowWall);
|
|
7504
8481
|
const stepFor = (0, import_react15.useCallback)(
|
|
7505
8482
|
(dir) => {
|
|
7506
|
-
if (view === "week" || view === "agenda"
|
|
8483
|
+
if (view === "week" || view === "agenda" || view === "resource") {
|
|
8484
|
+
return addDays(focusedDate, dir * 7);
|
|
8485
|
+
}
|
|
7507
8486
|
if (view === "day") return addDays(focusedDate, dir);
|
|
7508
8487
|
return addMonths(focusedDate, dir);
|
|
7509
8488
|
},
|
|
@@ -7530,7 +8509,7 @@ var Calendar = (props) => {
|
|
|
7530
8509
|
rangeEnd: endOfDay(flat[flat.length - 1])
|
|
7531
8510
|
};
|
|
7532
8511
|
}
|
|
7533
|
-
if (view === "week") {
|
|
8512
|
+
if (view === "week" || view === "resource") {
|
|
7534
8513
|
const days = buildWeekDays(focusedDate, weekStartsOn, hideWeekends);
|
|
7535
8514
|
return {
|
|
7536
8515
|
weeks: null,
|
|
@@ -7603,14 +8582,18 @@ var Calendar = (props) => {
|
|
|
7603
8582
|
);
|
|
7604
8583
|
const normalized = (0, import_react15.useMemo)(
|
|
7605
8584
|
() => (events || []).map((raw, index) => {
|
|
7606
|
-
const
|
|
7607
|
-
const
|
|
8585
|
+
const sourceStart = toDate2(resolveField(raw, fields.start));
|
|
8586
|
+
const sourceEnd = toDate2(resolveField(raw, fields.end));
|
|
8587
|
+
const start = toWallClock(sourceStart, timeZone);
|
|
8588
|
+
const endRaw = toWallClock(sourceEnd, timeZone);
|
|
7608
8589
|
const id = resolveField(raw, fields.id);
|
|
7609
8590
|
return {
|
|
7610
8591
|
key: id != null ? String(id) : `evt-${index}`,
|
|
7611
8592
|
id,
|
|
7612
8593
|
start,
|
|
7613
8594
|
end: endRaw || start,
|
|
8595
|
+
sourceStart,
|
|
8596
|
+
sourceEnd: sourceEnd || sourceStart,
|
|
7614
8597
|
title: resolveField(raw, fields.title),
|
|
7615
8598
|
subtitle: resolveField(raw, fields.subtitle),
|
|
7616
8599
|
color: resolveField(raw, fields.color),
|
|
@@ -7647,13 +8630,60 @@ var Calendar = (props) => {
|
|
|
7647
8630
|
}, [rangeKey]);
|
|
7648
8631
|
const title = (0, import_react15.useMemo)(() => {
|
|
7649
8632
|
if (view === "day") return formatDayTitle(focusedDate);
|
|
7650
|
-
if (view === "week" || view === "agenda") {
|
|
7651
|
-
const days = buildWeekDays(focusedDate, weekStartsOn, view
|
|
8633
|
+
if (view === "week" || view === "agenda" || view === "resource") {
|
|
8634
|
+
const days = buildWeekDays(focusedDate, weekStartsOn, view !== "agenda" && hideWeekends);
|
|
7652
8635
|
return formatRangeTitle(days[0], days[days.length - 1]);
|
|
7653
8636
|
}
|
|
7654
8637
|
return formatMonthTitle(focusedDate);
|
|
7655
8638
|
}, [view, focusedDate, weekStartsOn, hideWeekends]);
|
|
7656
|
-
const
|
|
8639
|
+
const handleReschedulePreset = (0, import_react15.useCallback)(
|
|
8640
|
+
(event, option) => {
|
|
8641
|
+
const target = resolveRescheduleTarget(
|
|
8642
|
+
{ start: event.sourceStart, end: event.sourceEnd },
|
|
8643
|
+
option,
|
|
8644
|
+
event
|
|
8645
|
+
);
|
|
8646
|
+
if (target && onEventReschedule) onEventReschedule(event.raw, target, event);
|
|
8647
|
+
},
|
|
8648
|
+
[onEventReschedule]
|
|
8649
|
+
);
|
|
8650
|
+
const handleReschedulePick = (0, import_react15.useCallback)(
|
|
8651
|
+
(event, value) => {
|
|
8652
|
+
const newStart = applyDatePick(event.sourceStart, value);
|
|
8653
|
+
if (!newStart) return;
|
|
8654
|
+
const target = rescheduleToStart({ start: event.sourceStart, end: event.sourceEnd }, newStart);
|
|
8655
|
+
if (target && onEventReschedule) onEventReschedule(event.raw, target, event);
|
|
8656
|
+
},
|
|
8657
|
+
[onEventReschedule]
|
|
8658
|
+
);
|
|
8659
|
+
const reschedule = (0, import_react15.useMemo)(() => {
|
|
8660
|
+
if (!rescheduleOptions) return null;
|
|
8661
|
+
return {
|
|
8662
|
+
options: normalizeRescheduleOptions(rescheduleOptions),
|
|
8663
|
+
onPreset: handleReschedulePreset,
|
|
8664
|
+
onPick: handleReschedulePick
|
|
8665
|
+
};
|
|
8666
|
+
}, [rescheduleOptions, handleReschedulePreset, handleReschedulePick]);
|
|
8667
|
+
const safeMonthEventStyle = MONTH_EVENT_STYLES.has(monthEventStyle) ? monthEventStyle : "statusTag";
|
|
8668
|
+
const chipProps = {
|
|
8669
|
+
overlayMode,
|
|
8670
|
+
renderEventDetail,
|
|
8671
|
+
onEventClick,
|
|
8672
|
+
labels,
|
|
8673
|
+
monthEventStyle: safeMonthEventStyle,
|
|
8674
|
+
monthEventMaxChars,
|
|
8675
|
+
reschedule
|
|
8676
|
+
};
|
|
8677
|
+
const resourceLaneData = (0, import_react15.useMemo)(() => {
|
|
8678
|
+
if (view !== "resource") return null;
|
|
8679
|
+
return buildResourceLanes(queried, {
|
|
8680
|
+
resources,
|
|
8681
|
+
resourceLabels,
|
|
8682
|
+
getId: (e) => resolveResourceId(e.raw, resourceField),
|
|
8683
|
+
showUnassignedLane,
|
|
8684
|
+
unassignedLabel: labels.unassigned
|
|
8685
|
+
});
|
|
8686
|
+
}, [view, queried, resources, resourceLabels, resourceField, showUnassignedLane, labels]);
|
|
7657
8687
|
const timeZoneOptions = (0, import_react15.useMemo)(() => {
|
|
7658
8688
|
if (!showTimeZoneSelect) return null;
|
|
7659
8689
|
const base = (timeZoneOptionsProp && timeZoneOptionsProp.length ? timeZoneOptionsProp : DEFAULT_TIME_ZONES).map(
|
|
@@ -7714,6 +8744,19 @@ var Calendar = (props) => {
|
|
|
7714
8744
|
labels
|
|
7715
8745
|
}
|
|
7716
8746
|
);
|
|
8747
|
+
} else if (view === "resource") {
|
|
8748
|
+
body = /* @__PURE__ */ import_react15.default.createElement(
|
|
8749
|
+
ResourceView,
|
|
8750
|
+
{
|
|
8751
|
+
days: gridDays,
|
|
8752
|
+
now: nowWall,
|
|
8753
|
+
lanes: resourceLaneData,
|
|
8754
|
+
maxEventsPerDay,
|
|
8755
|
+
chipProps,
|
|
8756
|
+
labels,
|
|
8757
|
+
renderEmptyState
|
|
8758
|
+
}
|
|
8759
|
+
);
|
|
7717
8760
|
} else if (view === "week" || view === "day") {
|
|
7718
8761
|
body = /* @__PURE__ */ import_react15.default.createElement(
|
|
7719
8762
|
TimeGridView,
|
|
@@ -7743,11 +8786,687 @@ var Calendar = (props) => {
|
|
|
7743
8786
|
}
|
|
7744
8787
|
return /* @__PURE__ */ import_react15.default.createElement(import_ui_extensions15.Flex, { direction: "column", gap: "sm" }, toolbar, body);
|
|
7745
8788
|
};
|
|
8789
|
+
Calendar.displayName = "Calendar";
|
|
7746
8790
|
|
|
7747
|
-
// src/
|
|
8791
|
+
// src/filter/FilterBuilder.jsx
|
|
7748
8792
|
var import_react16 = __toESM(require("react"));
|
|
7749
8793
|
var import_ui_extensions16 = require("@hubspot/ui-extensions");
|
|
7750
8794
|
|
|
8795
|
+
// src/filter/filterTree.js
|
|
8796
|
+
var NUMERIC_OPERATORS = ["EQ", "NEQ", "GT", "GTE", "LT", "LTE", "BETWEEN", "HAS_PROPERTY", "NOT_HAS_PROPERTY"];
|
|
8797
|
+
var FILTER_OPERATORS = {
|
|
8798
|
+
string: ["EQ", "NEQ", "CONTAINS_TOKEN", "NOT_CONTAINS_TOKEN", "HAS_PROPERTY", "NOT_HAS_PROPERTY"],
|
|
8799
|
+
number: NUMERIC_OPERATORS,
|
|
8800
|
+
date: NUMERIC_OPERATORS,
|
|
8801
|
+
datetime: NUMERIC_OPERATORS,
|
|
8802
|
+
enum: ["IN", "NOT_IN", "HAS_PROPERTY", "NOT_HAS_PROPERTY"],
|
|
8803
|
+
bool: ["EQ"]
|
|
8804
|
+
};
|
|
8805
|
+
var ALL_OPERATORS = [...new Set(Object.values(FILTER_OPERATORS).flat())];
|
|
8806
|
+
var BASE_OPERATOR_LABELS = {
|
|
8807
|
+
EQ: "is equal to",
|
|
8808
|
+
NEQ: "is not equal to",
|
|
8809
|
+
CONTAINS_TOKEN: "contains",
|
|
8810
|
+
NOT_CONTAINS_TOKEN: "doesn't contain",
|
|
8811
|
+
GT: "is greater than",
|
|
8812
|
+
GTE: "is greater than or equal to",
|
|
8813
|
+
LT: "is less than",
|
|
8814
|
+
LTE: "is less than or equal to",
|
|
8815
|
+
BETWEEN: "is between",
|
|
8816
|
+
IN: "is any of",
|
|
8817
|
+
NOT_IN: "is none of",
|
|
8818
|
+
HAS_PROPERTY: "is known",
|
|
8819
|
+
NOT_HAS_PROPERTY: "is unknown"
|
|
8820
|
+
};
|
|
8821
|
+
var DATE_OPERATOR_LABELS = {
|
|
8822
|
+
EQ: "is",
|
|
8823
|
+
NEQ: "is not",
|
|
8824
|
+
GT: "is after",
|
|
8825
|
+
GTE: "is on or after",
|
|
8826
|
+
LT: "is before",
|
|
8827
|
+
LTE: "is on or before"
|
|
8828
|
+
};
|
|
8829
|
+
var getOperatorOptions = (type, labelOverrides) => {
|
|
8830
|
+
const operators = FILTER_OPERATORS[type] || [];
|
|
8831
|
+
const dateLabels = type === "date" || type === "datetime" ? DATE_OPERATOR_LABELS : null;
|
|
8832
|
+
return operators.map((operator) => ({
|
|
8833
|
+
label: (labelOverrides == null ? void 0 : labelOverrides[operator]) ?? (dateLabels == null ? void 0 : dateLabels[operator]) ?? BASE_OPERATOR_LABELS[operator] ?? operator,
|
|
8834
|
+
value: operator
|
|
8835
|
+
}));
|
|
8836
|
+
};
|
|
8837
|
+
var operatorExpectsValue = (operator) => operator !== "HAS_PROPERTY" && operator !== "NOT_HAS_PROPERTY";
|
|
8838
|
+
var operatorExpectsHighValue = (operator) => operator === "BETWEEN";
|
|
8839
|
+
var operatorExpectsValues = (operator) => operator === "IN" || operator === "NOT_IN";
|
|
8840
|
+
var isGroupNode = (node) => node != null && node.type === "group";
|
|
8841
|
+
var isConditionNode = (node) => node != null && node.type === "condition";
|
|
8842
|
+
var createCondition = (property = "", operator = "", value, highValue) => {
|
|
8843
|
+
const node = { type: "condition", property, operator };
|
|
8844
|
+
if (value !== void 0) node.value = value;
|
|
8845
|
+
if (highValue !== void 0) node.highValue = highValue;
|
|
8846
|
+
return node;
|
|
8847
|
+
};
|
|
8848
|
+
var createGroup = (operator = "AND", filters = []) => ({
|
|
8849
|
+
type: "group",
|
|
8850
|
+
operator,
|
|
8851
|
+
filters
|
|
8852
|
+
});
|
|
8853
|
+
var getNodeAtPath = (tree, path) => {
|
|
8854
|
+
let node = tree;
|
|
8855
|
+
for (const index of path || []) {
|
|
8856
|
+
if (!isGroupNode(node) || !Array.isArray(node.filters)) return void 0;
|
|
8857
|
+
node = node.filters[index];
|
|
8858
|
+
if (node === void 0) return void 0;
|
|
8859
|
+
}
|
|
8860
|
+
return node;
|
|
8861
|
+
};
|
|
8862
|
+
var updateNodeAtPath = (node, path, fn) => {
|
|
8863
|
+
if (!path || path.length === 0) return fn(node);
|
|
8864
|
+
if (!isGroupNode(node) || !Array.isArray(node.filters)) {
|
|
8865
|
+
throw new Error("filterTree: path descends into a non-group node");
|
|
8866
|
+
}
|
|
8867
|
+
const [index, ...rest] = path;
|
|
8868
|
+
if (typeof index !== "number" || index < 0 || index >= node.filters.length) {
|
|
8869
|
+
throw new Error(`filterTree: no filter at index ${index} (group has ${node.filters.length})`);
|
|
8870
|
+
}
|
|
8871
|
+
const filters = node.filters.slice();
|
|
8872
|
+
filters[index] = updateNodeAtPath(filters[index], rest, fn);
|
|
8873
|
+
return { ...node, filters };
|
|
8874
|
+
};
|
|
8875
|
+
var addFilter = (tree, path, node) => updateNodeAtPath(tree, path, (group) => {
|
|
8876
|
+
if (!isGroupNode(group)) {
|
|
8877
|
+
throw new Error("filterTree: addFilter path must point at a group node");
|
|
8878
|
+
}
|
|
8879
|
+
return { ...group, filters: [...group.filters || [], node] };
|
|
8880
|
+
});
|
|
8881
|
+
var updateFilter = (tree, path, patch) => updateNodeAtPath(
|
|
8882
|
+
tree,
|
|
8883
|
+
path,
|
|
8884
|
+
(node) => typeof patch === "function" ? patch(node) : { ...node, ...patch }
|
|
8885
|
+
);
|
|
8886
|
+
var removeFilter = (tree, path, options = {}) => {
|
|
8887
|
+
if (!path || path.length === 0) {
|
|
8888
|
+
throw new Error("filterTree: cannot remove the root group");
|
|
8889
|
+
}
|
|
8890
|
+
const doRemove = (currentTree, targetPath) => {
|
|
8891
|
+
const parentPath = targetPath.slice(0, -1);
|
|
8892
|
+
const index = targetPath[targetPath.length - 1];
|
|
8893
|
+
return updateNodeAtPath(currentTree, parentPath, (group) => {
|
|
8894
|
+
if (!isGroupNode(group)) {
|
|
8895
|
+
throw new Error("filterTree: removeFilter parent is not a group node");
|
|
8896
|
+
}
|
|
8897
|
+
if (typeof index !== "number" || index < 0 || index >= group.filters.length) {
|
|
8898
|
+
throw new Error(`filterTree: no filter at index ${index} (group has ${group.filters.length})`);
|
|
8899
|
+
}
|
|
8900
|
+
return { ...group, filters: group.filters.filter((_, i) => i !== index) };
|
|
8901
|
+
});
|
|
8902
|
+
};
|
|
8903
|
+
let next = doRemove(tree, path);
|
|
8904
|
+
if (options.pruneEmptyGroups) {
|
|
8905
|
+
let parentPath = path.slice(0, -1);
|
|
8906
|
+
while (parentPath.length > 0) {
|
|
8907
|
+
const parent = getNodeAtPath(next, parentPath);
|
|
8908
|
+
if (!isGroupNode(parent) || parent.filters.length > 0) break;
|
|
8909
|
+
next = doRemove(next, parentPath);
|
|
8910
|
+
parentPath = parentPath.slice(0, -1);
|
|
8911
|
+
}
|
|
8912
|
+
}
|
|
8913
|
+
return next;
|
|
8914
|
+
};
|
|
8915
|
+
var cloneNode = (node) => {
|
|
8916
|
+
if (Array.isArray(node)) return node.map(cloneNode);
|
|
8917
|
+
if (node !== null && typeof node === "object") {
|
|
8918
|
+
const copy = {};
|
|
8919
|
+
for (const key of Object.keys(node)) copy[key] = cloneNode(node[key]);
|
|
8920
|
+
return copy;
|
|
8921
|
+
}
|
|
8922
|
+
return node;
|
|
8923
|
+
};
|
|
8924
|
+
var duplicateFilter = (tree, path) => {
|
|
8925
|
+
if (!path || path.length === 0) {
|
|
8926
|
+
throw new Error("filterTree: cannot duplicate the root group");
|
|
8927
|
+
}
|
|
8928
|
+
const parentPath = path.slice(0, -1);
|
|
8929
|
+
const index = path[path.length - 1];
|
|
8930
|
+
return updateNodeAtPath(tree, parentPath, (group) => {
|
|
8931
|
+
if (!isGroupNode(group)) {
|
|
8932
|
+
throw new Error("filterTree: duplicateFilter parent is not a group node");
|
|
8933
|
+
}
|
|
8934
|
+
if (typeof index !== "number" || index < 0 || index >= group.filters.length) {
|
|
8935
|
+
throw new Error(`filterTree: no filter at index ${index} (group has ${group.filters.length})`);
|
|
8936
|
+
}
|
|
8937
|
+
const filters = group.filters.slice();
|
|
8938
|
+
filters.splice(index + 1, 0, cloneNode(group.filters[index]));
|
|
8939
|
+
return { ...group, filters };
|
|
8940
|
+
});
|
|
8941
|
+
};
|
|
8942
|
+
var countConditions = (node) => {
|
|
8943
|
+
if (isConditionNode(node)) return 1;
|
|
8944
|
+
if (!isGroupNode(node) || !Array.isArray(node.filters)) return 0;
|
|
8945
|
+
return node.filters.reduce((sum, child) => sum + countConditions(child), 0);
|
|
8946
|
+
};
|
|
8947
|
+
var changeConditionProperty = (condition, property) => {
|
|
8948
|
+
const name = typeof property === "string" ? property : (property == null ? void 0 : property.name) ?? "";
|
|
8949
|
+
const type = typeof property === "object" && property !== null ? property.type : void 0;
|
|
8950
|
+
const operators = FILTER_OPERATORS[type] || [];
|
|
8951
|
+
const operator = operators.includes(condition == null ? void 0 : condition.operator) ? condition.operator : operators[0] ?? "";
|
|
8952
|
+
const next = { type: "condition", property: name, operator };
|
|
8953
|
+
if (operatorExpectsValues(operator)) next.value = [];
|
|
8954
|
+
return next;
|
|
8955
|
+
};
|
|
8956
|
+
var changeConditionOperator = (condition, operator) => {
|
|
8957
|
+
const next = { type: "condition", property: (condition == null ? void 0 : condition.property) ?? "", operator };
|
|
8958
|
+
if (!operatorExpectsValue(operator)) return next;
|
|
8959
|
+
if (operatorExpectsValues(operator)) {
|
|
8960
|
+
next.value = Array.isArray(condition == null ? void 0 : condition.value) ? condition.value : [];
|
|
8961
|
+
return next;
|
|
8962
|
+
}
|
|
8963
|
+
if ((condition == null ? void 0 : condition.value) !== void 0 && !Array.isArray(condition.value)) {
|
|
8964
|
+
next.value = condition.value;
|
|
8965
|
+
}
|
|
8966
|
+
if (operatorExpectsHighValue(operator) && (condition == null ? void 0 : condition.highValue) !== void 0) {
|
|
8967
|
+
next.highValue = condition.highValue;
|
|
8968
|
+
}
|
|
8969
|
+
return next;
|
|
8970
|
+
};
|
|
8971
|
+
var isMissing = (value) => value == null || value === "";
|
|
8972
|
+
var validateTree = (tree, properties) => {
|
|
8973
|
+
const errors = [];
|
|
8974
|
+
const byName = Array.isArray(properties) ? new Map(properties.map((property) => [property.name, property])) : null;
|
|
8975
|
+
if (!isGroupNode(tree)) {
|
|
8976
|
+
return { valid: false, errors: [{ path: [], message: "Root must be a group node." }] };
|
|
8977
|
+
}
|
|
8978
|
+
const visitCondition = (node, path) => {
|
|
8979
|
+
if (!node.property) {
|
|
8980
|
+
errors.push({ path, message: "Condition is missing a property." });
|
|
8981
|
+
return;
|
|
8982
|
+
}
|
|
8983
|
+
let type;
|
|
8984
|
+
if (byName) {
|
|
8985
|
+
const def = byName.get(node.property);
|
|
8986
|
+
if (!def) {
|
|
8987
|
+
errors.push({ path, message: `Unknown property "${node.property}".` });
|
|
8988
|
+
return;
|
|
8989
|
+
}
|
|
8990
|
+
type = def.type;
|
|
8991
|
+
}
|
|
8992
|
+
const allowed = type !== void 0 ? FILTER_OPERATORS[type] || [] : ALL_OPERATORS;
|
|
8993
|
+
if (!node.operator) {
|
|
8994
|
+
errors.push({ path, message: "Condition is missing an operator." });
|
|
8995
|
+
return;
|
|
8996
|
+
}
|
|
8997
|
+
if (!allowed.includes(node.operator)) {
|
|
8998
|
+
errors.push({
|
|
8999
|
+
path,
|
|
9000
|
+
message: type !== void 0 ? `Operator "${node.operator}" is not valid for type "${type}".` : `Unknown operator "${node.operator}".`
|
|
9001
|
+
});
|
|
9002
|
+
return;
|
|
9003
|
+
}
|
|
9004
|
+
if (!operatorExpectsValue(node.operator)) return;
|
|
9005
|
+
if (operatorExpectsValues(node.operator)) {
|
|
9006
|
+
if (!Array.isArray(node.value) || node.value.length === 0) {
|
|
9007
|
+
errors.push({ path, message: `Operator "${node.operator}" requires at least one value.` });
|
|
9008
|
+
}
|
|
9009
|
+
return;
|
|
9010
|
+
}
|
|
9011
|
+
if (isMissing(node.value)) {
|
|
9012
|
+
errors.push({ path, message: `Operator "${node.operator}" requires a value.` });
|
|
9013
|
+
}
|
|
9014
|
+
if (operatorExpectsHighValue(node.operator) && isMissing(node.highValue)) {
|
|
9015
|
+
errors.push({ path, message: 'Operator "BETWEEN" requires an upper bound (highValue).' });
|
|
9016
|
+
}
|
|
9017
|
+
};
|
|
9018
|
+
const visit = (node, path) => {
|
|
9019
|
+
if (node == null || typeof node !== "object") {
|
|
9020
|
+
errors.push({ path, message: "Filter node must be an object." });
|
|
9021
|
+
return;
|
|
9022
|
+
}
|
|
9023
|
+
if (node.type === "group") {
|
|
9024
|
+
if (node.operator !== "AND" && node.operator !== "OR") {
|
|
9025
|
+
errors.push({ path, message: `Group operator must be "AND" or "OR" (got "${node.operator}").` });
|
|
9026
|
+
}
|
|
9027
|
+
if (!Array.isArray(node.filters)) {
|
|
9028
|
+
errors.push({ path, message: "Group filters must be an array." });
|
|
9029
|
+
return;
|
|
9030
|
+
}
|
|
9031
|
+
if (node.filters.length === 0 && path.length > 0) {
|
|
9032
|
+
errors.push({ path, message: "Group has no filters." });
|
|
9033
|
+
}
|
|
9034
|
+
node.filters.forEach((child, index) => visit(child, [...path, index]));
|
|
9035
|
+
return;
|
|
9036
|
+
}
|
|
9037
|
+
if (node.type === "condition") {
|
|
9038
|
+
visitCondition(node, path);
|
|
9039
|
+
return;
|
|
9040
|
+
}
|
|
9041
|
+
errors.push({ path, message: `Unknown node type "${node.type}".` });
|
|
9042
|
+
};
|
|
9043
|
+
visit(tree, []);
|
|
9044
|
+
return { valid: errors.length === 0, errors };
|
|
9045
|
+
};
|
|
9046
|
+
var isDateValueObject4 = (value) => value != null && typeof value === "object" && typeof value.year === "number" && typeof value.month === "number" && typeof value.date === "number";
|
|
9047
|
+
var dateValueToTimestamp = (dateObj) => new Date(dateObj.year, dateObj.month, dateObj.date).getTime();
|
|
9048
|
+
var coerceCrmValue = (value) => {
|
|
9049
|
+
if (isDateValueObject4(value)) return dateValueToTimestamp(value);
|
|
9050
|
+
if (typeof value === "boolean") return String(value);
|
|
9051
|
+
return value;
|
|
9052
|
+
};
|
|
9053
|
+
var conditionToCrmFilter = (condition, options = {}) => {
|
|
9054
|
+
const { coerceValues = true } = options;
|
|
9055
|
+
if (!isConditionNode(condition)) {
|
|
9056
|
+
throw new Error("filterTree: conditionToCrmFilter expects a condition node");
|
|
9057
|
+
}
|
|
9058
|
+
if (!condition.property) {
|
|
9059
|
+
throw new Error("filterTree: condition is missing a property");
|
|
9060
|
+
}
|
|
9061
|
+
if (!condition.operator) {
|
|
9062
|
+
throw new Error(`filterTree: condition on "${condition.property}" is missing an operator`);
|
|
9063
|
+
}
|
|
9064
|
+
const coerce = coerceValues ? coerceCrmValue : (value) => value;
|
|
9065
|
+
const filter = { propertyName: condition.property, operator: condition.operator };
|
|
9066
|
+
if (!operatorExpectsValue(condition.operator)) return filter;
|
|
9067
|
+
if (operatorExpectsValues(condition.operator)) {
|
|
9068
|
+
const values = Array.isArray(condition.value) ? condition.value : condition.value == null ? [] : [condition.value];
|
|
9069
|
+
filter.values = values.map(coerce);
|
|
9070
|
+
return filter;
|
|
9071
|
+
}
|
|
9072
|
+
filter.value = coerce(condition.value);
|
|
9073
|
+
if (operatorExpectsHighValue(condition.operator)) {
|
|
9074
|
+
filter.highValue = coerce(condition.highValue);
|
|
9075
|
+
}
|
|
9076
|
+
return filter;
|
|
9077
|
+
};
|
|
9078
|
+
var nodeToDnf = (node, path, options) => {
|
|
9079
|
+
if (isConditionNode(node)) {
|
|
9080
|
+
return [[conditionToCrmFilter(node, options)]];
|
|
9081
|
+
}
|
|
9082
|
+
if (!isGroupNode(node)) {
|
|
9083
|
+
throw new Error(`filterTree: unknown node type "${node == null ? void 0 : node.type}" at [${path.join(", ")}]`);
|
|
9084
|
+
}
|
|
9085
|
+
if (!Array.isArray(node.filters) || node.filters.length === 0) {
|
|
9086
|
+
throw new Error(
|
|
9087
|
+
`filterTree: empty group at [${path.join(", ")}] cannot be converted \u2014 remove it or add a condition (run validateTree first)`
|
|
9088
|
+
);
|
|
9089
|
+
}
|
|
9090
|
+
const childDnfs = node.filters.map((child, index) => nodeToDnf(child, [...path, index], options));
|
|
9091
|
+
if (node.operator === "OR") {
|
|
9092
|
+
return childDnfs.flat();
|
|
9093
|
+
}
|
|
9094
|
+
return childDnfs.reduce(
|
|
9095
|
+
(acc, childDnf) => {
|
|
9096
|
+
const out = [];
|
|
9097
|
+
for (const left of acc) {
|
|
9098
|
+
for (const right of childDnf) out.push([...left, ...right]);
|
|
9099
|
+
}
|
|
9100
|
+
return out;
|
|
9101
|
+
},
|
|
9102
|
+
[[]]
|
|
9103
|
+
);
|
|
9104
|
+
};
|
|
9105
|
+
var toCrmSearchFilterGroups = (tree, options = {}) => {
|
|
9106
|
+
const {
|
|
9107
|
+
maxGroups = 5,
|
|
9108
|
+
maxFiltersPerGroup = 6,
|
|
9109
|
+
maxTotalFilters = 18,
|
|
9110
|
+
enforceLimits = true,
|
|
9111
|
+
coerceValues = true
|
|
9112
|
+
} = options;
|
|
9113
|
+
if (!isGroupNode(tree)) {
|
|
9114
|
+
throw new Error("filterTree: toCrmSearchFilterGroups expects a group node at the root");
|
|
9115
|
+
}
|
|
9116
|
+
if (!Array.isArray(tree.filters) || tree.filters.length === 0) {
|
|
9117
|
+
return { filterGroups: [] };
|
|
9118
|
+
}
|
|
9119
|
+
const conjunctions = nodeToDnf(tree, [], { coerceValues });
|
|
9120
|
+
if (enforceLimits) {
|
|
9121
|
+
if (conjunctions.length > maxGroups) {
|
|
9122
|
+
throw new Error(
|
|
9123
|
+
`filterTree: tree expands to ${conjunctions.length} filterGroups; HubSpot CRM search allows at most ${maxGroups}. Reduce OR branches (each OR nested under an AND multiplies groups).`
|
|
9124
|
+
);
|
|
9125
|
+
}
|
|
9126
|
+
const oversized = conjunctions.findIndex((filters) => filters.length > maxFiltersPerGroup);
|
|
9127
|
+
if (oversized !== -1) {
|
|
9128
|
+
throw new Error(
|
|
9129
|
+
`filterTree: filterGroup ${oversized} has ${conjunctions[oversized].length} filters; HubSpot CRM search allows at most ${maxFiltersPerGroup} per group.`
|
|
9130
|
+
);
|
|
9131
|
+
}
|
|
9132
|
+
const total = conjunctions.reduce((sum, filters) => sum + filters.length, 0);
|
|
9133
|
+
if (total > maxTotalFilters) {
|
|
9134
|
+
throw new Error(
|
|
9135
|
+
`filterTree: tree expands to ${total} total filters; HubSpot CRM search allows at most ${maxTotalFilters}.`
|
|
9136
|
+
);
|
|
9137
|
+
}
|
|
9138
|
+
}
|
|
9139
|
+
return { filterGroups: conjunctions.map((filters) => ({ filters })) };
|
|
9140
|
+
};
|
|
9141
|
+
|
|
9142
|
+
// src/filter/FilterBuilder.jsx
|
|
9143
|
+
var DEFAULT_LABELS6 = {
|
|
9144
|
+
addFilter: "Add filter",
|
|
9145
|
+
addGroup: "Add filter group",
|
|
9146
|
+
remove: "Remove filter",
|
|
9147
|
+
removeGroup: "Delete group",
|
|
9148
|
+
cloneGroup: "Clone group",
|
|
9149
|
+
group: "Group",
|
|
9150
|
+
and: "AND",
|
|
9151
|
+
or: "OR",
|
|
9152
|
+
property: "Select a property",
|
|
9153
|
+
operator: "Select an operator",
|
|
9154
|
+
value: "Enter a value",
|
|
9155
|
+
values: "Select values",
|
|
9156
|
+
between: "and",
|
|
9157
|
+
empty: "No filters yet.",
|
|
9158
|
+
true: "True",
|
|
9159
|
+
false: "False"
|
|
9160
|
+
};
|
|
9161
|
+
var GROUP_OPERATOR_OPTIONS = (labels) => [
|
|
9162
|
+
{ label: labels.and, value: "AND" },
|
|
9163
|
+
{ label: labels.or, value: "OR" }
|
|
9164
|
+
];
|
|
9165
|
+
var normalizeTree = (tree) => isGroupNode(tree) ? tree : createGroup("AND", []);
|
|
9166
|
+
var pathName = (prefix, path, suffix) => `${prefix}-${path.length ? path.join("-") : "root"}-${suffix}`;
|
|
9167
|
+
var ValueEditor = ({ condition, propertyDef, path, namePrefix, labels, readOnly, onPatch }) => {
|
|
9168
|
+
const { operator } = condition;
|
|
9169
|
+
if (!operator || !operatorExpectsValue(operator)) return null;
|
|
9170
|
+
const type = (propertyDef == null ? void 0 : propertyDef.type) || "string";
|
|
9171
|
+
const setValue = (value) => onPatch(path, { value });
|
|
9172
|
+
const setHighValue = (highValue) => onPatch(path, { highValue });
|
|
9173
|
+
if (operatorExpectsValues(operator)) {
|
|
9174
|
+
return /* @__PURE__ */ import_react16.default.createElement(import_ui_extensions16.Box, { flex: 1 }, /* @__PURE__ */ import_react16.default.createElement(
|
|
9175
|
+
import_ui_extensions16.MultiSelect,
|
|
9176
|
+
{
|
|
9177
|
+
label: "",
|
|
9178
|
+
name: pathName(namePrefix, path, "value"),
|
|
9179
|
+
placeholder: labels.values,
|
|
9180
|
+
options: (propertyDef == null ? void 0 : propertyDef.options) || [],
|
|
9181
|
+
value: Array.isArray(condition.value) ? condition.value : [],
|
|
9182
|
+
readOnly,
|
|
9183
|
+
onChange: setValue
|
|
9184
|
+
}
|
|
9185
|
+
));
|
|
9186
|
+
}
|
|
9187
|
+
if (type === "bool") {
|
|
9188
|
+
return /* @__PURE__ */ import_react16.default.createElement(import_ui_extensions16.Box, { flex: 1 }, /* @__PURE__ */ import_react16.default.createElement(
|
|
9189
|
+
import_ui_extensions16.Select,
|
|
9190
|
+
{
|
|
9191
|
+
label: "",
|
|
9192
|
+
name: pathName(namePrefix, path, "value"),
|
|
9193
|
+
placeholder: labels.value,
|
|
9194
|
+
options: [
|
|
9195
|
+
{ label: labels.true, value: "true" },
|
|
9196
|
+
{ label: labels.false, value: "false" }
|
|
9197
|
+
],
|
|
9198
|
+
value: condition.value,
|
|
9199
|
+
readOnly,
|
|
9200
|
+
onChange: setValue
|
|
9201
|
+
}
|
|
9202
|
+
));
|
|
9203
|
+
}
|
|
9204
|
+
if (type === "enum") {
|
|
9205
|
+
return /* @__PURE__ */ import_react16.default.createElement(import_ui_extensions16.Box, { flex: 1 }, /* @__PURE__ */ import_react16.default.createElement(
|
|
9206
|
+
import_ui_extensions16.Select,
|
|
9207
|
+
{
|
|
9208
|
+
label: "",
|
|
9209
|
+
name: pathName(namePrefix, path, "value"),
|
|
9210
|
+
placeholder: labels.value,
|
|
9211
|
+
options: (propertyDef == null ? void 0 : propertyDef.options) || [],
|
|
9212
|
+
value: condition.value,
|
|
9213
|
+
readOnly,
|
|
9214
|
+
onChange: setValue
|
|
9215
|
+
}
|
|
9216
|
+
));
|
|
9217
|
+
}
|
|
9218
|
+
const isBetween = operatorExpectsHighValue(operator);
|
|
9219
|
+
if (type === "number") {
|
|
9220
|
+
return /* @__PURE__ */ import_react16.default.createElement(import_react16.default.Fragment, null, /* @__PURE__ */ import_react16.default.createElement(import_ui_extensions16.Box, { flex: 1 }, /* @__PURE__ */ import_react16.default.createElement(
|
|
9221
|
+
import_ui_extensions16.NumberInput,
|
|
9222
|
+
{
|
|
9223
|
+
label: "",
|
|
9224
|
+
name: pathName(namePrefix, path, "value"),
|
|
9225
|
+
placeholder: labels.value,
|
|
9226
|
+
value: condition.value ?? "",
|
|
9227
|
+
readOnly,
|
|
9228
|
+
onChange: setValue
|
|
9229
|
+
}
|
|
9230
|
+
)), isBetween && /* @__PURE__ */ import_react16.default.createElement(import_react16.default.Fragment, null, /* @__PURE__ */ import_react16.default.createElement(import_ui_extensions16.Text, { variant: "microcopy" }, labels.between), /* @__PURE__ */ import_react16.default.createElement(import_ui_extensions16.Box, { flex: 1 }, /* @__PURE__ */ import_react16.default.createElement(
|
|
9231
|
+
import_ui_extensions16.NumberInput,
|
|
9232
|
+
{
|
|
9233
|
+
label: "",
|
|
9234
|
+
name: pathName(namePrefix, path, "high-value"),
|
|
9235
|
+
placeholder: labels.value,
|
|
9236
|
+
value: condition.highValue ?? "",
|
|
9237
|
+
readOnly,
|
|
9238
|
+
onChange: setHighValue
|
|
9239
|
+
}
|
|
9240
|
+
))));
|
|
9241
|
+
}
|
|
9242
|
+
if (type === "date" || type === "datetime") {
|
|
9243
|
+
return /* @__PURE__ */ import_react16.default.createElement(import_react16.default.Fragment, null, /* @__PURE__ */ import_react16.default.createElement(import_ui_extensions16.Box, { flex: 1 }, /* @__PURE__ */ import_react16.default.createElement(
|
|
9244
|
+
import_ui_extensions16.DateInput,
|
|
9245
|
+
{
|
|
9246
|
+
label: "",
|
|
9247
|
+
name: pathName(namePrefix, path, "value"),
|
|
9248
|
+
format: "medium",
|
|
9249
|
+
value: condition.value ?? null,
|
|
9250
|
+
readOnly,
|
|
9251
|
+
onChange: setValue
|
|
9252
|
+
}
|
|
9253
|
+
)), isBetween && /* @__PURE__ */ import_react16.default.createElement(import_react16.default.Fragment, null, /* @__PURE__ */ import_react16.default.createElement(import_ui_extensions16.Text, { variant: "microcopy" }, labels.between), /* @__PURE__ */ import_react16.default.createElement(import_ui_extensions16.Box, { flex: 1 }, /* @__PURE__ */ import_react16.default.createElement(
|
|
9254
|
+
import_ui_extensions16.DateInput,
|
|
9255
|
+
{
|
|
9256
|
+
label: "",
|
|
9257
|
+
name: pathName(namePrefix, path, "high-value"),
|
|
9258
|
+
format: "medium",
|
|
9259
|
+
value: condition.highValue ?? null,
|
|
9260
|
+
readOnly,
|
|
9261
|
+
onChange: setHighValue
|
|
9262
|
+
}
|
|
9263
|
+
))));
|
|
9264
|
+
}
|
|
9265
|
+
return /* @__PURE__ */ import_react16.default.createElement(import_ui_extensions16.Box, { flex: 1 }, /* @__PURE__ */ import_react16.default.createElement(
|
|
9266
|
+
import_ui_extensions16.Input,
|
|
9267
|
+
{
|
|
9268
|
+
label: "",
|
|
9269
|
+
name: pathName(namePrefix, path, "value"),
|
|
9270
|
+
placeholder: labels.value,
|
|
9271
|
+
value: condition.value ?? "",
|
|
9272
|
+
readOnly,
|
|
9273
|
+
onChange: setValue
|
|
9274
|
+
}
|
|
9275
|
+
));
|
|
9276
|
+
};
|
|
9277
|
+
var IconButton = ({ icon, label, onClick, size }) => /* @__PURE__ */ import_react16.default.createElement(import_ui_extensions16.Button, { size: "extra-small", variant: "transparent", onClick }, /* @__PURE__ */ import_react16.default.createElement(Icon, { name: icon, screenReaderText: label, ...size ? { size } : {} }));
|
|
9278
|
+
var ConditionRow = ({
|
|
9279
|
+
condition,
|
|
9280
|
+
path,
|
|
9281
|
+
properties,
|
|
9282
|
+
propertyOptions,
|
|
9283
|
+
namePrefix,
|
|
9284
|
+
labels,
|
|
9285
|
+
operatorLabels,
|
|
9286
|
+
readOnly,
|
|
9287
|
+
onPropertyChange,
|
|
9288
|
+
onOperatorChange,
|
|
9289
|
+
onPatch,
|
|
9290
|
+
onRemove
|
|
9291
|
+
}) => {
|
|
9292
|
+
const propertyDef = properties.find((property) => property.name === condition.property);
|
|
9293
|
+
const operatorOptions = getOperatorOptions(propertyDef == null ? void 0 : propertyDef.type, operatorLabels);
|
|
9294
|
+
return /* @__PURE__ */ import_react16.default.createElement(import_ui_extensions16.Flex, { direction: "row", gap: "xs", align: "center", wrap: "wrap" }, /* @__PURE__ */ import_react16.default.createElement(import_ui_extensions16.Box, { flex: 1 }, /* @__PURE__ */ import_react16.default.createElement(
|
|
9295
|
+
import_ui_extensions16.Select,
|
|
9296
|
+
{
|
|
9297
|
+
label: "",
|
|
9298
|
+
name: pathName(namePrefix, path, "property"),
|
|
9299
|
+
placeholder: labels.property,
|
|
9300
|
+
options: propertyOptions,
|
|
9301
|
+
value: condition.property || void 0,
|
|
9302
|
+
readOnly,
|
|
9303
|
+
onChange: (name) => onPropertyChange(path, name)
|
|
9304
|
+
}
|
|
9305
|
+
)), /* @__PURE__ */ import_react16.default.createElement(import_ui_extensions16.Box, { flex: 1 }, /* @__PURE__ */ import_react16.default.createElement(
|
|
9306
|
+
import_ui_extensions16.Select,
|
|
9307
|
+
{
|
|
9308
|
+
label: "",
|
|
9309
|
+
name: pathName(namePrefix, path, "operator"),
|
|
9310
|
+
placeholder: labels.operator,
|
|
9311
|
+
options: operatorOptions,
|
|
9312
|
+
value: condition.operator || void 0,
|
|
9313
|
+
readOnly: readOnly || !condition.property,
|
|
9314
|
+
onChange: (operator) => onOperatorChange(path, operator)
|
|
9315
|
+
}
|
|
9316
|
+
)), /* @__PURE__ */ import_react16.default.createElement(
|
|
9317
|
+
ValueEditor,
|
|
9318
|
+
{
|
|
9319
|
+
condition,
|
|
9320
|
+
propertyDef,
|
|
9321
|
+
path,
|
|
9322
|
+
namePrefix,
|
|
9323
|
+
labels,
|
|
9324
|
+
readOnly,
|
|
9325
|
+
onPatch
|
|
9326
|
+
}
|
|
9327
|
+
), !readOnly && /* @__PURE__ */ import_react16.default.createElement(IconButton, { icon: "remove", label: labels.remove, onClick: () => onRemove(path) }));
|
|
9328
|
+
};
|
|
9329
|
+
var GroupOperatorSeparator = ({ group, path, namePrefix, labels, readOnly, index, onGroupOperatorChange }) => {
|
|
9330
|
+
if (readOnly) {
|
|
9331
|
+
return /* @__PURE__ */ import_react16.default.createElement(import_ui_extensions16.Text, { variant: "microcopy", format: { fontWeight: "demibold" } }, group.operator === "OR" ? labels.or : labels.and);
|
|
9332
|
+
}
|
|
9333
|
+
return /* @__PURE__ */ import_react16.default.createElement(import_ui_extensions16.Box, { alignSelf: "start" }, /* @__PURE__ */ import_react16.default.createElement(
|
|
9334
|
+
import_ui_extensions16.Select,
|
|
9335
|
+
{
|
|
9336
|
+
label: "",
|
|
9337
|
+
name: pathName(namePrefix, path, `separator-${index}`),
|
|
9338
|
+
variant: "transparent",
|
|
9339
|
+
options: GROUP_OPERATOR_OPTIONS(labels),
|
|
9340
|
+
value: group.operator,
|
|
9341
|
+
onChange: (operator) => onGroupOperatorChange(path, operator)
|
|
9342
|
+
}
|
|
9343
|
+
));
|
|
9344
|
+
};
|
|
9345
|
+
var GroupEditor = ({ group, path, depth, ctx }) => {
|
|
9346
|
+
const { labels, maxDepth, readOnly, namePrefix, handlers } = ctx;
|
|
9347
|
+
const isRoot = path.length === 0;
|
|
9348
|
+
const filters = Array.isArray(group.filters) ? group.filters : [];
|
|
9349
|
+
let groupNumber = 0;
|
|
9350
|
+
const children = filters.map((child, index) => {
|
|
9351
|
+
const childPath = [...path, index];
|
|
9352
|
+
if (isGroupNode(child)) groupNumber += 1;
|
|
9353
|
+
const row = isGroupNode(child) ? /* @__PURE__ */ import_react16.default.createElement(import_ui_extensions16.Tile, { compact: true }, /* @__PURE__ */ import_react16.default.createElement(import_ui_extensions16.Flex, { direction: "column", gap: "xs" }, /* @__PURE__ */ import_react16.default.createElement(import_ui_extensions16.Flex, { direction: "row", justify: "between", align: "center" }, /* @__PURE__ */ import_react16.default.createElement(import_ui_extensions16.Text, { format: { fontWeight: "demibold" } }, `${labels.group}\xA0${groupNumber}`), !readOnly && /* @__PURE__ */ import_react16.default.createElement(import_ui_extensions16.Flex, { direction: "row", gap: "xs", justify: "end" }, /* @__PURE__ */ import_react16.default.createElement(
|
|
9354
|
+
IconButton,
|
|
9355
|
+
{
|
|
9356
|
+
icon: "copy",
|
|
9357
|
+
label: labels.cloneGroup,
|
|
9358
|
+
size: "sm",
|
|
9359
|
+
onClick: () => handlers.onDuplicate(childPath)
|
|
9360
|
+
}
|
|
9361
|
+
), /* @__PURE__ */ import_react16.default.createElement(
|
|
9362
|
+
IconButton,
|
|
9363
|
+
{
|
|
9364
|
+
icon: "delete",
|
|
9365
|
+
label: labels.removeGroup,
|
|
9366
|
+
size: "sm",
|
|
9367
|
+
onClick: () => handlers.onRemove(childPath)
|
|
9368
|
+
}
|
|
9369
|
+
))), /* @__PURE__ */ import_react16.default.createElement(GroupEditor, { group: child, path: childPath, depth: depth + 1, ctx }))) : /* @__PURE__ */ import_react16.default.createElement(
|
|
9370
|
+
ConditionRow,
|
|
9371
|
+
{
|
|
9372
|
+
condition: child,
|
|
9373
|
+
path: childPath,
|
|
9374
|
+
properties: ctx.properties,
|
|
9375
|
+
propertyOptions: ctx.propertyOptions,
|
|
9376
|
+
namePrefix,
|
|
9377
|
+
labels,
|
|
9378
|
+
operatorLabels: ctx.operatorLabels,
|
|
9379
|
+
readOnly,
|
|
9380
|
+
onPropertyChange: handlers.onPropertyChange,
|
|
9381
|
+
onOperatorChange: handlers.onOperatorChange,
|
|
9382
|
+
onPatch: handlers.onPatch,
|
|
9383
|
+
onRemove: handlers.onRemove
|
|
9384
|
+
}
|
|
9385
|
+
);
|
|
9386
|
+
return /* @__PURE__ */ import_react16.default.createElement(import_react16.default.Fragment, { key: childPath.join("-") }, index > 0 && /* @__PURE__ */ import_react16.default.createElement(
|
|
9387
|
+
GroupOperatorSeparator,
|
|
9388
|
+
{
|
|
9389
|
+
group,
|
|
9390
|
+
path,
|
|
9391
|
+
namePrefix,
|
|
9392
|
+
labels,
|
|
9393
|
+
readOnly,
|
|
9394
|
+
index,
|
|
9395
|
+
onGroupOperatorChange: handlers.onGroupOperatorChange
|
|
9396
|
+
}
|
|
9397
|
+
), row);
|
|
9398
|
+
});
|
|
9399
|
+
return (
|
|
9400
|
+
// Nested groups pack tight (row / AND-OR / row reads as one unit, like
|
|
9401
|
+
// HubSpot's builder); the root keeps more air between its sections.
|
|
9402
|
+
/* @__PURE__ */ import_react16.default.createElement(import_ui_extensions16.Flex, { direction: "column", gap: isRoot ? "sm" : "xs" }, isRoot && filters.length === 0 && /* @__PURE__ */ import_react16.default.createElement(import_ui_extensions16.Text, { variant: "microcopy" }, labels.empty), children, !readOnly && /* @__PURE__ */ import_react16.default.createElement(import_ui_extensions16.Flex, { direction: "row", gap: "md", align: "center" }, /* @__PURE__ */ import_react16.default.createElement(
|
|
9403
|
+
import_ui_extensions16.Button,
|
|
9404
|
+
{
|
|
9405
|
+
size: "extra-small",
|
|
9406
|
+
variant: "transparent",
|
|
9407
|
+
onClick: () => handlers.onAddCondition(path)
|
|
9408
|
+
},
|
|
9409
|
+
/* @__PURE__ */ import_react16.default.createElement(Icon, { name: "add" }),
|
|
9410
|
+
" ",
|
|
9411
|
+
labels.addFilter
|
|
9412
|
+
), depth < maxDepth && /* @__PURE__ */ import_react16.default.createElement(
|
|
9413
|
+
import_ui_extensions16.Button,
|
|
9414
|
+
{
|
|
9415
|
+
size: "extra-small",
|
|
9416
|
+
variant: "transparent",
|
|
9417
|
+
onClick: () => handlers.onAddGroup(path)
|
|
9418
|
+
},
|
|
9419
|
+
/* @__PURE__ */ import_react16.default.createElement(Icon, { name: "add" }),
|
|
9420
|
+
" ",
|
|
9421
|
+
labels.addGroup
|
|
9422
|
+
)))
|
|
9423
|
+
);
|
|
9424
|
+
};
|
|
9425
|
+
var FilterBuilder = ({
|
|
9426
|
+
properties = [],
|
|
9427
|
+
value,
|
|
9428
|
+
defaultValue,
|
|
9429
|
+
onChange,
|
|
9430
|
+
maxDepth = 2,
|
|
9431
|
+
labels: labelOverrides,
|
|
9432
|
+
operatorLabels,
|
|
9433
|
+
readOnly = false,
|
|
9434
|
+
namePrefix = "filter-builder",
|
|
9435
|
+
...rest
|
|
9436
|
+
}) => {
|
|
9437
|
+
const labels = (0, import_react16.useMemo)(() => ({ ...DEFAULT_LABELS6, ...labelOverrides || {} }), [labelOverrides]);
|
|
9438
|
+
const [internalTree, setInternalTree] = (0, import_react16.useState)(() => normalizeTree(defaultValue));
|
|
9439
|
+
const isControlled = value !== void 0;
|
|
9440
|
+
const tree = isControlled ? normalizeTree(value) : internalTree;
|
|
9441
|
+
const propertyOptions = (0, import_react16.useMemo)(
|
|
9442
|
+
() => properties.map((property) => ({ label: property.label ?? property.name, value: property.name })),
|
|
9443
|
+
[properties]
|
|
9444
|
+
);
|
|
9445
|
+
const commit = (next) => {
|
|
9446
|
+
if (!isControlled) setInternalTree(next);
|
|
9447
|
+
onChange == null ? void 0 : onChange(next);
|
|
9448
|
+
};
|
|
9449
|
+
const handlers = {
|
|
9450
|
+
onAddCondition: (groupPath) => commit(addFilter(tree, groupPath, createCondition())),
|
|
9451
|
+
onAddGroup: (groupPath) => commit(addFilter(tree, groupPath, createGroup("AND", [createCondition()]))),
|
|
9452
|
+
onRemove: (path) => commit(removeFilter(tree, path, { pruneEmptyGroups: true })),
|
|
9453
|
+
onDuplicate: (path) => commit(duplicateFilter(tree, path)),
|
|
9454
|
+
onGroupOperatorChange: (groupPath, operator) => commit(updateFilter(tree, groupPath, { operator })),
|
|
9455
|
+
onPropertyChange: (path, name) => {
|
|
9456
|
+
const def = properties.find((property) => property.name === name);
|
|
9457
|
+
commit(updateFilter(tree, path, (node) => changeConditionProperty(node, def ?? name)));
|
|
9458
|
+
},
|
|
9459
|
+
onOperatorChange: (path, operator) => commit(updateFilter(tree, path, (node) => changeConditionOperator(node, operator))),
|
|
9460
|
+
onPatch: (path, patch) => commit(updateFilter(tree, path, patch))
|
|
9461
|
+
};
|
|
9462
|
+
const ctx = { properties, propertyOptions, labels, operatorLabels, maxDepth, readOnly, namePrefix, handlers };
|
|
9463
|
+
return /* @__PURE__ */ import_react16.default.createElement(import_ui_extensions16.Flex, { direction: "column", gap: "sm", ...rest }, /* @__PURE__ */ import_react16.default.createElement(GroupEditor, { group: tree, path: [], depth: 1, ctx }));
|
|
9464
|
+
};
|
|
9465
|
+
|
|
9466
|
+
// src/common-components/AutoTag.js
|
|
9467
|
+
var import_react17 = __toESM(require("react"));
|
|
9468
|
+
var import_ui_extensions17 = require("@hubspot/ui-extensions");
|
|
9469
|
+
|
|
7751
9470
|
// src/utils/tagVariants.js
|
|
7752
9471
|
var DEFAULT_VARIANT = "default";
|
|
7753
9472
|
var DANGER_VARIANT = "danger";
|
|
@@ -7944,16 +9663,16 @@ var AutoTag = ({
|
|
|
7944
9663
|
overrides,
|
|
7945
9664
|
fallback
|
|
7946
9665
|
});
|
|
7947
|
-
return
|
|
7948
|
-
|
|
9666
|
+
return import_react17.default.createElement(
|
|
9667
|
+
import_ui_extensions17.Tag,
|
|
7949
9668
|
{ variant: resolvedVariant, ...props },
|
|
7950
9669
|
displayValue
|
|
7951
9670
|
);
|
|
7952
9671
|
};
|
|
7953
9672
|
|
|
7954
9673
|
// src/common-components/AutoStatusTag.js
|
|
7955
|
-
var
|
|
7956
|
-
var
|
|
9674
|
+
var import_react18 = __toESM(require("react"));
|
|
9675
|
+
var import_ui_extensions18 = require("@hubspot/ui-extensions");
|
|
7957
9676
|
var AutoStatusTag = ({
|
|
7958
9677
|
value,
|
|
7959
9678
|
status,
|
|
@@ -7969,20 +9688,20 @@ var AutoStatusTag = ({
|
|
|
7969
9688
|
overrides,
|
|
7970
9689
|
fallback
|
|
7971
9690
|
});
|
|
7972
|
-
return
|
|
7973
|
-
|
|
9691
|
+
return import_react18.default.createElement(
|
|
9692
|
+
import_ui_extensions18.StatusTag,
|
|
7974
9693
|
{ variant: resolvedVariant, ...props },
|
|
7975
9694
|
displayValue
|
|
7976
9695
|
);
|
|
7977
9696
|
};
|
|
7978
9697
|
|
|
7979
9698
|
// src/common-components/CrmLookupSelect.js
|
|
7980
|
-
var
|
|
7981
|
-
var
|
|
9699
|
+
var import_react20 = __toESM(require("react"));
|
|
9700
|
+
var import_ui_extensions20 = require("@hubspot/ui-extensions");
|
|
7982
9701
|
|
|
7983
9702
|
// src/utils/crmSearchAdapters.js
|
|
7984
|
-
var
|
|
7985
|
-
var
|
|
9703
|
+
var import_react19 = __toESM(require("react"));
|
|
9704
|
+
var import_ui_extensions19 = require("@hubspot/ui-extensions");
|
|
7986
9705
|
|
|
7987
9706
|
// src/utils/objectPath.js
|
|
7988
9707
|
var getByPath = (obj, path) => {
|
|
@@ -8099,9 +9818,9 @@ var useCrmSearchDataSource = (params = EMPTY_OBJECT, options = EMPTY_OBJECT) =>
|
|
|
8099
9818
|
error,
|
|
8100
9819
|
mapResponse
|
|
8101
9820
|
} = options;
|
|
8102
|
-
const config = (0,
|
|
8103
|
-
const response = (0,
|
|
8104
|
-
return (0,
|
|
9821
|
+
const config = (0, import_react19.useMemo)(() => buildCrmSearchConfig(params, options), [params, options]);
|
|
9822
|
+
const response = (0, import_ui_extensions19.useCrmSearch)(config, format);
|
|
9823
|
+
return (0, import_react19.useMemo)(() => {
|
|
8105
9824
|
var _a;
|
|
8106
9825
|
const rows = mapResponse ? mapResponse(response) : normalizeCrmSearchRows(response, { idField: rowIdField, ...row || EMPTY_OBJECT });
|
|
8107
9826
|
const resolvedTotal = typeof totalCount === "function" ? totalCount(response) : totalCount ?? pickTotal(response, rows.length);
|
|
@@ -8139,7 +9858,7 @@ var crmSearchResultToOption = (row, options = EMPTY_OBJECT) => {
|
|
|
8139
9858
|
var useCrmSearchOptions = (params = EMPTY_OBJECT, options = EMPTY_OBJECT) => {
|
|
8140
9859
|
const dataSource = useCrmSearchDataSource(params, options);
|
|
8141
9860
|
const optionConfig = options.option || options;
|
|
8142
|
-
return (0,
|
|
9861
|
+
return (0, import_react19.useMemo)(() => ({
|
|
8143
9862
|
...dataSource,
|
|
8144
9863
|
options: dataSource.rows.map((row) => crmSearchResultToOption(row, optionConfig))
|
|
8145
9864
|
}), [dataSource, optionConfig]);
|
|
@@ -8268,29 +9987,29 @@ var CrmDataTable = ({
|
|
|
8268
9987
|
...props
|
|
8269
9988
|
}) => {
|
|
8270
9989
|
var _a, _b;
|
|
8271
|
-
const [params, setParams] = (0,
|
|
8272
|
-
const resolvedProperties = (0,
|
|
8273
|
-
const resolvedColumns = (0,
|
|
9990
|
+
const [params, setParams] = (0, import_react19.useState)({ search: "", filters: {}, sort: null });
|
|
9991
|
+
const resolvedProperties = (0, import_react19.useMemo)(() => properties, [properties]);
|
|
9992
|
+
const resolvedColumns = (0, import_react19.useMemo)(
|
|
8274
9993
|
() => columns || inferCrmColumns(resolvedProperties),
|
|
8275
9994
|
[columns, resolvedProperties]
|
|
8276
9995
|
);
|
|
8277
9996
|
const resolvedSearchFields = searchFields || resolvedProperties;
|
|
8278
|
-
const autoFilterFields = (0,
|
|
9997
|
+
const autoFilterFields = (0, import_react19.useMemo)(
|
|
8279
9998
|
() => normalizeAutoFilterFields(autoFilters, resolvedProperties),
|
|
8280
9999
|
[autoFilters, resolvedProperties]
|
|
8281
10000
|
);
|
|
8282
|
-
const autoFilterLabelsRef = (0,
|
|
8283
|
-
const defaultPropertyMap = (0,
|
|
10001
|
+
const autoFilterLabelsRef = (0, import_react19.useRef)({});
|
|
10002
|
+
const defaultPropertyMap = (0, import_react19.useMemo)(
|
|
8284
10003
|
() => Object.fromEntries(resolvedProperties.map((property) => [property, property])),
|
|
8285
10004
|
[resolvedProperties]
|
|
8286
10005
|
);
|
|
8287
10006
|
const effectivePropertyMap = propertyMap || defaultPropertyMap;
|
|
8288
|
-
const resolvedSortMap = (0,
|
|
10007
|
+
const resolvedSortMap = (0, import_react19.useMemo)(
|
|
8289
10008
|
() => sortMap || ((sort) => crmSortsFromState(sort, effectivePropertyMap)),
|
|
8290
10009
|
[sortMap, effectivePropertyMap]
|
|
8291
10010
|
);
|
|
8292
10011
|
const resolvedMapRecord = mapRecord || defaultCrmMapRecord;
|
|
8293
|
-
const dataSourceOptions = (0,
|
|
10012
|
+
const dataSourceOptions = (0, import_react19.useMemo)(
|
|
8294
10013
|
() => ({
|
|
8295
10014
|
objectType: resolveCrmObjectType(objectType),
|
|
8296
10015
|
properties: resolvedProperties,
|
|
@@ -8304,18 +10023,18 @@ var CrmDataTable = ({
|
|
|
8304
10023
|
}),
|
|
8305
10024
|
[objectType, resolvedProperties, pageLength, format, filterMap, effectivePropertyMap, resolvedSortMap, rowIdField, resolvedMapRecord]
|
|
8306
10025
|
);
|
|
8307
|
-
const [serverQuerying, setServerQuerying] = (0,
|
|
10026
|
+
const [serverQuerying, setServerQuerying] = (0, import_react19.useState)(!!serverSide);
|
|
8308
10027
|
const effectiveParams = serverQuerying ? params : EMPTY_CRM_PARAMS;
|
|
8309
10028
|
const dataSource = useCrmSearchDataSource(effectiveParams, dataSourceOptions);
|
|
8310
|
-
const queryKey = (0,
|
|
10029
|
+
const queryKey = (0, import_react19.useMemo)(
|
|
8311
10030
|
() => stableStringify({ effectiveParams, objectType, properties: resolvedProperties, pageLength }),
|
|
8312
10031
|
[effectiveParams, objectType, resolvedProperties, pageLength]
|
|
8313
10032
|
);
|
|
8314
|
-
const [accumulatedRows, setAccumulatedRows] = (0,
|
|
8315
|
-
const [requestedPage, setRequestedPage] = (0,
|
|
8316
|
-
const lastQueryKeyRef = (0,
|
|
10033
|
+
const [accumulatedRows, setAccumulatedRows] = (0, import_react19.useState)(EMPTY_ARRAY);
|
|
10034
|
+
const [requestedPage, setRequestedPage] = (0, import_react19.useState)(1);
|
|
10035
|
+
const lastQueryKeyRef = (0, import_react19.useRef)(queryKey);
|
|
8317
10036
|
const loadedRows = accumulatedRows.length ? accumulatedRows : dataSource.data;
|
|
8318
|
-
(0,
|
|
10037
|
+
(0, import_react19.useEffect)(() => {
|
|
8319
10038
|
var _a2;
|
|
8320
10039
|
if (lastQueryKeyRef.current !== queryKey) {
|
|
8321
10040
|
lastQueryKeyRef.current = queryKey;
|
|
@@ -8325,12 +10044,12 @@ var CrmDataTable = ({
|
|
|
8325
10044
|
const currentPage = ((_a2 = dataSource.pagination) == null ? void 0 : _a2.currentPage) || 1;
|
|
8326
10045
|
setAccumulatedRows((prev) => currentPage <= 1 ? dataSource.data : appendUniqueRows(prev, dataSource.data, rowIdField));
|
|
8327
10046
|
}, [queryKey, dataSource.data, (_a = dataSource.pagination) == null ? void 0 : _a.currentPage, rowIdField]);
|
|
8328
|
-
(0,
|
|
10047
|
+
(0, import_react19.useEffect)(() => {
|
|
8329
10048
|
if (!serverQuerying && typeof dataSource.totalCount === "number" && dataSource.totalCount > loadedRows.length) {
|
|
8330
10049
|
setServerQuerying(true);
|
|
8331
10050
|
}
|
|
8332
10051
|
}, [serverQuerying, dataSource.totalCount, loadedRows.length]);
|
|
8333
|
-
const ensurePageLoaded = (0,
|
|
10052
|
+
const ensurePageLoaded = (0, import_react19.useCallback)((page) => {
|
|
8334
10053
|
var _a2, _b2, _c;
|
|
8335
10054
|
const pageNumber = Number(page) || 1;
|
|
8336
10055
|
const requiredRows = pageNumber * pageSize;
|
|
@@ -8338,10 +10057,10 @@ var CrmDataTable = ({
|
|
|
8338
10057
|
if (!dataSource.hasMore || dataSource.loading || ((_a2 = dataSource.response) == null ? void 0 : _a2.isRefetching)) return;
|
|
8339
10058
|
(_c = (_b2 = dataSource.pagination) == null ? void 0 : _b2.nextPage) == null ? void 0 : _c.call(_b2);
|
|
8340
10059
|
}, [pageSize, loadedRows.length, dataSource.hasMore, dataSource.loading, dataSource.response, dataSource.pagination]);
|
|
8341
|
-
(0,
|
|
10060
|
+
(0, import_react19.useEffect)(() => {
|
|
8342
10061
|
ensurePageLoaded(requestedPage);
|
|
8343
10062
|
}, [requestedPage, ensurePageLoaded]);
|
|
8344
|
-
const generatedFilters = (0,
|
|
10063
|
+
const generatedFilters = (0, import_react19.useMemo)(
|
|
8345
10064
|
() => buildAutoFiltersFromRows({
|
|
8346
10065
|
rows: loadedRows,
|
|
8347
10066
|
fields: autoFilterFields,
|
|
@@ -8351,7 +10070,7 @@ var CrmDataTable = ({
|
|
|
8351
10070
|
[loadedRows, autoFilterFields, autoFilterMaxOptions]
|
|
8352
10071
|
);
|
|
8353
10072
|
const resolvedFilters = filters || generatedFilters;
|
|
8354
|
-
const table =
|
|
10073
|
+
const table = import_react19.default.createElement(DataTable, {
|
|
8355
10074
|
title: title || `${prettifyPropertyName(objectType)} records`,
|
|
8356
10075
|
data: loadedRows,
|
|
8357
10076
|
loading: dataSource.loading || ((_b = dataSource.response) == null ? void 0 : _b.isRefetching),
|
|
@@ -8375,11 +10094,11 @@ var CrmDataTable = ({
|
|
|
8375
10094
|
const total = dataSource.totalCount;
|
|
8376
10095
|
const capped = typeof total === "number" && total > loadedRows.length;
|
|
8377
10096
|
if (!capped) return table;
|
|
8378
|
-
return
|
|
8379
|
-
|
|
10097
|
+
return import_react19.default.createElement(
|
|
10098
|
+
import_ui_extensions19.Flex,
|
|
8380
10099
|
{ direction: "column", gap: "xs" },
|
|
8381
|
-
|
|
8382
|
-
|
|
10100
|
+
import_react19.default.createElement(
|
|
10101
|
+
import_ui_extensions19.Text,
|
|
8383
10102
|
{ variant: "microcopy" },
|
|
8384
10103
|
dataSource.hasMore ? `Loaded ${loadedRows.length} of ${total} matching. Use the table pagination to load more CRM results.` : `Showing ${loadedRows.length} of ${total} matching. Refine your search or filters to narrow the results.`
|
|
8385
10104
|
),
|
|
@@ -8413,25 +10132,25 @@ var CrmKanban = ({
|
|
|
8413
10132
|
...props
|
|
8414
10133
|
}) => {
|
|
8415
10134
|
var _a, _b;
|
|
8416
|
-
const [params, setParams] = (0,
|
|
8417
|
-
const resolvedProperties = (0,
|
|
10135
|
+
const [params, setParams] = (0, import_react19.useState)(EMPTY_CRM_PARAMS);
|
|
10136
|
+
const resolvedProperties = (0, import_react19.useMemo)(() => properties, [properties]);
|
|
8418
10137
|
const resolvedSearchFields = searchFields || resolvedProperties;
|
|
8419
|
-
const autoFilterFields = (0,
|
|
10138
|
+
const autoFilterFields = (0, import_react19.useMemo)(
|
|
8420
10139
|
() => normalizeAutoFilterFields(autoFilters, resolvedProperties),
|
|
8421
10140
|
[autoFilters, resolvedProperties]
|
|
8422
10141
|
);
|
|
8423
|
-
const autoFilterLabelsRef = (0,
|
|
8424
|
-
const defaultPropertyMap = (0,
|
|
10142
|
+
const autoFilterLabelsRef = (0, import_react19.useRef)({});
|
|
10143
|
+
const defaultPropertyMap = (0, import_react19.useMemo)(
|
|
8425
10144
|
() => Object.fromEntries(resolvedProperties.map((property) => [property, property])),
|
|
8426
10145
|
[resolvedProperties]
|
|
8427
10146
|
);
|
|
8428
10147
|
const effectivePropertyMap = propertyMap || defaultPropertyMap;
|
|
8429
|
-
const resolvedSortMap = (0,
|
|
10148
|
+
const resolvedSortMap = (0, import_react19.useMemo)(
|
|
8430
10149
|
() => sortMap || ((sort) => crmSortsFromState(sort, effectivePropertyMap)),
|
|
8431
10150
|
[sortMap, effectivePropertyMap]
|
|
8432
10151
|
);
|
|
8433
10152
|
const resolvedMapRecord = mapRecord || defaultCrmMapRecord;
|
|
8434
|
-
const dataSourceOptions = (0,
|
|
10153
|
+
const dataSourceOptions = (0, import_react19.useMemo)(
|
|
8435
10154
|
() => ({
|
|
8436
10155
|
objectType: resolveCrmObjectType(objectType),
|
|
8437
10156
|
properties: resolvedProperties,
|
|
@@ -8445,17 +10164,17 @@ var CrmKanban = ({
|
|
|
8445
10164
|
}),
|
|
8446
10165
|
[objectType, resolvedProperties, pageLength, format, filterMap, effectivePropertyMap, resolvedSortMap, rowIdField, resolvedMapRecord]
|
|
8447
10166
|
);
|
|
8448
|
-
const [serverQuerying, setServerQuerying] = (0,
|
|
10167
|
+
const [serverQuerying, setServerQuerying] = (0, import_react19.useState)(!!serverSide);
|
|
8449
10168
|
const effectiveParams = serverQuerying ? params : EMPTY_CRM_PARAMS;
|
|
8450
10169
|
const dataSource = useCrmSearchDataSource(effectiveParams, dataSourceOptions);
|
|
8451
|
-
const queryKey = (0,
|
|
10170
|
+
const queryKey = (0, import_react19.useMemo)(
|
|
8452
10171
|
() => stableStringify({ effectiveParams, objectType, properties: resolvedProperties, pageLength }),
|
|
8453
10172
|
[effectiveParams, objectType, resolvedProperties, pageLength]
|
|
8454
10173
|
);
|
|
8455
|
-
const [accumulatedRows, setAccumulatedRows] = (0,
|
|
8456
|
-
const lastQueryKeyRef = (0,
|
|
10174
|
+
const [accumulatedRows, setAccumulatedRows] = (0, import_react19.useState)(EMPTY_ARRAY);
|
|
10175
|
+
const lastQueryKeyRef = (0, import_react19.useRef)(queryKey);
|
|
8457
10176
|
const loadedRows = accumulatedRows.length ? accumulatedRows : dataSource.data;
|
|
8458
|
-
(0,
|
|
10177
|
+
(0, import_react19.useEffect)(() => {
|
|
8459
10178
|
var _a2;
|
|
8460
10179
|
if (lastQueryKeyRef.current !== queryKey) {
|
|
8461
10180
|
lastQueryKeyRef.current = queryKey;
|
|
@@ -8465,12 +10184,12 @@ var CrmKanban = ({
|
|
|
8465
10184
|
const currentPage = ((_a2 = dataSource.pagination) == null ? void 0 : _a2.currentPage) || 1;
|
|
8466
10185
|
setAccumulatedRows((prev) => currentPage <= 1 ? dataSource.data : appendUniqueRows(prev, dataSource.data, rowIdField));
|
|
8467
10186
|
}, [queryKey, dataSource.data, (_a = dataSource.pagination) == null ? void 0 : _a.currentPage, rowIdField]);
|
|
8468
|
-
(0,
|
|
10187
|
+
(0, import_react19.useEffect)(() => {
|
|
8469
10188
|
if (!serverQuerying && typeof dataSource.totalCount === "number" && dataSource.totalCount > loadedRows.length) {
|
|
8470
10189
|
setServerQuerying(true);
|
|
8471
10190
|
}
|
|
8472
10191
|
}, [serverQuerying, dataSource.totalCount, loadedRows.length]);
|
|
8473
|
-
const handleLoadMore = (0,
|
|
10192
|
+
const handleLoadMore = (0, import_react19.useCallback)((stage) => {
|
|
8474
10193
|
var _a2, _b2, _c;
|
|
8475
10194
|
if (onLoadMore) {
|
|
8476
10195
|
onLoadMore(stage);
|
|
@@ -8479,7 +10198,7 @@ var CrmKanban = ({
|
|
|
8479
10198
|
if (!dataSource.hasMore || dataSource.loading || ((_a2 = dataSource.response) == null ? void 0 : _a2.isRefetching)) return;
|
|
8480
10199
|
(_c = (_b2 = dataSource.pagination) == null ? void 0 : _b2.nextPage) == null ? void 0 : _c.call(_b2);
|
|
8481
10200
|
}, [onLoadMore, dataSource.hasMore, dataSource.loading, dataSource.response, dataSource.pagination]);
|
|
8482
|
-
const generatedFilters = (0,
|
|
10201
|
+
const generatedFilters = (0, import_react19.useMemo)(
|
|
8483
10202
|
() => buildAutoFiltersFromRows({
|
|
8484
10203
|
rows: loadedRows,
|
|
8485
10204
|
fields: autoFilterFields,
|
|
@@ -8489,7 +10208,7 @@ var CrmKanban = ({
|
|
|
8489
10208
|
[loadedRows, autoFilterFields, autoFilterMaxOptions]
|
|
8490
10209
|
);
|
|
8491
10210
|
const resolvedFilters = filters || generatedFilters;
|
|
8492
|
-
const resolvedStages = (0,
|
|
10211
|
+
const resolvedStages = (0, import_react19.useMemo)(() => {
|
|
8493
10212
|
if (stages) return stages;
|
|
8494
10213
|
const seen = [];
|
|
8495
10214
|
for (const row of loadedRows) {
|
|
@@ -8501,7 +10220,7 @@ var CrmKanban = ({
|
|
|
8501
10220
|
label: typeof stageLabels === "function" ? stageLabels(value) : stageLabels && stageLabels[value] || prettifyPropertyName(String(value))
|
|
8502
10221
|
}));
|
|
8503
10222
|
}, [stages, stageLabels, loadedRows, groupBy]);
|
|
8504
|
-
const resolvedStageMeta = (0,
|
|
10223
|
+
const resolvedStageMeta = (0, import_react19.useMemo)(() => {
|
|
8505
10224
|
if (stageMeta || !dataSource.hasMore) return stageMeta;
|
|
8506
10225
|
return Object.fromEntries(resolvedStages.map((stage) => {
|
|
8507
10226
|
var _a2;
|
|
@@ -8515,7 +10234,7 @@ var CrmKanban = ({
|
|
|
8515
10234
|
];
|
|
8516
10235
|
}));
|
|
8517
10236
|
}, [stageMeta, dataSource.hasMore, dataSource.loading, dataSource.response, dataSource.totalCount, resolvedStages]);
|
|
8518
|
-
const board =
|
|
10237
|
+
const board = import_react19.default.createElement(Kanban, {
|
|
8519
10238
|
title: title || `${prettifyPropertyName(objectType)} board`,
|
|
8520
10239
|
data: loadedRows,
|
|
8521
10240
|
loading: dataSource.loading || ((_b = dataSource.response) == null ? void 0 : _b.isRefetching),
|
|
@@ -8538,17 +10257,19 @@ var CrmKanban = ({
|
|
|
8538
10257
|
const total = dataSource.totalCount;
|
|
8539
10258
|
const capped = typeof total === "number" && total > loadedRows.length;
|
|
8540
10259
|
if (!capped) return board;
|
|
8541
|
-
return
|
|
8542
|
-
|
|
10260
|
+
return import_react19.default.createElement(
|
|
10261
|
+
import_ui_extensions19.Flex,
|
|
8543
10262
|
{ direction: "column", gap: "xs" },
|
|
8544
|
-
|
|
8545
|
-
|
|
10263
|
+
import_react19.default.createElement(
|
|
10264
|
+
import_ui_extensions19.Text,
|
|
8546
10265
|
{ variant: "microcopy" },
|
|
8547
10266
|
dataSource.hasMore ? `Loaded ${loadedRows.length} of ${total} matching. Use Load more to fetch more CRM results.` : `Showing ${loadedRows.length} of ${total} matching. Refine your search or filters to narrow the results.`
|
|
8548
10267
|
),
|
|
8549
10268
|
board
|
|
8550
10269
|
);
|
|
8551
10270
|
};
|
|
10271
|
+
CrmDataTable.displayName = "CrmDataTable";
|
|
10272
|
+
CrmKanban.displayName = "CrmKanban";
|
|
8552
10273
|
|
|
8553
10274
|
// src/common-components/CrmLookupSelect.js
|
|
8554
10275
|
var EMPTY_ARRAY2 = [];
|
|
@@ -8601,12 +10322,12 @@ var CrmLookupSelect = ({
|
|
|
8601
10322
|
loadingOption,
|
|
8602
10323
|
selectProps = EMPTY_OBJECT2
|
|
8603
10324
|
}) => {
|
|
8604
|
-
const [inputValue, setInputValue] = (0,
|
|
8605
|
-
const [pickedOptions, setPickedOptions] = (0,
|
|
8606
|
-
const debouncedInput = (0,
|
|
10325
|
+
const [inputValue, setInputValue] = (0, import_react20.useState)(query || "");
|
|
10326
|
+
const [pickedOptions, setPickedOptions] = (0, import_react20.useState)(EMPTY_ARRAY2);
|
|
10327
|
+
const debouncedInput = (0, import_ui_extensions20.useDebounce)(inputValue, debounce > 0 ? debounce : 1);
|
|
8607
10328
|
const search = debounce > 0 ? debouncedInput : inputValue;
|
|
8608
10329
|
const effectiveSearch = search && search.length >= minSearchLength ? search : "";
|
|
8609
|
-
const optionConfig = (0,
|
|
10330
|
+
const optionConfig = (0, import_react20.useMemo)(
|
|
8610
10331
|
() => makeOptionConfig({ option, labelProperty, valueProperty, descriptionProperty }),
|
|
8611
10332
|
[option, labelProperty, valueProperty, descriptionProperty]
|
|
8612
10333
|
);
|
|
@@ -8624,7 +10345,7 @@ var CrmLookupSelect = ({
|
|
|
8624
10345
|
);
|
|
8625
10346
|
const isSearching = dataSource.loading || inputValue.trim() !== (search || "").trim();
|
|
8626
10347
|
const hasQuery = effectiveSearch.length > 0;
|
|
8627
|
-
const options = (0,
|
|
10348
|
+
const options = (0, import_react20.useMemo)(() => {
|
|
8628
10349
|
const remembered = [...selectedOptions || EMPTY_ARRAY2, ...pickedOptions];
|
|
8629
10350
|
const baseOptions = mergeSelectedOptions(dataSource.options || EMPTY_ARRAY2, remembered, value);
|
|
8630
10351
|
if (isSearching && loadingOption) return [loadingOption, ...baseOptions];
|
|
@@ -8663,7 +10384,281 @@ var CrmLookupSelect = ({
|
|
|
8663
10384
|
},
|
|
8664
10385
|
...selectProps
|
|
8665
10386
|
};
|
|
8666
|
-
return
|
|
10387
|
+
return import_react20.default.createElement(multiple ? import_ui_extensions20.MultiSelect : import_ui_extensions20.Select, commonProps);
|
|
10388
|
+
};
|
|
10389
|
+
|
|
10390
|
+
// src/common-components/CrmRecordPicker.js
|
|
10391
|
+
var import_react21 = __toESM(require("react"));
|
|
10392
|
+
var import_ui_extensions21 = require("@hubspot/ui-extensions");
|
|
10393
|
+
|
|
10394
|
+
// src/common-components/recordPickerCore.js
|
|
10395
|
+
var EMPTY_ARRAY3 = [];
|
|
10396
|
+
var CREATE_OPTION_VALUE = "__create__";
|
|
10397
|
+
var isRecordLike = (value) => value != null && typeof value === "object" && !Array.isArray(value);
|
|
10398
|
+
var getRecordId = (record) => {
|
|
10399
|
+
if (!isRecordLike(record)) return void 0;
|
|
10400
|
+
const id = record.objectId ?? record.id ?? record.hs_object_id ?? getByPath(record, "properties.hs_object_id");
|
|
10401
|
+
return id == null ? void 0 : String(id);
|
|
10402
|
+
};
|
|
10403
|
+
var toList = (value) => Array.isArray(value) ? value : value == null || value === "" ? EMPTY_ARRAY3 : [value];
|
|
10404
|
+
var normalizeRecordSelection = (value) => {
|
|
10405
|
+
const ids = [];
|
|
10406
|
+
const records = [];
|
|
10407
|
+
const seen = /* @__PURE__ */ new Set();
|
|
10408
|
+
for (const entry of toList(value)) {
|
|
10409
|
+
const rawId = isRecordLike(entry) ? getRecordId(entry) : entry;
|
|
10410
|
+
const id = rawId == null || rawId === "" ? rawId : String(rawId);
|
|
10411
|
+
if (id == null || id === "" || seen.has(id)) continue;
|
|
10412
|
+
seen.add(id);
|
|
10413
|
+
ids.push(id);
|
|
10414
|
+
if (isRecordLike(entry)) records.push(entry);
|
|
10415
|
+
}
|
|
10416
|
+
return { ids, records };
|
|
10417
|
+
};
|
|
10418
|
+
var recordToPickerOption = (record, config = {}) => {
|
|
10419
|
+
const { labelField, descriptionField, fallbackLabel = "Untitled record" } = config;
|
|
10420
|
+
const label = (labelField ? getByPath(record, labelField) : void 0) ?? (record == null ? void 0 : record.name) ?? getByPath(record, "properties.name") ?? fallbackLabel;
|
|
10421
|
+
const option = { label, value: getRecordId(record) };
|
|
10422
|
+
const description = descriptionField ? getByPath(record, descriptionField) : void 0;
|
|
10423
|
+
if (description != null && description !== "") option.description = description;
|
|
10424
|
+
return option;
|
|
10425
|
+
};
|
|
10426
|
+
var mergePickerOptions = (options, selectedOptions) => {
|
|
10427
|
+
const base = Array.isArray(options) ? options : EMPTY_ARRAY3;
|
|
10428
|
+
const selected = toList(selectedOptions);
|
|
10429
|
+
if (!selected.length) return base;
|
|
10430
|
+
const existing = new Set(base.map((option) => option == null ? void 0 : option.value));
|
|
10431
|
+
const missing = selected.filter((option) => option && !existing.has(option.value));
|
|
10432
|
+
return missing.length ? [...missing, ...base] : base;
|
|
10433
|
+
};
|
|
10434
|
+
var enforceSelectionMax = (ids, max) => {
|
|
10435
|
+
const list = toList(ids);
|
|
10436
|
+
if (!Number.isFinite(max) || max <= 0 || list.length <= max) return list;
|
|
10437
|
+
return list.slice(0, max);
|
|
10438
|
+
};
|
|
10439
|
+
var shouldShowCreateOption = ({
|
|
10440
|
+
allowCreate,
|
|
10441
|
+
searchTerm,
|
|
10442
|
+
options,
|
|
10443
|
+
searching = false,
|
|
10444
|
+
createPending = false,
|
|
10445
|
+
atMax = false
|
|
10446
|
+
} = {}) => {
|
|
10447
|
+
if (!allowCreate || typeof allowCreate.onCreate !== "function") return false;
|
|
10448
|
+
if (createPending || searching || atMax) return false;
|
|
10449
|
+
const term = String(searchTerm ?? "").trim();
|
|
10450
|
+
if (!term) return false;
|
|
10451
|
+
const lower = term.toLowerCase();
|
|
10452
|
+
return !(options || EMPTY_ARRAY3).some(
|
|
10453
|
+
(option) => String((option == null ? void 0 : option.label) ?? "").trim().toLowerCase() === lower
|
|
10454
|
+
);
|
|
10455
|
+
};
|
|
10456
|
+
var makeCreateOption = (term, label) => ({
|
|
10457
|
+
label: typeof label === "function" ? label(term) : label || `Create "${term}"`,
|
|
10458
|
+
value: CREATE_OPTION_VALUE
|
|
10459
|
+
});
|
|
10460
|
+
var splitCreateSelection = (next) => {
|
|
10461
|
+
const list = toList(next);
|
|
10462
|
+
const ids = list.filter((value) => value !== CREATE_OPTION_VALUE);
|
|
10463
|
+
return { ids, create: ids.length !== list.length };
|
|
10464
|
+
};
|
|
10465
|
+
var mapIdsToRecords = (ids, recordsById) => {
|
|
10466
|
+
const lookup = recordsById instanceof Map ? (id) => recordsById.get(id) : (id) => recordsById ? recordsById[id] : void 0;
|
|
10467
|
+
return toList(ids).map((id) => lookup(id) ?? { objectId: id });
|
|
10468
|
+
};
|
|
10469
|
+
var upsertRecords = (records, additions) => {
|
|
10470
|
+
const incoming = toList(additions).filter((record) => getRecordId(record) != null);
|
|
10471
|
+
if (!incoming.length) return Array.isArray(records) ? records : EMPTY_ARRAY3;
|
|
10472
|
+
const byId = new Map(toList(records).map((record) => [getRecordId(record), record]));
|
|
10473
|
+
for (const record of incoming) byId.set(getRecordId(record), record);
|
|
10474
|
+
return [...byId.values()];
|
|
10475
|
+
};
|
|
10476
|
+
|
|
10477
|
+
// src/common-components/CrmRecordPicker.js
|
|
10478
|
+
var EMPTY_ARRAY4 = [];
|
|
10479
|
+
var defaultMapRecord = (record) => ({ objectId: record.objectId, ...record.properties });
|
|
10480
|
+
var CrmRecordPicker = ({
|
|
10481
|
+
objectType,
|
|
10482
|
+
properties = EMPTY_ARRAY4,
|
|
10483
|
+
labelField,
|
|
10484
|
+
descriptionField,
|
|
10485
|
+
value,
|
|
10486
|
+
defaultValue,
|
|
10487
|
+
onChange,
|
|
10488
|
+
multi = true,
|
|
10489
|
+
max,
|
|
10490
|
+
placeholder,
|
|
10491
|
+
label,
|
|
10492
|
+
name,
|
|
10493
|
+
required,
|
|
10494
|
+
readOnly,
|
|
10495
|
+
error,
|
|
10496
|
+
validationMessage,
|
|
10497
|
+
description,
|
|
10498
|
+
tooltip,
|
|
10499
|
+
variant,
|
|
10500
|
+
pageLength = 20,
|
|
10501
|
+
debounce = 300,
|
|
10502
|
+
minSearchLength = 0,
|
|
10503
|
+
filterMap,
|
|
10504
|
+
allowCreate = false,
|
|
10505
|
+
fallbackLabel = "Untitled record",
|
|
10506
|
+
format,
|
|
10507
|
+
baseConfig,
|
|
10508
|
+
onSearchChange,
|
|
10509
|
+
...rest
|
|
10510
|
+
}) => {
|
|
10511
|
+
const isControlled = value !== void 0;
|
|
10512
|
+
const [internalValue, setInternalValue] = (0, import_react21.useState)(defaultValue);
|
|
10513
|
+
const effectiveValue = isControlled ? value : internalValue;
|
|
10514
|
+
const selection = (0, import_react21.useMemo)(() => normalizeRecordSelection(effectiveValue), [effectiveValue]);
|
|
10515
|
+
const [inputValue, setInputValue] = (0, import_react21.useState)("");
|
|
10516
|
+
const [seenRecords, setSeenRecords] = (0, import_react21.useState)(EMPTY_ARRAY4);
|
|
10517
|
+
const [createPending, setCreatePending] = (0, import_react21.useState)(false);
|
|
10518
|
+
const [createError, setCreateError] = (0, import_react21.useState)(null);
|
|
10519
|
+
const createPendingRef = (0, import_react21.useRef)(false);
|
|
10520
|
+
const debouncedInput = (0, import_ui_extensions21.useDebounce)(inputValue, debounce > 0 ? debounce : 1);
|
|
10521
|
+
const search = debounce > 0 ? debouncedInput : inputValue;
|
|
10522
|
+
const effectiveSearch = search && search.length >= minSearchLength ? search : "";
|
|
10523
|
+
const optionConfig = (0, import_react21.useMemo)(
|
|
10524
|
+
() => ({ labelField, descriptionField, fallbackLabel }),
|
|
10525
|
+
[labelField, descriptionField, fallbackLabel]
|
|
10526
|
+
);
|
|
10527
|
+
const searchParams = (0, import_react21.useMemo)(() => ({ search: effectiveSearch }), [effectiveSearch]);
|
|
10528
|
+
const dataSourceOptions = (0, import_react21.useMemo)(
|
|
10529
|
+
() => ({
|
|
10530
|
+
objectType: resolveCrmObjectType(objectType),
|
|
10531
|
+
properties,
|
|
10532
|
+
pageLength,
|
|
10533
|
+
format,
|
|
10534
|
+
filterMap,
|
|
10535
|
+
baseConfig,
|
|
10536
|
+
row: { mapRecord: defaultMapRecord },
|
|
10537
|
+
option: { mapOption: (row) => recordToPickerOption(row, optionConfig) }
|
|
10538
|
+
}),
|
|
10539
|
+
[objectType, properties, pageLength, format, filterMap, baseConfig, optionConfig]
|
|
10540
|
+
);
|
|
10541
|
+
const dataSource = useCrmSearchOptions(searchParams, dataSourceOptions);
|
|
10542
|
+
const recordsById = (0, import_react21.useMemo)(() => {
|
|
10543
|
+
const map = /* @__PURE__ */ new Map();
|
|
10544
|
+
for (const record of selection.records) map.set(getRecordId(record), record);
|
|
10545
|
+
for (const record of seenRecords) map.set(getRecordId(record), record);
|
|
10546
|
+
for (const row of dataSource.rows || EMPTY_ARRAY4) {
|
|
10547
|
+
const id = getRecordId(row);
|
|
10548
|
+
if (id != null) map.set(id, row);
|
|
10549
|
+
}
|
|
10550
|
+
return map;
|
|
10551
|
+
}, [selection.records, seenRecords, dataSource.rows]);
|
|
10552
|
+
const selectedOptions = (0, import_react21.useMemo)(
|
|
10553
|
+
() => selection.ids.map((id) => {
|
|
10554
|
+
const record = recordsById.get(id);
|
|
10555
|
+
return record ? recordToPickerOption(record, optionConfig) : { label: String(id), value: id };
|
|
10556
|
+
}),
|
|
10557
|
+
[selection.ids, recordsById, optionConfig]
|
|
10558
|
+
);
|
|
10559
|
+
const isSearching = dataSource.loading || inputValue.trim() !== (search || "").trim();
|
|
10560
|
+
const atMax = multi && Number.isFinite(max) && max > 0 && selection.ids.length >= max;
|
|
10561
|
+
const options = (0, import_react21.useMemo)(() => {
|
|
10562
|
+
const merged = mergePickerOptions(dataSource.options || EMPTY_ARRAY4, selectedOptions);
|
|
10563
|
+
const showCreate = shouldShowCreateOption({
|
|
10564
|
+
allowCreate,
|
|
10565
|
+
searchTerm: effectiveSearch,
|
|
10566
|
+
options: merged,
|
|
10567
|
+
searching: isSearching,
|
|
10568
|
+
createPending,
|
|
10569
|
+
atMax
|
|
10570
|
+
});
|
|
10571
|
+
if (!showCreate) return merged;
|
|
10572
|
+
return [...merged, makeCreateOption(effectiveSearch.trim(), allowCreate == null ? void 0 : allowCreate.label)];
|
|
10573
|
+
}, [dataSource.options, selectedOptions, allowCreate, effectiveSearch, isSearching, createPending, atMax]);
|
|
10574
|
+
const commitChange = (ids, extraRecords) => {
|
|
10575
|
+
let map = recordsById;
|
|
10576
|
+
if (extraRecords && extraRecords.length) {
|
|
10577
|
+
map = new Map(recordsById);
|
|
10578
|
+
for (const record of extraRecords) {
|
|
10579
|
+
const id = getRecordId(record);
|
|
10580
|
+
if (id != null) map.set(id, record);
|
|
10581
|
+
}
|
|
10582
|
+
}
|
|
10583
|
+
const trimmed = multi ? enforceSelectionMax(ids, max) : ids.slice(0, 1);
|
|
10584
|
+
const records = mapIdsToRecords(trimmed, map);
|
|
10585
|
+
if (!isControlled) setInternalValue(multi ? trimmed : trimmed[0] ?? null);
|
|
10586
|
+
if (onChange) {
|
|
10587
|
+
if (multi) onChange(trimmed, records);
|
|
10588
|
+
else onChange(trimmed[0] ?? null, records[0] ?? null);
|
|
10589
|
+
}
|
|
10590
|
+
};
|
|
10591
|
+
const startCreate = (term, baseIds) => {
|
|
10592
|
+
const onCreate = allowCreate && typeof allowCreate.onCreate === "function" ? allowCreate.onCreate : null;
|
|
10593
|
+
if (!onCreate || createPendingRef.current) return;
|
|
10594
|
+
createPendingRef.current = true;
|
|
10595
|
+
setCreatePending(true);
|
|
10596
|
+
setCreateError(null);
|
|
10597
|
+
Promise.resolve(onCreate(term)).then((created) => {
|
|
10598
|
+
const record = isRecordLike(created) ? created : created != null && created !== "" ? { objectId: created, name: term } : null;
|
|
10599
|
+
const id = getRecordId(record);
|
|
10600
|
+
if (id == null) return;
|
|
10601
|
+
setSeenRecords((prev) => upsertRecords(prev, [record]));
|
|
10602
|
+
const nextIds = multi ? [...baseIds.filter((v) => v !== id), id] : [id];
|
|
10603
|
+
commitChange(nextIds, [record]);
|
|
10604
|
+
}).catch((err) => {
|
|
10605
|
+
setCreateError((err == null ? void 0 : err.message) || "Could not create the record.");
|
|
10606
|
+
}).finally(() => {
|
|
10607
|
+
createPendingRef.current = false;
|
|
10608
|
+
setCreatePending(false);
|
|
10609
|
+
});
|
|
10610
|
+
};
|
|
10611
|
+
const handleChange = (next) => {
|
|
10612
|
+
if (createError) setCreateError(null);
|
|
10613
|
+
const { ids, create } = splitCreateSelection(next);
|
|
10614
|
+
const picked = ids.map((id) => recordsById.get(id)).filter(Boolean);
|
|
10615
|
+
if (picked.length) setSeenRecords((prev) => upsertRecords(prev, picked));
|
|
10616
|
+
if (create) {
|
|
10617
|
+
startCreate(effectiveSearch.trim(), ids);
|
|
10618
|
+
if (multi) commitChange(ids);
|
|
10619
|
+
return;
|
|
10620
|
+
}
|
|
10621
|
+
commitChange(ids);
|
|
10622
|
+
};
|
|
10623
|
+
const handleSearchInput = (next) => {
|
|
10624
|
+
setInputValue(next || "");
|
|
10625
|
+
if (onSearchChange) onSearchChange(next || "");
|
|
10626
|
+
};
|
|
10627
|
+
const commonProps = {
|
|
10628
|
+
name,
|
|
10629
|
+
label,
|
|
10630
|
+
value: multi ? selection.ids : selection.ids[0],
|
|
10631
|
+
options,
|
|
10632
|
+
placeholder: placeholder || (createPending ? "Creating record..." : dataSource.loading ? "Searching CRM..." : "Search CRM records..."),
|
|
10633
|
+
description,
|
|
10634
|
+
tooltip,
|
|
10635
|
+
required,
|
|
10636
|
+
readOnly: readOnly || createPending,
|
|
10637
|
+
error: error || !!createError || !!dataSource.error,
|
|
10638
|
+
validationMessage: validationMessage || createError || (typeof dataSource.error === "string" ? dataSource.error : void 0),
|
|
10639
|
+
variant,
|
|
10640
|
+
onChange: handleChange,
|
|
10641
|
+
...rest
|
|
10642
|
+
};
|
|
10643
|
+
if (!multi) {
|
|
10644
|
+
return import_react21.default.createElement(import_ui_extensions21.Select, { ...commonProps, onInput: handleSearchInput });
|
|
10645
|
+
}
|
|
10646
|
+
return import_react21.default.createElement(
|
|
10647
|
+
import_ui_extensions21.Flex,
|
|
10648
|
+
{ direction: "column", gap: "xs" },
|
|
10649
|
+
import_react21.default.createElement(import_ui_extensions21.SearchInput, {
|
|
10650
|
+
name: name ? `${name}-search` : void 0,
|
|
10651
|
+
label: "",
|
|
10652
|
+
placeholder: "Search CRM records...",
|
|
10653
|
+
value: inputValue,
|
|
10654
|
+
readOnly: readOnly || createPending,
|
|
10655
|
+
onInput: handleSearchInput,
|
|
10656
|
+
// The clear "x" emits onChange (not onInput) — wire both so clearing
|
|
10657
|
+
// resets the term (same pattern as CollectionToolbar).
|
|
10658
|
+
onChange: handleSearchInput
|
|
10659
|
+
}),
|
|
10660
|
+
import_react21.default.createElement(import_ui_extensions21.MultiSelect, commonProps)
|
|
10661
|
+
);
|
|
8667
10662
|
};
|
|
8668
10663
|
|
|
8669
10664
|
// src/common-components/datePresets.js
|
|
@@ -8688,13 +10683,472 @@ var HS_DATE_DIRECTION_LABELS = {
|
|
|
8688
10683
|
desc: "Descending"
|
|
8689
10684
|
};
|
|
8690
10685
|
|
|
10686
|
+
// src/common-components/dateRangePresets.js
|
|
10687
|
+
var DATE_RANGE_CUSTOM_VALUE = "custom";
|
|
10688
|
+
var DATE_FILTER_OPERATORS = [
|
|
10689
|
+
{ label: "is", value: "InRollingDateRange" },
|
|
10690
|
+
{ label: "is equal to", value: "Equal" },
|
|
10691
|
+
{ label: "is before", value: "BeforeDateStaticOrDynamic" },
|
|
10692
|
+
{ label: "is after", value: "AfterDateStaticOrDynamic" },
|
|
10693
|
+
{ label: "is between", value: "InRange" },
|
|
10694
|
+
{ label: "is more than", value: "GreaterRolling" },
|
|
10695
|
+
{ label: "is less than", value: "LessRolling" },
|
|
10696
|
+
{ label: "is known", value: "Known" },
|
|
10697
|
+
{ label: "is unknown", value: "NotKnown" }
|
|
10698
|
+
];
|
|
10699
|
+
var DATE_ROLLING_UNIT_OPTIONS = [
|
|
10700
|
+
{ label: "day ago", value: "day:backward" },
|
|
10701
|
+
{ label: "days from now", value: "day:forward" },
|
|
10702
|
+
{ label: "week ago", value: "week:backward" },
|
|
10703
|
+
{ label: "weeks from now", value: "week:forward" },
|
|
10704
|
+
{ label: "month ago", value: "month:backward" },
|
|
10705
|
+
{ label: "months from now", value: "month:forward" },
|
|
10706
|
+
{ label: "year ago", value: "year:backward" },
|
|
10707
|
+
{ label: "years from now", value: "year:forward" }
|
|
10708
|
+
];
|
|
10709
|
+
var toHsDateValue = (date) => {
|
|
10710
|
+
if (!(date instanceof Date) || Number.isNaN(date.getTime())) return null;
|
|
10711
|
+
return { year: date.getFullYear(), month: date.getMonth(), date: date.getDate() };
|
|
10712
|
+
};
|
|
10713
|
+
var compareHsDateValues = (a, b) => {
|
|
10714
|
+
if (!a || !b) return 0;
|
|
10715
|
+
return a.year - b.year || a.month - b.month || a.date - b.date;
|
|
10716
|
+
};
|
|
10717
|
+
var isValidDateRange = (range) => {
|
|
10718
|
+
if (!range) return true;
|
|
10719
|
+
return compareHsDateValues(range.from, range.to) <= 0;
|
|
10720
|
+
};
|
|
10721
|
+
var dayAt = (now, offset = 0) => toHsDateValue(new Date(now.getFullYear(), now.getMonth(), now.getDate() + offset));
|
|
10722
|
+
var monthStart = (now, monthOffset = 0) => toHsDateValue(new Date(now.getFullYear(), now.getMonth() + monthOffset, 1));
|
|
10723
|
+
var monthEnd = (now, monthOffset = 0) => toHsDateValue(new Date(now.getFullYear(), now.getMonth() + monthOffset + 1, 0));
|
|
10724
|
+
var quarterStartMonth = (now, quarterOffset = 0) => Math.floor(now.getMonth() / 3) * 3 + quarterOffset * 3;
|
|
10725
|
+
var presetToRange = (presetKey, now = /* @__PURE__ */ new Date()) => {
|
|
10726
|
+
if (!presetKey || presetKey === DATE_RANGE_CUSTOM_VALUE) return null;
|
|
10727
|
+
if (!(now instanceof Date) || Number.isNaN(now.getTime())) return null;
|
|
10728
|
+
const dow = now.getDay();
|
|
10729
|
+
const year = now.getFullYear();
|
|
10730
|
+
const qm = quarterStartMonth(now);
|
|
10731
|
+
switch (presetKey) {
|
|
10732
|
+
case "today":
|
|
10733
|
+
return { from: dayAt(now, 0), to: dayAt(now, 0) };
|
|
10734
|
+
case "yesterday":
|
|
10735
|
+
return { from: dayAt(now, -1), to: dayAt(now, -1) };
|
|
10736
|
+
case "tomorrow":
|
|
10737
|
+
return { from: dayAt(now, 1), to: dayAt(now, 1) };
|
|
10738
|
+
case "this_week":
|
|
10739
|
+
return { from: dayAt(now, -dow), to: dayAt(now, 6 - dow) };
|
|
10740
|
+
case "last_week":
|
|
10741
|
+
return { from: dayAt(now, -dow - 7), to: dayAt(now, -dow - 1) };
|
|
10742
|
+
case "7d":
|
|
10743
|
+
return { from: dayAt(now, -6), to: dayAt(now, 0) };
|
|
10744
|
+
case "30d":
|
|
10745
|
+
return { from: dayAt(now, -29), to: dayAt(now, 0) };
|
|
10746
|
+
case "90d":
|
|
10747
|
+
return { from: dayAt(now, -89), to: dayAt(now, 0) };
|
|
10748
|
+
case "this_month":
|
|
10749
|
+
return { from: monthStart(now, 0), to: monthEnd(now, 0) };
|
|
10750
|
+
case "last_month":
|
|
10751
|
+
return { from: monthStart(now, -1), to: monthEnd(now, -1) };
|
|
10752
|
+
case "this_quarter":
|
|
10753
|
+
return {
|
|
10754
|
+
from: toHsDateValue(new Date(year, qm, 1)),
|
|
10755
|
+
to: toHsDateValue(new Date(year, qm + 3, 0))
|
|
10756
|
+
};
|
|
10757
|
+
case "last_quarter":
|
|
10758
|
+
return {
|
|
10759
|
+
from: toHsDateValue(new Date(year, qm - 3, 1)),
|
|
10760
|
+
to: toHsDateValue(new Date(year, qm, 0))
|
|
10761
|
+
};
|
|
10762
|
+
case "this_year":
|
|
10763
|
+
return { from: { year, month: 0, date: 1 }, to: { year, month: 11, date: 31 } };
|
|
10764
|
+
case "last_year":
|
|
10765
|
+
return {
|
|
10766
|
+
from: { year: year - 1, month: 0, date: 1 },
|
|
10767
|
+
to: { year: year - 1, month: 11, date: 31 }
|
|
10768
|
+
};
|
|
10769
|
+
default:
|
|
10770
|
+
return null;
|
|
10771
|
+
}
|
|
10772
|
+
};
|
|
10773
|
+
|
|
10774
|
+
// src/common-components/DateRangePicker.js
|
|
10775
|
+
var import_react22 = __toESM(require("react"));
|
|
10776
|
+
var import_ui_extensions22 = require("@hubspot/ui-extensions");
|
|
10777
|
+
var h6 = import_react22.default.createElement;
|
|
10778
|
+
var IN_ROLLING = "InRollingDateRange";
|
|
10779
|
+
var EQUAL = "Equal";
|
|
10780
|
+
var BEFORE = "BeforeDateStaticOrDynamic";
|
|
10781
|
+
var AFTER = "AfterDateStaticOrDynamic";
|
|
10782
|
+
var GREATER_ROLLING = "GreaterRolling";
|
|
10783
|
+
var LESS_ROLLING = "LessRolling";
|
|
10784
|
+
var IN_RANGE = "InRange";
|
|
10785
|
+
var KNOWN = "Known";
|
|
10786
|
+
var NOT_KNOWN = "NotKnown";
|
|
10787
|
+
var EMPTY_RANGE = { from: null, to: null };
|
|
10788
|
+
var EMPTY_DATE = { date: null };
|
|
10789
|
+
var COMPACT_LABEL = "";
|
|
10790
|
+
var STATIC_DATE_OPERATORS = /* @__PURE__ */ new Set([EQUAL, BEFORE, AFTER]);
|
|
10791
|
+
var ROLLING_OPERATORS = /* @__PURE__ */ new Set([GREATER_ROLLING, LESS_ROLLING]);
|
|
10792
|
+
var PRESENCE_OPERATORS = /* @__PURE__ */ new Set([KNOWN, NOT_KNOWN]);
|
|
10793
|
+
var keyOfDate = (v) => v ? `${v.year}-${v.month}-${v.date}` : "";
|
|
10794
|
+
var keyOfRange = (r) => `${keyOfDate(r == null ? void 0 : r.from)}|${keyOfDate(r == null ? void 0 : r.to)}`;
|
|
10795
|
+
var isRangeLike = (value) => value && typeof value === "object" && ("from" in value || "to" in value) && !("operator" in value);
|
|
10796
|
+
var normalizeValue = (value) => {
|
|
10797
|
+
if (isRangeLike(value)) {
|
|
10798
|
+
return { operator: IN_RANGE, from: value.from ?? null, to: value.to ?? null };
|
|
10799
|
+
}
|
|
10800
|
+
if (!value || typeof value !== "object") {
|
|
10801
|
+
return { operator: IN_ROLLING, preset: "today" };
|
|
10802
|
+
}
|
|
10803
|
+
const operator = value.operator || IN_ROLLING;
|
|
10804
|
+
if (operator === IN_RANGE) {
|
|
10805
|
+
return { operator, from: value.from ?? null, to: value.to ?? null };
|
|
10806
|
+
}
|
|
10807
|
+
if (STATIC_DATE_OPERATORS.has(operator)) {
|
|
10808
|
+
return { operator, date: value.date ?? null };
|
|
10809
|
+
}
|
|
10810
|
+
if (ROLLING_OPERATORS.has(operator)) {
|
|
10811
|
+
return {
|
|
10812
|
+
operator,
|
|
10813
|
+
amount: Number.isFinite(Number(value.amount)) ? Number(value.amount) : 1,
|
|
10814
|
+
unit: value.unit || "day",
|
|
10815
|
+
direction: value.direction || "backward"
|
|
10816
|
+
};
|
|
10817
|
+
}
|
|
10818
|
+
if (PRESENCE_OPERATORS.has(operator)) {
|
|
10819
|
+
return { operator };
|
|
10820
|
+
}
|
|
10821
|
+
return { operator: IN_ROLLING, preset: value.preset || value.value || "today" };
|
|
10822
|
+
};
|
|
10823
|
+
var rangeFromValue = (value) => ({
|
|
10824
|
+
from: (value == null ? void 0 : value.from) ?? null,
|
|
10825
|
+
to: (value == null ? void 0 : value.to) ?? null
|
|
10826
|
+
});
|
|
10827
|
+
var getPresetOptions = (presets, customPresetLabel) => {
|
|
10828
|
+
const presetList = presets === true ? HS_DATE_PRESETS : Array.isArray(presets) ? presets : null;
|
|
10829
|
+
if (!presetList) return null;
|
|
10830
|
+
return [
|
|
10831
|
+
...presetList.map((p) => ({ label: p.label, value: p.value })),
|
|
10832
|
+
...presetList.some((p) => p.value === DATE_RANGE_CUSTOM_VALUE) ? [] : [{ label: customPresetLabel, value: DATE_RANGE_CUSTOM_VALUE }]
|
|
10833
|
+
];
|
|
10834
|
+
};
|
|
10835
|
+
var DateRangePicker = ({
|
|
10836
|
+
value,
|
|
10837
|
+
defaultValue,
|
|
10838
|
+
onChange,
|
|
10839
|
+
label,
|
|
10840
|
+
name = "date-range",
|
|
10841
|
+
field,
|
|
10842
|
+
defaultField,
|
|
10843
|
+
onFieldChange,
|
|
10844
|
+
showFieldSelect = false,
|
|
10845
|
+
fieldOptions = [],
|
|
10846
|
+
operator,
|
|
10847
|
+
defaultOperator = IN_ROLLING,
|
|
10848
|
+
onOperatorChange,
|
|
10849
|
+
showOperatorSelect = true,
|
|
10850
|
+
operatorOptions = DATE_FILTER_OPERATORS,
|
|
10851
|
+
presets = true,
|
|
10852
|
+
rollingUnitOptions = DATE_ROLLING_UNIT_OPTIONS,
|
|
10853
|
+
direction = "row",
|
|
10854
|
+
clearable = false,
|
|
10855
|
+
min,
|
|
10856
|
+
max,
|
|
10857
|
+
fromLabel = "Start date",
|
|
10858
|
+
toLabel = "End date",
|
|
10859
|
+
dateLabel = "Date",
|
|
10860
|
+
showDateLabels = false,
|
|
10861
|
+
format = "medium",
|
|
10862
|
+
presetPlaceholder = "Enter value",
|
|
10863
|
+
customPresetLabel = "Custom",
|
|
10864
|
+
clearLabel = "Clear",
|
|
10865
|
+
invalidRangeMessage = "Start date must be on or before end date",
|
|
10866
|
+
readOnly = false,
|
|
10867
|
+
gap,
|
|
10868
|
+
gridColumnWidth = 260
|
|
10869
|
+
}) => {
|
|
10870
|
+
const isControlled = value !== void 0;
|
|
10871
|
+
const controlledValue = normalizeValue(value);
|
|
10872
|
+
const [internalValue, setInternalValue] = (0, import_react22.useState)(
|
|
10873
|
+
() => normalizeValue(defaultValue ?? { operator: defaultOperator })
|
|
10874
|
+
);
|
|
10875
|
+
const [internalField, setInternalField] = (0, import_react22.useState)(
|
|
10876
|
+
() => {
|
|
10877
|
+
var _a;
|
|
10878
|
+
return defaultField ?? ((_a = fieldOptions == null ? void 0 : fieldOptions[0]) == null ? void 0 : _a.value) ?? "";
|
|
10879
|
+
}
|
|
10880
|
+
);
|
|
10881
|
+
const current = normalizeValue(isControlled ? controlledValue : internalValue);
|
|
10882
|
+
const currentOperator = operator || current.operator || defaultOperator;
|
|
10883
|
+
const currentField = field !== void 0 ? field : internalField;
|
|
10884
|
+
const resolvedCurrent = normalizeValue({ ...current, operator: currentOperator });
|
|
10885
|
+
const [pending, setPending] = (0, import_react22.useState)(null);
|
|
10886
|
+
const [lastPreset, setLastPreset] = (0, import_react22.useState)({
|
|
10887
|
+
key: resolvedCurrent.preset || "",
|
|
10888
|
+
rangeKey: null
|
|
10889
|
+
});
|
|
10890
|
+
const isColumn = direction === "column";
|
|
10891
|
+
const presetOptions = getPresetOptions(presets, customPresetLabel);
|
|
10892
|
+
const showClear = clearable && !readOnly && (resolvedCurrent.preset || resolvedCurrent.date || resolvedCurrent.amount || resolvedCurrent.from || resolvedCurrent.to || pending);
|
|
10893
|
+
const emit = (next, meta = {}) => {
|
|
10894
|
+
const normalized = normalizeValue(next);
|
|
10895
|
+
if (!isControlled) setInternalValue(normalized);
|
|
10896
|
+
if (normalized.operator !== currentOperator) {
|
|
10897
|
+
onOperatorChange == null ? void 0 : onOperatorChange(normalized.operator);
|
|
10898
|
+
}
|
|
10899
|
+
onChange == null ? void 0 : onChange(normalized, {
|
|
10900
|
+
operator: normalized.operator,
|
|
10901
|
+
field: currentField || null,
|
|
10902
|
+
preset: normalized.operator === IN_ROLLING ? normalized.preset ?? null : null,
|
|
10903
|
+
...meta
|
|
10904
|
+
});
|
|
10905
|
+
};
|
|
10906
|
+
const handleFieldChange = (nextField) => {
|
|
10907
|
+
if (field === void 0) setInternalField(nextField);
|
|
10908
|
+
onFieldChange == null ? void 0 : onFieldChange(nextField);
|
|
10909
|
+
onChange == null ? void 0 : onChange(resolvedCurrent, {
|
|
10910
|
+
operator: resolvedCurrent.operator,
|
|
10911
|
+
field: nextField || null,
|
|
10912
|
+
preset: resolvedCurrent.operator === IN_ROLLING ? resolvedCurrent.preset ?? null : null
|
|
10913
|
+
});
|
|
10914
|
+
};
|
|
10915
|
+
const handleOperatorChange = (nextOperator) => {
|
|
10916
|
+
setPending(null);
|
|
10917
|
+
if (nextOperator === IN_RANGE) {
|
|
10918
|
+
emit({ operator: IN_RANGE, ...EMPTY_RANGE }, { previousOperator: currentOperator });
|
|
10919
|
+
} else if (STATIC_DATE_OPERATORS.has(nextOperator)) {
|
|
10920
|
+
emit({ operator: nextOperator, ...EMPTY_DATE }, { previousOperator: currentOperator });
|
|
10921
|
+
} else if (ROLLING_OPERATORS.has(nextOperator)) {
|
|
10922
|
+
emit(
|
|
10923
|
+
{ operator: nextOperator, amount: 1, unit: "day", direction: "backward" },
|
|
10924
|
+
{ previousOperator: currentOperator }
|
|
10925
|
+
);
|
|
10926
|
+
} else if (PRESENCE_OPERATORS.has(nextOperator)) {
|
|
10927
|
+
emit({ operator: nextOperator }, { previousOperator: currentOperator });
|
|
10928
|
+
} else {
|
|
10929
|
+
emit({ operator: IN_ROLLING, preset: "today" }, { previousOperator: currentOperator });
|
|
10930
|
+
}
|
|
10931
|
+
};
|
|
10932
|
+
const handlePresetChange = (preset) => {
|
|
10933
|
+
if (!preset || preset === DATE_RANGE_CUSTOM_VALUE) {
|
|
10934
|
+
emit({ operator: IN_ROLLING, preset: DATE_RANGE_CUSTOM_VALUE });
|
|
10935
|
+
return;
|
|
10936
|
+
}
|
|
10937
|
+
const option = presets === true ? HS_DATE_PRESETS.find((p) => p.value === preset) : Array.isArray(presets) ? presets.find((p) => p.value === preset) : null;
|
|
10938
|
+
const range = option && typeof option.getRange === "function" ? option.getRange(/* @__PURE__ */ new Date()) : presetToRange(preset);
|
|
10939
|
+
setLastPreset({ key: preset, rangeKey: range ? keyOfRange(range) : null });
|
|
10940
|
+
emit({ operator: IN_ROLLING, preset }, { range });
|
|
10941
|
+
};
|
|
10942
|
+
const handleRollingUnitChange = (compound) => {
|
|
10943
|
+
const [unit, unitDirection] = String(compound || "day:backward").split(":");
|
|
10944
|
+
emit({
|
|
10945
|
+
operator: currentOperator,
|
|
10946
|
+
amount: resolvedCurrent.amount || 1,
|
|
10947
|
+
unit,
|
|
10948
|
+
direction: unitDirection || "backward"
|
|
10949
|
+
});
|
|
10950
|
+
};
|
|
10951
|
+
const handleDateChange = (side, next) => {
|
|
10952
|
+
const displayRange = {
|
|
10953
|
+
...rangeFromValue(resolvedCurrent),
|
|
10954
|
+
...pending ? { [pending.side]: pending.value } : {}
|
|
10955
|
+
};
|
|
10956
|
+
const candidate = { ...displayRange, [side]: next ?? null };
|
|
10957
|
+
if (isValidDateRange(candidate)) {
|
|
10958
|
+
setPending(null);
|
|
10959
|
+
setLastPreset({ key: "", rangeKey: null });
|
|
10960
|
+
emit({ operator: IN_RANGE, ...candidate });
|
|
10961
|
+
} else {
|
|
10962
|
+
setPending({ side, value: next ?? null });
|
|
10963
|
+
}
|
|
10964
|
+
};
|
|
10965
|
+
const handleStaticDateChange = (next) => {
|
|
10966
|
+
emit({ operator: currentOperator, date: next ?? null });
|
|
10967
|
+
};
|
|
10968
|
+
const handleClear = () => {
|
|
10969
|
+
setPending(null);
|
|
10970
|
+
setLastPreset({ key: "", rangeKey: null });
|
|
10971
|
+
if (currentOperator === IN_RANGE) {
|
|
10972
|
+
emit({ operator: IN_RANGE, ...EMPTY_RANGE });
|
|
10973
|
+
} else if (STATIC_DATE_OPERATORS.has(currentOperator)) {
|
|
10974
|
+
emit({ operator: currentOperator, ...EMPTY_DATE });
|
|
10975
|
+
} else if (ROLLING_OPERATORS.has(currentOperator)) {
|
|
10976
|
+
emit({ operator: currentOperator, amount: 1, unit: "day", direction: "backward" });
|
|
10977
|
+
} else if (PRESENCE_OPERATORS.has(currentOperator)) {
|
|
10978
|
+
emit({ operator: currentOperator });
|
|
10979
|
+
} else {
|
|
10980
|
+
emit({ operator: IN_ROLLING, preset: "" });
|
|
10981
|
+
}
|
|
10982
|
+
};
|
|
10983
|
+
const operatorSelect = showOperatorSelect ? h6(import_ui_extensions22.Select, {
|
|
10984
|
+
key: "operator",
|
|
10985
|
+
name: `${name}-operator`,
|
|
10986
|
+
label: COMPACT_LABEL,
|
|
10987
|
+
options: operatorOptions,
|
|
10988
|
+
value: currentOperator,
|
|
10989
|
+
onChange: handleOperatorChange,
|
|
10990
|
+
readOnly
|
|
10991
|
+
}) : null;
|
|
10992
|
+
const fieldSelect = showFieldSelect ? h6(import_ui_extensions22.Select, {
|
|
10993
|
+
key: "field",
|
|
10994
|
+
name: `${name}-field`,
|
|
10995
|
+
label: "",
|
|
10996
|
+
options: fieldOptions,
|
|
10997
|
+
value: currentField,
|
|
10998
|
+
onChange: handleFieldChange,
|
|
10999
|
+
readOnly
|
|
11000
|
+
}) : null;
|
|
11001
|
+
let valueInput = null;
|
|
11002
|
+
const fromInputLabel = showDateLabels ? fromLabel : COMPACT_LABEL;
|
|
11003
|
+
const toInputLabel = showDateLabels ? toLabel : COMPACT_LABEL;
|
|
11004
|
+
const singleDateInputLabel = showDateLabels ? dateLabel : COMPACT_LABEL;
|
|
11005
|
+
if (currentOperator === IN_RANGE) {
|
|
11006
|
+
const committed = rangeFromValue(resolvedCurrent);
|
|
11007
|
+
const display = {
|
|
11008
|
+
...committed,
|
|
11009
|
+
...pending ? { [pending.side]: pending.value } : {}
|
|
11010
|
+
};
|
|
11011
|
+
const invalidSide = pending ? pending.side : null;
|
|
11012
|
+
valueInput = [
|
|
11013
|
+
h6(import_ui_extensions22.DateInput, {
|
|
11014
|
+
key: "from",
|
|
11015
|
+
name: `${name}-from`,
|
|
11016
|
+
label: fromInputLabel,
|
|
11017
|
+
format,
|
|
11018
|
+
value: display.from ?? null,
|
|
11019
|
+
onChange: (next) => handleDateChange("from", next),
|
|
11020
|
+
min,
|
|
11021
|
+
max,
|
|
11022
|
+
readOnly,
|
|
11023
|
+
error: invalidSide === "from",
|
|
11024
|
+
validationMessage: invalidSide === "from" ? invalidRangeMessage : void 0
|
|
11025
|
+
}),
|
|
11026
|
+
isColumn ? null : h6(import_ui_extensions22.Text, { key: "to" }, "to"),
|
|
11027
|
+
h6(import_ui_extensions22.DateInput, {
|
|
11028
|
+
key: "toDate",
|
|
11029
|
+
name: `${name}-to`,
|
|
11030
|
+
label: toInputLabel,
|
|
11031
|
+
format,
|
|
11032
|
+
value: display.to ?? null,
|
|
11033
|
+
onChange: (next) => handleDateChange("to", next),
|
|
11034
|
+
min,
|
|
11035
|
+
max,
|
|
11036
|
+
readOnly,
|
|
11037
|
+
error: invalidSide === "to",
|
|
11038
|
+
validationMessage: invalidSide === "to" ? invalidRangeMessage : void 0
|
|
11039
|
+
})
|
|
11040
|
+
];
|
|
11041
|
+
} else if (STATIC_DATE_OPERATORS.has(currentOperator)) {
|
|
11042
|
+
valueInput = h6(import_ui_extensions22.DateInput, {
|
|
11043
|
+
key: "date",
|
|
11044
|
+
name: `${name}-date`,
|
|
11045
|
+
label: singleDateInputLabel,
|
|
11046
|
+
format,
|
|
11047
|
+
value: resolvedCurrent.date ?? null,
|
|
11048
|
+
onChange: handleStaticDateChange,
|
|
11049
|
+
min,
|
|
11050
|
+
max,
|
|
11051
|
+
readOnly
|
|
11052
|
+
});
|
|
11053
|
+
} else if (ROLLING_OPERATORS.has(currentOperator)) {
|
|
11054
|
+
const compound = `${resolvedCurrent.unit || "day"}:${resolvedCurrent.direction || "backward"}`;
|
|
11055
|
+
valueInput = [
|
|
11056
|
+
h6(import_ui_extensions22.NumberInput, {
|
|
11057
|
+
key: "amount",
|
|
11058
|
+
name: `${name}-amount`,
|
|
11059
|
+
label: COMPACT_LABEL,
|
|
11060
|
+
min: 0,
|
|
11061
|
+
value: resolvedCurrent.amount ?? 1,
|
|
11062
|
+
onChange: (amount) => emit({
|
|
11063
|
+
operator: currentOperator,
|
|
11064
|
+
amount: Number.isFinite(Number(amount)) ? Number(amount) : 0,
|
|
11065
|
+
unit: resolvedCurrent.unit || "day",
|
|
11066
|
+
direction: resolvedCurrent.direction || "backward"
|
|
11067
|
+
}),
|
|
11068
|
+
readOnly
|
|
11069
|
+
}),
|
|
11070
|
+
h6(import_ui_extensions22.Select, {
|
|
11071
|
+
key: "unit",
|
|
11072
|
+
name: `${name}-rolling-unit`,
|
|
11073
|
+
label: COMPACT_LABEL,
|
|
11074
|
+
options: rollingUnitOptions,
|
|
11075
|
+
value: compound,
|
|
11076
|
+
onChange: handleRollingUnitChange,
|
|
11077
|
+
readOnly
|
|
11078
|
+
})
|
|
11079
|
+
];
|
|
11080
|
+
} else if (PRESENCE_OPERATORS.has(currentOperator)) {
|
|
11081
|
+
valueInput = null;
|
|
11082
|
+
} else {
|
|
11083
|
+
const range = presetToRange(resolvedCurrent.preset);
|
|
11084
|
+
const presetValue = resolvedCurrent.preset || (lastPreset.rangeKey && range && lastPreset.rangeKey === keyOfRange(range) ? lastPreset.key : "");
|
|
11085
|
+
valueInput = h6(import_ui_extensions22.Select, {
|
|
11086
|
+
key: "preset",
|
|
11087
|
+
name: `${name}-preset`,
|
|
11088
|
+
label: COMPACT_LABEL,
|
|
11089
|
+
placeholder: presetPlaceholder,
|
|
11090
|
+
options: presetOptions || [],
|
|
11091
|
+
value: presetValue,
|
|
11092
|
+
onChange: handlePresetChange,
|
|
11093
|
+
readOnly
|
|
11094
|
+
});
|
|
11095
|
+
}
|
|
11096
|
+
const valueChildren = [
|
|
11097
|
+
...Array.isArray(valueInput) ? valueInput : valueInput ? [valueInput] : [],
|
|
11098
|
+
showClear ? h6(import_ui_extensions22.Link, { key: "clear", onClick: handleClear }, clearLabel) : null
|
|
11099
|
+
];
|
|
11100
|
+
const children = [operatorSelect, ...valueChildren];
|
|
11101
|
+
if (fieldSelect) {
|
|
11102
|
+
const rowChildren = [
|
|
11103
|
+
h6(import_ui_extensions22.Box, { key: "field-box", flex: "auto", alignSelf: "stretch" }, fieldSelect),
|
|
11104
|
+
operatorSelect ? h6(import_ui_extensions22.Box, { key: "operator-box", flex: "auto", alignSelf: "stretch" }, operatorSelect) : null,
|
|
11105
|
+
...valueChildren.map(
|
|
11106
|
+
(child, index) => (child == null ? void 0 : child.type) === import_ui_extensions22.Text || (child == null ? void 0 : child.type) === import_ui_extensions22.Link ? child : h6(import_ui_extensions22.Box, { key: `value-box-${index}`, flex: "auto", alignSelf: "stretch" }, child)
|
|
11107
|
+
)
|
|
11108
|
+
].filter(Boolean);
|
|
11109
|
+
const fieldControl = h6(
|
|
11110
|
+
import_ui_extensions22.AutoGrid,
|
|
11111
|
+
{
|
|
11112
|
+
columnWidth: gridColumnWidth,
|
|
11113
|
+
flexible: true,
|
|
11114
|
+
gap: gap ?? "xs"
|
|
11115
|
+
},
|
|
11116
|
+
...rowChildren
|
|
11117
|
+
);
|
|
11118
|
+
if (!label) return fieldControl;
|
|
11119
|
+
return h6(
|
|
11120
|
+
import_ui_extensions22.Flex,
|
|
11121
|
+
{ direction: "column", gap: "xs" },
|
|
11122
|
+
h6(import_ui_extensions22.Text, { format: { fontWeight: "demibold" } }, label),
|
|
11123
|
+
fieldControl
|
|
11124
|
+
);
|
|
11125
|
+
}
|
|
11126
|
+
const control = h6(
|
|
11127
|
+
import_ui_extensions22.Flex,
|
|
11128
|
+
{
|
|
11129
|
+
direction: isColumn ? "column" : "row",
|
|
11130
|
+
align: isColumn ? "stretch" : "center",
|
|
11131
|
+
gap: gap ?? (isColumn ? "sm" : "xs"),
|
|
11132
|
+
wrap: isColumn ? void 0 : "wrap"
|
|
11133
|
+
},
|
|
11134
|
+
...children
|
|
11135
|
+
);
|
|
11136
|
+
if (!label) return control;
|
|
11137
|
+
return h6(
|
|
11138
|
+
import_ui_extensions22.Flex,
|
|
11139
|
+
{ direction: "column", gap: "xs" },
|
|
11140
|
+
h6(import_ui_extensions22.Text, { format: { fontWeight: "demibold" } }, label),
|
|
11141
|
+
control
|
|
11142
|
+
);
|
|
11143
|
+
};
|
|
11144
|
+
|
|
8691
11145
|
// src/common-components/KeyValueList.js
|
|
8692
|
-
var
|
|
8693
|
-
var
|
|
11146
|
+
var import_react23 = __toESM(require("react"));
|
|
11147
|
+
var import_ui_extensions23 = require("@hubspot/ui-extensions");
|
|
8694
11148
|
var KeyValueList = ({ items = [], direction = "row", gap = "sm" }) => {
|
|
8695
11149
|
const rows = items.map(
|
|
8696
|
-
(item, index) =>
|
|
8697
|
-
|
|
11150
|
+
(item, index) => import_react23.default.createElement(
|
|
11151
|
+
import_ui_extensions23.DescriptionListItem,
|
|
8698
11152
|
{
|
|
8699
11153
|
key: item.key ?? item.label ?? `kv-${index}`,
|
|
8700
11154
|
label: item.label
|
|
@@ -8702,16 +11156,17 @@ var KeyValueList = ({ items = [], direction = "row", gap = "sm" }) => {
|
|
|
8702
11156
|
item.value
|
|
8703
11157
|
)
|
|
8704
11158
|
);
|
|
8705
|
-
return
|
|
8706
|
-
|
|
11159
|
+
return import_react23.default.createElement(
|
|
11160
|
+
import_ui_extensions23.Flex,
|
|
8707
11161
|
{ direction: "column", gap },
|
|
8708
|
-
|
|
11162
|
+
import_react23.default.createElement(import_ui_extensions23.DescriptionList, { direction }, ...rows)
|
|
8709
11163
|
);
|
|
8710
11164
|
};
|
|
11165
|
+
KeyValueList.displayName = "KeyValueList";
|
|
8711
11166
|
|
|
8712
11167
|
// src/common-components/SectionHeader.js
|
|
8713
|
-
var
|
|
8714
|
-
var
|
|
11168
|
+
var import_react24 = __toESM(require("react"));
|
|
11169
|
+
var import_ui_extensions24 = require("@hubspot/ui-extensions");
|
|
8715
11170
|
var SectionHeader = ({
|
|
8716
11171
|
title,
|
|
8717
11172
|
description,
|
|
@@ -8722,12 +11177,12 @@ var SectionHeader = ({
|
|
|
8722
11177
|
}) => {
|
|
8723
11178
|
const body = [];
|
|
8724
11179
|
if (title != null) {
|
|
8725
|
-
body.push(
|
|
11180
|
+
body.push(import_react24.default.createElement(import_ui_extensions24.Heading, { key: "title", as: titleAs }, title));
|
|
8726
11181
|
}
|
|
8727
11182
|
if (description != null) {
|
|
8728
11183
|
body.push(
|
|
8729
|
-
|
|
8730
|
-
|
|
11184
|
+
import_react24.default.createElement(
|
|
11185
|
+
import_ui_extensions24.Text,
|
|
8731
11186
|
{ key: "description", variant: "microcopy" },
|
|
8732
11187
|
description
|
|
8733
11188
|
)
|
|
@@ -8736,10 +11191,10 @@ var SectionHeader = ({
|
|
|
8736
11191
|
if (children != null) {
|
|
8737
11192
|
body.push(children);
|
|
8738
11193
|
}
|
|
8739
|
-
const content =
|
|
11194
|
+
const content = import_react24.default.createElement(import_ui_extensions24.Flex, { direction: "column", gap }, ...body);
|
|
8740
11195
|
if (actions == null) return content;
|
|
8741
|
-
return
|
|
8742
|
-
|
|
11196
|
+
return import_react24.default.createElement(
|
|
11197
|
+
import_ui_extensions24.Flex,
|
|
8743
11198
|
{ direction: "row", justify: "between", align: "start", gap: "sm" },
|
|
8744
11199
|
content,
|
|
8745
11200
|
actions
|
|
@@ -8747,8 +11202,8 @@ var SectionHeader = ({
|
|
|
8747
11202
|
};
|
|
8748
11203
|
|
|
8749
11204
|
// src/common-components/Spinner.js
|
|
8750
|
-
var
|
|
8751
|
-
var
|
|
11205
|
+
var import_react25 = __toESM(require("react"));
|
|
11206
|
+
var import_ui_extensions25 = require("@hubspot/ui-extensions");
|
|
8752
11207
|
|
|
8753
11208
|
// src/common-components/spinners.js
|
|
8754
11209
|
var BRAILLE_DOT_MAP = [
|
|
@@ -9088,10 +11543,10 @@ var Spinner = ({
|
|
|
9088
11543
|
const preset = SPINNERS[name] || SPINNERS[DEFAULT_NAME];
|
|
9089
11544
|
const resolvedFrames = Array.isArray(frames) && frames.length > 0 ? frames : preset.frames;
|
|
9090
11545
|
const resolvedInterval = Number.isFinite(interval) ? interval : preset.interval;
|
|
9091
|
-
const [index, setIndex] = (0,
|
|
9092
|
-
const indexRef = (0,
|
|
11546
|
+
const [index, setIndex] = (0, import_react25.useState)(0);
|
|
11547
|
+
const indexRef = (0, import_react25.useRef)(0);
|
|
9093
11548
|
indexRef.current = index;
|
|
9094
|
-
(0,
|
|
11549
|
+
(0, import_react25.useEffect)(() => {
|
|
9095
11550
|
if (paused || resolvedFrames.length <= 1) return void 0;
|
|
9096
11551
|
const id = setInterval(() => {
|
|
9097
11552
|
indexRef.current = (indexRef.current + 1) % resolvedFrames.length;
|
|
@@ -9099,17 +11554,17 @@ var Spinner = ({
|
|
|
9099
11554
|
}, Math.max(16, resolvedInterval));
|
|
9100
11555
|
return () => clearInterval(id);
|
|
9101
11556
|
}, [paused, resolvedFrames, resolvedInterval]);
|
|
9102
|
-
(0,
|
|
11557
|
+
(0, import_react25.useEffect)(() => {
|
|
9103
11558
|
indexRef.current = 0;
|
|
9104
11559
|
setIndex(0);
|
|
9105
11560
|
}, [resolvedFrames]);
|
|
9106
11561
|
const frame = resolvedFrames[index % resolvedFrames.length];
|
|
9107
11562
|
const suffix = children != null ? children : label;
|
|
9108
11563
|
if (suffix == null || suffix === "") {
|
|
9109
|
-
return
|
|
11564
|
+
return import_react25.default.createElement(import_ui_extensions25.Text, rest, frame);
|
|
9110
11565
|
}
|
|
9111
|
-
return
|
|
9112
|
-
|
|
11566
|
+
return import_react25.default.createElement(
|
|
11567
|
+
import_ui_extensions25.Text,
|
|
9113
11568
|
rest,
|
|
9114
11569
|
frame,
|
|
9115
11570
|
gap,
|
|
@@ -9117,6 +11572,378 @@ var Spinner = ({
|
|
|
9117
11572
|
);
|
|
9118
11573
|
};
|
|
9119
11574
|
|
|
11575
|
+
// src/safe/catalogs.js
|
|
11576
|
+
var ICON_NAME_ALIASES2 = {
|
|
11577
|
+
alert: "warning",
|
|
11578
|
+
// "alert" is a color, not an icon
|
|
11579
|
+
check: "success",
|
|
11580
|
+
checkmark: "success",
|
|
11581
|
+
danger: "xCircle",
|
|
11582
|
+
// "danger" is a StatusTag variant
|
|
11583
|
+
duplicate: "copy",
|
|
11584
|
+
error: "xCircle",
|
|
11585
|
+
// "error" is a Tag variant, not an icon
|
|
11586
|
+
trash: "delete",
|
|
11587
|
+
pencil: "edit",
|
|
11588
|
+
arrowLeft: "left",
|
|
11589
|
+
arrowRight: "right",
|
|
11590
|
+
arrowUp: "upCarat",
|
|
11591
|
+
arrowDown: "downCarat",
|
|
11592
|
+
cog: "settings",
|
|
11593
|
+
gear: "settings",
|
|
11594
|
+
close: "xCircle",
|
|
11595
|
+
plus: "add",
|
|
11596
|
+
minus: "remove",
|
|
11597
|
+
ok: "success"
|
|
11598
|
+
};
|
|
11599
|
+
var EMPTY_STATE_IMAGES = /* @__PURE__ */ new Set([
|
|
11600
|
+
"addOnReporting",
|
|
11601
|
+
"announcement",
|
|
11602
|
+
"api",
|
|
11603
|
+
"automatedTesting",
|
|
11604
|
+
"beta",
|
|
11605
|
+
"building",
|
|
11606
|
+
"callingSetUp",
|
|
11607
|
+
"companies",
|
|
11608
|
+
"components",
|
|
11609
|
+
"cone",
|
|
11610
|
+
"contacts",
|
|
11611
|
+
"contentStrategy",
|
|
11612
|
+
"customObjects",
|
|
11613
|
+
"customerExperience",
|
|
11614
|
+
"customerSupport",
|
|
11615
|
+
"deals",
|
|
11616
|
+
"developerSecurityUpdate",
|
|
11617
|
+
"electronicSignature",
|
|
11618
|
+
"electronicSignatureEmptyState",
|
|
11619
|
+
"emailConfirmation",
|
|
11620
|
+
"emptyStateCharts",
|
|
11621
|
+
"idea",
|
|
11622
|
+
"integrations",
|
|
11623
|
+
"leads",
|
|
11624
|
+
"lock",
|
|
11625
|
+
"missedGoal",
|
|
11626
|
+
"multipleObjects",
|
|
11627
|
+
"object",
|
|
11628
|
+
"productsShoppingCart",
|
|
11629
|
+
"registration",
|
|
11630
|
+
"sandboxAddOn",
|
|
11631
|
+
"social",
|
|
11632
|
+
"store",
|
|
11633
|
+
"storeDisabled",
|
|
11634
|
+
"successfullyConnectedEmail",
|
|
11635
|
+
"target",
|
|
11636
|
+
"task",
|
|
11637
|
+
"voteAndSearch",
|
|
11638
|
+
"meetings",
|
|
11639
|
+
"tickets"
|
|
11640
|
+
]);
|
|
11641
|
+
var EMPTY_STATE_IMAGE_ALIASES = {
|
|
11642
|
+
"new-project": "components",
|
|
11643
|
+
newProject: "components",
|
|
11644
|
+
empty: "components",
|
|
11645
|
+
default: "components"
|
|
11646
|
+
};
|
|
11647
|
+
var TREND_DIRECTIONS = /* @__PURE__ */ new Set(["increase", "decrease"]);
|
|
11648
|
+
var TREND_DIRECTION_ALIASES = {
|
|
11649
|
+
increasing: "increase",
|
|
11650
|
+
decreasing: "decrease",
|
|
11651
|
+
up: "increase",
|
|
11652
|
+
down: "decrease",
|
|
11653
|
+
positive: "increase",
|
|
11654
|
+
negative: "decrease"
|
|
11655
|
+
};
|
|
11656
|
+
var SAFE_ARRAY_PROPS = {
|
|
11657
|
+
// native @hubspot/ui-extensions
|
|
11658
|
+
Select: ["options"],
|
|
11659
|
+
MultiSelect: ["options"],
|
|
11660
|
+
ToggleGroup: ["options"],
|
|
11661
|
+
StepIndicator: ["stepNames"],
|
|
11662
|
+
// hs-uix
|
|
11663
|
+
DataTable: ["data", "columns", "searchFields", "filters", "selectionActions"],
|
|
11664
|
+
Kanban: ["data", "stages"],
|
|
11665
|
+
FormBuilder: ["fields"],
|
|
11666
|
+
AvatarStack: ["items"],
|
|
11667
|
+
KeyValueList: ["items"],
|
|
11668
|
+
Feed: ["items", "fields"],
|
|
11669
|
+
Calendar: ["events"],
|
|
11670
|
+
CrmKanban: ["cardFields"]
|
|
11671
|
+
};
|
|
11672
|
+
var SAFE_DERIVE_PROPS = {
|
|
11673
|
+
CrmDataTable: ["columns"],
|
|
11674
|
+
CrmKanban: ["stages"]
|
|
11675
|
+
};
|
|
11676
|
+
|
|
11677
|
+
// src/safe/warnings.js
|
|
11678
|
+
var warned = /* @__PURE__ */ new Set();
|
|
11679
|
+
function warnOnce(key, message) {
|
|
11680
|
+
if (warned.has(key)) return;
|
|
11681
|
+
warned.add(key);
|
|
11682
|
+
console.warn(message);
|
|
11683
|
+
}
|
|
11684
|
+
function resetSafeWarnings() {
|
|
11685
|
+
warned.clear();
|
|
11686
|
+
}
|
|
11687
|
+
|
|
11688
|
+
// src/safe/withSafeArrayProps.js
|
|
11689
|
+
var import_react26 = __toESM(require("react"));
|
|
11690
|
+
var arrayProp = (value, componentName, propName) => {
|
|
11691
|
+
if (Array.isArray(value)) return value;
|
|
11692
|
+
if (value == null) return [];
|
|
11693
|
+
warnOnce(
|
|
11694
|
+
`${componentName}-${propName}-not-array`,
|
|
11695
|
+
`[hs-uix/safe] ${componentName}.${propName} must be an array \u2014 received ${typeof value}; using [].`
|
|
11696
|
+
);
|
|
11697
|
+
return [];
|
|
11698
|
+
};
|
|
11699
|
+
function withSafeArrayProps(Component, componentName, propNames, derivePropNames = []) {
|
|
11700
|
+
if (!Component) return void 0;
|
|
11701
|
+
const SafeComponent = import_react26.default.forwardRef((props, ref) => {
|
|
11702
|
+
const next = { ...props || {} };
|
|
11703
|
+
for (const propName of propNames) {
|
|
11704
|
+
next[propName] = arrayProp(next[propName], componentName, propName);
|
|
11705
|
+
}
|
|
11706
|
+
for (const propName of derivePropNames) {
|
|
11707
|
+
const value = next[propName];
|
|
11708
|
+
if (value == null || Array.isArray(value)) continue;
|
|
11709
|
+
warnOnce(
|
|
11710
|
+
`${componentName}-${propName}-not-array`,
|
|
11711
|
+
`[hs-uix/safe] ${componentName}.${propName} must be an array \u2014 received ${typeof value}; omitting it so ${componentName} derives it automatically.`
|
|
11712
|
+
);
|
|
11713
|
+
delete next[propName];
|
|
11714
|
+
}
|
|
11715
|
+
return import_react26.default.createElement(Component, ref != null ? { ...next, ref } : next);
|
|
11716
|
+
});
|
|
11717
|
+
SafeComponent.displayName = `Safe${componentName}`;
|
|
11718
|
+
return SafeComponent;
|
|
11719
|
+
}
|
|
11720
|
+
|
|
11721
|
+
// src/safe/SafeIcon.js
|
|
11722
|
+
var import_react27 = __toESM(require("react"));
|
|
11723
|
+
var import_ui_extensions26 = require("@hubspot/ui-extensions");
|
|
11724
|
+
var SafeIcon = (props) => {
|
|
11725
|
+
const { name, ...rest } = props || {};
|
|
11726
|
+
if (typeof name === "string" && NATIVE_ICON_NAMES.has(name)) {
|
|
11727
|
+
return import_react27.default.createElement(import_ui_extensions26.Icon, { name, ...rest });
|
|
11728
|
+
}
|
|
11729
|
+
const alias = ICON_NAME_ALIASES2[name];
|
|
11730
|
+
if (alias && NATIVE_ICON_NAMES.has(alias)) {
|
|
11731
|
+
warnOnce(
|
|
11732
|
+
`icon-alias-${name}`,
|
|
11733
|
+
`[hs-uix/safe] Icon name "${name}" is not in the catalog \u2014 auto-repaired to "${alias}".`
|
|
11734
|
+
);
|
|
11735
|
+
return import_react27.default.createElement(import_ui_extensions26.Icon, { name: alias, ...rest });
|
|
11736
|
+
}
|
|
11737
|
+
warnOnce(
|
|
11738
|
+
`icon-invalid-${name}`,
|
|
11739
|
+
`[hs-uix/safe] Icon name "${name}" is not in the catalog. Rendering a red xCircle placeholder. See NATIVE_ICON_NAMES for the valid list.`
|
|
11740
|
+
);
|
|
11741
|
+
return import_react27.default.createElement(import_ui_extensions26.Icon, {
|
|
11742
|
+
...rest,
|
|
11743
|
+
name: "xCircle",
|
|
11744
|
+
color: "alert",
|
|
11745
|
+
screenReaderText: `Invalid icon: ${name ?? "(missing)"}`
|
|
11746
|
+
});
|
|
11747
|
+
};
|
|
11748
|
+
SafeIcon.displayName = "SafeIcon";
|
|
11749
|
+
|
|
11750
|
+
// src/safe/SafeEmptyState.js
|
|
11751
|
+
var import_react28 = __toESM(require("react"));
|
|
11752
|
+
var import_ui_extensions27 = require("@hubspot/ui-extensions");
|
|
11753
|
+
var SafeEmptyState = (props) => {
|
|
11754
|
+
const { imageName, ...rest } = props || {};
|
|
11755
|
+
if (imageName == null || EMPTY_STATE_IMAGES.has(imageName)) {
|
|
11756
|
+
return import_react28.default.createElement(import_ui_extensions27.EmptyState, { imageName, ...rest });
|
|
11757
|
+
}
|
|
11758
|
+
const alias = EMPTY_STATE_IMAGE_ALIASES[imageName];
|
|
11759
|
+
const fallback = alias && EMPTY_STATE_IMAGES.has(alias) ? alias : "components";
|
|
11760
|
+
warnOnce(
|
|
11761
|
+
`emptystate-image-${imageName}`,
|
|
11762
|
+
`[hs-uix/safe] EmptyState imageName "${imageName}" is not valid \u2014 using "${fallback}". See EMPTY_STATE_IMAGES for the valid list.`
|
|
11763
|
+
);
|
|
11764
|
+
return import_react28.default.createElement(import_ui_extensions27.EmptyState, { imageName: fallback, ...rest });
|
|
11765
|
+
};
|
|
11766
|
+
SafeEmptyState.displayName = "SafeEmptyState";
|
|
11767
|
+
|
|
11768
|
+
// src/safe/SafeStatisticsTrend.js
|
|
11769
|
+
var import_react29 = __toESM(require("react"));
|
|
11770
|
+
var import_ui_extensions28 = require("@hubspot/ui-extensions");
|
|
11771
|
+
var SafeStatisticsTrend = (props) => {
|
|
11772
|
+
const { direction, ...rest } = props || {};
|
|
11773
|
+
if (typeof direction !== "string" || TREND_DIRECTIONS.has(direction)) {
|
|
11774
|
+
return import_react29.default.createElement(import_ui_extensions28.StatisticsTrend, { direction, ...rest });
|
|
11775
|
+
}
|
|
11776
|
+
const alias = TREND_DIRECTION_ALIASES[direction];
|
|
11777
|
+
if (alias && TREND_DIRECTIONS.has(alias)) {
|
|
11778
|
+
warnOnce(
|
|
11779
|
+
`trend-alias-${direction}`,
|
|
11780
|
+
`[hs-uix/safe] StatisticsTrend direction "${direction}" \u2192 "${alias}". Valid values: increase, decrease.`
|
|
11781
|
+
);
|
|
11782
|
+
return import_react29.default.createElement(import_ui_extensions28.StatisticsTrend, { direction: alias, ...rest });
|
|
11783
|
+
}
|
|
11784
|
+
warnOnce(
|
|
11785
|
+
`trend-invalid-${direction}`,
|
|
11786
|
+
`[hs-uix/safe] StatisticsTrend direction "${direction}" is not valid \u2014 defaulting to "increase".`
|
|
11787
|
+
);
|
|
11788
|
+
return import_react29.default.createElement(import_ui_extensions28.StatisticsTrend, { ...rest, direction: "increase" });
|
|
11789
|
+
};
|
|
11790
|
+
SafeStatisticsTrend.displayName = "SafeStatisticsTrend";
|
|
11791
|
+
|
|
11792
|
+
// src/safe/SafePopover.js
|
|
11793
|
+
var import_react30 = __toESM(require("react"));
|
|
11794
|
+
var import_ui_extensions29 = require("@hubspot/ui-extensions");
|
|
11795
|
+
var import_experimental2 = require("@hubspot/ui-extensions/experimental");
|
|
11796
|
+
var SafePopover = (props) => {
|
|
11797
|
+
const { children, ...rest } = props || {};
|
|
11798
|
+
return import_react30.default.createElement(
|
|
11799
|
+
import_experimental2.Popover,
|
|
11800
|
+
rest,
|
|
11801
|
+
import_react30.default.createElement(import_ui_extensions29.Tile, { compact: true }, children)
|
|
11802
|
+
);
|
|
11803
|
+
};
|
|
11804
|
+
SafePopover.displayName = "SafePopover";
|
|
11805
|
+
|
|
11806
|
+
// src/safe/safeComponents.js
|
|
11807
|
+
var import_ui_extensions30 = require("@hubspot/ui-extensions");
|
|
11808
|
+
var wrap = (Component, name) => withSafeArrayProps(Component, name, SAFE_ARRAY_PROPS[name] ?? [], SAFE_DERIVE_PROPS[name] ?? []);
|
|
11809
|
+
var SafeSelect = wrap(import_ui_extensions30.Select, "Select");
|
|
11810
|
+
var SafeMultiSelect = wrap(import_ui_extensions30.MultiSelect, "MultiSelect");
|
|
11811
|
+
var SafeToggleGroup = wrap(import_ui_extensions30.ToggleGroup, "ToggleGroup");
|
|
11812
|
+
var SafeStepIndicator = wrap(import_ui_extensions30.StepIndicator, "StepIndicator");
|
|
11813
|
+
var SafeDataTable = wrap(DataTable, "DataTable");
|
|
11814
|
+
var SafeKanban = wrap(Kanban, "Kanban");
|
|
11815
|
+
var SafeFormBuilder = wrap(FormBuilder, "FormBuilder");
|
|
11816
|
+
var SafeAvatarStack = wrap(AvatarStack, "AvatarStack");
|
|
11817
|
+
var SafeKeyValueList = wrap(KeyValueList, "KeyValueList");
|
|
11818
|
+
var SafeFeed = wrap(Feed, "Feed");
|
|
11819
|
+
var SafeCalendar = wrap(Calendar, "Calendar");
|
|
11820
|
+
var SafeCrmDataTable = wrap(CrmDataTable, "CrmDataTable");
|
|
11821
|
+
var SafeCrmKanban = wrap(CrmKanban, "CrmKanban");
|
|
11822
|
+
|
|
11823
|
+
// src/utils/applyPatches.js
|
|
11824
|
+
function applyPatches(doc, patches) {
|
|
11825
|
+
if (!patches || patches.length === 0) return doc;
|
|
11826
|
+
let out = doc ?? {};
|
|
11827
|
+
for (const op of patches) {
|
|
11828
|
+
out = applyOne(out, op);
|
|
11829
|
+
}
|
|
11830
|
+
return out;
|
|
11831
|
+
}
|
|
11832
|
+
function applyOne(doc, op) {
|
|
11833
|
+
const path = parsePointer(op.path);
|
|
11834
|
+
switch (op.op) {
|
|
11835
|
+
case "add":
|
|
11836
|
+
return setAt(doc, path, op.value, true);
|
|
11837
|
+
case "replace":
|
|
11838
|
+
return setAt(doc, path, op.value, false);
|
|
11839
|
+
case "remove":
|
|
11840
|
+
return removeAt(doc, path);
|
|
11841
|
+
case "move": {
|
|
11842
|
+
const from = parsePointer(op.from);
|
|
11843
|
+
const value = getAt(doc, from);
|
|
11844
|
+
const removed = removeAt(doc, from);
|
|
11845
|
+
return setAt(removed, path, value, true);
|
|
11846
|
+
}
|
|
11847
|
+
case "copy": {
|
|
11848
|
+
const from = parsePointer(op.from);
|
|
11849
|
+
const value = getAt(doc, from);
|
|
11850
|
+
return setAt(doc, path, deepClone2(value), true);
|
|
11851
|
+
}
|
|
11852
|
+
default:
|
|
11853
|
+
console.warn("[hs-uix] applyPatches: ignoring unsupported op:", op.op);
|
|
11854
|
+
return doc;
|
|
11855
|
+
}
|
|
11856
|
+
}
|
|
11857
|
+
function parsePointer(pointer) {
|
|
11858
|
+
if (!pointer || pointer === "/") return [];
|
|
11859
|
+
if (pointer[0] !== "/") {
|
|
11860
|
+
throw new Error(`invalid JSON Pointer (must start with /): ${pointer}`);
|
|
11861
|
+
}
|
|
11862
|
+
return pointer.slice(1).split("/").map((seg) => seg.replace(/~1/g, "/").replace(/~0/g, "~"));
|
|
11863
|
+
}
|
|
11864
|
+
function getAt(obj, segs) {
|
|
11865
|
+
let cur = obj;
|
|
11866
|
+
for (const seg of segs) {
|
|
11867
|
+
if (cur == null) return void 0;
|
|
11868
|
+
if (Array.isArray(cur)) {
|
|
11869
|
+
cur = cur[Number(seg)];
|
|
11870
|
+
} else if (typeof cur === "object") {
|
|
11871
|
+
cur = Object.prototype.hasOwnProperty.call(cur, seg) ? cur[seg] : void 0;
|
|
11872
|
+
} else {
|
|
11873
|
+
return void 0;
|
|
11874
|
+
}
|
|
11875
|
+
}
|
|
11876
|
+
return cur;
|
|
11877
|
+
}
|
|
11878
|
+
function setAt(obj, segs, value, insert) {
|
|
11879
|
+
if (segs.length === 0) return value;
|
|
11880
|
+
const [head, ...rest] = segs;
|
|
11881
|
+
if (Array.isArray(obj)) {
|
|
11882
|
+
const next = obj.slice();
|
|
11883
|
+
const idx = head === "-" ? next.length : Number(head);
|
|
11884
|
+
if (rest.length === 0) {
|
|
11885
|
+
if (head === "-") {
|
|
11886
|
+
next.push(value);
|
|
11887
|
+
} else if (insert && Number.isInteger(idx) && idx >= 0 && idx <= next.length) {
|
|
11888
|
+
next.splice(idx, 0, value);
|
|
11889
|
+
} else {
|
|
11890
|
+
next[idx] = value;
|
|
11891
|
+
}
|
|
11892
|
+
return next;
|
|
11893
|
+
}
|
|
11894
|
+
const existing2 = idx >= 0 && idx < next.length ? next[idx] : void 0;
|
|
11895
|
+
next[idx] = setAt(
|
|
11896
|
+
existing2 ?? (looksLikeArrayIndex(rest[0]) ? [] : {}),
|
|
11897
|
+
rest,
|
|
11898
|
+
value,
|
|
11899
|
+
insert
|
|
11900
|
+
);
|
|
11901
|
+
return next;
|
|
11902
|
+
}
|
|
11903
|
+
const base = obj && typeof obj === "object" ? obj : {};
|
|
11904
|
+
if (rest.length === 0) {
|
|
11905
|
+
return { ...base, [head]: value };
|
|
11906
|
+
}
|
|
11907
|
+
const existing = base[head];
|
|
11908
|
+
const child = setAt(
|
|
11909
|
+
existing ?? (looksLikeArrayIndex(rest[0]) ? [] : {}),
|
|
11910
|
+
rest,
|
|
11911
|
+
value,
|
|
11912
|
+
insert
|
|
11913
|
+
);
|
|
11914
|
+
return { ...base, [head]: child };
|
|
11915
|
+
}
|
|
11916
|
+
function removeAt(obj, segs) {
|
|
11917
|
+
if (segs.length === 0) return void 0;
|
|
11918
|
+
const [head, ...rest] = segs;
|
|
11919
|
+
if (Array.isArray(obj)) {
|
|
11920
|
+
const idx = Number(head);
|
|
11921
|
+
if (!Number.isInteger(idx) || idx < 0 || idx >= obj.length) return obj;
|
|
11922
|
+
const next = obj.slice();
|
|
11923
|
+
if (rest.length === 0) {
|
|
11924
|
+
next.splice(idx, 1);
|
|
11925
|
+
} else {
|
|
11926
|
+
next[idx] = removeAt(next[idx], rest);
|
|
11927
|
+
}
|
|
11928
|
+
return next;
|
|
11929
|
+
}
|
|
11930
|
+
if (!obj || typeof obj !== "object") return obj;
|
|
11931
|
+
if (rest.length === 0) {
|
|
11932
|
+
const next = { ...obj };
|
|
11933
|
+
delete next[head];
|
|
11934
|
+
return next;
|
|
11935
|
+
}
|
|
11936
|
+
if (!(head in obj)) return obj;
|
|
11937
|
+
return { ...obj, [head]: removeAt(obj[head], rest) };
|
|
11938
|
+
}
|
|
11939
|
+
function looksLikeArrayIndex(seg) {
|
|
11940
|
+
return seg === "-" || /^\d+$/.test(seg);
|
|
11941
|
+
}
|
|
11942
|
+
function deepClone2(v) {
|
|
11943
|
+
const json = v === void 0 ? void 0 : JSON.stringify(v);
|
|
11944
|
+
return json === void 0 ? void 0 : JSON.parse(json);
|
|
11945
|
+
}
|
|
11946
|
+
|
|
9120
11947
|
// src/utils/collections.js
|
|
9121
11948
|
var sumBy = (items, keyOrFn) => (items || []).reduce((total, item) => {
|
|
9122
11949
|
const value = typeof keyOrFn === "function" ? keyOrFn(item) : item == null ? void 0 : item[keyOrFn];
|
|
@@ -9205,9 +12032,19 @@ var findOptionLabel2 = (options, value, fallback = "") => {
|
|
|
9205
12032
|
CrmDataTable,
|
|
9206
12033
|
CrmKanban,
|
|
9207
12034
|
CrmLookupSelect,
|
|
12035
|
+
CrmRecordPicker,
|
|
12036
|
+
DATE_FILTER_OPERATORS,
|
|
12037
|
+
DATE_RANGE_CUSTOM_VALUE,
|
|
12038
|
+
DATE_ROLLING_UNIT_OPTIONS,
|
|
12039
|
+
DEFAULT_FEED_TYPE_PRESETS,
|
|
9208
12040
|
DEFAULT_SVG_FONT_WEIGHT,
|
|
9209
12041
|
DataTable,
|
|
12042
|
+
DateRangePicker,
|
|
12043
|
+
EMPTY_STATE_IMAGES,
|
|
12044
|
+
EMPTY_STATE_IMAGE_ALIASES,
|
|
12045
|
+
FILTER_OPERATORS,
|
|
9210
12046
|
Feed,
|
|
12047
|
+
FilterBuilder,
|
|
9211
12048
|
FormBuilder,
|
|
9212
12049
|
HS_DATE_DIRECTION_LABELS,
|
|
9213
12050
|
HS_DATE_PRESETS,
|
|
@@ -9226,21 +12063,61 @@ var findOptionLabel2 = (options, value, fallback = "") => {
|
|
|
9226
12063
|
HS_TEXT_COLOR,
|
|
9227
12064
|
ICONS,
|
|
9228
12065
|
ICON_NAMES,
|
|
12066
|
+
ICON_NAME_ALIASES,
|
|
9229
12067
|
Icon,
|
|
9230
12068
|
Kanban,
|
|
9231
12069
|
KanbanCardActions,
|
|
9232
12070
|
KeyValueList,
|
|
12071
|
+
NATIVE_ICON_NAMES,
|
|
9233
12072
|
NATIVE_ICON_NAME_LIST,
|
|
12073
|
+
SAFE_ARRAY_PROPS,
|
|
12074
|
+
SAFE_DERIVE_PROPS,
|
|
12075
|
+
SKELETON_FILL,
|
|
9234
12076
|
SPINNERS,
|
|
9235
12077
|
SPINNER_NAMES,
|
|
12078
|
+
SafeAvatarStack,
|
|
12079
|
+
SafeCalendar,
|
|
12080
|
+
SafeCrmDataTable,
|
|
12081
|
+
SafeCrmKanban,
|
|
12082
|
+
SafeDataTable,
|
|
12083
|
+
SafeEmptyState,
|
|
12084
|
+
SafeFeed,
|
|
12085
|
+
SafeFormBuilder,
|
|
12086
|
+
SafeIcon,
|
|
12087
|
+
SafeKanban,
|
|
12088
|
+
SafeKeyValueList,
|
|
12089
|
+
SafeMultiSelect,
|
|
12090
|
+
SafePopover,
|
|
12091
|
+
SafeSelect,
|
|
12092
|
+
SafeStatisticsTrend,
|
|
12093
|
+
SafeStepIndicator,
|
|
12094
|
+
SafeToggleGroup,
|
|
9236
12095
|
SectionHeader,
|
|
9237
12096
|
Spinner,
|
|
9238
12097
|
StyledText,
|
|
12098
|
+
TREND_DIRECTIONS,
|
|
12099
|
+
TREND_DIRECTION_ALIASES,
|
|
12100
|
+
UNASSIGNED_LANE_KEY,
|
|
12101
|
+
addFilter,
|
|
12102
|
+
applyPatches,
|
|
12103
|
+
applyTypePreset,
|
|
9239
12104
|
buildCrmSearchConfig,
|
|
9240
12105
|
buildOptions,
|
|
12106
|
+
changeConditionOperator,
|
|
12107
|
+
changeConditionProperty,
|
|
12108
|
+
compareHsDateValues,
|
|
12109
|
+
computeStageCounts,
|
|
12110
|
+
conditionToCrmFilter,
|
|
12111
|
+
countConditions,
|
|
12112
|
+
createCondition,
|
|
12113
|
+
createGroup,
|
|
9241
12114
|
createStatusTagSortComparator,
|
|
9242
12115
|
crmSearchResultToOption,
|
|
12116
|
+
evaluateWip,
|
|
12117
|
+
fieldsFromHubSpotProperties,
|
|
12118
|
+
findNewlyExceededWip,
|
|
9243
12119
|
findOptionLabel,
|
|
12120
|
+
flushBuffer,
|
|
9244
12121
|
formatCurrency,
|
|
9245
12122
|
formatCurrencyCompact,
|
|
9246
12123
|
formatDate,
|
|
@@ -9248,7 +12125,14 @@ var findOptionLabel2 = (options, value, fallback = "") => {
|
|
|
9248
12125
|
formatPercentage,
|
|
9249
12126
|
getAutoStatusTagVariant,
|
|
9250
12127
|
getAutoTagVariant,
|
|
12128
|
+
getLaneKey,
|
|
12129
|
+
getNodeAtPath,
|
|
12130
|
+
getOperatorOptions,
|
|
9251
12131
|
gridToBraille,
|
|
12132
|
+
isConditionNode,
|
|
12133
|
+
isGroupNode,
|
|
12134
|
+
isValidDateRange,
|
|
12135
|
+
lookupTypePreset,
|
|
9252
12136
|
makeAvatarStackDataUri,
|
|
9253
12137
|
makeCrmSearchMultiSelectField,
|
|
9254
12138
|
makeCrmSearchSelectField,
|
|
@@ -9257,10 +12141,28 @@ var findOptionLabel2 = (options, value, fallback = "") => {
|
|
|
9257
12141
|
makeStyledTextDataUri,
|
|
9258
12142
|
normalizeCrmSearchRecord,
|
|
9259
12143
|
normalizeCrmSearchRows,
|
|
12144
|
+
operatorExpectsHighValue,
|
|
12145
|
+
operatorExpectsValue,
|
|
12146
|
+
operatorExpectsValues,
|
|
12147
|
+
orderLaneKeys,
|
|
12148
|
+
partitionLanes,
|
|
12149
|
+
partitionNewItems,
|
|
12150
|
+
presetToRange,
|
|
12151
|
+
removeFilter,
|
|
12152
|
+
resetSafeWarnings,
|
|
9260
12153
|
resolveCrmObjectType,
|
|
12154
|
+
resolveLaneLabel,
|
|
12155
|
+
resolveWipLimit,
|
|
9261
12156
|
sumBy,
|
|
9262
12157
|
svgToIconEntry,
|
|
12158
|
+
toCrmSearchFilterGroups,
|
|
12159
|
+
toHsDateValue,
|
|
12160
|
+
toTimestampMs,
|
|
12161
|
+
updateFilter,
|
|
9263
12162
|
useCrmSearchDataSource,
|
|
9264
12163
|
useCrmSearchOptions,
|
|
9265
|
-
useFormPrefill
|
|
12164
|
+
useFormPrefill,
|
|
12165
|
+
validateTree,
|
|
12166
|
+
warnOnce,
|
|
12167
|
+
withSafeArrayProps
|
|
9266
12168
|
});
|