datajunction-ui 0.0.12 → 0.0.14

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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "datajunction-ui",
3
- "version": "0.0.12",
3
+ "version": "0.0.14",
4
4
  "description": "DataJunction Metrics Platform UI",
5
5
  "module": "src/index.tsx",
6
6
  "repository": {
@@ -1,10 +1,33 @@
1
1
  /**
2
2
  * Custom metadata field component for nodes
3
3
  */
4
- import { ErrorMessage, Field } from 'formik';
5
- import { useEffect } from 'react';
4
+ import { ErrorMessage, Field, useFormikContext } from 'formik';
5
+ import CodeMirror from '@uiw/react-codemirror';
6
+ import { langs } from '@uiw/codemirror-extensions-langs';
7
+ import { useState, useEffect } from 'react';
8
+
9
+ export const CustomMetadataField = ({ value }) => {
10
+ const formik = useFormikContext();
11
+ const jsonExt = langs.json();
12
+ const [hasError, setHasError] = useState(false);
13
+
14
+ useEffect(() => {
15
+ if (!value || value === '') {
16
+ setHasError(false);
17
+ return;
18
+ }
19
+
20
+ const stringValue =
21
+ typeof value === 'string' ? value : JSON.stringify(value, null, 2);
22
+
23
+ try {
24
+ JSON.parse(stringValue);
25
+ setHasError(false);
26
+ } catch (err) {
27
+ setHasError(true);
28
+ }
29
+ }, [value]);
6
30
 
7
- export const CustomMetadataField = () => {
8
31
  const formatValue = value => {
9
32
  if (value === null || value === undefined) {
10
33
  return '';
@@ -15,74 +38,107 @@ export const CustomMetadataField = () => {
15
38
  return JSON.stringify(value, null, 2);
16
39
  };
17
40
 
18
- const handleChange = (e, setFieldValue) => {
19
- setFieldValue('custom_metadata', e.target.value);
41
+ const updateFormik = val => {
42
+ formik.setFieldValue('custom_metadata', val);
43
+ formik.setFieldTouched('custom_metadata', true);
44
+
45
+ if (!val || val.trim() === '') {
46
+ setHasError(false);
47
+ } else {
48
+ try {
49
+ JSON.parse(val);
50
+ setHasError(false);
51
+ } catch (err) {
52
+ setHasError(true);
53
+ }
54
+ }
20
55
  };
21
56
 
22
57
  return (
23
- <div className="NodeCreationInput" style={{ marginTop: '20px' }}>
24
- <label htmlFor="CustomMetadata">Custom Metadata (JSON)</label>
25
- <Field
26
- name="custom_metadata"
27
- validate={value => {
28
- if (!value || value.trim() === '') {
29
- return undefined;
30
- }
31
- try {
32
- const parsed = JSON.parse(value);
58
+ <div className="QueryInput NodeCreationInput">
59
+ <details>
60
+ <summary style={{ cursor: 'pointer' }}>
61
+ <label
62
+ style={{
63
+ paddingLeft: '3px',
64
+ display: 'inline-block',
65
+ pointerEvents: 'none',
66
+ }}
67
+ >
68
+ Custom Metadata (JSON)
69
+ </label>
70
+ </summary>
71
+ <ErrorMessage name="custom_metadata" component="span" />
72
+ <Field
73
+ type="textarea"
74
+ style={{ display: 'none' }}
75
+ as="textarea"
76
+ name="custom_metadata"
77
+ id="CustomMetadata"
78
+ validate={value => {
79
+ if (!value || value.trim() === '') {
80
+ return undefined;
81
+ }
82
+ try {
83
+ const parsed = JSON.parse(value);
33
84
 
34
- if (
35
- typeof parsed === 'object' &&
36
- parsed !== null &&
37
- !Array.isArray(parsed)
38
- ) {
39
- const keys = Object.keys(parsed);
40
- const originalKeyMatches = value.match(/"([^"]+)"\s*:/g);
41
85
  if (
42
- originalKeyMatches &&
43
- originalKeyMatches.length > keys.length
86
+ typeof parsed === 'object' &&
87
+ parsed !== null &&
88
+ !Array.isArray(parsed)
44
89
  ) {
45
- return 'Duplicate keys detected';
90
+ const keys = Object.keys(parsed);
91
+ const originalKeyMatches = value.match(/"([^"]+)"\s*:/g);
92
+ if (
93
+ originalKeyMatches &&
94
+ originalKeyMatches.length > keys.length
95
+ ) {
96
+ return 'Duplicate keys detected';
97
+ }
46
98
  }
47
- }
48
-
49
- return undefined;
50
- } catch (err) {
51
- return 'Invalid JSON format';
52
- }
53
- }}
54
- >
55
- {({ field, form }) => {
56
- const errorMessage = form.errors.custom_metadata;
57
- const hasError = errorMessage && form.touched.custom_metadata;
58
99
 
59
- return (
60
- <div>
61
- <textarea
62
- id="CustomMetadata"
63
- value={formatValue(field.value)}
64
- onChange={e => handleChange(e, form.setFieldValue)}
65
- onBlur={() => form.setFieldTouched('custom_metadata', true)}
66
- style={{
67
- width: '100%',
68
- minHeight: '100px',
69
- fontFamily: 'monospace',
70
- fontSize: '12px',
71
- padding: '8px',
72
- border: hasError ? '1px solid red' : '1px solid #ccc',
73
- borderRadius: '4px',
74
- }}
75
- placeholder="Define custom node metadata here..."
76
- />
77
- {hasError && (
78
- <span style={{ color: 'red', fontSize: '12px' }}>
79
- {errorMessage}
80
- </span>
81
- )}
82
- </div>
83
- );
84
- }}
85
- </Field>
100
+ return undefined;
101
+ } catch (err) {
102
+ return 'Invalid JSON format';
103
+ }
104
+ }}
105
+ />
106
+ <div
107
+ role="button"
108
+ tabIndex={0}
109
+ className={`relative flex ${
110
+ hasError ? 'bg-red-900/20' : 'bg-[#282a36]'
111
+ }`}
112
+ style={{
113
+ border: hasError ? '2px solid #ef4444' : 'none',
114
+ borderRadius: '4px',
115
+ boxShadow: hasError ? '0 0 0 1px rgba(239, 68, 68, 0.3)' : 'none',
116
+ }}
117
+ >
118
+ <CodeMirror
119
+ id={'custom_metadata'}
120
+ name={'custom_metadata'}
121
+ extensions={[jsonExt]}
122
+ value={formatValue(value)}
123
+ placeholder={'{\n "key": "value"\n}'}
124
+ options={{
125
+ theme: 'default',
126
+ lineNumbers: true,
127
+ }}
128
+ width="100%"
129
+ height="200px"
130
+ style={{
131
+ margin: '0 0 23px 0',
132
+ flex: 1,
133
+ fontSize: '150%',
134
+ textAlign: 'left',
135
+ }}
136
+ onChange={(value, viewUpdate) => {
137
+ updateFormik(value);
138
+ }}
139
+ />
140
+ </div>
141
+ </details>
86
142
  </div>
87
143
  );
88
144
  };
@@ -474,7 +474,6 @@ export function AddEditNodePage({ extensions = {} }) {
474
474
  ) : (
475
475
  ''
476
476
  )}
477
- <CustomMetadataField />
478
477
  {nodeType !== 'metric' && node.type !== 'metric' ? (
479
478
  action === Action.Edit ? (
480
479
  selectPrimaryKey
@@ -491,6 +490,11 @@ export function AddEditNodePage({ extensions = {} }) {
491
490
  ) : (
492
491
  <RequiredDimensionsSelect />
493
492
  )}
493
+ <CustomMetadataField
494
+ value={
495
+ node.custom_metadata ? node.custom_metadata : ''
496
+ }
497
+ />
494
498
  {Object.entries(extensions).map(
495
499
  ([key, ExtensionComponent]) => (
496
500
  <div key={key} className="mt-4 border-t pt-4">