@openg2p/registry-widgets 1.1.0-dev.0 → 1.1.0-dev.1

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
@@ -9527,6 +9527,13 @@ const HeaderSectionWidget = ({ config }) => {
9527
9527
  } })) : null, jsxRuntimeExports.jsx("div", { className: "hdr-avatar-placeholder", style: { display: imageUrl ? 'none' : 'flex' }, children: jsxRuntimeExports.jsx("img", { src: img$f, alt: "Profile Placeholder" }) })] }), jsxRuntimeExports.jsxs("div", { className: "hdr-info", children: [displayName && jsxRuntimeExports.jsx("div", { className: "hdr-name", children: displayName }), jsxRuntimeExports.jsxs("div", { className: "hdr-field-row", children: [jsxRuntimeExports.jsx(Dot, { color: "#9CA3AF" }), jsxRuntimeExports.jsxs("span", { className: "hdr-field-label", children: [getLabel('functionalId'), " :"] }), jsxRuntimeExports.jsx("span", { className: "hdr-field-value", children: functionalId || '-' })] }), jsxRuntimeExports.jsxs("div", { className: "hdr-field-row", children: [jsxRuntimeExports.jsx(Dot, { color: isReadonly ? statusColor : '#F59E0B' }), jsxRuntimeExports.jsx("span", { className: "hdr-field-label", children: getLabel('status') }), isReadonly ? (statusLabel ? (jsxRuntimeExports.jsx("span", { className: "hdr-status-badge", style: { backgroundColor: statusColor }, children: statusLabel })) : (jsxRuntimeExports.jsx("span", { className: "hdr-field-value", children: "-" }))) : (jsxRuntimeExports.jsxs("select", { className: "hdr-select", value: statusValue, onChange: (e) => updateFieldValue('status', e.target.value), children: [jsxRuntimeExports.jsx("option", { value: "", children: getLabel('select') }), statusOptions.map((opt) => (jsxRuntimeExports.jsx("option", { value: opt.value, children: opt.label }, opt.value)))] }))] }), jsxRuntimeExports.jsxs("div", { className: "hdr-field-row", children: [jsxRuntimeExports.jsx(Dot, { color: isReadonly ? '#9CA3AF' : '#F59E0B' }), jsxRuntimeExports.jsxs("span", { className: "hdr-field-label", children: [getLabel('statusReason'), " :"] }), isReadonly ? (jsxRuntimeExports.jsx("span", { className: "hdr-field-value", children: statusReason || '-' })) : (jsxRuntimeExports.jsx("input", { type: "text", className: "hdr-input", value: statusReason, placeholder: getLabel('enterReason'), onChange: (e) => updateFieldValue('statusReason', e.target.value) }))] })] })] }), jsxRuntimeExports.jsxs("div", { className: "hdr-right", children: [jsxRuntimeExports.jsxs("div", { className: "hdr-meta-row", children: [jsxRuntimeExports.jsxs("span", { className: "hdr-meta-label", children: [getLabel('createdBy'), " :"] }), jsxRuntimeExports.jsx("span", { className: "hdr-meta-value", children: createdBy || '-' })] }), jsxRuntimeExports.jsxs("div", { className: "hdr-meta-row", children: [jsxRuntimeExports.jsxs("span", { className: "hdr-meta-label", children: [getLabel('createdAt'), " :"] }), jsxRuntimeExports.jsx("span", { className: "hdr-meta-value", children: createdAt || '-' })] }), jsxRuntimeExports.jsxs("div", { className: "hdr-meta-row", children: [jsxRuntimeExports.jsxs("span", { className: "hdr-meta-label", children: [getLabel('lastApprovedBy'), " :"] }), jsxRuntimeExports.jsx("span", { className: "hdr-meta-value", children: lastApprovedBy || '-' })] }), jsxRuntimeExports.jsxs("div", { className: "hdr-meta-row", children: [jsxRuntimeExports.jsxs("span", { className: "hdr-meta-label", children: [getLabel('lastApprovedAt'), " :"] }), jsxRuntimeExports.jsx("span", { className: "hdr-meta-value", children: lastApprovedAt || '-' })] })] })] })] }));
9528
9528
  };
9529
9529
 
