• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

eclipsesource / jsonforms / 9513795064

14 Jun 2024 09:21AM UTC coverage: 83.244% (-0.09%) from 83.337%
9513795064

Pull #2346

github

lucas-koehler
improve compose method comments
Pull Request #2346: Unify path handling to consistenly use JSON Pointer

9295 of 21268 branches covered (43.7%)

38 of 45 new or added lines in 16 files covered. (84.44%)

271 existing lines in 46 files now uncovered.

16459 of 19772 relevant lines covered (83.24%)

28.62 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.33
/packages/vanilla-renderers/src/complex/TableArrayControl.tsx
1
/*
2
  The MIT License
3
  
4
  Copyright (c) 2017-2019 EclipseSource Munich
5
  https://github.com/eclipsesource/jsonforms
6
  
7
  Permission is hereby granted, free of charge, to any person obtaining a copy
8
  of this software and associated documentation files (the "Software"), to deal
9
  in the Software without restriction, including without limitation the rights
10
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
  copies of the Software, and to permit persons to whom the Software is
12
  furnished to do so, subject to the following conditions:
13
  
14
  The above copyright notice and this permission notice shall be included in
15
  all copies or substantial portions of the Software.
16
  
17
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
  THE SOFTWARE.
24
*/
25
import React from 'react';
7✔
26
import fpfilter from 'lodash/fp/filter';
7✔
27
import fpmap from 'lodash/fp/map';
7✔
28
import fpflow from 'lodash/fp/flow';
7✔
29
import filter from 'lodash/filter';
7✔
30
import join from 'lodash/join';
7✔
31
import fpkeys from 'lodash/fp/keys';
7✔
32
import fpstartCase from 'lodash/fp/startCase';
7✔
33
import {
7✔
34
  ArrayControlProps,
35
  ControlElement,
36
  createDefaultValue,
37
  Helpers,
38
  Paths,
39
  RankedTester,
40
  Resolve,
41
  Test,
42
  getControlPath,
43
} from '@jsonforms/core';
44
import { DispatchCell, withJsonFormsArrayControlProps } from '@jsonforms/react';
7✔
45
import { withVanillaControlProps } from '../util';
7✔
46
import type { VanillaRendererProps } from '../index';
47

48
const { convertToValidClassName } = Helpers;
7✔
49

50
const { or, isObjectArrayControl, isPrimitiveArrayControl, rankWith } = Test;
28✔
51

52
/**
53
 * Alternative tester for an array that also checks whether the 'table'
54
 * option is set.
55
 * @type {RankedTester}
56
 */
57
export const tableArrayControlTester: RankedTester = rankWith(
7✔
58
  3,
59
  or(isObjectArrayControl, isPrimitiveArrayControl)
60
);
61

62
class TableArrayControl extends React.Component<
15✔
63
  ArrayControlProps & VanillaRendererProps,
64
  any
