@visns-studio/visns-components 5.10.10 → 5.10.11
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/package.json
CHANGED
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
"react-dom": "^17.0.0 || ^18.0.0"
|
|
88
88
|
},
|
|
89
89
|
"name": "@visns-studio/visns-components",
|
|
90
|
-
"version": "5.10.
|
|
90
|
+
"version": "5.10.11",
|
|
91
91
|
"description": "Various packages to assist in the development of our Custom Applications.",
|
|
92
92
|
"main": "src/index.js",
|
|
93
93
|
"files": [
|
|
@@ -763,9 +763,89 @@ const DataGrid = ({
|
|
|
763
763
|
data[column.id] &&
|
|
764
764
|
data[column.id][column.jsonData]
|
|
765
765
|
) {
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
return
|
|
766
|
+
const jsonValue = data[column.id][column.jsonData];
|
|
767
|
+
|
|
768
|
+
if (!jsonValue) return null;
|
|
769
|
+
|
|
770
|
+
try {
|
|
771
|
+
const jsonData = typeof jsonValue === 'string' ? JSON.parse(jsonValue) : jsonValue;
|
|
772
|
+
|
|
773
|
+
// Check if this looks like a question/answer format
|
|
774
|
+
const isQuestionAnswerFormat = Object.values(jsonData).every(item =>
|
|
775
|
+
item && typeof item === 'object' &&
|
|
776
|
+
(item.hasOwnProperty('question') || item.hasOwnProperty('answer'))
|
|
777
|
+
);
|
|
778
|
+
|
|
779
|
+
if (isQuestionAnswerFormat) {
|
|
780
|
+
return (
|
|
781
|
+
<div style={{ fontSize: '0.8rem' }}>
|
|
782
|
+
{Object.entries(jsonData).map(([key, item]) => {
|
|
783
|
+
if (!item || typeof item !== 'object') return null;
|
|
784
|
+
|
|
785
|
+
const question = item.question || key.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase());
|
|
786
|
+
const answer = item.answer !== undefined ?
|
|
787
|
+
(typeof item.answer === 'boolean' ? (item.answer ? 'Yes' : 'No') : String(item.answer)) :
|
|
788
|
+
'N/A';
|
|
789
|
+
|
|
790
|
+
return (
|
|
791
|
+
<div key={key} style={{ marginBottom: '0.3rem' }}>
|
|
792
|
+
<div style={{ fontWeight: '600', color: 'var(--primary-color)', marginBottom: '0.1rem', fontSize: '0.75rem' }}>
|
|
793
|
+
{question.length > 60 ? question.substring(0, 60) + '...' : question}
|
|
794
|
+
</div>
|
|
795
|
+
<div style={{ marginLeft: '0.5rem', color: 'var(--paragraph-color)', fontSize: '0.75rem' }}>
|
|
796
|
+
{answer}
|
|
797
|
+
</div>
|
|
798
|
+
</div>
|
|
799
|
+
);
|
|
800
|
+
})}
|
|
801
|
+
</div>
|
|
802
|
+
);
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
// Check if this is a simple key-value object
|
|
806
|
+
const isSimpleKeyValue = Object.values(jsonData).every(val =>
|
|
807
|
+
typeof val !== 'object' || val === null
|
|
808
|
+
);
|
|
809
|
+
|
|
810
|
+
if (isSimpleKeyValue) {
|
|
811
|
+
return (
|
|
812
|
+
<div style={{ fontSize: '0.8rem' }}>
|
|
813
|
+
{Object.entries(jsonData).slice(0, 3).map(([key, val]) => (
|
|
814
|
+
<div key={key} style={{ marginBottom: '0.2rem', display: 'flex', gap: '0.3rem' }}>
|
|
815
|
+
<strong style={{ color: 'var(--primary-color)', fontSize: '0.7rem' }}>
|
|
816
|
+
{key.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase())}:
|
|
817
|
+
</strong>
|
|
818
|
+
<span style={{ color: 'var(--paragraph-color)', fontSize: '0.7rem' }}>
|
|
819
|
+
{val !== null && val !== undefined ?
|
|
820
|
+
(typeof val === 'boolean' ? (val ? 'Yes' : 'No') : String(val).substring(0, 20)) :
|
|
821
|
+
'N/A'}
|
|
822
|
+
</span>
|
|
823
|
+
</div>
|
|
824
|
+
))}
|
|
825
|
+
{Object.keys(jsonData).length > 3 && (
|
|
826
|
+
<div style={{ fontSize: '0.65rem', color: 'var(--secondary-color)', fontStyle: 'italic' }}>
|
|
827
|
+
+{Object.keys(jsonData).length - 3} more...
|
|
828
|
+
</div>
|
|
829
|
+
)}
|
|
830
|
+
</div>
|
|
831
|
+
);
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
// For complex nested objects, show a summary
|
|
835
|
+
const keyCount = Object.keys(jsonData).length;
|
|
836
|
+
return (
|
|
837
|
+
<div style={{ fontSize: '0.75rem', color: 'var(--paragraph-color)', fontStyle: 'italic' }}>
|
|
838
|
+
JSON ({keyCount} {keyCount === 1 ? 'property' : 'properties'})
|
|
839
|
+
</div>
|
|
840
|
+
);
|
|
841
|
+
|
|
842
|
+
} catch (error) {
|
|
843
|
+
// If parsing fails, show raw value truncated
|
|
844
|
+
const displayValue = typeof jsonValue === 'string' && jsonValue.length > 30
|
|
845
|
+
? jsonValue.substring(0, 30) + '...'
|
|
846
|
+
: jsonValue;
|
|
847
|
+
return <span style={{ fontSize: '0.75rem', fontFamily: 'monospace', color: 'var(--paragraph-color)' }}>{displayValue}</span>;
|
|
848
|
+
}
|
|
769
849
|
} else {
|
|
770
850
|
return null;
|
|
771
851
|
}
|
|
@@ -376,13 +376,108 @@ export const renderJsonColumn = ({ column, commonProps }) => {
|
|
|
376
376
|
data[column.id][column.jsonData]
|
|
377
377
|
) {
|
|
378
378
|
const jsonValue = data[column.id][column.jsonData];
|
|
379
|
+
|
|
380
|
+
if (!jsonValue) return null;
|
|
381
|
+
|
|
382
|
+
let displayContent;
|
|
383
|
+
let tooltipValue = jsonValue;
|
|
384
|
+
|
|
385
|
+
try {
|
|
386
|
+
const jsonData = typeof jsonValue === 'string' ? JSON.parse(jsonValue) : jsonValue;
|
|
387
|
+
|
|
388
|
+
// Check if this looks like a question/answer format
|
|
389
|
+
const isQuestionAnswerFormat = Object.values(jsonData).every(item =>
|
|
390
|
+
item && typeof item === 'object' &&
|
|
391
|
+
(item.hasOwnProperty('question') || item.hasOwnProperty('answer'))
|
|
392
|
+
);
|
|
393
|
+
|
|
394
|
+
if (isQuestionAnswerFormat) {
|
|
395
|
+
const entries = Object.entries(jsonData);
|
|
396
|
+
if (entries.length === 1) {
|
|
397
|
+
const [key, item] = entries[0];
|
|
398
|
+
const question = item.question || key.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase());
|
|
399
|
+
const answer = item.answer !== undefined ?
|
|
400
|
+
(typeof item.answer === 'boolean' ? (item.answer ? 'Yes' : 'No') : String(item.answer)) :
|
|
401
|
+
'N/A';
|
|
402
|
+
|
|
403
|
+
displayContent = (
|
|
404
|
+
<div style={{ fontSize: '0.8rem' }}>
|
|
405
|
+
<div style={{ fontWeight: '600', color: 'var(--primary-color)', marginBottom: '0.1rem', fontSize: '0.75rem' }}>
|
|
406
|
+
{question.length > 50 ? question.substring(0, 50) + '...' : question}
|
|
407
|
+
</div>
|
|
408
|
+
<div style={{ color: 'var(--paragraph-color)', fontSize: '0.75rem' }}>
|
|
409
|
+
{answer}
|
|
410
|
+
</div>
|
|
411
|
+
</div>
|
|
412
|
+
);
|
|
413
|
+
} else {
|
|
414
|
+
displayContent = (
|
|
415
|
+
<div style={{ fontSize: '0.75rem', color: 'var(--paragraph-color)' }}>
|
|
416
|
+
Q&A ({entries.length} items)
|
|
417
|
+
</div>
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
tooltipValue = JSON.stringify(jsonData, null, 2);
|
|
421
|
+
}
|
|
422
|
+
// Check if this is a simple key-value object
|
|
423
|
+
else if (Object.values(jsonData).every(val => typeof val !== 'object' || val === null)) {
|
|
424
|
+
const entries = Object.entries(jsonData);
|
|
425
|
+
if (entries.length <= 2) {
|
|
426
|
+
displayContent = (
|
|
427
|
+
<div style={{ fontSize: '0.8rem' }}>
|
|
428
|
+
{entries.map(([key, val]) => (
|
|
429
|
+
<div key={key} style={{ marginBottom: '0.1rem', display: 'flex', gap: '0.3rem' }}>
|
|
430
|
+
<strong style={{ color: 'var(--primary-color)', fontSize: '0.7rem' }}>
|
|
431
|
+
{key.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase())}:
|
|
432
|
+
</strong>
|
|
433
|
+
<span style={{ color: 'var(--paragraph-color)', fontSize: '0.7rem' }}>
|
|
434
|
+
{val !== null && val !== undefined ?
|
|
435
|
+
(typeof val === 'boolean' ? (val ? 'Yes' : 'No') : String(val).substring(0, 15)) :
|
|
436
|
+
'N/A'}
|
|
437
|
+
</span>
|
|
438
|
+
</div>
|
|
439
|
+
))}
|
|
440
|
+
</div>
|
|
441
|
+
);
|
|
442
|
+
} else {
|
|
443
|
+
displayContent = (
|
|
444
|
+
<div style={{ fontSize: '0.75rem', color: 'var(--paragraph-color)' }}>
|
|
445
|
+
Data ({entries.length} properties)
|
|
446
|
+
</div>
|
|
447
|
+
);
|
|
448
|
+
}
|
|
449
|
+
tooltipValue = JSON.stringify(jsonData, null, 2);
|
|
450
|
+
}
|
|
451
|
+
// For complex nested objects
|
|
452
|
+
else {
|
|
453
|
+
const keyCount = Object.keys(jsonData).length;
|
|
454
|
+
displayContent = (
|
|
455
|
+
<div style={{ fontSize: '0.75rem', color: 'var(--paragraph-color)', fontStyle: 'italic' }}>
|
|
456
|
+
JSON ({keyCount} {keyCount === 1 ? 'property' : 'properties'})
|
|
457
|
+
</div>
|
|
458
|
+
);
|
|
459
|
+
tooltipValue = JSON.stringify(jsonData, null, 2);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
} catch (error) {
|
|
463
|
+
// If parsing fails, show truncated raw value
|
|
464
|
+
const displayValue = typeof jsonValue === 'string' && jsonValue.length > 30
|
|
465
|
+
? jsonValue.substring(0, 30) + '...'
|
|
466
|
+
: jsonValue;
|
|
467
|
+
displayContent = (
|
|
468
|
+
<span style={{ fontSize: '0.75rem', fontFamily: 'monospace', color: 'var(--paragraph-color)' }}>
|
|
469
|
+
{displayValue}
|
|
470
|
+
</span>
|
|
471
|
+
);
|
|
472
|
+
tooltipValue = jsonValue;
|
|
473
|
+
}
|
|
379
474
|
|
|
380
475
|
return (
|
|
381
476
|
<CellWithTooltip
|
|
382
|
-
value={
|
|
477
|
+
value={tooltipValue}
|
|
383
478
|
columnType="json"
|
|
384
479
|
>
|
|
385
|
-
|
|
480
|
+
{displayContent}
|
|
386
481
|
</CellWithTooltip>
|
|
387
482
|
);
|
|
388
483
|
} else {
|
|
@@ -686,8 +686,73 @@ function GenericDetail({
|
|
|
686
686
|
|
|
687
687
|
const renderExist = () => (truncatedValue ? 'Yes' : 'No');
|
|
688
688
|
|
|
689
|
-
const renderJson = () =>
|
|
690
|
-
|
|
689
|
+
const renderJson = () => {
|
|
690
|
+
if (!value) return null;
|
|
691
|
+
|
|
692
|
+
try {
|
|
693
|
+
const jsonData = typeof value === 'string' ? JSON.parse(value) : value;
|
|
694
|
+
|
|
695
|
+
// Check if this looks like a question/answer format
|
|
696
|
+
const isQuestionAnswerFormat = Object.values(jsonData).every(item =>
|
|
697
|
+
item && typeof item === 'object' &&
|
|
698
|
+
(item.hasOwnProperty('question') || item.hasOwnProperty('answer'))
|
|
699
|
+
);
|
|
700
|
+
|
|
701
|
+
if (isQuestionAnswerFormat) {
|
|
702
|
+
return (
|
|
703
|
+
<div className={styles.jsonQuestionAnswer}>
|
|
704
|
+
{Object.entries(jsonData).map(([key, item]) => {
|
|
705
|
+
if (!item || typeof item !== 'object') return null;
|
|
706
|
+
|
|
707
|
+
const question = item.question || key.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase());
|
|
708
|
+
const answer = item.answer !== undefined ?
|
|
709
|
+
(typeof item.answer === 'boolean' ? (item.answer ? 'Yes' : 'No') : String(item.answer)) :
|
|
710
|
+
'N/A';
|
|
711
|
+
|
|
712
|
+
return (
|
|
713
|
+
<div key={key} className={styles.questionAnswerPair}>
|
|
714
|
+
<div className={styles.question}>
|
|
715
|
+
<strong>{question}</strong>
|
|
716
|
+
</div>
|
|
717
|
+
<div className={styles.answer}>
|
|
718
|
+
{answer}
|
|
719
|
+
</div>
|
|
720
|
+
</div>
|
|
721
|
+
);
|
|
722
|
+
})}
|
|
723
|
+
</div>
|
|
724
|
+
);
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
// Check if this is a simple key-value object
|
|
728
|
+
const isSimpleKeyValue = Object.values(jsonData).every(val =>
|
|
729
|
+
typeof val !== 'object' || val === null
|
|
730
|
+
);
|
|
731
|
+
|
|
732
|
+
if (isSimpleKeyValue) {
|
|
733
|
+
return (
|
|
734
|
+
<div className={styles.jsonKeyValue}>
|
|
735
|
+
{Object.entries(jsonData).map(([key, val]) => (
|
|
736
|
+
<div key={key} className={styles.keyValuePair}>
|
|
737
|
+
<strong>{key.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase())}:</strong> {
|
|
738
|
+
val !== null && val !== undefined ?
|
|
739
|
+
(typeof val === 'boolean' ? (val ? 'Yes' : 'No') : String(val)) :
|
|
740
|
+
'N/A'
|
|
741
|
+
}
|
|
742
|
+
</div>
|
|
743
|
+
))}
|
|
744
|
+
</div>
|
|
745
|
+
);
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
// For complex nested objects, fall back to formatted JSON
|
|
749
|
+
return <pre className={styles.jsonRaw}>{JSON.stringify(jsonData, null, 2)}</pre>;
|
|
750
|
+
|
|
751
|
+
} catch (error) {
|
|
752
|
+
// If parsing fails, show raw value
|
|
753
|
+
return <pre className={styles.jsonRaw}>{JSON.stringify(value, null, 2)}</pre>;
|
|
754
|
+
}
|
|
755
|
+
};
|
|
691
756
|
|
|
692
757
|
const renderLatestNotes = () => formatNoteValue();
|
|
693
758
|
|
|
@@ -742,3 +742,80 @@
|
|
|
742
742
|
box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.1); /* Gentle shadow for depth */
|
|
743
743
|
font-style: italic; /* Optional: Add a subtle font style */
|
|
744
744
|
}
|
|
745
|
+
|
|
746
|
+
/* Enhanced JSON Rendering Styles */
|
|
747
|
+
.jsonQuestionAnswer {
|
|
748
|
+
padding: 0.75rem;
|
|
749
|
+
background: rgba(var(--primary-rgb), 0.02);
|
|
750
|
+
border-radius: 4px;
|
|
751
|
+
border: 1px solid rgba(var(--primary-rgb), 0.08);
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
.questionAnswerPair {
|
|
755
|
+
margin-bottom: 1rem;
|
|
756
|
+
padding: 0.75rem;
|
|
757
|
+
background: rgba(var(--primary-rgb), 0.01);
|
|
758
|
+
border-radius: 4px;
|
|
759
|
+
border-left: 3px solid var(--secondary-color);
|
|
760
|
+
|
|
761
|
+
&:last-child {
|
|
762
|
+
margin-bottom: 0;
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
.question {
|
|
767
|
+
margin-bottom: 0.4rem;
|
|
768
|
+
|
|
769
|
+
strong {
|
|
770
|
+
color: var(--primary-color);
|
|
771
|
+
font-size: 0.9rem;
|
|
772
|
+
font-weight: 600;
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
.answer {
|
|
777
|
+
color: var(--paragraph-color);
|
|
778
|
+
font-size: 0.85rem;
|
|
779
|
+
margin-left: 1rem;
|
|
780
|
+
font-weight: 500;
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
.jsonKeyValue {
|
|
784
|
+
padding: 0.75rem;
|
|
785
|
+
background: rgba(var(--primary-rgb), 0.02);
|
|
786
|
+
border-radius: 4px;
|
|
787
|
+
border: 1px solid rgba(var(--primary-rgb), 0.08);
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
.keyValuePair {
|
|
791
|
+
margin-bottom: 0.6rem;
|
|
792
|
+
padding: 0.5rem;
|
|
793
|
+
background: rgba(var(--primary-rgb), 0.01);
|
|
794
|
+
border-radius: 3px;
|
|
795
|
+
display: flex;
|
|
796
|
+
gap: 0.5rem;
|
|
797
|
+
|
|
798
|
+
&:last-child {
|
|
799
|
+
margin-bottom: 0;
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
strong {
|
|
803
|
+
color: var(--primary-color);
|
|
804
|
+
font-size: 0.85rem;
|
|
805
|
+
min-width: 120px;
|
|
806
|
+
flex: 0 0 auto;
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
.jsonRaw {
|
|
811
|
+
background: rgba(var(--primary-rgb), 0.03);
|
|
812
|
+
border: 1px solid rgba(var(--primary-rgb), 0.1);
|
|
813
|
+
border-radius: 4px;
|
|
814
|
+
padding: 0.75rem;
|
|
815
|
+
font-family: monospace;
|
|
816
|
+
font-size: 0.8rem;
|
|
817
|
+
line-height: 1.4;
|
|
818
|
+
color: var(--paragraph-color);
|
|
819
|
+
overflow-x: auto;
|
|
820
|
+
white-space: pre-wrap;
|
|
821
|
+
}
|