@streamoid/catalogix-chat 0.2.6 → 0.2.8

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.
Files changed (2) hide show
  1. package/dist/index.js +100 -26
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2444,16 +2444,29 @@ import {
2444
2444
  Search as Search3,
2445
2445
  ArrowRight,
2446
2446
  ArrowLeft as ArrowLeft2,
2447
- Send
2447
+ Send,
2448
+ AlertTriangle
2448
2449
  } from "lucide-react";
2449
- import { jsx as jsx21, jsxs as jsxs10 } from "react/jsx-runtime";
2450
+ import { Fragment as Fragment4, jsx as jsx21, jsxs as jsxs10 } from "react/jsx-runtime";
2450
2451
  function getAllAttributes(mpAttributes) {
2451
2452
  return Object.values(mpAttributes).flat();
2452
2453
  }
2454
+ function hasIncompleteLovValues(item, valuesOntologyAttributes, uniqueValues) {
2455
+ if (!item.isConfirmed || item.isIgnored) return false;
2456
+ for (const attr of item.mappedCols) {
2457
+ if (!valuesOntologyAttributes.includes(attr)) continue;
2458
+ const rawVals = uniqueValues[item.feedCol] || [];
2459
+ if (rawVals.length === 0) continue;
2460
+ const mapped = item.mappedValues[attr] || {};
2461
+ if (rawVals.some((v) => !mapped[v])) return true;
2462
+ }
2463
+ return false;
2464
+ }
2453
2465
  function AttributeRow({
2454
2466
  item,
2455
2467
  index,
2456
2468
  allAttributes,
2469
+ needsValueAttention,
2457
2470
  onMap,
2458
2471
  onConfirm,
2459
2472
  onIgnore,
@@ -2467,11 +2480,15 @@ function AttributeRow({
2467
2480
  return allAttributes.filter((a) => !mapped.has(a));
2468
2481
  }, [allAttributes, item.mappedCols, item.customCols]);
2469
2482
  if (item.isConfirmed) {
2470
- return /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-2 py-1.5 group", children: [
2471
- /* @__PURE__ */ jsx21(Check2, { className: "size-3 shrink-0 text-emerald-600 dark:text-emerald-400" }),
2483
+ return /* @__PURE__ */ jsxs10("div", { className: cn(
2484
+ "flex items-center gap-2 py-1.5 group",
2485
+ needsValueAttention && "border-l-2 border-amber-500/60 pl-2"
2486
+ ), children: [
2487
+ needsValueAttention ? /* @__PURE__ */ jsx21(AlertTriangle, { className: "size-3 shrink-0 text-amber-500" }) : /* @__PURE__ */ jsx21(Check2, { className: "size-3 shrink-0 text-emerald-600 dark:text-emerald-400" }),
2472
2488
  /* @__PURE__ */ jsx21("span", { className: "text-xs font-medium truncate", children: item.feedCol }),
2473
2489
  /* @__PURE__ */ jsx21(ChevronRight2, { className: "size-3 shrink-0 text-muted-foreground" }),
2474
2490
  /* @__PURE__ */ jsx21("span", { className: "text-xs text-muted-foreground truncate", children: [...item.mappedCols, ...item.customCols].join(", ") }),
2491
+ needsValueAttention && /* @__PURE__ */ jsx21(Badge, { variant: "outline", className: "text-[10px] h-4 px-1 border-amber-500/50 text-amber-600 dark:text-amber-400 shrink-0", children: "values needed" }),
2475
2492
  /* @__PURE__ */ jsx21(
2476
2493
  "button",
2477
2494
  {
@@ -2596,7 +2613,7 @@ function ValueMappingPanel({
2596
2613
  const existing = item.mappedValues[attr] || {};
2597
2614
  const valueMap = {};
2598
2615
  rawVals.forEach((v) => {
2599
- valueMap[v] = existing[v] ?? null;
2616
+ valueMap[v] = existing[v] || null;
2600
2617
  });
2601
2618
  items.push({
2602
2619
  itemIndex,
@@ -2609,6 +2626,11 @@ function ValueMappingPanel({
2609
2626
  });
2610
2627
  });
2611
2628
  });
2629
+ items.sort((a, b) => {
2630
+ const aIncomplete = a.mappedCount < a.totalCount ? 0 : 1;
2631
+ const bIncomplete = b.mappedCount < b.totalCount ? 0 : 1;
2632
+ return aIncomplete - bIncomplete;
2633
+ });
2612
2634
  return items;
2613
2635
  }, [data, valuesOntologyAttributes, uniqueValues]);
2614
2636
  if (lovItems.length === 0) {
@@ -2642,7 +2664,7 @@ function ValueMappingPanel({
2642
2664
  /* @__PURE__ */ jsxs10(
2643
2665
  Select,
2644
2666
  {
2645
- value: mapped ?? "__unmapped__",
2667
+ value: mapped || "__unmapped__",
2646
2668
  onValueChange: (v) => {
2647
2669
  const val = v === "__skip__" ? null : v;
2648
2670
  onValueChange(
@@ -2700,11 +2722,42 @@ function MapAttributesChat({
2700
2722
  if (!valuesOntologyAttributes.includes(attr)) continue;
2701
2723
  const rawVals = uniqueValues[item.feedCol] || [];
2702
2724
  const mapped = item.mappedValues[attr] || {};
2703
- if (rawVals.some((v) => mapped[v] == null)) return false;
2725
+ if (rawVals.some((v) => !mapped[v])) return false;
2704
2726
  }
2705
2727
  }
2706
2728
  return true;
2707
2729
  }, [data, valuesOntologyAttributes, uniqueValues]);
2730
+ const lovAttentionSet = useMemo5(() => {
2731
+ const set = /* @__PURE__ */ new Set();
2732
+ data.forEach((item, idx) => {
2733
+ if (hasIncompleteLovValues(item, valuesOntologyAttributes, uniqueValues)) {
2734
+ set.add(idx);
2735
+ }
2736
+ });
2737
+ return set;
2738
+ }, [data, valuesOntologyAttributes, uniqueValues]);
2739
+ const attentionSummary = useMemo5(() => {
2740
+ const unmappedCount = data.filter(
2741
+ (i) => !i.isConfirmed && !i.isIgnored
2742
+ ).length;
2743
+ const lovIncompleteCount = lovAttentionSet.size;
2744
+ return { unmappedCount, lovIncompleteCount };
2745
+ }, [data, lovAttentionSet]);
2746
+ const sortedIndices = useMemo5(() => {
2747
+ const indices = data.map((_, i) => i);
2748
+ indices.sort((a, b) => {
2749
+ const itemA = data[a];
2750
+ const itemB = data[b];
2751
+ const priorityOf = (item, idx) => {
2752
+ if (!item.isConfirmed && !item.isIgnored) return 0;
2753
+ if (lovAttentionSet.has(idx)) return 1;
2754
+ if (item.isConfirmed) return 2;
2755
+ return 3;
2756
+ };
2757
+ return priorityOf(itemA, a) - priorityOf(itemB, b);
2758
+ });
2759
+ return indices;
2760
+ }, [data, lovAttentionSet]);
2708
2761
  const handleMap = useCallback5((index, attribute) => {
2709
2762
  setData((prev) => {
2710
2763
  const next = [...prev];
@@ -2784,27 +2837,48 @@ function MapAttributesChat({
2784
2837
  /* @__PURE__ */ jsx21("h3", { className: "text-sm font-semibold tracking-tight", children: step === "attributes" ? "Map Attributes" : "Map Values" }),
2785
2838
  /* @__PURE__ */ jsx21("p", { className: "text-xs text-muted-foreground leading-snug", children: step === "attributes" ? "Match each feed column to a marketplace attribute" : "Normalize values for controlled-vocabulary attributes" })
2786
2839
  ] }),
2787
- step === "attributes" && /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-2", children: [
2788
- /* @__PURE__ */ jsx21("div", { className: "h-1 flex-1 overflow-hidden rounded-full bg-muted", children: /* @__PURE__ */ jsx21(
2789
- "div",
2790
- {
2791
- className: "h-full rounded-full bg-primary transition-all",
2792
- style: { width: `${progress.percent}%` }
2793
- }
2794
- ) }),
2795
- /* @__PURE__ */ jsxs10("span", { className: "text-[11px] text-muted-foreground tabular-nums shrink-0", children: [
2796
- progress.done,
2797
- "/",
2798
- progress.total
2840
+ step === "attributes" && /* @__PURE__ */ jsxs10(Fragment4, { children: [
2841
+ /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-2", children: [
2842
+ /* @__PURE__ */ jsx21("div", { className: "h-1 flex-1 overflow-hidden rounded-full bg-muted", children: /* @__PURE__ */ jsx21(
2843
+ "div",
2844
+ {
2845
+ className: "h-full rounded-full bg-primary transition-all",
2846
+ style: { width: `${progress.percent}%` }
2847
+ }
2848
+ ) }),
2849
+ /* @__PURE__ */ jsxs10("span", { className: "text-[11px] text-muted-foreground tabular-nums shrink-0", children: [
2850
+ progress.done,
2851
+ "/",
2852
+ progress.total
2853
+ ] })
2854
+ ] }),
2855
+ (attentionSummary.unmappedCount > 0 || attentionSummary.lovIncompleteCount > 0) && /* @__PURE__ */ jsxs10("div", { className: "flex items-start gap-1.5 rounded-md bg-amber-500/10 border border-amber-500/20 px-2.5 py-1.5", children: [
2856
+ /* @__PURE__ */ jsx21(AlertTriangle, { className: "size-3 mt-0.5 shrink-0 text-amber-500" }),
2857
+ /* @__PURE__ */ jsxs10("div", { className: "text-[11px] text-amber-700 dark:text-amber-400 leading-snug", children: [
2858
+ attentionSummary.unmappedCount > 0 && /* @__PURE__ */ jsxs10("span", { children: [
2859
+ attentionSummary.unmappedCount,
2860
+ " attribute",
2861
+ attentionSummary.unmappedCount > 1 ? "s" : "",
2862
+ " unmapped"
2863
+ ] }),
2864
+ attentionSummary.unmappedCount > 0 && attentionSummary.lovIncompleteCount > 0 && /* @__PURE__ */ jsx21("span", { children: " \xB7 " }),
2865
+ attentionSummary.lovIncompleteCount > 0 && /* @__PURE__ */ jsxs10("span", { children: [
2866
+ attentionSummary.lovIncompleteCount,
2867
+ " attribute",
2868
+ attentionSummary.lovIncompleteCount > 1 ? "s" : "",
2869
+ " need value mapping"
2870
+ ] })
2871
+ ] })
2799
2872
  ] })
2800
2873
  ] })
2801
2874
  ] }),
2802
- /* @__PURE__ */ jsx21("div", { className: "px-4 overflow-y-auto flex-1 min-h-0", children: step === "attributes" ? /* @__PURE__ */ jsx21("div", { className: "divide-y divide-border/50", children: data.map((item, idx) => /* @__PURE__ */ jsx21(
2875
+ /* @__PURE__ */ jsx21("div", { className: "px-4 overflow-y-auto flex-1 min-h-0", children: step === "attributes" ? /* @__PURE__ */ jsx21("div", { className: "divide-y divide-border/50", children: sortedIndices.map((idx) => /* @__PURE__ */ jsx21(
2803
2876
  AttributeRow,
2804
2877
  {
2805
- item,
2878
+ item: data[idx],
2806
2879
  index: idx,
2807
2880
  allAttributes,
2881
+ needsValueAttention: lovAttentionSet.has(idx),
2808
2882
  onMap: handleMap,
2809
2883
  onConfirm: handleConfirm,
2810
2884
  onIgnore: handleIgnore,
@@ -3329,7 +3403,7 @@ function BooleanField({
3329
3403
  }
3330
3404
 
3331
3405
  // src/Automations/ProductAutomation.tsx
3332
- import { Fragment as Fragment4, jsx as jsx23, jsxs as jsxs12 } from "react/jsx-runtime";
3406
+ import { Fragment as Fragment5, jsx as jsx23, jsxs as jsxs12 } from "react/jsx-runtime";
3333
3407
  function ProductAutomation({
3334
3408
  storeId,
3335
3409
  workspaceId,
@@ -3609,10 +3683,10 @@ function ProductAutomation({
3609
3683
  onClick: handleRun,
3610
3684
  disabled: !isRunAllowed() || applying,
3611
3685
  className: "flex-1",
3612
- children: applying ? /* @__PURE__ */ jsxs12(Fragment4, { children: [
3686
+ children: applying ? /* @__PURE__ */ jsxs12(Fragment5, { children: [
3613
3687
  /* @__PURE__ */ jsx23(Loader26, { className: "size-4 animate-spin" }),
3614
3688
  "Applying..."
3615
- ] }) : /* @__PURE__ */ jsxs12(Fragment4, { children: [
3689
+ ] }) : /* @__PURE__ */ jsxs12(Fragment5, { children: [
3616
3690
  /* @__PURE__ */ jsx23(Play, { className: "size-4" }),
3617
3691
  "Run Automation"
3618
3692
  ] })
@@ -3656,7 +3730,7 @@ function formatTimeSaved(totalSeconds) {
3656
3730
  // src/Automations/StoreAutomation.tsx
3657
3731
  import { useState as useState10, useEffect as useEffect6, useCallback as useCallback8, useRef as useRef6 } from "react";
3658
3732
  import { ArrowLeft as ArrowLeft4, Settings } from "lucide-react";
3659
- import { Fragment as Fragment5, jsx as jsx24, jsxs as jsxs13 } from "react/jsx-runtime";
3733
+ import { Fragment as Fragment6, jsx as jsx24, jsxs as jsxs13 } from "react/jsx-runtime";
3660
3734
  function StoreAutomation({
3661
3735
  storeId,
3662
3736
  channelsWithVersion,
@@ -3904,7 +3978,7 @@ function AutomationConfigEditor({
3904
3978
  onConfigChange: handleConfigChange
3905
3979
  }
3906
3980
  ) : /* @__PURE__ */ jsx24("p", { className: "py-4 text-center text-sm text-muted-foreground", children: "Enable this automation to configure it." }) }),
3907
- automation.preview && /* @__PURE__ */ jsxs13(Fragment5, { children: [
3981
+ automation.preview && /* @__PURE__ */ jsxs13(Fragment6, { children: [
3908
3982
  /* @__PURE__ */ jsx24(Separator2, {}),
3909
3983
  /* @__PURE__ */ jsxs13("div", { className: "space-y-2 rounded-lg bg-muted/50 p-3 text-sm", children: [
3910
3984
  automation.preview.info_text.map((text, i) => /* @__PURE__ */ jsx24("p", { className: "text-muted-foreground", children: text }, i)),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@streamoid/catalogix-chat",
3
- "version": "0.2.6",
3
+ "version": "0.2.8",
4
4
  "description": "Catalogix chat components for the Streamoid chat host — store creation, product selection, automations",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",