@truedat/cx 4.44.2 → 4.44.5

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.
Files changed (29) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/package.json +23 -15
  3. package/src/configurations/components/ConfigurationForm.js +44 -30
  4. package/src/configurations/components/EditConfiguration.js +23 -14
  5. package/src/configurations/components/NewConfiguration.js +10 -9
  6. package/src/configurations/components/__tests__/ConfigurationForm.spec.js +18 -25
  7. package/src/configurations/components/__tests__/EditConfiguration.spec.js +8 -15
  8. package/src/configurations/components/__tests__/NewConfiguration.spec.js +3 -13
  9. package/src/configurations/components/__tests__/__snapshots__/ConfigurationForm.spec.js.snap +111 -78
  10. package/src/configurations/components/__tests__/__snapshots__/EditConfiguration.spec.js.snap +142 -32
  11. package/src/configurations/components/__tests__/__snapshots__/NewConfiguration.spec.js.snap +131 -23
  12. package/src/jobs/components/JobFilters.js +1 -5
  13. package/src/jobs/components/__tests__/Jobs.spec.js +1 -5
  14. package/src/jobs/components/__tests__/JobsTable.spec.js +1 -5
  15. package/src/jobs/components/__tests__/JobsView.spec.js +1 -5
  16. package/src/jobs/components/__tests__/SourceJobs.spec.js +1 -5
  17. package/src/jobs/components/__tests__/__snapshots__/Jobs.spec.js.snap +31 -5
  18. package/src/jobs/components/__tests__/__snapshots__/JobsView.spec.js.snap +31 -1
  19. package/src/jobs/components/__tests__/__snapshots__/SourceJobs.spec.js.snap +31 -5
  20. package/src/sources/api/queries.js +0 -12
  21. package/src/sources/components/SourceForm.js +1 -1
  22. package/src/sources/components/Sources.js +1 -2
  23. package/src/sources/components/__tests__/SourceBreadcrumbs.spec.js +4 -4
  24. package/src/sources/components/__tests__/SourceDetail.spec.js +0 -2
  25. package/src/sources/components/__tests__/SourceForm.spec.js +0 -1
  26. package/src/sources/components/__tests__/SourceHeader.spec.js +1 -5
  27. package/src/sources/components/__tests__/SourceTabs.spec.js +1 -5
  28. package/src/sources/components/__tests__/__snapshots__/SourceBreadcrumbs.spec.js.snap +19 -30
  29. package/src/sources/components/__tests__/__snapshots__/SourceDetail.spec.js.snap +31 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## [4.44.4] 2022-05-19
4
+
5
+ ### Changed
6
+
7
+ - Use `lowerDeburrTrim` function from `@truedat/core`
8
+
3
9
  ## [4.41.4] 2022-04-04
4
10
 
5
11
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@truedat/cx",
3
- "version": "4.44.2",
3
+ "version": "4.44.5",
4
4
  "description": "Truedat Web Connectors",
5
5
  "sideEffects": false,
6
6
  "jsnext:main": "src/index.js",
@@ -22,17 +22,20 @@
22
22
  "eslint:fix": "eslint --fix src/**"
23
23
  },
