@almadar/ui 5.128.0 → 5.129.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.
@@ -29654,12 +29654,12 @@ var init_MapView = __esm({
29654
29654
  shadowSize: [41, 41]
29655
29655
  });
29656
29656
  L.Marker.prototype.options.icon = defaultIcon;
29657
- const { useEffect: useEffect63, useRef: useRef61, useCallback: useCallback93, useState: useState97 } = React91__namespace.default;
29657
+ const { useEffect: useEffect63, useRef: useRef62, useCallback: useCallback93, useState: useState97 } = React91__namespace.default;
29658
29658
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
29659
29659
  const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
29660
29660
  function MapUpdater({ centerLat, centerLng, zoom }) {
29661
29661
  const map = useMap();
29662
- const prevRef = useRef61({ centerLat, centerLng, zoom });
29662
+ const prevRef = useRef62({ centerLat, centerLng, zoom });
29663
29663
  useEffect63(() => {
29664
29664
  const prev = prevRef.current;
29665
29665
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
@@ -38440,6 +38440,290 @@ var init_GraphCanvas = __esm({
38440
38440
  GraphCanvas.displayName = "GraphCanvas";
38441
38441
  }
38442
38442
  });
38443
+ var ImportSourcePicker;
38444
+ var init_ImportSourcePicker = __esm({
38445
+ "components/core/molecules/import/ImportSourcePicker.tsx"() {
38446
+ "use client";
38447
+ init_Box();
38448
+ init_Icon();
38449
+ init_Typography();
38450
+ init_cn();
38451
+ ImportSourcePicker = ({
38452
+ sources,
38453
+ onSelect,
38454
+ onFilesSelected,
38455
+ title,
38456
+ moreSources,
38457
+ className
38458
+ }) => {
38459
+ const fileInputRef = React91.useRef(null);
38460
+ const handlePick = (source) => {
38461
+ if (source.disabled) return;
38462
+ if (source.kind === "file") {
38463
+ const input = fileInputRef.current;
38464
+ if (!input) return;
38465
+ input.accept = source.accept ?? "";
38466
+ input.multiple = source.multiple ?? false;
38467
+ input.click();
38468
+ return;
38469
+ }
38470
+ onSelect?.(source.id);
38471
+ };
38472
+ const handleFiles = (event) => {
38473
+ const files = event.target.files ? Array.from(event.target.files) : [];
38474
+ event.target.value = "";
38475
+ if (files.length > 0) onFilesSelected?.(files);
38476
+ };
38477
+ return /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: cn("flex flex-col gap-2", className), children: [
38478
+ title ? /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", children: title }) : null,
38479
+ sources.map((source) => /* @__PURE__ */ jsxRuntime.jsxs(
38480
+ Box,
38481
+ {
38482
+ role: "button",
38483
+ tabIndex: source.disabled ? -1 : 0,
38484
+ "aria-disabled": source.disabled,
38485
+ onClick: () => handlePick(source),
38486
+ onKeyDown: (event) => {
38487
+ if (event.key === "Enter" || event.key === " ") {
38488
+ event.preventDefault();
38489
+ handlePick(source);
38490
+ }
38491
+ },
38492
+ className: cn(
38493
+ "flex items-center gap-3 rounded-md border border-border bg-card px-4 py-3 text-left",
38494
+ source.disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer hover:bg-accent hover:text-accent-foreground"
38495
+ ),
38496
+ children: [
38497
+ source.icon ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: source.icon, size: "md" }) : null,
38498
+ /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex flex-col", children: [
38499
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "label", children: source.label }),
38500
+ source.description ? /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: source.description }) : null
38501
+ ] })
38502
+ ]
38503
+ },
38504
+ source.id
38505
+ )),
38506
+ moreSources,
38507
+ /* @__PURE__ */ jsxRuntime.jsx(
38508
+ "input",
38509
+ {
38510
+ ref: fileInputRef,
38511
+ type: "file",
38512
+ className: "hidden",
38513
+ onChange: handleFiles,
38514
+ "data-testid": "import-source-file-input"
38515
+ }
38516
+ )
38517
+ ] });
38518
+ };
38519
+ }
38520
+ });
38521
+ function formatFieldValue(value) {
38522
+ if (value === null) return "\u2014";
38523
+ if (value instanceof Date) return value.toISOString();
38524
+ if (Array.isArray(value)) return value.map(formatFieldValue).join(", ");
38525
+ if (typeof value === "object") return JSON.stringify(value);
38526
+ return String(value);
38527
+ }
38528
+ function unitTitle(unit) {
38529
+ for (const key of TITLE_KEYS) {
38530
+ const value = unit.fields[key];
38531
+ if (typeof value === "string" && value.length > 0) return value;
38532
+ }
38533
+ return unit.ref;
38534
+ }
38535
+ function fieldSummary(unit) {
38536
+ return Object.entries(unit.fields).filter(([key]) => !TITLE_KEYS.includes(key)).map(([key, value]) => `${key}: ${formatFieldValue(value)}`).join(" \xB7 ");
38537
+ }
38538
+ var TITLE_KEYS, ImportPreviewTree;
38539
+ var init_ImportPreviewTree = __esm({
38540
+ "components/core/molecules/import/ImportPreviewTree.tsx"() {
38541
+ "use client";
38542
+ init_Box();
38543
+ init_Badge();
38544
+ init_Button();
38545
+ init_Icon();
38546
+ init_Typography();
38547
+ init_cn();
38548
+ TITLE_KEYS = ["title", "name", "label"];
38549
+ ImportPreviewTree = ({
38550
+ units,
38551
+ skipped = [],
38552
+ entityDisplay,
38553
+ onConfirm,
38554
+ onCancel,
38555
+ confirmLabel = "Confirm import",
38556
+ cancelLabel = "Cancel",
38557
+ indent = 16,
38558
+ className
38559
+ }) => {
38560
+ const groups = /* @__PURE__ */ new Map();
38561
+ for (const unit of units) {
38562
+ const group = groups.get(unit.targetEntity);
38563
+ if (group) group.push(unit);
38564
+ else groups.set(unit.targetEntity, [unit]);
38565
+ }
38566
+ const renderUnit = (unit, childrenByParent, depth) => {
38567
+ const summary = fieldSummary(unit);
38568
+ const children = childrenByParent.get(unit.ref) ?? [];
38569
+ return /* @__PURE__ */ jsxRuntime.jsxs(React91__namespace.default.Fragment, { children: [
38570
+ /* @__PURE__ */ jsxRuntime.jsxs(
38571
+ Box,
38572
+ {
38573
+ className: "flex flex-col py-1",
38574
+ style: { paddingLeft: depth * indent },
38575
+ "data-testid": `import-preview-unit-${unit.ref}`,
38576
+ children: [
38577
+ /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-center gap-2", children: [
38578
+ /* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: "file-text", size: "xs", className: "text-muted-foreground" }),
38579
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", children: unitTitle(unit) })
38580
+ ] }),
38581
+ summary ? /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: summary }) : null
38582
+ ]
38583
+ }
38584
+ ),
38585
+ children.map((child) => renderUnit(child, childrenByParent, depth + 1))
38586
+ ] }, unit.ref);
38587
+ };
38588
+ return /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: cn("flex flex-col gap-4", className), children: [
38589
+ units.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: "No units staged." }) : null,
38590
+ Array.from(groups.entries()).map(([entity, groupUnits]) => {
38591
+ const refs = new Set(groupUnits.map((unit) => unit.ref));
38592
+ const childrenByParent = /* @__PURE__ */ new Map();
38593
+ const roots = [];
38594
+ for (const unit of groupUnits) {
38595
+ if (unit.parentRef && refs.has(unit.parentRef)) {
38596
+ const siblings = childrenByParent.get(unit.parentRef);
38597
+ if (siblings) siblings.push(unit);
38598
+ else childrenByParent.set(unit.parentRef, [unit]);
38599
+ } else {
38600
+ roots.push(unit);
38601
+ }
38602
+ }
38603
+ const label = entityDisplay[entity]?.plural ?? entity;
38604
+ return /* @__PURE__ */ jsxRuntime.jsxs(Box, { border: true, className: "rounded-md border-border bg-card p-3", children: [
38605
+ /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-center gap-2 pb-2", children: [
38606
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "label", children: label }),
38607
+ /* @__PURE__ */ jsxRuntime.jsx(Badge, { amount: groupUnits.length })
38608
+ ] }),
38609
+ roots.map((unit) => renderUnit(unit, childrenByParent, 0))
38610
+ ] }, entity);
38611
+ }),
38612
+ skipped.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(Box, { border: true, className: "rounded-md border-border bg-card p-3", children: [
38613
+ /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-center gap-2 pb-2", children: [
38614
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "label", children: "Skipped" }),
38615
+ /* @__PURE__ */ jsxRuntime.jsx(Badge, { amount: skipped.length })
38616
+ ] }),
38617
+ skipped.map((element) => /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-baseline gap-2 py-1", children: [
38618
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", children: element.ref }),
38619
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: element.reason })
38620
+ ] }, element.ref))
38621
+ ] }) : null,
38622
+ onConfirm || onCancel ? /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-center justify-end gap-2", children: [
38623
+ onCancel ? /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "default", label: cancelLabel, onClick: onCancel }) : null,
38624
+ onConfirm ? /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "primary", label: confirmLabel, onClick: onConfirm }) : null
38625
+ ] }) : null
38626
+ ] });
38627
+ };
38628
+ }
38629
+ });
38630
+ var PIPELINE, DEFAULT_LABELS, ImportProgress;
38631
+ var init_ImportProgress = __esm({
38632
+ "components/core/molecules/import/ImportProgress.tsx"() {
38633
+ "use client";
38634
+ init_Box();
38635
+ init_Badge();
38636
+ init_Icon();
38637
+ init_Typography();
38638
+ init_cn();
38639
+ PIPELINE = [
38640
+ "fetching",
38641
+ "mapping",
38642
+ "reviewing",
38643
+ "committing"
38644
+ ];
38645
+ DEFAULT_LABELS = {
38646
+ fetching: "Fetching",
38647
+ mapping: "Mapping",
38648
+ reviewing: "Reviewing",
38649
+ committing: "Committing",
38650
+ done: "Done",
38651
+ failed: "Failed"
38652
+ };
38653
+ ImportProgress = ({
38654
+ step,
38655
+ counts,
38656
+ labels,
38657
+ className
38658
+ }) => {
38659
+ const label = (key) => labels?.[key] ?? DEFAULT_LABELS[key];
38660
+ const currentIndex = step === "done" || step === "failed" ? PIPELINE.length : PIPELINE.indexOf(step);
38661
+ return /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: cn("flex flex-col gap-3", className), children: [
38662
+ /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-center gap-2", children: [
38663
+ PIPELINE.map((key, index) => {
38664
+ const isComplete = index < currentIndex;
38665
+ const isActive = index === currentIndex;
38666
+ return /* @__PURE__ */ jsxRuntime.jsxs(React91__namespace.default.Fragment, { children: [
38667
+ index > 0 ? /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "h-px w-4 bg-border" }) : null,
38668
+ /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-center gap-1", "data-testid": `import-progress-step-${key}`, children: [
38669
+ /* @__PURE__ */ jsxRuntime.jsx(
38670
+ Icon,
38671
+ {
38672
+ icon: isComplete ? "check" : isActive ? "loader" : "circle",
38673
+ size: "sm",
38674
+ className: cn(
38675
+ isComplete ? "text-success" : isActive ? "text-primary" : "text-muted-foreground"
38676
+ )
38677
+ }
38678
+ ),
38679
+ /* @__PURE__ */ jsxRuntime.jsx(
38680
+ Typography,
38681
+ {
38682
+ variant: "caption",
38683
+ className: cn(isActive ? "text-foreground" : "text-muted-foreground"),
38684
+ children: label(key)
38685
+ }
38686
+ )
38687
+ ] })
38688
+ ] }, key);
38689
+ }),
38690
+ step === "done" || step === "failed" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
38691
+ /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "h-px w-4 bg-border" }),
38692
+ /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-center gap-1", "data-testid": `import-progress-step-${step}`, children: [
38693
+ /* @__PURE__ */ jsxRuntime.jsx(
38694
+ Icon,
38695
+ {
38696
+ icon: step === "done" ? "check" : "x",
38697
+ size: "sm",
38698
+ className: step === "done" ? "text-success" : "text-error"
38699
+ }
38700
+ ),
38701
+ /* @__PURE__ */ jsxRuntime.jsx(
38702
+ Typography,
38703
+ {
38704
+ variant: "caption",
38705
+ className: step === "done" ? "text-success" : "text-error",
38706
+ children: label(step)
38707
+ }
38708
+ )
38709
+ ] })
38710
+ ] }) : null
38711
+ ] }),
38712
+ counts ? /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-center gap-2", children: [
38713
+ counts.staged !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(Badge, { label: `Staged ${counts.staged}` }) : null,
38714
+ counts.committed !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "success", label: `Committed ${counts.committed}` }) : null,
38715
+ counts.failed !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "danger", label: `Failed ${counts.failed}` }) : null
38716
+ ] }) : null
38717
+ ] });
38718
+ };
38719
+ }
38720
+ });
38721
+
38722
+ // components/core/molecules/import/index.ts
38723
+ var init_import = __esm({
38724
+ "components/core/molecules/import/index.ts"() {
38725
+ }
38726
+ });
38443
38727
  var ReflectionBlock;