65
> {
66
  confirmDelete = (path: string, index: number) => {
15✔
NEW
67
    const p = path.substring(0, path.lastIndexOf('/'));
×
68
    this.props.removeItems(p, [index])();
×
69
  };
70

71
  render() {
25✔
72
    const {
73
      addItem,
25✔
74
      uischema,
25✔
75
      schema,
25✔
76
      rootSchema,
25✔
77
      path,
25✔
78
      data,
25✔
79
      visible,
25✔
80
      errors,
25✔
81
      label,
25✔
82
      getStyleAsClassName,
25✔
83
      childErrors,
25✔
84
      translations,
25✔
85
    } = this.props;
25✔
86

87
    const controlElement = uischema as ControlElement;
25✔
88
    const tableClass = getStyleAsClassName('array.table.table');
25✔
89
    const labelClass = getStyleAsClassName('array.table.label');
25✔
90
    const buttonClass = getStyleAsClassName('array.table.button');
25✔
91
    const validationClass = getStyleAsClassName('array.table.validation');
25✔
92
    const controlClass = [
25✔
93
      getStyleAsClassName('array.table'),
94
      convertToValidClassName(controlElement.scope),
95
    ].join(' ');
96
    const createControlElement = (key?: string): ControlElement => ({
40✔
97
      type: 'Control',
98
      label: false,
99
      scope:
100
        schema.type === 'object' ? Paths.compose('#', 'properties', key) : '#',
40✔
101
    });
102
    const isValid = errors.length === 0;
25✔
103
    const divClassNames = [validationClass]
25✔
104
      .concat(
105
        isValid ? '' : getStyleAsClassName('array.table.validation.error')
25✔
106
      )
107
      .join(' ');
108

109
    return (
25✔
110
      <div className={controlClass} hidden={!visible}>
111
        <header>
112
          <label className={labelClass}>{label}</label>
113
          <button
114
            type='button'
115
            className={buttonClass}
116
            onClick={addItem(path, createDefaultValue(schema, rootSchema))}
117
          >
118
            {translations.addTooltip}
119
          </button>
120
        </header>
121
        <div className={divClassNames}>{!isValid ? errors : ''}</div>
25✔
122
        <table className={tableClass}>
123
          <thead>
124
            <tr>
125
              {schema.properties ? (
25✔
126
                fpflow(
127
                  fpkeys,
128
                  fpfilter((prop) => schema.properties[prop].type !== 'array'),
48✔
129
                  fpmap((prop) => (
48✔
130
                    <th key={prop}>
131
                      {schema.properties[prop].title ?? fpstartCase(prop)}
144✔
132
                    </th>
133
                  ))
134
                )(schema.properties)
135
              ) : (
136
                <th>Items</th>
137
              )}
138
              <th>Valid</th>
139
              <th>&nbsp;</th>
140
            </tr>
141
          </thead>
142
          <tbody>
143
            {!data || !Array.isArray(data) || data.length === 0 ? (
91✔
144
              <tr>
145
                <td>{translations.noDataMessage}</td>
146
              </tr>
147
            ) : (
148
              data.map((_child, index) => {
149
                const childPath = Paths.compose(path, index);
21✔
150
                const errorsPerEntry: any[] = filter(childErrors, (error) => {
21✔
151
                  const errorPath = getControlPath(error);
2✔
152
                  return errorPath.startsWith(childPath);
2✔
153
                });
154

155
                const validationClassName =
156
                  getStyleAsClassName('array.validation');
21✔
157
                const errorValidationClassName = getStyleAsClassName(
21✔
158
                  'array.validation.error'
159
                );
160
                const errorClassNames = errorsPerEntry
21!
161
                  ? [validationClassName]
162
                      .concat(errorValidationClassName)
163
                      .join(' ')
164
                  : validationClassName;
165

166
                return (
21✔
167
                  <tr key={childPath}>
168
                    {schema.properties ? (
21✔
169
                      fpflow(
170
                        fpkeys,
171
                        fpfilter(
172
                          (prop) => schema.properties[prop].type !== 'array'
38✔
173
                        ),
174
                        fpmap((prop) => {
175
                          const childPropPath = Paths.compose(childPath, prop);
38✔
176
                          return (
38✔
177
                            <td key={childPropPath}>
178
                              <DispatchCell
179
                                schema={Resolve.schema(
180
                                  schema,
181
                                  Paths.compose('#', 'properties', prop),
182
                                  rootSchema
183
                                )}
184
                                uischema={createControlElement(prop)}
185
                                path={childPropPath}
186
                              />
187
                            </td>
188
                          );
189
                        })
190
                      )(schema.properties)
191
                    ) : (
192
                      <td key={Paths.compose(childPath, index)}>
193
                        <DispatchCell
194
                          schema={schema}
195
                          uischema={createControlElement()}
196
                          path={childPath}
197
                        />
198
                      </td>
199
                    )}
200
                    <td>
201
                      {errorsPerEntry ? (
21!
202
                        <span className={errorClassNames}>
203
                          {join(
204
                            errorsPerEntry.map((e) => e.message),
1✔
205
                            ' and '
206
                          )}
207
                        </span>
208
                      ) : (
209
                        <span className={errorClassNames}>OK</span>
210
                      )}
211
                    </td>
212
                    <td>
213
                      <button
214
                        type='button'
215
                        aria-label={translations.removeAriaLabel}
216
                        onClick={() => {
217
                          if (
×
218
                            window.confirm(translations.deleteDialogMessage)
219
                          ) {
220
                            this.confirmDelete(childPath, index);
×
221
                          }
222
                        }}
223
                      >
224
                        {translations.removeTooltip}
225
                      </button>
226
                    </td>
227
                  </tr>
228
                );
229
              })
230
            )}
231
          </tbody>
232
        </table>
233
      </div>
234
    );
235
  }
236
}
7✔
237

238
export default withVanillaControlProps(
7✔
239
  withJsonFormsArrayControlProps(TableArrayControl)
240
);
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc