@@ -7,6 +7,7 @@ import { extractFieldOptions } from '@/vdb/framework/form-engine/utils.js';
77import { transformValue } from '@/vdb/framework/form-engine/value-transformers.js' ;
88import { api } from '@/vdb/graphql/api.js' ;
99import { graphql } from '@/vdb/graphql/graphql.js' ;
10+ import { useChannel } from '@/vdb/hooks/use-channel.js' ;
1011import { useLocalFormat } from '@/vdb/hooks/use-local-format.js' ;
1112import { useUserSettings } from '@/vdb/hooks/use-user-settings.js' ;
1213import { useLingui } from '@lingui/react/macro' ;
@@ -33,6 +34,17 @@ export interface ArgSummaryProps {
3334 fieldDef : ConfigurableFieldDef ;
3435 /** The raw json-string encoded arg value */
3536 value : string ;
37+ omitPrefix ?: boolean ;
38+ omitSuffix ?: boolean ;
39+ }
40+
41+ export function shouldUseListCountSummary (
42+ isListField : boolean ,
43+ value : unknown ,
44+ listInputMode : boolean | 'dynamic' | undefined ,
45+ ) : boolean {
46+ const componentHandlesList = listInputMode === true || listInputMode === 'dynamic' ;
47+ return isListField && Array . isArray ( value ) && ! componentHandlesList ;
3648}
3749
3850/**
@@ -47,17 +59,32 @@ export interface ArgSummaryProps {
4759 * 3. A default summary based on the arg type (boolean, datetime, list count,
4860 * plain value)
4961 */
50- export function ArgSummary ( { fieldDef, value } : Readonly < ArgSummaryProps > ) {
62+ export function ArgSummary ( { fieldDef, value, omitPrefix , omitSuffix } : Readonly < ArgSummaryProps > ) {
5163 const componentId = fieldDef . ui ?. component as string | undefined ;
5264 const CustomComponent = getInputComponent ( componentId ) ;
5365 const parsedValue = transformValue ( value , fieldDef , 'json-string' , 'parse' ) ;
66+ const isListValue = fieldDef . list === true && Array . isArray ( parsedValue ) ;
67+ const listInputMode = CustomComponent ?. metadata ?. isListInput ;
68+ const useListCountSummary = shouldUseListCountSummary ( fieldDef . list , parsedValue , listInputMode ) ;
5469
55- const Summary =
56- CustomComponent ?. metadata ?. summary ??
57- ( componentId ? BUILT_IN_SUMMARIES [ componentId ] : undefined ) ??
58- DefaultArgSummary ;
70+ const Summary = useListCountSummary
71+ ? DefaultArgSummary
72+ : ( CustomComponent ?. metadata ?. summary ??
73+ ( componentId ? BUILT_IN_SUMMARIES [ componentId ] : undefined ) ??
74+ DefaultArgSummary ) ;
5975
60- return < Summary value = { parsedValue } fieldDef = { fieldDef } /> ;
76+ const isAffixedComponent =
77+ ! isListValue && ( componentId === 'number-form-input' || componentId === 'text-form-input' ) ;
78+ const prefix = isAffixedComponent && ! omitPrefix ? fieldDef . ui ?. prefix : undefined ;
79+ const suffix = isAffixedComponent && ! omitSuffix ? fieldDef . ui ?. suffix : undefined ;
80+
81+ return (
82+ < >
83+ { prefix }
84+ < Summary value = { parsedValue } fieldDef = { fieldDef } />
85+ { suffix }
86+ </ >
87+ ) ;
6188}
6289
6390function DefaultArgSummary ( { value, fieldDef } : Readonly < DashboardFormComponentSummaryProps > ) {
@@ -77,8 +104,83 @@ function DefaultArgSummary({ value, fieldDef }: Readonly<DashboardFormComponentS
77104}
78105
79106function CurrencySummary ( { value } : Readonly < DashboardFormComponentSummaryProps > ) {
80- const { toMajorUnits, formatNumber } = useLocalFormat ( ) ;
81- return < > { formatNumber ( toMajorUnits ( Number ( value ) ) ) } </ > ;
107+ const { activeChannel } = useChannel ( ) ;
108+ const { formatCurrency, toMajorUnits, formatNumber } = useLocalFormat ( ) ;
109+ const currencyCode = activeChannel ?. defaultCurrencyCode ;
110+ return (
111+ < >
112+ { currencyCode
113+ ? formatCurrency ( Number ( value ) , currencyCode )
114+ : formatNumber ( toMajorUnits ( Number ( value ) ) ) }
115+ </ >
116+ ) ;
117+ }
118+
119+ function PasswordSummary ( ) {
120+ return < > { '\u2022' . repeat ( 8 ) } </ > ;
121+ }
122+
123+ const MAX_TEXT_SUMMARY_LENGTH = 80 ;
124+
125+ export function compactText ( value : unknown ) : { full : string ; compact : string } {
126+ const raw = String ( value ?? '' )
127+ . replace ( / < ( s c r i p t | s t y l e ) [ ^ > ] * > [ \s \S ] * ?< \/ \1> / gi, '' )
128+ . replace (
129+ / < \/ ( a d d r e s s | a r t i c l e | a s i d e | b l o c k q u o t e | d i v | f i g c a p t i o n | f i g u r e | f o o t e r | h e a d e r | h [ 1 - 6 ] | l i | m a i n | n a v | o l | p | p r e | s e c t i o n | t a b l e | t r | u l ) > / gi,
130+ ' ' ,
131+ ) ;
132+ let plainText : string ;
133+ if ( typeof DOMParser === 'undefined' ) {
134+ plainText = raw . replace ( / < [ ^ > ] * > / g, ' ' ) ;
135+ } else {
136+ plainText = new DOMParser ( ) . parseFromString ( raw , 'text/html' ) . body . textContent ?? '' ;
137+ }
138+ const full = plainText . replace ( / \s + / g, ' ' ) . trim ( ) ;
139+ const compact =
140+ full . length > MAX_TEXT_SUMMARY_LENGTH
141+ ? `${ full . slice ( 0 , MAX_TEXT_SUMMARY_LENGTH - 1 ) . trimEnd ( ) } \u2026`
142+ : full ;
143+ return { full, compact } ;
144+ }
145+
146+ function RichTextSummary ( { value } : Readonly < DashboardFormComponentSummaryProps > ) {
147+ const { full, compact } = compactText ( value ) ;
148+ return < span title = { full } > { compact } </ span > ;
149+ }
150+
151+ export type JsonSummary =
152+ | { type : 'items' ; count : number }
153+ | { type : 'properties' ; count : number }
154+ | { type : 'text' ; value : string } ;
155+
156+ export function getJsonSummary ( value : unknown ) : JsonSummary {
157+ let parsed = value ;
158+ if ( typeof value === 'string' ) {
159+ try {
160+ parsed = JSON . parse ( value ) ;
161+ } catch {
162+ return { type : 'text' , value : compactText ( value ) . compact } ;
163+ }
164+ }
165+ if ( Array . isArray ( parsed ) ) {
166+ return { type : 'items' , count : parsed . length } ;
167+ }
168+ if ( parsed !== null && typeof parsed === 'object' ) {
169+ return { type : 'properties' , count : Object . keys ( parsed ) . length } ;
170+ }
171+ return { type : 'text' , value : String ( parsed ) } ;
172+ }
173+
174+ function JsonSummary ( { value } : Readonly < DashboardFormComponentSummaryProps > ) {
175+ const { t } = useLingui ( ) ;
176+ const summary = getJsonSummary ( value ) ;
177+ if ( summary . type === 'items' ) {
178+ return < > { summary . count === 1 ? t `1 item` : t `${ summary . count } items` } </ > ;
179+ }
180+ if ( summary . type === 'properties' ) {
181+ return < > { summary . count === 1 ? t `1 property` : t `${ summary . count } properties` } </ > ;
182+ }
183+ return < > { summary . value } </ > ;
82184}
83185
84186function SelectOptionsSummary ( { value, fieldDef } : Readonly < DashboardFormComponentSummaryProps > ) {
@@ -143,8 +245,7 @@ function ProductVariantSummary({ value }: Readonly<DashboardFormComponentSummary
143245 const ids = toIdArray ( value ) ;
144246 const { data } = useQuery ( {
145247 queryKey : [ 'ProductVariantSummary' , ids ] ,
146- queryFn : ( ) =>
147- api . query ( productVariantSummaryDocument , { options : { filter : { id : { in : ids } } } } ) ,
248+ queryFn : ( ) => api . query ( productVariantSummaryDocument , { options : { filter : { id : { in : ids } } } } ) ,
148249 enabled : ids . length > 0 ,
149250 placeholderData : undefined ,
150251 } ) ;
@@ -155,6 +256,40 @@ function ProductVariantSummary({ value }: Readonly<DashboardFormComponentSummary
155256 return < NameList names = { items . map ( item => item . name ) } /> ;
156257}
157258
259+ const productSummaryDocument = graphql ( `
260+ query ProductSummary($options: ProductListOptions) {
261+ products(options: $options) {
262+ items {
263+ id
264+ name
265+ }
266+ }
267+ }
268+ ` ) ;
269+
270+ function ProductSummary ( { value } : Readonly < DashboardFormComponentSummaryProps > ) {
271+ const ids = toIdArray ( value ) ;
272+ const { data } = useQuery ( {
273+ queryKey : [ 'ProductSummary' , ids ] ,
274+ queryFn : ( ) => api . query ( productSummaryDocument , { options : { filter : { id : { in : ids } } } } ) ,
275+ enabled : ids . length > 0 ,
276+ placeholderData : undefined ,
277+ } ) ;
278+ const items = data ?. products . items ;
279+ if ( ! items ) {
280+ return < EntityCountFallback count = { ids . length } /> ;
281+ }
282+ return < NameList names = { items . map ( item => item . name ) } /> ;
283+ }
284+
285+ function ProductMultiSummary ( { value, fieldDef } : Readonly < DashboardFormComponentSummaryProps > ) {
286+ return fieldDef . ui ?. selectionMode === 'variant' ? (
287+ < ProductVariantSummary value = { value } fieldDef = { fieldDef } />
288+ ) : (
289+ < ProductSummary value = { value } fieldDef = { fieldDef } />
290+ ) ;
291+ }
292+
158293const customerGroupSummaryDocument = graphql ( `
159294 query CustomerGroupSummary($options: CustomerGroupListOptions) {
160295 customerGroups(options: $options) {
@@ -170,8 +305,7 @@ function CustomerGroupSummary({ value }: Readonly<DashboardFormComponentSummaryP
170305 const ids = toIdArray ( value ) ;
171306 const { data } = useQuery ( {
172307 queryKey : [ 'CustomerGroupSummary' , ids ] ,
173- queryFn : ( ) =>
174- api . query ( customerGroupSummaryDocument , { options : { filter : { id : { in : ids } } } } ) ,
308+ queryFn : ( ) => api . query ( customerGroupSummaryDocument , { options : { filter : { id : { in : ids } } } } ) ,
175309 enabled : ids . length > 0 ,
176310 placeholderData : undefined ,
177311 } ) ;
@@ -212,6 +346,12 @@ function toIdArray(value: any): string[] {
212346
213347const BUILT_IN_SUMMARIES : Record < string , ComponentType < DashboardFormComponentSummaryProps > > = {
214348 'currency-form-input' : CurrencySummary ,
349+ 'html-editor-form-input' : RichTextSummary ,
350+ 'json-editor-form-input' : JsonSummary ,
351+ 'password-form-input' : PasswordSummary ,
352+ 'product-multi-form-input' : ProductMultiSummary ,
353+ 'product-multi-input' : ProductMultiSummary ,
354+ 'rich-text-form-input' : RichTextSummary ,
215355 'select-form-input' : SelectOptionsSummary ,
216356 'facet-value-form-input' : FacetValueSummary ,
217357 'facet-value-input' : FacetValueSummary ,
0 commit comments