Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/add insee multiselect and licence groups #347

Merged
merged 37 commits into from
Apr 10, 2024
Merged
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
6152fe7
feat: :sparkles: Add Insee codes to publishingform spatial coverage
Jorek57 Jan 24, 2024
87de072
add optgroups to Multiselect
Jorek57 Jan 30, 2024
9a89d86
feat: :sparkles: groups working with description and code
Jorek57 Jan 30, 2024
99c7a18
refactor: :art: improve code readability
Jorek57 Jan 31, 2024
d3d94e3
Revert "refactor: :art: improve code readability"
Jorek57 Jan 31, 2024
826e7e9
fix: revert error commit
Jorek57 Jan 31, 2024
c7029aa
fix: revert error commit
Jorek57 Jan 31, 2024
4c1f5e6
fix: correct minor syntax error
Jorek57 Jan 31, 2024
27443e8
fix: remove console.log
Jorek57 Jan 31, 2024
bcddd82
Merge branch 'master' into feat/add-insee-multiselect
Jorek57 Feb 2, 2024
dee9b95
refac: improve code organization
Jorek57 Feb 2, 2024
85ec3c8
refactor: :art: add types + pass spatialGranularities as a initialOpt…
Jorek57 Feb 5, 2024
3c7c0d1
fix: remove commented code and syntax changes
Jorek57 Feb 19, 2024
048483d
fix: put spatial granularities api call in an api file
Jorek57 Feb 26, 2024
8783f1d
fix: edit syntax
Jorek57 Feb 27, 2024
187251e
fix: corrected previous emrge error
Jorek57 Feb 27, 2024
6e81144
fix: various types fixes
Jorek57 Feb 27, 2024
3234817
fix: edit wrong types + fix granularities call
Jorek57 Feb 27, 2024
bd26e91
Merge branch 'fix/correct-multiselect' into feat/add-insee-multiselect
Jorek57 Feb 27, 2024
0aa2571
fix: remove double placeholder in Multiselect
Jorek57 Feb 27, 2024
10b9bb8
fix: remove duplicate types
Jorek57 Feb 29, 2024
a6954fa
fix: add LocalizedUrl to spatial granularities
Jorek57 Feb 29, 2024
b1a54a4
fix: make description in multiselect optionnal + fix granularitiesUrl
Jorek57 Feb 29, 2024
c3b5c0d
fix: remove console.log
Jorek57 Mar 6, 2024
d0badef
fix: handle LICENSE_GROUPS not defined + correct wrong type in Multis…
Jorek57 Mar 21, 2024
4aaeb8c
fix: another type corrected in Multiselect
Jorek57 Mar 21, 2024
3347537
feat: :lipstick: update optgroup style in Multiselect to match design
Jorek57 Mar 26, 2024
182580b
docs: :memo: add changelog
Jorek57 Mar 26, 2024
7a1cc08
Merge branch 'master' into feat/add-insee-multiselect
Jorek57 Apr 2, 2024
5431e23
fix: fix conflicts
Jorek57 Apr 2, 2024
1939da4
refactor: :art: various types of syntax corrections
Jorek57 Apr 3, 2024
f37a1f0
fix: display description in Spatial coverage
Jorek57 Apr 4, 2024
084c9a8
style: :art: fix indentation in types.ts
Jorek57 Apr 8, 2024
b4ff3c0
Merge branch 'master' into feat/add-insee-multiselect
Jorek57 Apr 8, 2024
fdfd237
fix: :lipstick: edit multiselect css to match design expectations
Jorek57 Apr 8, 2024
ad48f10
fix multiselect line-heights and align
Jorek57 Apr 8, 2024
04ba1d0
fix: correct line-heights in multiselect
Jorek57 Apr 8, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,4 @@ cypress/screenshots
.lighthouseci/*.html
maudetes marked this conversation as resolved.
Show resolved Hide resolved

storybook-static/
venv/pyvenv.cfg
1 change: 1 addition & 0 deletions .storybook/preview-head.html
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,4 @@

<meta name="tags-config" content="%7B%22MAX_LENGTH%22%3A%2096%2C%20%22MIN_LENGTH%22%3A%203%7D" />
<meta name="read-only-enabled" content="false">
<meta name="license-groups-options" content="%5B%5B%22Autorit%5Cu00e9s%20administratives%22%2C%20%5B%7B%22value%22%3A%20%22lov2%22%2C%20%22recommended%22%3A%20true%2C%20%22description%22%3A%20%22Recommand%C3%A9e%22%2C%20%22code%22%3A%20%22etalab-2.0%22%7D%2C%20%7B%22value%22%3A%20%22odc-odbl%22%2C%20%22description%22%3A%20%22License%20avec%20obligation%20de%20partage%20%C3%A0%20l%E2%80%99identique%22%2C%20%22code%22%3A%20%22ODbL-1.0%22%7D%2C%20%7B%22value%22%3A%20%22notspecified%22%2C%20%22description%22%3A%20%22Le%20Code%20des%20relations%20entre%20le%20public%20et%20l%E2%80%99administration%20ne%20s%E2%80%99applique%20pas%22%7D%5D%5D%2C%20%5B%22Tous%20producteurs%22%2C%20%5B%7B%22value%22%3A%20%22lov2%22%2C%20%22recommended%22%3A%20true%2C%20%22description%22%3A%20%22Recommand%C3%A9e%22%7D%2C%20%7B%22value%22%3A%20%22cc-by%22%2C%20%22code%22%3A%20%22Apache-2.0%22%7D%2C%20%7B%22value%22%3A%20%22cc-by-sa%22%2C%20%22code%22%3A%20%22CECILL-2.1%22%7D%2C%20%7B%22value%22%3A%20%22cc-zero%22%2C%20%22code%22%3A%20%22Apache-2.0%22%7D%2C%20%7B%22value%22%3A%20%22fr-lo%22%2C%20%22code%22%3A%20%22Apache-2.0%22%7D%2C%20%7B%22value%22%3A%20%22odc-by%22%2C%20%22code%22%3A%20%22Apache-2.0%22%7D%2C%20%7B%22value%22%3A%20%22odc-odbl%22%2C%20%22code%22%3A%20%22Apache-2.0%22%7D%2C%20%7B%22value%22%3A%20%22odc-pdbl%22%2C%20%22code%22%3A%20%22Apache-2.0%22%7D%2C%20%7B%22value%22%3A%20%22other-at%22%7D%2C%20%7B%22value%22%3A%20%22other-open%22%7D%2C%20%7B%22value%22%3A%20%22other-pd%22%7D%2C%20%7B%22value%22%3A%20%22notspecified%22%7D%5D%5D%5D">
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
- Move Well to datagouv-components [#382](https://github.com/etalab/udata-front/pull/382)
- Add markdown editor [#351](https://github.com/etalab/udata-front/pull/351)
- Upgrade vue dependency [#386](https://github.com/etalab/udata-front/pull/386)
- Add codes and optgroups in Multiselect to display Insee codes and Licence groups [#347] (https://github.com/etalab/udata-front/pull/347)

## 3.5.4 (2024-03-20)

Expand Down
7 changes: 7 additions & 0 deletions udata_front/theme/gouvfr/assets/js/api/datasets.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,10 @@ export function publishDataset(dataset) {
export function getFrequenciesUrl () {
return getLocalizedUrl("datasets/frequencies/");
}

/**
* @returns {Promise<Array<import("../types").SpatialGranularity>>}
*/
export function getSpatialGranularities () {
return api.get(getLocalizedUrl("spatial/granularities/")).then(resp => resp.data);
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,28 @@ const args = {
values: null,
};

const argsWithExtraDatas = {
placeholder: "Complex select with extra datas",
searchPlaceholder: "Type to search",
emptyPlaceholder: "Select an option",
allOption: "Select something",
initialOptions: Promise.resolve([
{
label: "Option 1",
value: "Option 1",
helper: "Insee: 53350",
nicolaskempf57 marked this conversation as resolved.
Show resolved Hide resolved
description: "French region"
},
{
label: "Option 2",
value: "Option 2",
helper: "Insee: 12005",
description: "French department"
},
]),
values: null,
};

export const SimpleMultiSelect = {
render: (args) => ({
components: { MultiSelect },
Expand Down Expand Up @@ -125,3 +147,16 @@ export const MultipleMultiSelect = {
addAllOption: false,
},
};

export const SimpleMultiSelectWithHelperAndDescription = {
render: (args) => ({
components: { MultiSelect },
setup() {
return { args };
},
template: '<MultiSelect v-bind="args"/>',
}),
args: {
...argsWithExtraDatas,
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
<div class="multiselect w-100 fr-select-group" :class="selectGroupClass" ref="container" :data-selected="!!selected">
<div>
<label :for="id" :title="explanation">
{{placeholder}}
<Required :required="required"/>
{{ placeholder }}
<Required :required="required" />
<span v-if="explanation" class="fr-icon-information-line" aria-hidden="true"></span>
<span class="fr-hint-text" v-if="hintText">{{ hintText }}</span>
</label>
Expand All @@ -15,15 +15,52 @@
:required="required"
:multiple="multiple"
>
<option
v-for="option in displayedOptions"
:key="option.value"
:value="option.value"
:data-image="option.image"
:hidden="option.hidden"
>
{{option.label}}
</option>
<template v-if="groups">
Jorek57 marked this conversation as resolved.
Show resolved Hide resolved
<template v-for="group in groups">
<optgroup :label="group.name">
maudetes marked this conversation as resolved.
Show resolved Hide resolved
<template v-for="option in displayedOptions" :key="option.value">
<option
v-if="group.name == option.group"
:value="option.value"
:data-image="option.image"
:hidden="option.hidden"
:data-helper="option.helper"
:data-description="option.description"
:data-show-icon="option.recommended"
>
{{ option.label }}
</option>
</template>
</optgroup>
</template>
<template v-for="option in displayedOptions" :key="option.value">
<option
v-if="!option.group"
:value="option.value"
:data-image="option.image"
:hidden="option.hidden"
:data-helper="option.helper"
:data-description="option.description"
:data-show-icon="option.recommended"
>
{{ option.label }}
</option>
</template>
</template>
<template v-else>
<option
v-for="option in displayedOptions"
:key="option.value"
:value="option.value"
:data-image="option.image"
:hidden="option.hidden"
:data-helper="option.helper"
:data-description="option.description"
:data-show-icon="option.recommended"
>
{{ option.label }}
</option>
</template>
</select>
</div>
<p :id="validTextId" class="fr-valid-text" v-if="isValid">
Expand Down Expand Up @@ -127,6 +164,23 @@ export default defineComponent({
addNewOption: {
type: Boolean,
default: false,
},
helperLabel: {
type: String,
default: '',
},
groups: {
nicolaskempf57 marked this conversation as resolved.
Show resolved Hide resolved
/** @type {import("vue").PropType<Array<{name: string, values: Array<{code: string, description: string, recommended: boolean, value: string}>}>>} */
type: Array,
default: null
},
onSuggest: {
type: Function,
default: null
},
showDescription: {
type: Boolean,
default: false
}
},
setup(props, { emit }) {
Expand Down Expand Up @@ -181,7 +235,7 @@ export default defineComponent({
* Current options
* @type {import("vue").Ref<Array<import("../../types").MultiSelectOption>>}
*/
const options = ref([]);
const options = ref([]);

/**
* Displayed Options limited to {@link maxOptionsCount}
Expand Down Expand Up @@ -233,15 +287,42 @@ export default defineComponent({
if (!props.listUrl) return options.value;

/**
* @type {import("axios").AxiosResponse<{data: Array}|Array>}
* @typedef {object} Data
* @property {string} id
* @property {String} title
*/
return api.get(props.listUrl)

/**
* @type {Promise<import("axios").AxiosResponse<Array<Data> | {data: Array<Data> }>>}
*/
const request = api.get(props.listUrl)
return request
.then(resp => {
let data = resp.data;
if(!Array.isArray(data)) {
data = data.data;
}
return mapToOption(data);
if (props.groups) {
const groupData = data.map(option => {
Jorek57 marked this conversation as resolved.
Show resolved Hide resolved
const matchingGroup = props.groups.find(group => group.values.some(groupValue => groupValue.value === option.id))
if (matchingGroup) {
const matchingGroupValue = matchingGroup.values.find(groupValue => groupValue.value === option.id);
if (matchingGroupValue) {
return {
...option,
group: matchingGroup.name,
description: matchingGroupValue.description || null,
recommended: matchingGroupValue.recommended,
code: matchingGroupValue.code
};
}
}
return option;
});
return mapToOption(groupData);
} else {
return mapToOption(data);
}
}).catch((error) => {
if (!axios.isCancel(error)) {
toast.error(t("Error getting {type}.", {type: props.placeholder}));
Expand All @@ -255,18 +336,19 @@ export default defineComponent({
* @param {Array} data
* @returns {Array<import("../../types").MultiSelectOption>}
**/
const mapToOption = (data) => data.map((obj) => ({
label: obj.name ?? obj.title ?? obj.text ?? obj?.properties?.name ?? obj.label ?? obj,
value: obj.id ?? obj.text ?? obj.value ?? obj,
image: obj.logo_thumbnail ?? obj.logo ?? obj.image_url ?? obj.image,
hidden: obj.hidden,
selected: !!obj.selected,
}));

/**
* @typedef Suggestion
* @property {string} text
*/
const mapToOption = (data) => data.map((obj) => {
return {
label: obj.name ?? obj.title ?? obj.text ?? obj?.properties?.name ?? obj.label ?? obj,
value: obj.id ?? obj.text ?? obj.value ?? obj,
image: obj.logo_thumbnail ?? obj.logo ?? obj.image_url ?? obj.image,
hidden: obj.hidden,
selected: !!obj.selected,
helper: obj?.code ? props.helperLabel + obj.code : obj?.helper,
description: props.showDescription ? (obj?.description ?? '') : '',
group: obj?.group,
recommended: obj?.recommended
};
});

/**
* Get options from suggest API
Expand All @@ -286,24 +368,26 @@ export default defineComponent({
currentRequest.value = generateCancelToken();
return api
.get(props.suggestUrl, {
params: { q, size: maxOptionsCount },
cancelToken: currentRequest.value.token,
params: { q, size: maxOptionsCount },
cancelToken: currentRequest.value.token,
})
.then((resp) => {
/** @type {Array<Suggestion>} */
const suggestions = resp.data;
return props.onSuggest ? props.onSuggest(resp.data) : resp.data;
})
.then((suggestions) => {
const addQToSuggestion = props.addNewOption && !suggestions.some(suggestion => suggestion.text === q);
if(addQToSuggestion) {
suggestions.push({text: q});
if (addQToSuggestion) {
suggestions.push({ text: q });
}
return mapToOption(suggestions);
})
.catch((error) => {
if (!axios.isCancel(error)) {
toast.error(t("Error getting {type}.", {type: props.placeholder}));
toast.error(t("Error getting {type}.", { type: props.placeholder }));
}
return /** @type {Array<import("../../types").MultiSelectOption>} */([]);
});
return /** @type {Array<import("../../types").MultiSelectOption>} */ ([]);
}
);
};

const suggestAndMapToOption = (q = '') => suggest(q).then(addAllOptionAndMapToOption);
Expand Down Expand Up @@ -370,7 +454,7 @@ export default defineComponent({
* @param {Array<import("../../types").MultiSelectOption>} values
* @returns {Array<import("../../types").MultiSelectOption>}
*/
const setOptions = (values) => {
const setOptions = (values) => {
options.value = values;
return values;
};
Expand Down Expand Up @@ -432,7 +516,7 @@ export default defineComponent({
* @param {string | null} value
* @returns {Promise<string | null>}
*/
const augmentFromValue = (value) => {
const augmentFromValue = (value) => {
let selectedPromise = null;
if (value && props.entityUrl) {
selectedPromise = api
Expand Down Expand Up @@ -463,7 +547,7 @@ export default defineComponent({
}
return "";
});
}
}

/**
* Register event listener to trigger on change on select change event
Expand Down
7 changes: 7 additions & 0 deletions udata_front/theme/gouvfr/assets/js/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,12 @@ export const resources_min_count_to_show_search = _jsonMeta("resources-min-count
*/
export const markdown = _jsonMeta("markdown-config");

/**
* License groups options configuration.
*/
export const license_groups_options = _jsonMeta("license-groups-options");


/**
* Whether the 'read only mode' feature is enabled or not.
*/
Expand Down Expand Up @@ -318,6 +324,7 @@ export default {
resources_default_page_size,
resources_min_count_to_show_search,
markdown,
license_groups_options,
read_only_enabled,
quality_description_length,
quality_metadata_backend_ignore,
Expand Down