Skip to content

Commit 178b746

Browse files
mmiaskP0lip
andauthored
feat: display format next to type (#84)
* feat: display format next to type * fix: fixed linting issues * feat: refactored 'Format' moved Format to Validations added formats-schema fixture added unit tests * fix: add empty line * fix: review comments * fix: lint issue * feat: remove 'format' from common validation types refactor Validations component * fix: linting issues * Update src/components/shared/Validations.tsx * feat: refactor 'format' validation * fix: changed attribute name * fix: rever change in getValidations * fix: changed prop nodeSchema to schema Co-authored-by: Jakub Rożek <jakub@stoplight.io>
1 parent 425b67e commit 178b746

File tree

4 files changed

+117
-6
lines changed

4 files changed

+117
-6
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{
2+
"title": "model-with-formats",
3+
"type": "object",
4+
"properties": {
5+
"date-of-birth": {
6+
"type": [
7+
"number",
8+
"string",
9+
"array"
10+
],
11+
"format": "date-time",
12+
"items": {}
13+
},
14+
"name": {
15+
"type": "string"
16+
},
17+
"id": {
18+
"type": "number",
19+
"format": "float"
20+
},
21+
"notype": {
22+
"format": "date-time"
23+
},
24+
"permissions": {
25+
"type": [
26+
"string",
27+
"object"
28+
],
29+
"format": "password",
30+
"properties": {
31+
"ids": {
32+
"type": "array",
33+
"items": {
34+
"type": "integer",
35+
"format": "int32"
36+
}
37+
}
38+
}
39+
}
40+
}
41+
}

src/components/SchemaRow.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { getNodeMetadata, getSchemaNodeMetadata } from '../tree/metadata';
77
import { GoToRefHandler, SchemaKind, SchemaTreeListNode } from '../types';
88
import { getPrimaryType } from '../utils/getPrimaryType';
99
import { hasRefItems, isArrayNodeWithItems, isRefNode } from '../utils/guards';
10-
import { Caret, Description, Divider, Property, Validations } from './shared';
10+
import { Caret, Description, Divider, Format, Property, Validations } from './shared';
1111

1212
export interface ISchemaRow {
1313
className?: string;
@@ -90,6 +90,7 @@ export const SchemaPropertyRow: typeof SchemaRow = ({ node, onGoToRef, rowOption
9090

9191
<div className="flex-1 flex truncate">
9292
<Property node={node} onGoToRef={onGoToRef} />
93+
{metadata.schema.type && typeof metadata.schema.format === 'string' && <Format schema={metadata.schema} />}
9394
{description && <Description value={description} />}
9495
</div>
9596

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,29 @@
1+
import { TreeState } from '@stoplight/tree-list';
12
import { Dictionary } from '@stoplight/types';
23
import { Popover } from '@stoplight/ui-kit';
34
import { shallow } from 'enzyme';
45
import 'jest-enzyme';
6+
import { JSONSchema4 } from 'json-schema';
57
import * as React from 'react';
8+
import { SchemaTree } from '../../tree';
69

710
import { getValidations } from '../../utils/getValidations';
8-
import { Validations } from '../shared/Validations';
11+
import { SchemaPropertyRow, SchemaRow } from '../SchemaRow';
12+
import { Format, Validations } from '../shared/Validations';
913

1014
describe('Validations component', () => {
1115
describe('when property is deprecated', () => {
1216
let validations: Dictionary<unknown>;
1317

1418
beforeEach(() => {
15-
validations = getValidations({ 'x-deprecated': true, type: 'string', format: 'email', minLength: 2 });
19+
validations = getValidations({ 'x-deprecated': true, type: 'string', minLength: 2, default: 'foo' });
1620
});
1721

1822
test('should exclude deprecated from general validations', () => {
1923
const wrapper = shallow(<Validations required={false} validations={validations} />).find(Popover);
2024

25+
expect(shallow(wrapper.prop('content') as React.ReactElement)).toHaveText('default:"foo"minLength:2');
2126
expect(shallow(wrapper.prop('target') as React.ReactElement)).toHaveText('+2');
22-
expect(shallow(wrapper.prop('content') as React.ReactElement)).toHaveText('format:"email"minLength:2');
2327
});
2428

2529
test('should render deprecated box next to popover', () => {
@@ -29,3 +33,49 @@ describe('Validations component', () => {
2933
});
3034
});
3135
});
36+
37+
describe('Format', () => {
38+
let tree: SchemaTree;
39+
40+
beforeEach(() => {
41+
const schema: JSONSchema4 = require('../../__fixtures__/formats-schema.json');
42+
43+
tree = new SchemaTree(schema, new TreeState(), {
44+
expandedDepth: Infinity,
45+
mergeAllOf: false,
46+
resolveRef: void 0,
47+
shouldResolveEagerly: false,
48+
onPopulate: void 0,
49+
});
50+
51+
tree.populate();
52+
});
53+
54+
test('should render next to a single type with and inherit its color', () => {
55+
const wrapper = shallow(<SchemaRow node={tree.itemAt(3)!} rowOptions={{}} />)
56+
.find(SchemaPropertyRow)
57+
.shallow()
58+
.find(Format)
59+
.shallow();
60+
61+
expect(wrapper).toHaveProp('className', 'ml-2 text-red-7 dark:text-red-6');
62+
});
63+
64+
test('should render next to an array of types in default (black) color', () => {
65+
const wrapper = shallow(<SchemaRow node={tree.itemAt(1)!} rowOptions={{}} />)
66+
.find(SchemaPropertyRow)
67+
.shallow()
68+
.find(Format)
69+
.shallow();
70+
71+
expect(wrapper).toHaveProp('className', 'ml-2');
72+
});
73+
74+
test('should not render when the type(s) is/are missing', () => {
75+
const wrapper = shallow(<SchemaRow node={tree.itemAt(4)!} rowOptions={{}} />)
76+
.find(SchemaPropertyRow)
77+
.shallow();
78+
79+
expect(wrapper).not.toContain(Format);
80+
});
81+
});

src/components/shared/Validations.tsx

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,24 @@
11
import { safeStringify } from '@stoplight/json';
22
import { Dictionary } from '@stoplight/types';
33
import { Popover } from '@stoplight/ui-kit';
4+
import { JSONSchema4 } from 'json-schema';
45
import * as React from 'react';
56
import { ViewModeContext } from '../JsonSchemaViewer';
7+
import { PropertyTypeColors } from './Types';
68

79
export interface IValidations {
810
required: boolean;
9-
validations: (Dictionary<unknown> | {}) & { deprecated?: boolean; readOnly?: unknown; writeOnly?: unknown };
11+
validations: (Dictionary<unknown> | {}) & {
12+
deprecated?: boolean;
13+
readOnly?: unknown;
14+
writeOnly?: unknown;
15+
format?: unknown;
16+
};
1017
}
1118

1219
export const Validations: React.FunctionComponent<IValidations> = ({
1320
required,
14-
validations: { deprecated, readOnly, writeOnly, ...validations },
21+
validations: { deprecated, readOnly, writeOnly, format, ...validations },
1522
}) => {
1623
const viewMode = React.useContext(ViewModeContext);
1724
const validationCount = Object.keys(validations).length;
@@ -85,3 +92,15 @@ export const Validations: React.FunctionComponent<IValidations> = ({
8592
</>
8693
);
8794
};
95+
96+
export const Format: React.FunctionComponent<{ schema: JSONSchema4 }> = ({ schema }) => {
97+
return (
98+
<div
99+
{...(typeof schema.type === 'string' && schema.type in PropertyTypeColors
100+
? { className: `ml-2 ${PropertyTypeColors[schema.type as string]}` }
101+
: { className: 'ml-2' })}
102+
>
103+
{`<${schema.format}>`}
104+
</div>
105+
);
106+
};

0 commit comments

Comments
 (0)