9530
+ function getValueByPathOrKey(obj, path) {
9531
+ if (!obj || !path)
9532
+ return undefined;
9533
+ if (Object.prototype.hasOwnProperty.call(obj, path))
9534
+ return obj[path];
9535
+ return getValueByPath(obj, path);
9536
+ }
9530
9537
  function tryFormatDateTime(value) {
9531
9538
  if (typeof value !== 'string' || !value)
9532
9539
  return value ? String(value) : '-';
@@ -9546,157 +9553,80 @@ function tryFormatDateTime(value) {
9546
9553
  return value;
9547
9554
  }
9548
9555
  }
9549
- function pickLatestScore(scores) {
9550
- if (!scores || scores.length === 0)
9551
- return null;
9556
+ function sortScores(scores) {
9552
9557
  const withTime = scores
9553
- .map((s) => {
9558
+ .map((s, idx) => {
9554
9559
  const t = typeof s?.computed_at === 'string' ? new Date(s.computed_at).getTime() : NaN;
9555
- return { s, t };
9560
+ return { s, t, idx };
9556
9561
  })
9557
- .filter((x) => !Number.isNaN(x.t));
9558
- if (withTime.length === 0)
9559
- return scores[0] || null;
9560
- withTime.sort((a, b) => b.t - a.t);
9561
- return withTime[0]?.s || null;
9562
+ .sort((a, b) => {
9563
+ const aHas = !Number.isNaN(a.t);
9564
+ const bHas = !Number.isNaN(b.t);
9565
+ if (aHas && bHas)
9566
+ return b.t - a.t;
9567
+ if (aHas)
9568
+ return -1;
9569
+ if (bHas)
9570
+ return 1;
9571
+ return a.idx - b.idx;
9572
+ });
9573
+ return withTime.map((x) => x.s);
9562
9574
  }
9563
9575
  /**
9564
- * Scores Display Widget - full-width, view-only widget
9576
+ * Scores Display Widget - full-width, view-only widget (list)
9565
9577
  *
9566
9578
  * Expected config (reference):
9567
9579
  * {
9568
9580
  * "widget": "scores-display",
9569
9581
  * "widget-type": "group",
9570
9582
  * "widget-id": "record-scores",
9571
- * "widget-data-source": {
9572
- * "type": "api",
9573
- * "service": "staff-portal-api",
9574
- * "endpoint": "get_scores",
9575
- * "method": "POST",
9576
- * "params": { "internal_record_id_path": "internal_record_id" }
9577
- * }
9583
+ * "widget-data-path": "scores"
9578
9584
  * }
9579
- *
9580
- * The host's `dataSourceRequestHandler` is invoked with:
9581
- * - service: config.widget-data-source.service
9582
- * - endpoint: config.widget-data-source.endpoint
9583
- * - method: config.widget-data-source.method (default POST)
9584
- * - params: { internal_record_id: <resolved from internal_record_id_path> }
9585
9585
  */
9586
- const ScoresDisplayWidget = ({ config, dataSourceRequestHandler: propHandler, schemaData: propSchemaData, }) => {
9587
- const { dataSourceRequestHandler: ctxHandler, schemaData: ctxSchemaData } = useWidgetContext();
9588
- const handler = propHandler || ctxHandler;
9589
- const schemaData = propSchemaData || ctxSchemaData || {};
9586
+ const ScoresDisplayWidget = ({ config, schemaData: propSchemaData, }) => {
9587
+ const { schemaData: ctxSchemaData } = useWidgetContext();
9588
+ const schemaData = (propSchemaData || ctxSchemaData || {});
9590
9589
  const values = reactRedux.useSelector((state) => state.widget.values);
9591
- const api = config['widget-data-source'];
9592
- const isApi = api?.type === 'api';
9593
- const apiDs = isApi ? api : null;
9594
- const internalIdPath = React.useMemo(() => {
9595
- if (!apiDs)
9596
- return undefined;
9597
- const p = apiDs.params || {};
9598
- const fromParams = p.internal_record_id_path || p.internalRecordIdPath;
9599
- const fromConfig = typeof config.internal_record_id_path === 'string'
9600
- ? config.internal_record_id_path
9601
- : undefined;
9602
- return fromParams || fromConfig;
9603
- }, [apiDs, config]);
9604
- const internalRecordId = React.useMemo(() => {
9605
- if (!internalIdPath)
9590
+ const dataPath = config['widget-data-path'];
9591
+ const rawScores = React.useMemo(() => {
9592
+ if (!dataPath || typeof dataPath !== 'string')
9606
9593
  return undefined;
9607
- const fromValues = getValueByPath(values || {}, internalIdPath);
9608
- if (fromValues !== undefined && fromValues !== null && String(fromValues).trim() !== '') {
9609
- return String(fromValues);
9610
- }
9611
- const fromSchema = getValueByPath(schemaData || {}, internalIdPath);
9612
- if (fromSchema !== undefined && fromSchema !== null && String(fromSchema).trim() !== '') {
9613
- return String(fromSchema);
9594
+ const valuesObj = values;
9595
+ const tryResolve = (path) => {
9596
+ const fromValues = getValueByPathOrKey(valuesObj, path);
9597
+ if (fromValues !== undefined)
9598
+ return fromValues;
9599
+ return getValueByPathOrKey(schemaData, path);
9600
+ };
9601
+ // 1) Try exact path (works when schema/store is already namespaced)
9602
+ const direct = tryResolve(dataPath);
9603
+ if (direct !== undefined)
9604
+ return direct;
9605
+ // 2) If section/widget config has been namespaced (e.g. "rv-section-0.scores"),
9606
+ // fall back to the original path ("scores") so examples still work even when
9607
+ // schemaData/store are not namespaced.
9608
+ if (dataPath.includes('.')) {
9609
+ const unNamespaced = dataPath.split('.').slice(1).join('.');
9610
+ const fallback = tryResolve(unNamespaced);
9611
+ if (fallback !== undefined)
9612
+ return fallback;
9614
9613
  }
9615
9614
  return undefined;
9616
- }, [internalIdPath, values, schemaData]);
9617
- const [loading, setLoading] = React.useState(false);
9618
- const [error, setError] = React.useState(null);
9619
- const [response, setResponse] = React.useState(null);
9620
- React.useEffect(() => {
9621
- let cancelled = false;
9622
- const load = async () => {
9623
- if (!apiDs) {
9624
- setError('Scores widget requires an API data source.');
9625
- setResponse(null);
9626
- return;
9627
- }
9628
- if (!handler) {
9629
- setError(null);
9630
- setResponse(null);
9631
- return;
9632
- }
9633
- const service = apiDs.service;
9634
- const endpoint = apiDs.endpoint;
9635
- const method = apiDs.method || 'POST';
9636
- if (!service || !endpoint) {
9637
- setError('Scores widget API data source is missing service/endpoint.');
9638
- setResponse(null);
9639
- return;
9640
- }
9641
- if (!internalRecordId) {
9642
- setError(null);
9643
- setResponse(null);
9644
- return;
9645
- }
9646
- try {
9647
- setLoading(true);
9648
- setError(null);
9649
- const rawParams = apiDs.params || {};
9650
- // Never pass the path helper through to the API.
9651
- const { internal_record_id_path, internalRecordIdPath, ...rest } = rawParams;
9652
- void internal_record_id_path;
9653
- void internalRecordIdPath;
9654
- const params = {
9655
- ...rest,
9656
- internal_record_id: internalRecordId,
9657
- };
9658
- const res = await handler(service, endpoint, method, params, {
9659
- headers: apiDs.headers,
9660
- });
9661
- if (cancelled)
9662
- return;
9663
- // Accept either direct payload or OpenG2P wrapper objects.
9664
- const envelope = res && typeof res === 'object' ? res : null;
9665
- const payload = envelope?.response_body?.response_payload ?? envelope?.data ?? res;
9666
- if (payload && typeof payload === 'object' && !Array.isArray(payload)) {
9667
- setResponse(payload);
9668
- }
9669
- else {
9670
- setResponse({ scores: Array.isArray(payload) ? payload : [] });
9671
- }
9672
- }
9673
- catch (e) {
9674
- if (cancelled)
9675
- return;
9676
- const maybeErr = e;
9677
- const msg = maybeErr && typeof maybeErr === 'object' && typeof maybeErr.message === 'string'
9678
- ? maybeErr.message
9679
- : 'Failed to load scores.';
9680
- setError(msg);
9681
- setResponse(null);
9682
- }
9683
- finally {
9684
- if (!cancelled)
9685
- setLoading(false);
9686
- }
9687
- };
9688
- load();
9689
- return () => {
9690
- cancelled = true;
9691
- };
9692
- }, [apiDs, handler, internalRecordId]);
9693
- const latest = React.useMemo(() => pickLatestScore(response?.scores), [response]);
9615
+ }, [dataPath, values, schemaData]);
9616
+ const scores = React.useMemo(() => {
9617
+ if (!rawScores)
9618
+ return [];
9619
+ if (Array.isArray(rawScores))
9620
+ return rawScores;
9621
+ if (typeof rawScores === 'object') {
9622
+ const maybe = rawScores.scores;
9623
+ if (Array.isArray(maybe))
9624
+ return maybe;
9625
+ }
9626
+ return [];
9627
+ }, [rawScores]);
9628
+ const sortedScores = React.useMemo(() => sortScores(scores), [scores]);
9694
9629
  const cls = `scores-display-widget-${config['widget-id']}`;
9695
- const scoreType = latest?.score_type ? String(latest.score_type) : '-';
9696
- const scoreValue = latest?.computed_score !== undefined && latest?.computed_score !== null && String(latest.computed_score) !== ''
9697
- ? String(latest.computed_score)
9698
- : '-';
9699
- const computedAt = tryFormatDateTime(latest?.computed_at);
9700
9630
  return (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx("style", { children: `
9701
9631
  .${cls} {
9702
9632
  width: 100%;
@@ -9713,66 +9643,95 @@ const ScoresDisplayWidget = ({ config, dataSourceRequestHandler: propHandler, sc
9713
9643
  font-weight: 400;
9714
9644
  }
9715
9645
 
9716
- .${cls} .scores-card {
9646
+ .${cls} .scores-grid {
9717
9647
  width: 100%;
9718
- border: none;
9719
- border-radius: 0;
9720
- background: transparent;
9721
- padding: 0;
9722
9648
  display: grid;
9723
- grid-template-columns: 1fr 1fr 1fr;
9649
+ grid-template-columns: repeat(3, minmax(220px, 1fr));
9724
9650
  gap: 16px;
9725
- align-items: center;
9726
9651
  }
9727
9652
 
9728
- .${cls} .scores-col {
9729
- min-width: 0;
9653
+ .${cls} .scores-card {
9654
+ border: 1px solid var(--owt-color-border-light, #E4E4E4);
9655
+ border-radius: 10px;
9656
+ background: var(--owt-color-bg, #FFFFFF);
9657
+ padding: 14px 14px;
9730
9658
  display: flex;
9731
9659
  flex-direction: column;
9732
- gap: 6px;
9660
+ gap: 10px;
9661
+ min-width: 0;
9662
+ box-shadow: 0 1px 2px rgba(1, 22, 39, 0.06), 0 6px 16px rgba(1, 22, 39, 0.06);
9733
9663
  }
9734
9664
 
9735
- .${cls} .scores-label {
9736
- font-size: 12px;
9737
- color: var(--owt-color-text-muted, #727474);
9738
- font-weight: 600;
9739
- letter-spacing: 0.25px;
9740
- text-transform: uppercase;
9665
+ .${cls} .scores-type {
9666
+ font-size: 16px;
9667
+ font-weight: 800;
9668
+ color: var(--owt-color-primary-dark, #F07B1A);
9669
+ line-height: 1.2;
9670
+ word-break: break-word;
9741
9671
  }
9742
9672
 
9743
9673
  .${cls} .scores-value {
9744
- font-size: 16px;
9745
- font-weight: 600;
9674
+ font-size: 34px;
9675
+ font-weight: 800;
9746
9676
  color: var(--owt-color-text, #011627);
9747
- line-height: 1.25;
9748
- word-break: break-word;
9677
+ line-height: 1.05;
9678
+ letter-spacing: -0.25px;
9749
9679
  }
9750
9680
 
9751
- .${cls} .scores-value--highlight {
9752
- font-weight: 800;
9753
- color: var(--owt-color-primary-dark, #F07B1A);
9681
+ .${cls} .scores-separator {
9682
+ height: 1px;
9683
+ width: 100%;
9684
+ background-color: var(--owt-color-border-light, #E4E4E4);
9685
+ border: none;
9686
+ margin: 2px 0;
9754
9687
  }
9755
9688
 
9756
- .${cls} .scores-value-wrap {
9757
- display: inline-flex;
9758
- align-items: baseline;
9759
- gap: 10px;
9760
- flex-wrap: wrap;
9689
+ .${cls} .scores-value .scores-muted {
9690
+ font-size: 18px;
9691
+ font-weight: 600;
9692
+ color: var(--owt-color-text-muted, #727474);
9693
+ margin-left: 6px;
9761
9694
  }
9762
9695
 
9763
- .${cls} .scores-value-badge { display: inline; }
9696
+ .${cls} .scores-meta {
9697
+ display: flex;
9698
+ flex-direction: column;
9699
+ gap: 4px;
9700
+ }
9764
9701
 
9765
- .${cls} .scores-statusline {
9766
- grid-column: 1 / -1;
9767
- margin-top: 2px;
9702
+ .${cls} .scores-meta-line {
9703
+ font-size: 13px;
9704
+ color: var(--owt-color-text-muted, #727474);
9705
+ font-weight: 500;
9768
9706
  }
9769
9707
 
9770
- @media (max-width: 768px) {
9771
- .${cls} .scores-card {
9708
+ .${cls} .scores-meta-line strong {
9709
+ color: var(--owt-color-text, #011627);
9710
+ font-weight: 700;
9711
+ }
9712
+
9713
+ @media (max-width: 1024px) {
9714
+ .${cls} .scores-grid {
9715
+ grid-template-columns: repeat(2, minmax(220px, 1fr));
9716
+ }
9717
+ }
9718
+
9719
+ @media (max-width: 640px) {
9720
+ .${cls} .scores-grid {
9772
9721
  grid-template-columns: 1fr;
9773
9722
  }
9774
9723
  }
9775
- ` }), jsxRuntimeExports.jsx("div", { className: cls, children: jsxRuntimeExports.jsxs("div", { className: "scores-card", children: [jsxRuntimeExports.jsxs("div", { className: "scores-col", "aria-live": "polite", children: [jsxRuntimeExports.jsx("div", { className: "scores-label", children: "Score Type" }), jsxRuntimeExports.jsx("div", { className: "scores-value-wrap", children: jsxRuntimeExports.jsx("span", { className: "scores-value-badge", children: jsxRuntimeExports.jsx("span", { className: "scores-value scores-value--highlight", children: scoreType }) }) })] }), jsxRuntimeExports.jsxs("div", { className: "scores-col", children: [jsxRuntimeExports.jsx("div", { className: "scores-label", children: "Score" }), jsxRuntimeExports.jsx("div", { className: "scores-value-wrap", children: jsxRuntimeExports.jsx("span", { className: "scores-value-badge", children: jsxRuntimeExports.jsx("span", { className: "scores-value scores-value--highlight", children: scoreValue }) }) })] }), jsxRuntimeExports.jsxs("div", { className: "scores-col", children: [jsxRuntimeExports.jsx("div", { className: "scores-label", children: "Computed at" }), jsxRuntimeExports.jsx("div", { className: "scores-value", children: computedAt })] }), jsxRuntimeExports.jsx("div", { className: "scores-statusline", children: loading ? (jsxRuntimeExports.jsx("div", { className: "scores-subtle", children: "Loading scores\u2026" })) : error ? (jsxRuntimeExports.jsx("div", { className: "scores-subtle", style: { color: 'var(--owt-color-error, #B91C1C)' }, children: error })) : !latest ? (jsxRuntimeExports.jsx("div", { className: "scores-subtle", children: "No scores available." })) : null })] }) })] }));
9724
+ ` }), jsxRuntimeExports.jsx("div", { className: cls, children: sortedScores.length === 0 ? (jsxRuntimeExports.jsx("div", { className: "scores-subtle", children: "No scores available." })) : (jsxRuntimeExports.jsx("div", { className: "scores-grid", children: sortedScores.map((s, idx) => {
9725
+ const scoreType = s?.score_type ? String(s.score_type) : '-';
9726
+ const scoreValue = s?.computed_score !== undefined &&
9727
+ s?.computed_score !== null &&
9728
+ String(s.computed_score) !== ''
9729
+ ? String(s.computed_score)
9730
+ : '-';
9731
+ const computedAt = tryFormatDateTime(s?.computed_at);
9732
+ const key = `${scoreType}-${String(s?.computed_at || '')}-${idx}`;
9733
+ return (jsxRuntimeExports.jsxs("div", { className: "scores-card", "aria-live": idx === 0 ? 'polite' : undefined, children: [jsxRuntimeExports.jsx("div", { className: "scores-type", children: scoreType }), jsxRuntimeExports.jsx("div", { className: "scores-value", children: scoreValue }), jsxRuntimeExports.jsx("hr", { className: "scores-separator" }), jsxRuntimeExports.jsx("div", { className: "scores-meta", children: jsxRuntimeExports.jsxs("div", { className: "scores-meta-line", children: ["Computed at: ", jsxRuntimeExports.jsx("strong", { children: computedAt })] }) })] }, key));
9734
+ }) })) })] }));
9776
9735
  };
9777
9736
 
9778
9737
  /**