24
24
  "devDependencies": {
25
- "@babel/cli": "^7.14.8",
26
- "@babel/core": "^7.15.0",
27
- "@babel/plugin-proposal-class-properties": "^7.14.5",
28
- "@babel/plugin-proposal-object-rest-spread": "^7.14.7",
29
- "@babel/plugin-proposal-optional-chaining": "^7.14.5",
25
+ "@babel/cli": "^7.17.10",
26
+ "@babel/core": "^7.18.0",
27
+ "@babel/plugin-proposal-class-properties": "^7.17.12",
28
+ "@babel/plugin-proposal-object-rest-spread": "^7.18.0",
29
+ "@babel/plugin-proposal-optional-chaining": "^7.17.12",
30
30
  "@babel/plugin-syntax-dynamic-import": "^7.8.3",
31
- "@babel/plugin-transform-modules-commonjs": "^7.15.0",
32
- "@babel/preset-env": "^7.15.0",
33
- "@babel/preset-react": "^7.14.5",
34
- "@truedat/test": "4.44.2",
35
- "babel-jest": "^27.0.6",
31
+ "@babel/plugin-transform-modules-commonjs": "^7.18.0",
32
+ "@babel/preset-env": "^7.18.0",
33
+ "@babel/preset-react": "^7.17.12",
34
+ "@testing-library/jest-dom": "^5.16.4",
35
+ "@testing-library/react": "^12.0.0",
36
+ "@testing-library/user-event": "^13.2.1",
37
+ "@truedat/test": "4.44.5",
38
+ "babel-jest": "^28.1.0",
36
39
  "babel-plugin-dynamic-import-node": "^2.3.3",
37
40
  "babel-plugin-lodash": "^3.3.4",
38
41
  "babel-plugin-react-intl": "^5.1.18",
@@ -41,7 +44,8 @@
41
44
  "enzyme-adapter-react-16": "^1.15.6",
42
45
  "enzyme-to-json": "^3.6.2",
43
46
  "identity-obj-proxy": "^3.0.0",
44
- "jest": "^27.0.6",
47
+ "jest": "^28.1.0",
48
+ "jest-environment-jsdom": "^28.1.0",
45
49
  "jest-localstorage-mock": "^2.4.14",
46
50
  "react": "^16.14.0",
47
51
  "react-dom": "^16.14.0",
@@ -50,6 +54,8 @@
50
54
  "semantic-ui-react": "^2.0.3"
51
55
  },
52
56
  "jest": {
57
+ "maxWorkers": "50%",
58
+ "testTimeout": 10000,
53
59
  "moduleDirectories": [
54
60
  "<rootDir>/src",
55
61
  "../../node_modules"
@@ -85,12 +91,14 @@
85
91
  ]
86
92
  },
87
93
  "dependencies": {
88
- "@truedat/core": "4.44.2",
94
+ "@apollo/client": "^3.6.4",
95
+ "@truedat/core": "4.44.5",
89
96
  "lodash": "^4.17.21",
90
97
  "match-sorter": "^6.3.1",
91
98
  "path-to-regexp": "^1.7.0",
92
- "prop-types": "^15.7.2",
99
+ "prop-types": "^15.8.1",
93
100
  "react-intl": "^5.20.10",
101
+ "react-moment": "^1.1.2",
94
102
  "react-redux": "^7.2.4",
95
103
  "react-router-dom": "^5.2.0",
96
104
  "redux": "^4.1.1",
@@ -103,5 +111,5 @@
103
111
  "react-dom": ">= 16.8.6 < 17",
104
112
  "semantic-ui-react": ">= 0.88.2 < 2.1"
105
113
  },
106
- "gitHead": "ca0c5fffcba96736f7a2054f3c37789da8c30a9e"
114
+ "gitHead": "5a339468198c803592b285eddd0dd0c0b0eced93"
107
115
  }
@@ -1,13 +1,13 @@
1
1
  import _ from "lodash/fp";
2
- import React, { useState, useEffect } from "react";
2
+ import React, { useState, useEffect, Suspense } from "react";
3
3
  import PropTypes from "prop-types";
4
- import { useSelector, useDispatch } from "react-redux";
4
+ import { connect } from "react-redux";
5
5
  import { Button, Form, Label } from "semantic-ui-react";
6
6
  import { useIntl, FormattedMessage } from "react-intl";
7
7
  import { HistoryBackButton } from "@truedat/core/components";
8
8
  import {
9
9
  applyTemplate as applyTemplateGenerator,
10
- validateContent
10
+ validateContent,
11
11
  } from "@truedat/df/utils";
