@elaraai/e3-ui-components 1.0.31 → 1.0.33

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.
@@ -0,0 +1,23 @@
1
+ import { Decision, UrgencyKind } from './types.js';
2
+ /** Section labels for the built-in urgency grouping. */
3
+ export declare const URGENCY_GROUP_LABEL: Record<UrgencyKind, string>;
4
+ /** One Group-by toolbar option — a built-in key or a custom accessor facet. */
5
+ export interface GroupOption {
6
+ key: string;
7
+ label: string;
8
+ accessor?: (d: Decision) => string;
9
+ }
10
+ /** One resolved queue section. */
11
+ export interface QueueGroup {
12
+ label: string;
13
+ decisions: Decision[];
14
+ pastSla: number;
15
+ total: number;
16
+ /** Hosts the bulk Accept all (the urgency grouping's Routine section). */
17
+ bulk: boolean;
18
+ }
19
+ /** Folds the sorted rows into sections for the active grouping. Rows arrive
20
+ * urgency-sorted, so first-appearance order gives Overdue → Due today →
21
+ * Routine for the built-in and stable insertion order for the rest. */
22
+ export declare function buildGroups(rows: Decision[], option: GroupOption): QueueGroup[];
23
+ //# sourceMappingURL=grouping.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grouping.d.ts","sourceRoot":"","sources":["../../src/decision/grouping.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;GAOG;AAEH,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAE7D,wDAAwD;AACxD,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,WAAW,EAAE,MAAM,CAI3D,CAAC;AAEF,+EAA+E;AAC/E,MAAM,WAAW,WAAW;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,CAAC,CAAC,EAAE,QAAQ,KAAK,MAAM,CAAC;CACtC;AAED,kCAAkC;AAClC,MAAM,WAAW,UAAU;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,0EAA0E;IAC1E,IAAI,EAAE,OAAO,CAAC;CACjB;AAED;;wEAEwE;AACxE,wBAAgB,WAAW,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,WAAW,GAAG,UAAU,EAAE,CA2B/E"}
@@ -1 +1 @@
1
- {"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../../src/decision/queue.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAwBH,OAAO,EAAW,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAE1D,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAkBxD,KAAK,kBAAkB,GAAG,WAAW,CAAC,OAAO,aAAa,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;AA2T7E,MAAM,WAAW,4BAA4B;IACzC,KAAK,EAAE,kBAAkB,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;CACtB;AAED,QAAA,MAAM,uBAAuB,oEA6M3B,CAAC;AAIH,OAAO,EAAE,uBAAuB,EAAE,CAAC"}
1
+ {"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../../src/decision/queue.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AA8BH,OAAO,EAAW,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAE1D,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAoBxD,KAAK,kBAAkB,GAAG,WAAW,CAAC,OAAO,aAAa,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;AAiX7E,MAAM,WAAW,4BAA4B;IACzC,KAAK,EAAE,kBAAkB,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;CACtB;AAED,QAAA,MAAM,uBAAuB,oEA2S3B,CAAC;AAIH,OAAO,EAAE,uBAAuB,EAAE,CAAC"}
package/dist/index.cjs CHANGED
@@ -62928,6 +62928,39 @@ const URGENCY_RANK = {
62928
62928
  due: 1,
62929
62929
  routine: 2
62930
62930
  };
62931
+ const URGENCY_GROUP_LABEL = {
62932
+ overdue: "Overdue",
62933
+ due: "Due today",
62934
+ routine: "Routine"
62935
+ };
62936
+ function buildGroups(rows, option) {
62937
+ if (option.key === "none") {
62938
+ return [{ label: "", decisions: rows, pastSla: 0, total: 0, bulk: false }];
62939
+ }
62940
+ const labelFor = (d2) => {
62941
+ var _a2;
62942
+ return option.key === "urgency" ? URGENCY_GROUP_LABEL[d2.urgency.type] : option.key === "kind" ? d2.kind : ((_a2 = option.accessor) == null ? void 0 : _a2.call(option, d2)) ?? "";
62943
+ };
62944
+ const out = /* @__PURE__ */ new Map();
62945
+ for (const d2 of rows) {
62946
+ const label = labelFor(d2);
62947
+ let group2 = out.get(label);
62948
+ if (group2 === void 0) {
62949
+ group2 = {
62950
+ label,
62951
+ decisions: [],
62952
+ pastSla: 0,
62953
+ total: 0,
62954
+ bulk: option.key === "urgency" && d2.urgency.type === "routine"
62955
+ };
62956
+ out.set(label, group2);
62957
+ }
62958
+ group2.decisions.push(d2);
62959
+ group2.total += d2.value;
62960
+ if (d2.urgency.type === "overdue") group2.pastSla += 1;
62961
+ }
62962
+ return [...out.values()];
62963
+ }
62931
62964
  const FACETS = [
62932
62965
  { key: "evidence", label: "Evidence" },
62933
62966
  { key: "options", label: "Options" },
@@ -63044,7 +63077,8 @@ const Row = React.memo(function Row2({ decision, handle, selected: selected2, na
63044
63077
  ),
63045
63078
  /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "button", css: button({ variant: "ghost", size: "xs" }), onClick: handleReject, children: "Reject" })
63046
63079
  ] });
