@octaviaflow/core 3.1.0-beta.111 → 3.1.0-beta.113

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -5333,13 +5333,18 @@ var CommandPalette = forwardRef26(
5333
5333
  open,
5334
5334
  onClose,
5335
5335
  groups,
5336
- placeholder = "Search for actions, pages, datasets\u2026",
5336
+ placeholder = "Search\u2026",
5337
5337
  onSelect,
5338
5338
  emptyState,
5339
5339
  footer,
5340
5340
  filter = defaultFilter,
5341
5341
  container,
5342
5342
  disableAnimation = false,
5343
+ query: controlledQuery,
5344
+ onQueryChange,
5345
+ shouldFilter = true,
5346
+ loading = false,
5347
+ loadingLabel = "Searching\u2026",
5343
5348
  id: providedId,
5344
5349
  className,
5345
5350
  ...rest
@@ -5349,14 +5354,16 @@ var CommandPalette = forwardRef26(
5349
5354
  const reducedMotion = useReducedMotion3();
5350
5355
  const inputRef = useRef10(null);
5351
5356
  const listRef = useRef10(null);
5352
- const [query, setQuery] = useState16("");
5357
+ const isQueryControlled = controlledQuery !== void 0;
5358
+ const [internalQuery, setInternalQuery] = useState16("");
5359
+ const query = isQueryControlled ? controlledQuery : internalQuery;
5353
5360
  const [activeIndex, setActiveIndex] = useState16(0);
5354
5361
  const filteredGroups = useMemo5(() => {
5355
5362
  return groups.map((g) => ({
5356
5363
  ...g,
5357
- items: g.items.filter((it) => filter(it, query, g.heading))
5364
+ items: g.shouldFilter ?? shouldFilter ? g.items.filter((it) => filter(it, query, g.heading)) : g.items
5358
5365
  })).filter((g) => g.items.length > 0);
5359
- }, [groups, query, filter]);
5366
+ }, [groups, query, filter, shouldFilter]);
5360
5367
  const flatItems = useMemo5(
5361
5368
  () => filteredGroups.flatMap((g) => g.items),
5362
5369
  [filteredGroups]
@@ -5368,7 +5375,7 @@ var CommandPalette = forwardRef26(
5368
5375
  }, [flatItems.length, activeIndex]);
5369
5376
  useEffect8(() => {
5370
5377
  if (open) {
5371
- setQuery("");
5378
+ if (!isQueryControlled) setInternalQuery("");
5372
5379
  setActiveIndex(0);
5373
5380
  requestAnimationFrame(() => inputRef.current?.focus());
5374
5381
  }
@@ -5447,76 +5454,85 @@ var CommandPalette = forwardRef26(
5447
5454
  placeholder,
5448
5455
  value: query,
5449
5456
  onChange: (e) => {
5450
- setQuery(e.target.value);
5457
+ const next = e.target.value;
5458
+ if (!isQueryControlled) setInternalQuery(next);
5459
+ onQueryChange?.(next);
5451
5460
  setActiveIndex(0);
5452
5461
  }
5453
5462
  }
5454
5463
  ),
5455
5464
  /* @__PURE__ */ jsx30("kbd", { className: "ods-cmdk__esc-hint", "aria-hidden": "true", children: "Esc" })
5456
5465
  ] }),