12
12
  import { selectTemplate } from "@truedat/df/routines";
13
13
 
@@ -24,16 +24,19 @@ const isNonEmptyString = _.flow(_.trim, _.negate(_.isEmpty));
24
24
  const isValid = _.conforms({
25
25
  external_id: isNonEmptyString,
26
26
  type: isNonEmptyString,
27
- contentErrors: isEmptyArray
27
+ contentErrors: isEmptyArray,
28
28
  });
29
29
 
30
- const ConfigurationForm = ({ configuration, handleSubmit }) => {
31
- const dispatch = useDispatch();
30
+ const ConfigurationForm = ({
31
+ configuration,
32
+ handleSubmit,
33
+ selectTemplate,
34
+ template,
35
+ templates,
36
+ templatesLoading,
37
+ }) => {
32
38
  const [formState, setFormState] = useState(configuration || {});
33
39
  const { formatMessage } = useIntl();
34
- const { template, templates, templatesLoading } = useSelector(
35
- _.pick(["template", "templatesLoading", "templates"])
36
- );
37
40
  const applyTemplate = applyTemplateGenerator(template);
38
41
  const { external_id, type, content } = formState;
39
42
 
@@ -44,11 +47,11 @@ const ConfigurationForm = ({ configuration, handleSubmit }) => {
44
47
  ...formState,
45
48
  type: _.prop("name")(template),
46
49
  content: newContent,
47
- contentErrors: validateContent(template)(content)
50
+ contentErrors: validateContent(template)(content),
48
51
  });
49
52
  }
50
53
  // eslint-disable-next-line react-hooks/exhaustive-deps
51
- }, [_.get("id")(template)]);
54
+ }, [template]);
52
55
 
53
56
  useEffect(() => {
54
57
  const configurationType = _.get("type")(configuration);
@@ -58,34 +61,34 @@ const ConfigurationForm = ({ configuration, handleSubmit }) => {
58
61
  _.get("id")
59
62
  )(templates);
60
63
  if (!_.isNil(currentTemplateId))
61
- dispatch(selectTemplate({ id: currentTemplateId }));
64
+ selectTemplate({ id: currentTemplateId });
62
65
  }
63
66
  // eslint-disable-next-line react-hooks/exhaustive-deps
64
67
  }, [configuration]);
65
68
 
66
- const typeOptions = templates.map(({ name, id }, i) => ({
67
- key: i,
69
+ const typeOptions = _.map(({ name, id }) => ({
70
+ key: id,
68
71
  value: id,
69
- text: name
70
- }));
72
+ text: name,
73
+ }))(templates);
71
74
 
72
75
  const handleExternalIdChange = (e, { value: external_id }) => {
73
76
  e && e.preventDefault();
74
77
  setFormState({ ...formState, external_id });
75
78
  };