63047
- const title = /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { minW: 0, cursor: selected2 ? void 0 : "pointer", onClick: handleSelect, children: [
63080
+ const fullTitle = `${decision.kind} · ${decision.title}${summary !== void 0 ? ` · ${summary}` : ""}`;
63081
+ const title = /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: rs.titleText, title: fullTitle, cursor: selected2 ? void 0 : "pointer", onClick: handleSelect, children: [
63048
63082
  /* @__PURE__ */ jsxRuntime.jsx(react.Text, { as: "span", fontWeight: "semibold", children: decision.kind }),
63049
63083
  /* @__PURE__ */ jsxRuntime.jsx(react.Text, { as: "span", color: "fg.subtle", children: " · " }),
63050
63084
  /* @__PURE__ */ jsxRuntime.jsx(react.Text, { as: "span", children: decision.title }),
@@ -63129,10 +63163,39 @@ const RoutineGroup = React.memo(function RoutineGroup2({ routine, acceptAll, lea
63129
63163
  ] })
63130
63164
  ] });
63131
63165
  });
63166
+ const GroupHead = React.memo(function GroupHead2({ group: group2, collapsible, collapsed, onToggle, acceptAll }) {
63167
+ const dq = react.useSlotRecipe({ key: "decisionQueue" });
63168
+ const button = react.useRecipe({ key: "button" });
63169
+ const rs = dq({});
63170
+ const format2 = group2.decisions[0] ? eastUiComponents.getSomeorUndefined(group2.decisions[0].format) : void 0;
63171
+ const handleToggle = React.useCallback(() => {
63172
+ if (collapsible) onToggle(group2.label);
63173
+ }, [collapsible, onToggle, group2.label]);
63174
+ const handleAcceptAll = React.useCallback((e3) => {
63175
+ e3.stopPropagation();
63176
+ if (acceptAll) acceptAll(group2.decisions);
63177
+ }, [acceptAll, group2.decisions]);
63178
+ return /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: rs.groupHead, ...collapsible ? { "data-collapsible": "" } : {}, onClick: handleToggle, children: [
63179
+ collapsible && /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: rs.groupCaret, children: collapsed ? "▸" : "▾" }),
63180
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { as: "span", css: rs.groupLabel, children: [
63181
+ group2.label,
63182
+ " · ",
63183
+ group2.decisions.length
63184
+ ] }),
63185
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { as: "span", css: rs.groupSummary, children: [
63186
+ eastUiComponents.formatTick(group2.total, format2),
63187
+ group2.pastSla > 0 ? ` · ${group2.pastSla} past SLA` : ""
63188
+ ] }),
63189
+ acceptAll && /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "button", css: button({ variant: "solid", size: "xs" }), onClick: handleAcceptAll, children: "Accept all" })
63190
+ ] });
63191
+ });
63132
63192
  const EastChakraDecisionQueue = React.memo(function EastChakraDecisionQueue2({ value, storageKey }) {
63133
63193
  var _a2;
63134
63194
  const eyebrow = react.useSlotRecipe({ key: "eyebrowRow" });
63135
63195
  const es = eyebrow({});
63196
+ const dq = react.useSlotRecipe({ key: "decisionQueue" });
63197
+ const qs = dq({});
63198
+ const chip = react.useRecipe({ key: "chip" });
63136
63199
  const handleRef = value.handle;
63137
63200
  const handle = useDecisionHandle(handleRef);
63138
63201
  const decisions = handle.decisions;
@@ -63201,6 +63264,25 @@ const EastChakraDecisionQueue = React.memo(function EastChakraDecisionQueue2({ v
63201
63264
  return facets === void 0 ? null : new Set(facets.map((f2) => f2.type));
63202
63265
  }, [value.facets]);
63203
63266
  const defaultExpanded = eastUiComponents.getSomeorUndefined(value.defaultExpanded);
63267
+ const groupDefs = React.useMemo(
63268
+ () => eastUiComponents.getSomeorUndefined(value.groups) ?? [],
63269
+ [value.groups]
63270
+ );
63271
+ const defaultGroupKey = eastUiComponents.getSomeorUndefined(value.groupBy);
63272
+ const grouped = defaultGroupKey !== void 0;
63273
+ const collapsible = grouped && (eastUiComponents.getSomeorUndefined(value.collapsible) ?? true);
63274
+ const groupOptions = React.useMemo(() => [
63275
+ { key: "urgency", label: "Urgency" },
63276
+ { key: "kind", label: "Kind" },
63277
+ ...groupDefs.map((g2) => ({ key: g2.label, label: g2.label, accessor: g2.value })),
63278
+ { key: "none", label: "None" }
63279
+ ], [groupDefs]);
63280
+ const { state: toolbar, setState: setToolbar } = eastUiComponents.usePersistedState(`${storageKey}.toolbar`, {
63281
+ groupKey: defaultGroupKey ?? "urgency",
63282
+ // The urgency grouping's routine tail ships collapsed.
63283
+ collapsed: [URGENCY_GROUP_LABEL.routine]
63284
+ });
63285
+ const activeOption = groupOptions.find((o2) => o2.key === toolbar.groupKey) ?? groupOptions[0];
63204
63286
  const selectedId = handle.selected ?? (defaultExpanded == null ? void 0 : defaultExpanded.id) ?? null;
63205
63287
  const resolve2 = React.useCallback((ds, hook2, reason) => {
63206
63288
  if (hook2) for (const d2 of ds) {
@@ -63215,15 +63297,15 @@ const EastChakraDecisionQueue = React.memo(function EastChakraDecisionQueue2({ v
63215
63297
  const apply2 = React.useCallback((d2) => resolve2([d2], onApply, "apply"), [resolve2, onApply]);
63216
63298
  const reject2 = React.useCallback((d2) => resolve2([d2], onReject, "reject"), [resolve2, onReject]);
63217
63299
  const acceptAll = React.useCallback((ds) => resolve2(ds, onApply, "apply"), [resolve2, onApply]);
63218
- const { active, routine, pastSla, visible } = React.useMemo(() => {
63300
+ const { merged, active, routine, pastSla, visible } = React.useMemo(() => {
63219
63301
  const scoped = decisions ?? [];
63220
63302
  const now2 = /* @__PURE__ */ new Date();
63221
63303
  const live = sliceState !== null ? scoped.filter((d2) => internal$2.sliceMatches(sliceState, DECISION_SLICE_CONFIG, d2, now2)) : scoped;
63222
- const merged = [...live];
63304
+ const merged2 = [...live];
63223
63305
  for (const { decision } of exiting.values()) {
63224
- if (!merged.some((d2) => d2.id === decision.id)) merged.push(decision);
63306
+ if (!merged2.some((d2) => d2.id === decision.id)) merged2.push(decision);
63225
63307
  }
63226
- merged.sort((a2, b2) => {
63308
+ merged2.sort((a2, b2) => {
63227
63309
  var _a3, _b2;
63228
63310
  const r2 = URGENCY_RANK[a2.urgency.type] - URGENCY_RANK[b2.urgency.type];
63229
63311
  if (r2 !== 0) return r2;
@@ -63233,17 +63315,55 @@ const EastChakraDecisionQueue = React.memo(function EastChakraDecisionQueue2({ v
63233
63315
  return b2.value - a2.value;
63234
63316
  });
63235
63317
  return {
63236
- active: merged.filter((d2) => d2.urgency.type !== "routine"),
63237
- routine: merged.filter((d2) => d2.urgency.type === "routine"),
63238
- pastSla: merged.filter((d2) => d2.urgency.type === "overdue").length,
63318
+ merged: merged2,
63319
+ active: merged2.filter((d2) => d2.urgency.type !== "routine"),
63320
+ routine: merged2.filter((d2) => d2.urgency.type === "routine"),
63321
+ pastSla: merged2.filter((d2) => d2.urgency.type === "overdue").length,
63239
63322
  visible: live.length
63240
63323
  };
63241
63324
  }, [decisions, exiting, sliceState]);
63325
+ const groups = React.useMemo(
63326
+ () => grouped ? buildGroups(merged, activeOption) : [],
63327
+ [grouped, merged, activeOption]
63328
+ );
63329
+ const allCollapsed = groups.length > 0 && groups.every((g2) => g2.label === "" || toolbar.collapsed.includes(g2.label));
63330
+ const toggleGroup = React.useCallback((label) => {
63331
+ setToolbar((prev2) => ({
63332
+ ...prev2,
63333
+ collapsed: prev2.collapsed.includes(label) ? prev2.collapsed.filter((l2) => l2 !== label) : [...prev2.collapsed, label]
63334
+ }));
63335
+ }, [setToolbar]);
63336
+ const toggleAll = React.useCallback(() => {
63337
+ const next2 = allCollapsed ? [] : groups.map((g2) => g2.label).filter((l2) => l2 !== "");
63338
+ setToolbar((prev2) => ({ ...prev2, collapsed: next2 }));
63339
+ }, [setToolbar, allCollapsed, groups]);
63340
+ const setGroupKey = React.useCallback((key) => {
63341
+ setToolbar((prev2) => prev2.groupKey === key ? prev2 : { ...prev2, groupKey: key });
63342
+ }, [setToolbar]);
63242
63343
  const exitingReasons = React.useMemo(() => {
63243
63344
  const m2 = /* @__PURE__ */ new Map();
63244
63345
  for (const [id3, e3] of exiting) m2.set(id3, e3.reason);
63245
63346
  return m2;
63246
63347
  }, [exiting]);
63348
+ const renderRow = (d2) => /* @__PURE__ */ jsxRuntime.jsx(
63349
+ Row,
63350
+ {
63351
+ decision: d2,
63352
+ handle,
63353
+ selected: selectedId === d2.id,
63354
+ narrow,
63355
+ leverPayloads,
63356
+ modify,
63357
+ evidence,
63358
+ defaultFacet,
63359
+ facetInclude,
63360
+ apply: apply2,
63361
+ reject: reject2,
63362
+ leaving: exitingReasons.get(d2.id),
63363
+ storageKey
63364
+ },
63365
+ d2.id
63366
+ );
63247
63367
  if (decisions === null) {
63248
63368
  return /* @__PURE__ */ jsxRuntime.jsx(react.Box, { layerStyle: "surface.frameless", p: "16px", children: /* @__PURE__ */ jsxRuntime.jsx(react.Text, { color: "fg.muted", fontSize: "13px", children: "Loading decisions…" }) });
63249
63369
  }
@@ -63271,33 +63391,45 @@ const EastChakraDecisionQueue = React.memo(function EastChakraDecisionQueue2({ v
63271
63391
  ] })
63272
63392
  ] })
63273
63393
  ] }),
63274
- /* @__PURE__ */ jsxRuntime.jsxs(
63394
+ grouped && /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: qs.toolbar, children: [
63395
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: qs.segLabel, children: "Group by" }),
63396
+ groupOptions.map((o2) => /* @__PURE__ */ jsxRuntime.jsx(
63397
+ react.Box,
63398
+ {
63399
+ as: "button",
63400
+ css: { ...chip({ tone: toolbar.groupKey === o2.key ? "brand" : "neutral", size: "sm" }), cursor: "pointer" },
63401
+ "aria-pressed": toolbar.groupKey === o2.key,
63402
+ onClick: () => setGroupKey(o2.key),
63403
+ children: o2.label
63404
+ },
63405
+ o2.key
63406
+ )),
63407
+ collapsible && /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "button", css: qs.collapseAll, onClick: toggleAll, children: allCollapsed ? "Expand all" : "Collapse all" })
63408
+ ] }),
63409
+ /* @__PURE__ */ jsxRuntime.jsx(
63275
63410
  react.Box,
63276
63411
  {
63277
63412
  maxHeight: eastUiComponents.getSomeorUndefined(value.maxHeight),
63278
63413
  overflowY: value.maxHeight.type === "some" ? "auto" : void 0,
63279
- children: [
63280
- active.map((d2) => /* @__PURE__ */ jsxRuntime.jsx(
63281
- Row,
63282
- {
63283
- decision: d2,
63284
- handle,
63285
- selected: selectedId === d2.id,
63286
- narrow,
63287
- leverPayloads,
63288
- modify,
63289
- evidence,
63290
- defaultFacet,
63291
- facetInclude,
63292
- apply: apply2,
63293
- reject: reject2,
63294
- leaving: exitingReasons.get(d2.id),
63295
- storageKey
63296
- },
63297
- d2.id
63298
- )),
63414
+ children: grouped ? groups.map((g2) => {
63415
+ const isCollapsed = collapsible && g2.label !== "" && toolbar.collapsed.includes(g2.label);
63416
+ return /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { children: [
63417
+ g2.label !== "" && /* @__PURE__ */ jsxRuntime.jsx(
63418
+ GroupHead,
63419
+ {
63420
+ group: g2,
63421
+ collapsible,
63422
+ collapsed: isCollapsed,
63423
+ onToggle: toggleGroup,
63424
+ acceptAll: g2.bulk ? acceptAll : void 0
63425
+ }
63426
+ ),
63427
+ !isCollapsed && g2.decisions.map(renderRow)
63428
+ ] }, g2.label || "_flat");
63429
+ }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
63430
+ active.map(renderRow),
63299
63431
  /* @__PURE__ */ jsxRuntime.jsx(RoutineGroup, { routine, acceptAll, leaving: exitingReasons, narrow })
63300
- ]
63432
+ ] })
63301
63433
  }
63302
63434
  )
63303
63435
  ] });