@gitlab/ui 74.5.0 → 74.6.0
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/CHANGELOG.md +7 -0
- package/dist/components/base/form/form_fields/form_fields.js +11 -1
- package/dist/tokens/css/tokens.css +1 -1
- package/dist/tokens/css/tokens.dark.css +1 -1
- package/dist/tokens/js/tokens.dark.js +1 -1
- package/dist/tokens/js/tokens.js +1 -1
- package/dist/tokens/scss/_tokens.dark.scss +1 -1
- package/dist/tokens/scss/_tokens.scss +1 -1
- package/dist/utils/play_utils.js +1 -1
- package/package.json +15 -17
- package/src/components/base/filtered_search/filtered_search.stories.js +1 -2
- package/src/components/base/filtered_search/filtered_search_suggestion_list.stories.js +1 -1
- package/src/components/base/form/form_combobox/form_combobox.stories.js +1 -2
- package/src/components/base/form/form_fields/form_fields.spec.js +16 -0
- package/src/components/base/form/form_fields/form_fields.stories.js +26 -3
- package/src/components/base/form/form_fields/form_fields.vue +12 -1
- package/src/components/base/sorting/sorting.stories.js +1 -2
- package/src/components/base/toast/toast.stories.js +1 -2
- package/src/components/base/token_selector/token_selector.stories.js +1 -2
- package/src/components/base/tooltip/tooltip.stories.js +1 -2
- package/src/utils/play_utils.js +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
# [74.6.0](https://gitlab.com/gitlab-org/gitlab-ui/compare/v74.5.0...v74.6.0) (2024-02-14)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* **GlFormFields:** Add prop for server field validations ([6c23b37](https://gitlab.com/gitlab-org/gitlab-ui/commit/6c23b37773d0944953d9068de2bcec00a0e74a8f))
|
|
7
|
+
|
|
1
8
|
# [74.5.0](https://gitlab.com/gitlab-org/gitlab-ui/compare/v74.4.0...v74.5.0) (2024-02-12)
|
|
2
9
|
|
|
3
10
|
|
|
@@ -50,6 +50,16 @@ var script = {
|
|
|
50
50
|
formId: {
|
|
51
51
|
type: String,
|
|
52
52
|
required: true
|
|
53
|
+
},
|
|
54
|
+
/**
|
|
55
|
+
* Validation errors from the server. Generally passed to the component after making an API call.
|
|
56
|
+
*/
|
|
57
|
+
serverValidations: {
|
|
58
|
+
type: Object,
|
|
59
|
+
required: false,
|
|
60
|
+
default() {
|
|
61
|
+
return {};
|
|
62
|
+
}
|
|
53
63
|
}
|
|
54
64
|
},
|
|
55
65
|
data() {
|
|
@@ -64,7 +74,7 @@ var script = {
|
|
|
64
74
|
},
|
|
65
75
|
fieldValidationProps() {
|
|
66
76
|
return mapValues(this.fields, (_, fieldName) => {
|
|
67
|
-
const invalidFeedback = this.fieldValidations[fieldName] || '';
|
|
77
|
+
const invalidFeedback = this.serverValidations[fieldName] || this.fieldValidations[fieldName] || '';
|
|
68
78
|
return {
|
|
69
79
|
invalidFeedback,
|
|
70
80
|
state: invalidFeedback ? false : null
|
package/dist/tokens/js/tokens.js
CHANGED
package/dist/utils/play_utils.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gitlab/ui",
|
|
3
|
-
"version": "74.
|
|
3
|
+
"version": "74.6.0",
|
|
4
4
|
"description": "GitLab UI Components",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"markdownlint": "markdownlint '**/*.md' --ignore node_modules --ignore CHANGELOG.md",
|
|
62
62
|
"markdownlint:fix": "yarn markdownlint --fix",
|
|
63
63
|
"lint": "run-p prettier eslint stylelint markdownlint",
|
|
64
|
-
"lint:fix": "run-s
|
|
64
|
+
"lint:fix": "run-s eslint:fix prettier:fix stylelint:fix markdownlint:fix",
|
|
65
65
|
"generate:component": "plop",
|
|
66
66
|
"translations:collect": "make translations.json",
|
|
67
67
|
"tailwind-config-viewer": "tailwind-config-viewer -o"
|
|
@@ -106,21 +106,19 @@
|
|
|
106
106
|
"@rollup/plugin-commonjs": "^11.1.0",
|
|
107
107
|
"@rollup/plugin-node-resolve": "^7.1.3",
|
|
108
108
|
"@rollup/plugin-replace": "^2.3.2",
|
|
109
|
-
"@storybook/addon-a11y": "7.6.
|
|
110
|
-
"@storybook/addon-docs": "7.6.
|
|
111
|
-
"@storybook/addon-essentials": "7.6.
|
|
112
|
-
"@storybook/addon-interactions": "7.6.
|
|
113
|
-
"@storybook/addon-viewport": "7.6.
|
|
114
|
-
"@storybook/builder-webpack5": "7.6.
|
|
115
|
-
"@storybook/
|
|
109
|
+
"@storybook/addon-a11y": "7.6.14",
|
|
110
|
+
"@storybook/addon-docs": "7.6.14",
|
|
111
|
+
"@storybook/addon-essentials": "7.6.14",
|
|
112
|
+
"@storybook/addon-interactions": "7.6.14",
|
|
113
|
+
"@storybook/addon-viewport": "7.6.14",
|
|
114
|
+
"@storybook/builder-webpack5": "7.6.14",
|
|
115
|
+
"@storybook/test": "7.6.14",
|
|
116
116
|
"@storybook/test-runner": "0.16.0",
|
|
117
|
-
"@storybook/
|
|
118
|
-
"@storybook/
|
|
119
|
-
"@storybook/vue": "7.6.
|
|
120
|
-
"@storybook/
|
|
121
|
-
"@storybook/vue3": "7.6.
|
|
122
|
-
"@storybook/vue3-webpack5": "7.6.13",
|
|
123
|
-
"@types/jest": "^29.5.11",
|
|
117
|
+
"@storybook/theming": "7.6.14",
|
|
118
|
+
"@storybook/vue": "7.6.14",
|
|
119
|
+
"@storybook/vue-webpack5": "7.6.14",
|
|
120
|
+
"@storybook/vue3": "7.6.14",
|
|
121
|
+
"@storybook/vue3-webpack5": "7.6.14",
|
|
124
122
|
"@types/jest-image-snapshot": "^6.4.0",
|
|
125
123
|
"@vue/compat": "^3.2.40",
|
|
126
124
|
"@vue/compiler-sfc": "^3.2.40",
|
|
@@ -172,7 +170,7 @@
|
|
|
172
170
|
"sass-loader": "^10.2.0",
|
|
173
171
|
"sass-true": "^6.1.0",
|
|
174
172
|
"start-server-and-test": "^1.10.6",
|
|
175
|
-
"storybook": "7.6.
|
|
173
|
+
"storybook": "7.6.14",
|
|
176
174
|
"storybook-dark-mode": "3.0.3",
|
|
177
175
|
"style-dictionary": "^3.8.0",
|
|
178
176
|
"stylelint": "15.10.2",
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import last from 'lodash/last';
|
|
2
|
-
import { userEvent, within, waitFor } from '@storybook/
|
|
3
|
-
import { expect } from '@storybook/jest';
|
|
2
|
+
import { userEvent, within, waitFor, expect } from '@storybook/test';
|
|
4
3
|
import GlLoadingIcon from '../loading_icon/loading_icon.vue';
|
|
5
4
|
import GlIcon from '../icon/icon.vue';
|
|
6
5
|
import GlToken from '../token/token.vue';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { userEvent, within } from '@storybook/
|
|
1
|
+
import { userEvent, within } from '@storybook/test';
|
|
2
2
|
import GlFilteredSearchSuggestionList from './filtered_search_suggestion_list.vue';
|
|
3
3
|
import GlFilteredSearchSuggestion from './filtered_search_suggestion.vue';
|
|
4
4
|
import { provide } from './common_story_options';
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { userEvent, within, waitFor } from '@storybook/
|
|
2
|
-
import { expect } from '@storybook/jest';
|
|
1
|
+
import { userEvent, within, waitFor, expect } from '@storybook/test';
|
|
3
2
|
import { makeContainer } from '../../../../utils/story_decorators/container';
|
|
4
3
|
import { stringTokenList, labelText, objectTokenList, actionsList } from './constants';
|
|
5
4
|
import readme from './form_combobox.md';
|
|
@@ -345,6 +345,22 @@ describe('GlFormFields', () => {
|
|
|
345
345
|
});
|
|
346
346
|
}
|
|
347
347
|
);
|
|
348
|
+
|
|
349
|
+
describe('when there is a server validation message', () => {
|
|
350
|
+
beforeEach(async () => {
|
|
351
|
+
await submitForm();
|
|
352
|
+
|
|
353
|
+
wrapper.setProps({
|
|
354
|
+
serverValidations: { username: 'Username has already been taken.' },
|
|
355
|
+
});
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
it('renders error message', () => {
|
|
359
|
+
expect(
|
|
360
|
+
findFormGroupFromLabel(TEST_FIELDS.username.label).attributes('invalid-feedback')
|
|
361
|
+
).toBe('Username has already been taken.');
|
|
362
|
+
});
|
|
363
|
+
});
|
|
348
364
|
});
|
|
349
365
|
|
|
350
366
|
describe('with scoped slot', () => {
|
|
@@ -3,6 +3,7 @@ import omit from 'lodash/omit';
|
|
|
3
3
|
import GlModal from '../../modal/modal.vue';
|
|
4
4
|
import GlButton from '../../button/button.vue';
|
|
5
5
|
import GlListbox from '../../new_dropdowns/listbox/listbox.vue';
|
|
6
|
+
import { setStoryTimeout } from '../../../../utils/test_utils';
|
|
6
7
|
import GlFormFields from './form_fields.vue';
|
|
7
8
|
import readme from './form_fields.md';
|
|
8
9
|
import { required } from './validators';
|
|
@@ -49,6 +50,8 @@ const Template = () => ({
|
|
|
49
50
|
},
|
|
50
51
|
formValues: {},
|
|
51
52
|
testFormId: uniqueId('form_fields_story_'),
|
|
53
|
+
serverValidations: {},
|
|
54
|
+
loading: false,
|
|
52
55
|
};
|
|
53
56
|
},
|
|
54
57
|
computed: {
|
|
@@ -61,7 +64,27 @@ const Template = () => ({
|
|
|
61
64
|
},
|
|
62
65
|
},
|
|
63
66
|
methods: {
|
|
64
|
-
|
|
67
|
+
onInputField({ name }) {
|
|
68
|
+
this.$delete(this.serverValidations, name);
|
|
69
|
+
},
|
|
70
|
+
async onSubmit() {
|
|
71
|
+
this.loading = true;
|
|
72
|
+
|
|
73
|
+
// Simulate waiting for API request to resolve
|
|
74
|
+
await new Promise((resolve) => {
|
|
75
|
+
setStoryTimeout(resolve, 1000);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
this.loading = false;
|
|
79
|
+
|
|
80
|
+
// Manually checking field and validating for this example.
|
|
81
|
+
// In practice this error message would come from the API response.
|
|
82
|
+
if (this.formValues.USERNAME === 'FOO') {
|
|
83
|
+
this.$set(this.serverValidations, 'USERNAME', 'Username has already been taken.');
|
|
84
|
+
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
65
88
|
this.$refs.modal.show();
|
|
66
89
|
},
|
|
67
90
|
},
|
|
@@ -69,7 +92,7 @@ const Template = () => ({
|
|
|
69
92
|
<div>
|
|
70
93
|
<h3>Fields</h3>
|
|
71
94
|
<form :id="testFormId" @submit.prevent>
|
|
72
|
-
<gl-form-fields :fields="fields" v-model="formValues" :form-id="testFormId" @submit="onSubmit">
|
|
95
|
+
<gl-form-fields :fields="fields" v-model="formValues" :form-id="testFormId" :server-validations="serverValidations" @input-field="onInputField" @submit="onSubmit">
|
|
73
96
|
<template #input(custom)="{ id, value, input, blur }">
|
|
74
97
|
<button :id="id" @click="input(value + 1)" @blur="blur" type="button">{{value}}</button>
|
|
75
98
|
</template>
|
|
@@ -77,7 +100,7 @@ const Template = () => ({
|
|
|
77
100
|
<gl-listbox :id="id" :items="$options.ITEMS" :selected="value" @select="input" @hidden="blur" />
|
|
78
101
|
</template>
|
|
79
102
|
</gl-form-fields>
|
|
80
|
-
<gl-button type="submit" category="primary">Submit</gl-button>
|
|
103
|
+
<gl-button type="submit" category="primary" :loading="loading">Submit</gl-button>
|
|
81
104
|
</form>
|
|
82
105
|
<gl-modal ref="modal" modal-id="submission-modal" title="Form submission"><pre>{{ valuesJSON }}</pre></gl-modal>
|
|
83
106
|
</div>
|
|
@@ -51,6 +51,16 @@ export default {
|
|
|
51
51
|
type: String,
|
|
52
52
|
required: true,
|
|
53
53
|
},
|
|
54
|
+
/**
|
|
55
|
+
* Validation errors from the server. Generally passed to the component after making an API call.
|
|
56
|
+
*/
|
|
57
|
+
serverValidations: {
|
|
58
|
+
type: Object,
|
|
59
|
+
required: false,
|
|
60
|
+
default() {
|
|
61
|
+
return {};
|
|
62
|
+
},
|
|
63
|
+
},
|
|
54
64
|
},
|
|
55
65
|
data() {
|
|
56
66
|
return {
|
|
@@ -64,7 +74,8 @@ export default {
|
|
|
64
74
|
},
|
|
65
75
|
fieldValidationProps() {
|
|
66
76
|
return mapValues(this.fields, (_, fieldName) => {
|
|
67
|
-
const invalidFeedback =
|
|
77
|
+
const invalidFeedback =
|
|
78
|
+
this.serverValidations[fieldName] || this.fieldValidations[fieldName] || '';
|
|
68
79
|
|
|
69
80
|
return {
|
|
70
81
|
invalidFeedback,
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { userEvent, within, waitFor } from '@storybook/
|
|
2
|
-
import { expect } from '@storybook/jest';
|
|
1
|
+
import { userEvent, within, waitFor, expect } from '@storybook/test';
|
|
3
2
|
import { makeContainer } from '../../../utils/story_decorators/container';
|
|
4
3
|
import GlSorting from './sorting.vue';
|
|
5
4
|
import readme from './sorting.md';
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { userEvent, within, waitFor } from '@storybook/
|
|
2
|
-
import { expect } from '@storybook/jest';
|
|
1
|
+
import { userEvent, within, waitFor, expect } from '@storybook/test';
|
|
3
2
|
import Vue from 'vue';
|
|
4
3
|
import GlButton from '../button/button.vue';
|
|
5
4
|
import GlToast from './toast';
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { userEvent, within, waitFor } from '@storybook/
|
|
2
|
-
import { expect } from '@storybook/jest';
|
|
1
|
+
import { userEvent, within, waitFor, expect } from '@storybook/test';
|
|
3
2
|
import readme from './token_selector.md';
|
|
4
3
|
import GlTokenSelector from './token_selector.vue';
|
|
5
4
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { userEvent, within, waitFor } from '@storybook/
|
|
2
|
-
import { expect } from '@storybook/jest';
|
|
1
|
+
import { userEvent, within, waitFor, expect } from '@storybook/test';
|
|
3
2
|
import { GlTooltipDirective } from '../../../directives/tooltip';
|
|
4
3
|
import GlButton from '../button/button.vue';
|
|
5
4
|
import GlTooltip from './tooltip.vue';
|
package/src/utils/play_utils.js
CHANGED