76
- const handleContentChange = content => {
79
+ const handleContentChange = (content) => {
77
80
  const contentErrors = validateContent(template)(content);
78
81
  setFormState({ ...formState, content, contentErrors });
79
82
  };
80
83
 
81
84
  const handleTemplateSelected = (e, data) => {
82
85
  const { value } = data;
83
- dispatch(selectTemplate({ id: value }));
86
+ selectTemplate({ id: value });
84
87
  };
85
88
 
86
89
  const isInvalid = () => _.negate(isValid)(formState);
87
90
 
88
- const doHandleSubmit = e => {
91
+ const doHandleSubmit = (e) => {
89
92
  e.preventDefault();
90
93
  const newConfiguration = _.pick(["external_id", "type"])(formState);
91
94
  const appliedContent = _.flow(_.prop("content"), applyTemplate)(formState);
@@ -93,8 +96,8 @@ const ConfigurationForm = ({ configuration, handleSubmit }) => {
93
96
  handleSubmit({
94
97
  configuration: {
95
98
  ...newConfiguration,
96
- content: appliedContent
97
- }
99
+ content: appliedContent,
100
+ },
98
101
  });
99
102
  };
100
103
 
@@ -116,11 +119,11 @@ const ConfigurationForm = ({ configuration, handleSubmit }) => {
116
119
  />
117
120
  </Form.Field>
118
121
  <Form.Field required>
119
- <label>{formatMessage({ id: "type.selector.label" })}</label>
122
+ <label>
123
+ <FormattedMessage id="type.selector.label" />
124
+ </label>
120
125
  <Form.Dropdown
121
- placeholder={formatMessage({
122
- id: "type.selector.placeholder"
123
- })}
126
+ placeholder={formatMessage({ id: "type.selector.placeholder" })}
124
127
  name="type"
125
128
  search
126
129
  selection
@@ -136,12 +139,12 @@ const ConfigurationForm = ({ configuration, handleSubmit }) => {
136
139
  {type && !templatesLoading && (
137
140
  <Form.Field>
138
141
  <label className="label">
139
- {formatMessage({ id: "configuration.content.label" })}
142
+ <FormattedMessage id="configuration.content.label" />
140
143
  </label>
141
- <>
144
+ <Suspense fallback={null}>
142
145
  <TemplateLoader />
143
146
  <DynamicForm onChange={handleContentChange} content={content} />
144
- </>
147
+ </Suspense>
145
148
  </Form.Field>
146
149
  )}
147
150
  <div className="actions">
@@ -163,6 +166,17 @@ const ConfigurationForm = ({ configuration, handleSubmit }) => {
163
166
 
164
167
  ConfigurationForm.propTypes = {
165
168
  configuration: PropTypes.object,
166
- handleSubmit: PropTypes.func
169
+ handleSubmit: PropTypes.func,
170
+ selectTemplate: PropTypes.func,
171
+ template: PropTypes.object,
172
+ templates: PropTypes.array,
173
+ templatesLoading: PropTypes.bool,
167
174
  };
168
- export default ConfigurationForm;
175
+
176
+ export const mapStateToProps = ({ template, templates, templatesLoading }) => ({
177
+ template,
178
+ templates,
179
+ templatesLoading,
180
+ });
181
+
182
+ export default connect(mapStateToProps, { selectTemplate })(ConfigurationForm);
@@ -1,7 +1,6 @@
1
- import _ from "lodash/fp";
2
1
  import React from "react";
3
- import { useDispatch, useSelector } from "react-redux";
4
- import { bindActionCreators } from "redux";
2
+ import PropTypes from "prop-types";
3
+ import { connect } from "react-redux";
5
4
  import { Container, Header, Icon, Segment } from "semantic-ui-react";
6
5
  import { FormattedMessage, useIntl } from "react-intl";
7
6
  import { Loading } from "@truedat/core/components";
@@ -9,17 +8,12 @@ import { updateConfiguration } from "../routines";
9
8
  import ConfigurationBreadcrumbs from "./ConfigurationBreadcrumbs";
10
9
  import ConfigurationForm from "./ConfigurationForm";
11
10
 
12
- export default () => {
13
- const dispatch = useDispatch();
11
+ export const EditConfiguration = ({
12
+ configuration,
13
+ configurationLoading,
14
+ updateConfiguration,
15
+ }) => {
14
16
  const { formatMessage } = useIntl();
15
- const { update } = bindActionCreators(
16
- { update: updateConfiguration },
17
- dispatch
18
- );
19
-
20
- const { configuration, configurationLoading } = useSelector(
21
- _.pick(["configuration", "configurationLoading"])
22
- );
23
17
 
24
18
  return configurationLoading ? (
25
19
  <Loading />
@@ -37,9 +31,24 @@ export default () => {
37
31
  </Header>
38
32
  <ConfigurationForm
39
33
  configuration={configuration}
40
- handleSubmit={update}
34
+ onSubmit={updateConfiguration}
41
35
  />
42
36
  </Container>
43
37
  </>
44
38
  );
45
39
  };
40
+
41
+ EditConfiguration.propTypes = {
42
+ configuration: PropTypes.object,
43
+ configurationLoading: PropTypes.bool,
44
+ updateConfiguration: PropTypes.func,
45
+ };
46
+
47
+ export const mapStateToProps = ({ configurationLoading, configuration }) => ({
48
+ loading: configurationLoading,
49
+ configuration,
50
+ });
51
+
52
+ export default connect(mapStateToProps, { updateConfiguration })(
53
+ EditConfiguration
54
+ );
@@ -1,19 +1,14 @@
1
1
  import React from "react";
2
- import { useDispatch } from "react-redux";
3
- import { bindActionCreators } from "redux";
2
+ import PropTypes from "prop-types";
3
+ import { connect } from "react-redux";
4
4
  import { Container, Header, Icon, Segment } from "semantic-ui-react";
5
5
  import { FormattedMessage, useIntl } from "react-intl";
6
6
  import { createConfiguration } from "../routines";
7
7
  import ConfigurationBreadcrumbs from "./ConfigurationBreadcrumbs";
8
8
  import ConfigurationForm from "./ConfigurationForm";
9
9
 
10
- export default () => {
11
- const dispatch = useDispatch();
10
+ export const NewConfiguration = ({ createConfiguration }) => {
12
11
  const { formatMessage } = useIntl();
13
- const { create } = bindActionCreators(
14
- { create: createConfiguration },
15
- dispatch
16
- );
17
12
 
18
13
  return (
19
14
  <>
@@ -27,8 +22,14 @@ export default () => {
27
22
  <FormattedMessage id="configurations.actions.create" />
28
23
  </Header.Content>
29
24
  </Header>
30
- <ConfigurationForm handleSubmit={create} />
25
+ <ConfigurationForm onSubmit={createConfiguration} />
31
26
  </Container>
32
27
  </>
33
28
  );
34
29
  };
30
+
31
+ NewConfiguration.propTypes = {
32
+ createConfiguration: PropTypes.func,
33
+ };
34
+
35
+ export default connect(null, { createConfiguration })(NewConfiguration);
@@ -1,16 +1,9 @@
1
1
  import React from "react";
2
- import { shallow } from "enzyme";
3
- import { intl } from "@truedat/test/intl-stub";
2
+ import { render } from "@truedat/test/render";
4
3
  import ConfigurationForm from "../ConfigurationForm";
5
4
 
6
- // workaround for enzyme issue with React.useContext
7
- // see https://github.com/airbnb/enzyme/issues/2176#issuecomment-532361526
8
- jest.spyOn(React, "useContext").mockImplementation(() => intl);
9
-
10
- jest.mock("react-redux", () => ({
11
- ...jest.requireActual("react-redux"),
12
- useDispatch: jest.fn(),
13
- useSelector: jest.fn(() => ({
5
+ const renderOpts = {
6
+ state: {
14
7
  templates: [
15
8
  {
16
9
  content: [
@@ -22,37 +15,37 @@ jest.mock("react-redux", () => ({
22
15
  name: "new_field",
23
16
  type: "string",
24
17
  values: null,
25
- widget: "string"
26
- }
18
+ widget: "string",
19
+ },
27
20
  ],
28
21
  is_secret: false,
29
- name: ""
30
- }
22
+ name: "",
23
+ },
31
24
  ],
32
25
  id: 1,
33
26
  label: "test_config",
34
27
  name: "test_config",
35
- scope: "ca"
36
- }
28
+ scope: "ca",
29
+ },
37
30
  ],
38
31
  template: null,
39
- templatesLoading: false
40
- }))
41
- }));
32
+ templatesLoading: false,
33
+ },
34
+ };
42
35
 
43
36
  describe("<ConfigurationForm />", () => {
44
- const handleSubmit = jest.fn();
37
+ const onSubmit = jest.fn();
45
38
  const configuration = {
46
39
  external_id: "ext1",
47
40
  type: "test_config",
48
41
  content: {
49
- new_field: "value"
50
- }
42
+ new_field: "value",
43
+ },
51
44
  };
52
- const props = { handleSubmit, configuration };
45
+ const props = { onSubmit, configuration };
53
46
 
54
47
  it("matches the latest snapshot", () => {
55
- const wrapper = shallow(<ConfigurationForm {...props} />);
56
- expect(wrapper).toMatchSnapshot();
48
+ const { container } = render(<ConfigurationForm {...props} />, renderOpts);
49
+ expect(container).toMatchSnapshot();
57
50
  });
58
51
  });
@@ -1,24 +1,17 @@
1
1
  import React from "react";
2
- import { shallow } from "enzyme";
3
- import { intl } from "@truedat/test/intl-stub";
2
+ import { render } from "@truedat/test/render";
4
3
  import EditConfiguration from "../EditConfiguration";
5
4
 
6
- // workaround for enzyme issue with React.useContext
7
- // see https://github.com/airbnb/enzyme/issues/2176#issuecomment-532361526
8
- jest.spyOn(React, "useContext").mockImplementation(() => intl);
9
-
10
- jest.mock("react-redux", () => ({
11
- ...jest.requireActual("react-redux"),
12
- useDispatch: jest.fn(),
13
- useSelector: jest.fn(() => ({
5
+ const renderOpts = {
6
+ state: {
14
7
  configuration: { id: 1, type: "config", content: { field: "foo" } },
15
- configurationLoading: false
16
- }))
17
- }));
8
+ configurationLoading: false,
9
+ },
10
+ };
18
11
 
19
12
  describe("<EditConfiguration />", () => {
20
13
  it("matches the latest snapshot", () => {
21
- const wrapper = shallow(<EditConfiguration />);
22
- expect(wrapper).toMatchSnapshot();
14
+ const { container } = render(<EditConfiguration />, renderOpts);
15
+ expect(container).toMatchSnapshot();
23
16
  });
24
17
  });
@@ -1,23 +1,13 @@
1
1
  import React from "react";
2
- import { shallow } from "enzyme";
3
- import { intl } from "@truedat/test/intl-stub";
2
+ import { render } from "@truedat/test/render";
4
3
  import NewConfiguration from "../NewConfiguration";
5
4
 
6
- // workaround for enzyme issue with React.useContext
7
- // see https://github.com/airbnb/enzyme/issues/2176#issuecomment-532361526
8
- jest.spyOn(React, "useContext").mockImplementation(() => intl);
9
-
10
- jest.mock("react-redux", () => ({
11
- ...jest.requireActual("react-redux"),
12
- useDispatch: jest.fn()
13
- }));
14
-
15
5
  describe("<NewConfiguration />", () => {
16
6
  const createConfiguration = jest.fn();
17
7
  const props = { createConfiguration };
18
8
 
19
9
  it("matches the latest snapshot", () => {
20
- const wrapper = shallow(<NewConfiguration {...props} />);
21
- expect(wrapper).toMatchSnapshot();
10
+ const { container } = render(<NewConfiguration {...props} />);
11
+ expect(container).toMatchSnapshot();
22
12
  });
23
13
  });
@@ -1,84 +1,117 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
3
  exports[`<ConfigurationForm /> matches the latest snapshot 1`] = `
4
- <Form
5
- as="form"
6
- >
7
- <FormField
8
- required={true}
4
+ <div>
5
+ <form
6
+ class="ui form"
9
7
  >
10
- <label>
11
- configuration.props.external_id
12
- </label>
13
- <FormInput
14
- as={[Function]}
15
- control={[Function]}
16
- disabled={true}
17
- onChange={[Function]}
18
- value="ext1"
19
- />
20
- </FormField>
21
- <FormField
22
- required={true}
23
- >
24
- <label>
25
- type.selector.label
26
- </label>
27
- <FormDropdown
28
- as={[Function]}
29
- control={[Function]}
30
- disabled={true}
31
- loading={false}
32
- name="type"
33
- onChange={[Function]}
34
- options={
35
- Array [
36
- Object {
37
- "key": 0,
38
- "text": "test_config",
39
- "value": 1,
40
- },
41
- ]
42
- }
43
- placeholder="type.selector.placeholder"
44
- required={true}
45
- search={true}
46
- selection={true}
47
- />
48
- </FormField>
49
- <FormField>
50
- <label
51
- className="label"
8
+ <div
9
+ class="required field"
52
10
  >
53
- configuration.content.label
54
- </label>
55
- <lazy />
56
- <lazy
57
- content={
58
- Object {
59
- "new_field": "value",
60
- }
61
- }
62
- onChange={[Function]}
63
- />
64
- </FormField>
65
- <div
66
- className="actions"
67
- >
68
- <HistoryBackButton
69
- content="actions.cancel"
70
- />
71
- <Button
72
- as="button"
73
- content={
74
- <Memo(MemoizedFormattedMessage)
75
- id="actions.save"
76
- />
77
- }
78
- disabled={true}
79
- onClick={[Function]}
80
- primary={true}
81
- />
82
- </div>
83
- </Form>
11
+ <label>
12
+ Id Externo
13
+ </label>
14
+ <div
15
+ class="disabled field"
16
+ >
17
+ <div
18
+ class="ui disabled input"
19
+ >
20
+ <input
21
+ disabled=""
22
+ tabindex="-1"
23
+ type="text"
24
+ value="ext1"
25
+ />
26
+ </div>
27
+ </div>
28
+ </div>
29
+ <div
30
+ class="required field"
31
+ >
32
+ <label>
33
+ Type
34
+ </label>
35
+ <div
36
+ class="disabled required field"
37
+ >
38
+ <div
39
+ aria-busy="false"
40
+ aria-disabled="true"
41
+ aria-expanded="false"
42
+ class="ui disabled search selection dropdown"
43
+ name="type"
44
+ required=""
45
+ role="combobox"
46
+ >
47
+ <input
48
+ aria-autocomplete="list"
49
+ autocomplete="off"
50
+ class="search"
51
+ tabindex="-1"
52
+ type="text"
53
+ value=""
54
+ />
55
+ <div
56
+ aria-atomic="true"
57
+ aria-live="polite"
58
+ class="divider default text"
59
+ role="alert"
60
+ >
61
+ Source type (template)
62
+ </div>
63
+ <i
64
+ aria-hidden="true"
65
+ class="dropdown icon"
66
+ />
67
+ <div
68
+ class="menu transition"
69
+ role="listbox"
70
+ >
71
+ <div
72
+ aria-checked="false"
73
+ aria-selected="true"
74
+ class="selected item"
75
+ role="option"
76
+ style="pointer-events: all;"
77
+ >
78
+ <span
79
+ class="text"
80
+ >
81
+ test_config
82
+ </span>
83
+ </div>
84
+ </div>
85
+ </div>
86
+ </div>
87
+ </div>
88
+ <div
89
+ class="field"
90
+ >
91
+ <label
92
+ class="label"
93
+ >
94
+ Content
95
+ </label>
96
+ </div>
97
+ <div
98
+ class="actions"
99
+ >
100
+ <a
101
+ class="ui secondary button"
102
+ href="/"
103
+ role="button"
104
+ >
105
+ Cancel
106
+ </a>
107
+ <button
108
+ class="ui primary disabled button"
109
+ disabled=""
110
+ tabindex="-1"
111
+ >
112
+ Save
113
+ </button>
114
+ </div>
115
+ </form>
116
+ </div>
84
117
  `;