38444
38728
  var init_ReflectionBlock = __esm({
38445
38729
  "components/core/molecules/ReflectionBlock.tsx"() {
@@ -38514,6 +38798,7 @@ var init_molecules2 = __esm({
38514
38798
  init_EmptyState();
38515
38799
  init_Pagination();
38516
38800
  init_molecules();
38801
+ init_import();
38517
38802
  }
38518
38803
  });
38519
38804
 
@@ -38994,7 +39279,7 @@ function getBadgeVariant(fieldName, value) {
38994
39279
  function formatFieldLabel(fieldName) {
38995
39280
  return fieldName.replace(/([A-Z])/g, " $1").replace(/^./, (str) => str.toUpperCase());
38996
39281
  }
38997
- function formatFieldValue(value, fieldName) {
39282
+ function formatFieldValue2(value, fieldName) {
38998
39283
  if (typeof value === "number") {
38999
39284
  if (fieldName.toLowerCase().includes("progress") || fieldName.toLowerCase().includes("percent")) {
39000
39285
  return `${value}%`;
@@ -39089,7 +39374,7 @@ function renderRichFieldValue(value, fieldName, fieldType) {
39089
39374
  return str;
39090
39375
  }
39091
39376
  default:
39092
- return formatFieldValue(value, fieldName);
39377
+ return formatFieldValue2(value, fieldName);
39093
39378
  }
39094
39379
  }
39095
39380
  function normalizeFieldDefs(fields) {
@@ -39200,7 +39485,7 @@ var init_DetailPanel = __esm({
39200
39485
  const value = getNestedValue(normalizedData, field);
39201
39486
  return {
39202
39487
  label: labelFor(field),
39203
- value: formatFieldValue(value, field),
39488
+ value: formatFieldValue2(value, field),
39204
39489
  icon: getFieldIcon(field)
39205
39490
  };
39206
39491
  }
@@ -45231,6 +45516,9 @@ var init_component_registry_generated = __esm({
45231
45516
  init_HeroOrganism();
45232
45517
  init_HeroSection();
45233
45518
  init_Icon();
45519
+ init_ImportPreviewTree();
45520
+ init_ImportProgress();
45521
+ init_ImportSourcePicker();
45234
45522
  init_InfiniteScrollSentinel();
45235
45523
  init_Input();
45236
45524
  init_InputGroup();
@@ -45494,6 +45782,9 @@ var init_component_registry_generated = __esm({
45494
45782
  "HeroOrganism": HeroOrganism,
45495
45783
  "HeroSection": HeroSection,
45496
45784
  "Icon": Icon,
45785
+ "ImportPreviewTree": ImportPreviewTree,
45786
+ "ImportProgress": ImportProgress,
45787
+ "ImportSourcePicker": ImportSourcePicker,
45497
45788
  "InfiniteScrollSentinel": InfiniteScrollSentinel,
45498
45789
  "Input": Input,
45499
45790
  "InputGroup": InputGroup,