5457
- /* @__PURE__ */ jsx30(
5466
+ /* @__PURE__ */ jsxs30(
5458
5467
  "div",
5459
5468
  {
5460
5469
  ref: listRef,
5461
5470
  id: `${baseId}-list`,
5462
5471
  role: "listbox",
5463
5472
  className: "ods-cmdk__list",
5464
- children: filteredGroups.length === 0 ? /* @__PURE__ */ jsx30("div", { className: "ods-cmdk__empty", children: emptyState ?? /* @__PURE__ */ jsxs30(Fragment10, { children: [
5465
- /* @__PURE__ */ jsx30("p", { className: "ods-cmdk__empty-title", children: "No results" }),
5466
- /* @__PURE__ */ jsx30("p", { className: "ods-cmdk__empty-hint", children: "Try a different keyword." })
5467
- ] }) }) : (() => {
5468
- let flatIdx = -1;
5469
- return filteredGroups.map((g, gi) => /* @__PURE__ */ jsxs30(
5470
- "div",
5471
- {
5472
- className: "ods-cmdk__group",
5473
- role: "group",
5474
- "aria-label": typeof g.heading === "string" ? g.heading : void 0,
5475
- children: [
5476
- /* @__PURE__ */ jsx30("div", { className: "ods-cmdk__group-heading", children: g.heading }),
5477
- g.items.map((item) => {
5478
- flatIdx += 1;
5479
- const idx = flatIdx;
5480
- const isActive2 = idx === activeIndex;
5481
- return /* @__PURE__ */ jsxs30(
5482
- "div",
5483
- {
5484
- id: `${baseId}-opt-${idx}`,
5485
- role: "option",
5486
- "aria-selected": isActive2,
5487
- "aria-disabled": item.disabled || void 0,
5488
- className: cn(
5489
- "ods-cmdk__option",
5490
- isActive2 && "ods-cmdk__option--active",
5491
- item.danger && "ods-cmdk__option--danger",
5492
- item.disabled && "ods-cmdk__option--disabled"
5493
- ),
5494
- onMouseEnter: () => setActiveIndex(idx),
5495
- onClick: () => handleItemClick(item),
5496
- children: [
5497
- item.icon && /* @__PURE__ */ jsx30(
5498
- "span",
5499
- {
5500
- className: "ods-cmdk__option-icon",
5501
- "aria-hidden": "true",
5502
- children: item.icon
5503
- }
5473
+ "aria-busy": loading || void 0,
5474
+ children: [
5475
+ filteredGroups.length === 0 ? loading ? null : /* @__PURE__ */ jsx30("div", { className: "ods-cmdk__empty", children: emptyState ?? /* @__PURE__ */ jsxs30(Fragment10, { children: [
5476
+ /* @__PURE__ */ jsx30("p", { className: "ods-cmdk__empty-title", children: "No results" }),
5477
+ /* @__PURE__ */ jsx30("p", { className: "ods-cmdk__empty-hint", children: "Try a different keyword." })
5478
+ ] }) }) : (() => {
5479
+ let flatIdx = -1;
5480
+ return filteredGroups.map((g, gi) => /* @__PURE__ */ jsxs30(
5481
+ "div",
5482
+ {
5483
+ className: "ods-cmdk__group",
5484
+ role: "group",
5485
+ "aria-label": typeof g.heading === "string" ? g.heading : void 0,
5486
+ children: [
5487
+ /* @__PURE__ */ jsx30("div", { className: "ods-cmdk__group-heading", children: g.heading }),
5488
+ g.items.map((item) => {
5489
+ flatIdx += 1;
5490
+ const idx = flatIdx;
5491
+ const isActive2 = idx === activeIndex;
5492
+ return /* @__PURE__ */ jsxs30(
5493
+ "div",
5494
+ {
5495
+ id: `${baseId}-opt-${idx}`,
5496
+ role: "option",
5497
+ "aria-selected": isActive2,
5498
+ "aria-disabled": item.disabled || void 0,
5499
+ className: cn(
5500
+ "ods-cmdk__option",
5501
+ isActive2 && "ods-cmdk__option--active",
5502
+ item.danger && "ods-cmdk__option--danger",
5503
+ item.disabled && "ods-cmdk__option--disabled"
5504
5504
  ),
5505
- /* @__PURE__ */ jsxs30("span", { className: "ods-cmdk__option-body", children: [
5506
- /* @__PURE__ */ jsx30("span", { className: "ods-cmdk__option-label", children: item.label }),
5507
- item.description && /* @__PURE__ */ jsx30("span", { className: "ods-cmdk__option-desc", children: item.description })
5508
- ] }),
5509
- item.shortcut && /* @__PURE__ */ jsx30("kbd", { className: "ods-cmdk__option-shortcut", children: item.shortcut })
5510
- ]
5511
- },
5512
- item.id
5513
- );
5514
- })
5515
- ]
5516
- },
5517
- gi
5518
- ));
5519
- })()
5505
+ onMouseEnter: () => setActiveIndex(idx),
5506
+ onClick: () => handleItemClick(item),
5507
+ children: [
5508
+ item.icon && /* @__PURE__ */ jsx30(
5509
+ "span",
5510
+ {
5511
+ className: "ods-cmdk__option-icon",
5512
+ "aria-hidden": "true",
5513
+ children: item.icon
5514
+ }
5515
+ ),
5516
+ /* @__PURE__ */ jsxs30("span", { className: "ods-cmdk__option-body", children: [
5517
+ /* @__PURE__ */ jsx30("span", { className: "ods-cmdk__option-label", children: item.label }),
5518
+ item.description && /* @__PURE__ */ jsx30("span", { className: "ods-cmdk__option-desc", children: item.description })
5519
+ ] }),
5520
+ item.shortcut && /* @__PURE__ */ jsx30("kbd", { className: "ods-cmdk__option-shortcut", children: item.shortcut })
5521
+ ]
5522
+ },
5523
+ item.id
5524
+ );
5525
+ })
5526
+ ]
5527
+ },
5528
+ gi
5529
+ ));
5530
+ })(),
5531
+ loading && /* @__PURE__ */ jsxs30("div", { className: "ods-cmdk__loading", role: "status", "aria-live": "polite", children: [
5532
+ /* @__PURE__ */ jsx30(Spinner, { size: "sm", tone: "muted", "aria-hidden": "true" }),
5533
+ /* @__PURE__ */ jsx30("span", { children: loadingLabel })
5534
+ ] })
5535
+ ]
5520
5536
  }
5521
5537
  ),
5522
5538
  footer && /* @__PURE__ */ jsx30("div", { className: "ods-cmdk__footer", children: footer })
@@ -11734,7 +11750,10 @@ function shortReferenceLabel(token) {
11734
11750
  if (token.startsWith("{{ods://")) {
11735
11751
  const path = token.slice(8, -2);
11736
11752
  const parts = path.split("/");
11737
- if (parts[0] === "steps" && parts.length >= 4) return parts.slice(3).join(".");
11753
+ if (parts[0] === "steps") {
11754
+ if (parts.length >= 4) return parts.slice(3).join(".");
11755
+ return parts[2] ?? "output";
11756
+ }
11738
11757
  if (parts[0] === "flow") return `flow.${parts.slice(1).join(".")}`;
11739
11758
  return parts.join(".");
11740
11759
  }
@@ -33209,6 +33228,7 @@ function SlideoutContent({
33209
33228
  title,
33210
33229
  children,
33211
33230
  footer,
33231
+ headerActions,
33212
33232
  className,
33213
33233
  offsetTop = 0,
33214
33234
  offsetBottom = 0
@@ -33294,16 +33314,19 @@ function SlideoutContent({
33294
33314
  children: [
33295
33315
  title && /* @__PURE__ */ jsxs130("div", { className: "ods-slideout__header", children: [
33296
33316
  /* @__PURE__ */ jsx135("h2", { ...titleProps, className: "ods-slideout__title", children: title }),
33297
- /* @__PURE__ */ jsx135(
33298
- "button",
33299
- {
33300
- className: "ods-slideout__close",
33301
- onClick: onClose,
33302
- "aria-label": "Close panel",
33303
- type: "button",
33304
- children: /* @__PURE__ */ jsx135("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "currentColor", children: /* @__PURE__ */ jsx135("path", { d: "M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z" }) })
33305
- }
33306
- )
33317
+ /* @__PURE__ */ jsxs130("div", { className: "ods-slideout__header-actions", children: [
33318
+ headerActions,
33319
+ /* @__PURE__ */ jsx135(
33320
+ "button",
33321
+ {
33322
+ className: "ods-slideout__close",
33323
+ onClick: onClose,
33324
+ "aria-label": "Close panel",
33325
+ type: "button",
33326
+ children: /* @__PURE__ */ jsx135("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "currentColor", children: /* @__PURE__ */ jsx135("path", { d: "M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z" }) })
33327
+ }
33328
+ )
33329
+ ] })
33307
33330
  ] }),
33308
33331
  /* @__PURE__ */ jsx135("div", { className: "ods-slideout__body", children }),
33309
33332
  footer && /* @__PURE__ */ jsx135("div", { className: "ods-slideout__footer", children: footer })
@@ -34661,6 +34684,8 @@ import {
34661
34684
  createContext as createContext3,
34662
34685
  useCallback as useCallback51,
34663
34686
  useContext as useContext4,
34687
+ useEffect as useEffect57,
34688
+ useLayoutEffect as useLayoutEffect12,
34664
34689
  useMemo as useMemo37,
34665
34690
  useRef as useRef50,
34666
34691
  useState as useState71
@@ -34755,15 +34780,57 @@ var defaultIcons = {
34755
34780
  ] })
34756
34781
  };
34757
34782
  var ToastContext = createContext3(null);
34758
- function ToastBody({ item, onDismiss }) {
34783
+ function ToastBody({ item, stacked, onDismiss }) {
34759
34784
  const dismiss = () => onDismiss(item.id);
34785
+ const [expanded, setExpanded] = useState71(false);
34786
+ const [overflowing, setOverflowing] = useState71(false);
34787
+ const descRef = useRef50(null);
34788
+ const cut = item.clampLines > 0 && !expanded;
34789
+ useLayoutEffect12(() => {
34790
+ if (!cut) return;
34791
+ const el = descRef.current;
34792
+ if (el) setOverflowing(el.scrollHeight > el.clientHeight + 1);
34793
+ }, [cut, item.description]);
34760
34794
  if (item.render) return /* @__PURE__ */ jsx147(Fragment61, { children: item.render({ id: item.id, dismiss }) });
34761
34795
  const title = item.title ?? item.message;
34796
+ const toggles = overflowing && !stacked;
34797
+ const toggle = () => setExpanded((v) => !v);
34798
+ const onTextClick = (e) => {
34799
+ if (!toggles) return;
34800
+ if (window.getSelection()?.toString()) return;
34801
+ e.stopPropagation();
34802
+ toggle();
34803
+ };
34762
34804
  return /* @__PURE__ */ jsxs141(Fragment61, { children: [
34763
34805
  /* @__PURE__ */ jsx147("span", { className: "ods-toast__icon", "aria-hidden": "true", children: item.icon ?? defaultIcons[item.variant] }),
34764
- /* @__PURE__ */ jsxs141("div", { className: "ods-toast__body", children: [
34806
+ /* @__PURE__ */ jsxs141("div", { className: "ods-toast__body", onClick: onTextClick, children: [
34765
34807
  title && /* @__PURE__ */ jsx147("div", { className: "ods-toast__title", children: title }),
34766
- item.description && /* @__PURE__ */ jsx147("div", { className: "ods-toast__desc", children: item.description })
34808
+ item.description && /* @__PURE__ */ jsx147(
34809
+ "div",
34810
+ {
34811
+ ref: descRef,
34812
+ className: cn(
34813
+ "ods-toast__desc",
34814
+ cut && "ods-toast__desc--cut",
34815
+ toggles && "ods-toast__desc--toggles"
34816
+ ),
34817
+ style: cut ? { "--ods-toast-clamp": item.clampLines } : void 0,
34818
+ children: item.description
34819
+ }
34820
+ ),
34821
+ toggles && /* @__PURE__ */ jsx147(
34822
+ "button",
34823
+ {
34824
+ type: "button",
34825
+ className: "ods-toast__more",
34826
+ "aria-expanded": expanded,
34827
+ onClick: (e) => {
34828
+ e.stopPropagation();
34829
+ toggle();
34830
+ },
34831
+ children: expanded ? "Less" : "More"
34832
+ }
34833
+ )
34767
34834
  ] }),
34768
34835
  (item.actionLabel || item.action) && /* @__PURE__ */ jsx147("div", { className: "ods-toast__action", children: item.actionLabel ? (
34769
34836
  // First-class action chip — consistent styling, auto-dismiss
@@ -34811,10 +34878,17 @@ function ToastBody({ item, onDismiss }) {
34811
34878
  )
34812
34879
  ] });
34813
34880
  }
34814
- function PositionStack({ items, position, onDismiss, maxStack }) {
34881
+ function PositionStack({ items, position, onDismiss, onHold, onRelease, maxStack }) {
34815
34882
  const [hovered, setHovered] = useState71(false);
34883
+ const [focused, setFocused] = useState71(false);
34816
34884
  const [pinned, setPinned] = useState71(false);
34817
34885
  const expanded = hovered || pinned;
34886
+ const held = hovered || focused;
34887
+ const ids = useMemo37(() => items.map((t) => t.id), [items]);
34888
+ useEffect57(() => {
34889
+ if (held) onHold(ids);
34890
+ else onRelease(ids);
34891
+ }, [held, ids, onHold, onRelease]);
34818
34892
  const ordered = useMemo37(() => [...items].reverse(), [items]);
34819
34893
  const isBottom = position.startsWith("bottom");
34820
34894
  const dir = isBottom ? -1 : 1;
@@ -34842,6 +34916,10 @@ function PositionStack({ items, position, onDismiss, maxStack }) {
34842
34916
  ),
34843
34917
  onMouseEnter: () => setHovered(true),
34844
34918
  onMouseLeave: () => setHovered(false),
34919
+ onFocus: () => setFocused(true),
34920
+ onBlur: (e) => {
34921
+ if (!e.currentTarget.contains(e.relatedTarget)) setFocused(false);
34922
+ },
34845
34923
  "aria-live": "polite",
34846
34924
  children: [
34847
34925
  /* @__PURE__ */ jsx147(
@@ -34879,7 +34957,14 @@ function PositionStack({ items, position, onDismiss, maxStack }) {
34879
34957
  setPinned(true);
34880
34958
  }
34881
34959
  },
34882
- children: /* @__PURE__ */ jsx147(ToastBody, { item, onDismiss })
34960
+ children: /* @__PURE__ */ jsx147(
34961
+ ToastBody,
34962
+ {
34963
+ item,
34964
+ stacked: !expanded && items.length > 1,
34965
+ onDismiss
34966
+ }
34967
+ )
34883
34968
  },
34884
34969
  item.id
34885
34970
  );
@@ -34916,29 +35001,51 @@ function ToastProvider({
34916
35001
  const [toasts, setToasts] = useState71([]);
34917
35002
  const timers = useRef50(/* @__PURE__ */ new Map());
34918
35003
  const idCounter2 = useRef50(0);
34919
- const dismiss = useCallback51((id) => {
34920
- setToasts((prev) => prev.filter((t) => t.id !== id));
34921
- const timer = timers.current.get(id);
34922
- if (timer) {
34923
- clearTimeout(timer);
34924
- timers.current.delete(id);
34925
- }
35004
+ const forget = useCallback51((id) => {
35005
+ const c = timers.current.get(id);
35006
+ if (c?.handle) clearTimeout(c.handle);
35007
+ timers.current.delete(id);
34926
35008
  }, []);
34927
- const dismissAll = useCallback51((position) => {
34928
- setToasts((prev) => {
34929
- const remaining = position ? prev.filter((t) => t.position !== position) : [];
34930
- for (const t of prev) {
34931
- if (!remaining.find((r) => r.id === t.id)) {
34932
- const timer = timers.current.get(t.id);
34933
- if (timer) {
34934
- clearTimeout(timer);
34935
- timers.current.delete(t.id);
34936
- }
35009
+ const dismiss = useCallback51(
35010
+ (id) => {
35011
+ setToasts((prev) => prev.filter((t) => t.id !== id));
35012
+ forget(id);
35013
+ },
35014
+ [forget]
35015
+ );
35016
+ const dismissAll = useCallback51(
35017
+ (position) => {
35018
+ setToasts((prev) => {
35019
+ const remaining = position ? prev.filter((t) => t.position !== position) : [];
35020
+ for (const t of prev) {
35021
+ if (!remaining.find((r) => r.id === t.id)) forget(t.id);
34937
35022
  }
34938
- }
34939
- return remaining;
34940
- });
35023
+ return remaining;
35024
+ });
35025
+ },
35026
+ [forget]
35027
+ );
35028
+ const hold = useCallback51((ids) => {
35029
+ const now2 = Date.now();
35030
+ for (const id of ids) {
35031
+ const c = timers.current.get(id);
35032
+ if (!c || c.handle === null) continue;
35033
+ clearTimeout(c.handle);
35034
+ c.handle = null;
35035
+ c.remaining = Math.max(0, c.remaining - (now2 - c.since));
35036
+ }
34941
35037
  }, []);
35038
+ const release = useCallback51(
35039
+ (ids) => {
35040
+ for (const id of ids) {
35041
+ const c = timers.current.get(id);
35042
+ if (!c || c.handle !== null) continue;
35043
+ c.since = Date.now();
35044
+ c.handle = setTimeout(() => dismiss(id), c.remaining);
35045
+ }
35046
+ },
35047
+ [dismiss]
35048
+ );
34942
35049
  const toast = useCallback51(
34943
35050
  (options2) => {
34944
35051
  const id = `toast-${++idCounter2.current}`;
@@ -34955,12 +35062,16 @@ function ToastProvider({
34955
35062
  render: options2.render,
34956
35063
  duration: options2.duration ?? 5e3,
34957
35064
  closeable: options2.closeable ?? true,
34958
- position: options2.position ?? defaultPosition
35065
+ position: options2.position ?? defaultPosition,
35066
+ clampLines: options2.clampLines ?? 2
34959
35067
  };
34960
35068
  setToasts((prev) => [...prev, item]);
34961
35069
  if (item.duration > 0) {
34962
- const timer = setTimeout(() => dismiss(id), item.duration);
34963
- timers.current.set(id, timer);
35070
+ timers.current.set(id, {
35071
+ handle: setTimeout(() => dismiss(id), item.duration),
35072
+ remaining: item.duration,
35073
+ since: Date.now()
35074
+ });
34964
35075
  }
34965
35076
  return id;
34966
35077
  },
@@ -34988,7 +35099,9 @@ function ToastProvider({
34988
35099
  items: list,
34989
35100
  position: pos,
34990
35101
  maxStack,
34991
- onDismiss: dismiss
35102
+ onDismiss: dismiss,
35103
+ onHold: hold,
35104
+ onRelease: release
34992
35105
  },
34993
35106
  pos
34994
35107
  );
@@ -35840,7 +35953,7 @@ UserCard.displayName = "UserCard";
35840
35953
  import { useId as useId64, useState as useState74 } from "react";
35841
35954
 
35842
35955
  // src/hooks/useRelativeTime.ts
35843
- import { useEffect as useEffect57, useState as useState73 } from "react";
35956
+ import { useEffect as useEffect58, useState as useState73 } from "react";
35844
35957
  function toMs(t) {
35845
35958
  if (t == null) return null;
35846
35959
  return typeof t === "number" ? t : t.getTime();
@@ -35860,7 +35973,7 @@ function formatRelativeTime(when, now2 = Date.now()) {
35860
35973
  function useRelativeTime(date, options2 = {}) {
35861
35974
  const { intervalMs = 3e4 } = options2;
35862
35975
  const [now2, setNow] = useState73(() => Date.now());
35863
- useEffect57(() => {
35976
+ useEffect58(() => {
35864
35977
  if (typeof window === "undefined") return;
35865
35978
  const id = window.setInterval(() => setNow(Date.now()), intervalMs);
35866
35979
  return () => window.clearInterval(id);
@@ -35924,7 +36037,20 @@ function VersionHistory({
35924
36037
  }) {
35925
36038
  const [expandedId, setExpandedId] = useState74(defaultExpandedId);
35926
36039
  const baseId = useId64();
35927
- const showToolbar = Boolean(tabs && tabs.length > 0 || onRefresh);
36040
+ const showToolbar = Boolean(tabs && tabs.length > 0);
36041
+ const refreshButton = onRefresh ? /* @__PURE__ */ jsx155(
36042
+ "button",
36043
+ {
36044
+ type: "button",
36045
+ className: "ods-version-history__refresh",
36046
+ onClick: onRefresh,
36047
+ disabled: refreshing,
36048
+ "aria-label": "Refresh history",
36049
+ title: "Refresh",
36050
+ "data-spinning": refreshing || void 0,
36051
+ children: /* @__PURE__ */ jsx155(RefreshGlyph, {})
36052
+ }
36053
+ ) : null;
35928
36054
  return /* @__PURE__ */ jsxs149(
35929
36055
  SlideoutPanel,
35930
36056
  {
@@ -35933,6 +36059,7 @@ function VersionHistory({
35933
36059
  position,
35934
36060
  width,
35935
36061
  title,
36062
+ headerActions: showToolbar ? void 0 : refreshButton,
35936
36063
  offsetTop,
35937
36064
  offsetBottom,
35938
36065
  className: cn("ods-version-history", className),
@@ -35960,19 +36087,7 @@ function VersionHistory({
35960
36087
  tab.id
35961
36088
  );
35962
36089
  }) }) : /* @__PURE__ */ jsx155("span", {}),
35963
- onRefresh && /* @__PURE__ */ jsx155(
35964
- "button",
35965
- {
35966
- type: "button",
35967
- className: "ods-version-history__refresh",
35968
- onClick: onRefresh,
35969
- disabled: refreshing,
35970
- "aria-label": "Refresh history",
35971
- title: "Refresh",
35972
- "data-spinning": refreshing || void 0,
35973
- children: /* @__PURE__ */ jsx155(RefreshGlyph, {})
35974
- }
35975
- )
36090
+ refreshButton
35976
36091
  ] }),
35977
36092
  error && /* @__PURE__ */ jsx155("div", { className: "ods-version-history__banner", children: /* @__PURE__ */ jsx155(Banner, { variant: "error", appearance: "subtle", title: "Couldn't load history", description: error }) }),
35978
36093
  /* @__PURE__ */ jsx155("div", { className: "ods-version-history__body", role: "tabpanel", children: loading ? /* @__PURE__ */ jsxs149("div", { className: "ods-version-history__status", role: "status", "aria-live": "polite", children: [
@@ -37177,7 +37292,7 @@ import {
37177
37292
  } from "@octaviaflow/icons";
37178
37293
 
37179
37294
  // src/hooks/useWorkflowRuntime.ts
37180
- import { useEffect as useEffect58, useState as useState76 } from "react";
37295
+ import { useEffect as useEffect59, useState as useState76 } from "react";
37181
37296
  function toMs2(t) {
37182
37297
  if (t == null) return null;
37183
37298
  return typeof t === "number" ? t : t.getTime();
@@ -37192,7 +37307,7 @@ function formatWorkflowRuntime(ms) {
37192
37307
  }
37193
37308
  function useWorkflowRuntime(startedAt, active) {
37194
37309
  const [, force] = useState76(0);
37195
- useEffect58(() => {
37310
+ useEffect59(() => {
37196
37311
  if (!active || startedAt == null) return;
37197
37312
  if (typeof window === "undefined") return;
37198
37313
  const id = window.setInterval(() => force((n) => n + 1), 1e3);
@@ -37572,13 +37687,13 @@ function WorkflowHeaderExpanded({
37572
37687
  }
37573
37688
 
37574
37689
  // src/hooks/useBanner.ts
37575
- import { useCallback as useCallback56, useEffect as useEffect59, useRef as useRef52, useState as useState77 } from "react";
37690
+ import { useCallback as useCallback56, useEffect as useEffect60, useRef as useRef52, useState as useState77 } from "react";
37576
37691
  function useBanner(options2 = {}) {
37577
37692
  const { defaultOpen = false, autoDismissAfter, onDismiss } = options2;
37578
37693
  const [open, setOpen] = useState77(defaultOpen);
37579
37694
  const timerRef = useRef52(null);
37580
37695
  const onDismissRef = useRef52(onDismiss);
37581
- useEffect59(() => {
37696
+ useEffect60(() => {
37582
37697
  onDismissRef.current = onDismiss;
37583
37698
  }, [onDismiss]);
37584
37699
  const clearTimer = useCallback56(() => {
@@ -37609,7 +37724,7 @@ function useBanner(options2 = {}) {
37609
37724
  if (open) hide();
37610
37725
  else show();
37611
37726
  }, [open, show, hide]);
37612
- useEffect59(() => () => clearTimer(), [clearTimer]);
37727
+ useEffect60(() => () => clearTimer(), [clearTimer]);
37613
37728
  return {
37614
37729
  open,
37615
37730
  show,
@@ -37677,7 +37792,7 @@ function breakpointMinWidth(name) {
37677
37792
  }
37678
37793
 
37679
37794
  // src/hooks/useCallout.ts
37680
- import { useCallback as useCallback57, useEffect as useEffect60, useState as useState78 } from "react";
37795
+ import { useCallback as useCallback57, useEffect as useEffect61, useState as useState78 } from "react";
37681
37796
  var STORAGE_PREFIX = "ods:callout:dismissed:";
37682
37797
  function readPersisted(key) {
37683
37798
  if (!key || typeof window === "undefined") return false;
@@ -37701,7 +37816,7 @@ function writePersisted(key, value) {
37701
37816
  function useCallout(options2 = {}) {
37702
37817
  const { defaultOpen = true, persistKey, onDismiss } = options2;
37703
37818
  const [open, setOpen] = useState78(defaultOpen);
37704
- useEffect60(() => {
37819
+ useEffect61(() => {
37705
37820
  if (persistKey && readPersisted(persistKey)) {
37706
37821
  setOpen(false);
37707
37822
  }
@@ -38239,6 +38354,14 @@ var DEFAULT_NOTIFICATION_CATALOG = [
38239
38354
  subjectNoun: "app",
38240
38355
  defaultEmail: false
38241
38356
  },
38357
+ {
38358
+ key: "connector.expiring_soon",
38359
+ label: "App sign-in expires soon",
38360
+ phrase: "an app's sign-in is about to expire",
38361
+ severity: "warning",
38362
+ audience: "org",
38363
+ subjectNoun: "app"
38364
+ },
38242
38365
  {
38243
38366
  key: "connector.test_failed",
38244
38367
  label: "Connection test failed",
@@ -39522,7 +39645,7 @@ NotificationChannelCard.displayName = "NotificationChannelCard";
39522
39645
 
39523
39646
  // src/notifications/components/NotificationChannelDialog/NotificationChannelDialog.tsx
39524
39647
  import { SendIcon as SendIcon2 } from "@octaviaflow/icons";
39525
- import { useEffect as useEffect61, useMemo as useMemo42, useState as useState86 } from "react";
39648
+ import { useEffect as useEffect62, useMemo as useMemo42, useState as useState86 } from "react";
39526
39649
 
39527
39650
  // src/notifications/engine/channels.ts
39528
39651
  var CONNECTED_CHANNEL_TYPES = [
@@ -39980,7 +40103,7 @@ function NotificationChannelDialog({
39980
40103
  const [testing, setTesting] = useState86(false);
39981
40104
  const [testResult, setTestResult] = useState86(null);
39982
40105
  const [submitError, setSubmitError] = useState86(null);
39983
- useEffect61(() => {
40106
+ useEffect62(() => {
39984
40107
  if (!open) return;
39985
40108
  setDraft(draftFromChannel(channel, initialType));
39986
40109
  setSubmitted(false);
@@ -40921,13 +41044,13 @@ NotificationRuleList.displayName = "NotificationRuleList";
40921
41044
 
40922
41045
  // src/provider/OdsProvider.tsx
40923
41046
  import { generateCssVars, resolveConfig } from "@octaviaflow/config";
40924
- import { createContext as createContext4, useContext as useContext5, useEffect as useEffect62, useMemo as useMemo45 } from "react";
41047
+ import { createContext as createContext4, useContext as useContext5, useEffect as useEffect63, useMemo as useMemo45 } from "react";
40925
41048
  import { OverlayProvider as OverlayProvider3 } from "react-aria";
40926
41049
  import { jsx as jsx173 } from "react/jsx-runtime";
40927
41050
  var OdsContext = createContext4(null);
40928
41051
  function OdsProvider({ config: userConfig, children }) {
40929
41052
  const resolved = useMemo45(() => resolveConfig(userConfig), [userConfig]);
40930
- useEffect62(() => {
41053
+ useEffect63(() => {
40931
41054
  const cssVarsBlock = generateCssVars(resolved);
40932
41055
  const match = cssVarsBlock.match(/:root\s*\{([\s\S]*)\}/);
40933
41056
  if (match) {