diff --git a/front/package-lock.json b/front/package-lock.json index 2623ae73f8..2e3f424f90 100644 --- a/front/package-lock.json +++ b/front/package-lock.json @@ -38,7 +38,6 @@ "react-dnd-touch-backend": "^16.0.1", "react-select": "^4.3.1", "react-slider": "^2.0.6", - "react-tag-input-component": "^2.0.2", "unistore": "^3.5.2", "useragent-parser-js": "^1.0.3", "uuid": "^3.4.0" @@ -24562,15 +24561,6 @@ "react": "^16 || ^17 || ^18" } }, - "node_modules/react-tag-input-component": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/react-tag-input-component/-/react-tag-input-component-2.0.2.tgz", - "integrity": "sha512-dydI9luVwwv9vrjE5u1TTnkcOVkOVL6mhFti8r6hLi78V2F2EKWQOLptURz79UYbDHLSk6tnbvGl8FE+sMpADg==", - "peerDependencies": { - "react": "^16 || ^17 || ^18", - "react-dom": "^16 || ^17 || ^18" - } - }, "node_modules/react-transition-group": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.2.tgz", @@ -50567,12 +50557,6 @@ "prop-types": "^15.8.1" } }, - "react-tag-input-component": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/react-tag-input-component/-/react-tag-input-component-2.0.2.tgz", - "integrity": "sha512-dydI9luVwwv9vrjE5u1TTnkcOVkOVL6mhFti8r6hLi78V2F2EKWQOLptURz79UYbDHLSk6tnbvGl8FE+sMpADg==", - "requires": {} - }, "react-transition-group": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.2.tgz", diff --git a/front/package.json b/front/package.json index 0da2adf430..5bce21c9cc 100644 --- a/front/package.json +++ b/front/package.json @@ -76,7 +76,6 @@ "react-dnd-touch-backend": "^16.0.1", "react-select": "^4.3.1", "react-slider": "^2.0.6", - "react-tag-input-component": "^2.0.2", "unistore": "^3.5.2", "useragent-parser-js": "^1.0.3", "uuid": "^3.4.0" diff --git a/front/src/components/layout/CardFilter.jsx b/front/src/components/layout/CardFilter.jsx index be8c67d289..f1f3511f74 100644 --- a/front/src/components/layout/CardFilter.jsx +++ b/front/src/components/layout/CardFilter.jsx @@ -1,7 +1,16 @@ import { Fragment } from 'preact'; import { Text } from 'preact-i18n'; +import Select from 'react-select'; -const CardFilter = ({ changeOrderDir, orderValue = 'asc', search, searchValue, searchPlaceHolder }) => ( +const CardFilter = ({ + changeOrderDir, + orderValue = 'asc', + search, + searchValue, + searchPlaceHolder, + tags, + searchTags +}) => ( + {tags && ( +
+ +
); diff --git a/front/src/config/i18n/en.json b/front/src/config/i18n/en.json index ac1ccabbee..6fd4dc1711 100644 --- a/front/src/config/i18n/en.json +++ b/front/src/config/i18n/en.json @@ -1339,6 +1339,7 @@ "editDescriptionPlaceholder": "Enter a scene description", "tagsTitle": "Tags", "editTagsPlaceholder": "Enter a scene tags", + "createTag": "Create tag: '{{tagName}}'", "startButton": "Start", "saveButton": "Save", "deleteButton": "Delete", diff --git a/front/src/config/i18n/fr.json b/front/src/config/i18n/fr.json index a2b05dd334..9da94dfd63 100644 --- a/front/src/config/i18n/fr.json +++ b/front/src/config/i18n/fr.json @@ -1339,6 +1339,7 @@ "descriptionTitle": "Description", "iconLabel": "Icône", "editDescriptionPlaceholder": "Entrez une description pour la scène", + "createTag": "Créer le tag : '{{tagName}}'", "tagsTitle": "Tags", "editTagsPlaceholder": "Entrez un tag pour la scène", "startButton": "Démarrer", diff --git a/front/src/routes/scene/SceneCard.jsx b/front/src/routes/scene/SceneCard.jsx index e5388e4775..af4bf283e6 100644 --- a/front/src/routes/scene/SceneCard.jsx +++ b/front/src/routes/scene/SceneCard.jsx @@ -36,7 +36,7 @@ class SceneCard extends Component {
-
+
diff --git a/front/src/routes/scene/ScenePage.jsx b/front/src/routes/scene/ScenePage.jsx index 79b5fbb122..45fbdf2847 100644 --- a/front/src/routes/scene/ScenePage.jsx +++ b/front/src/routes/scene/ScenePage.jsx @@ -24,9 +24,11 @@ const ScenePage = ({ children, ...props }) => ( search={props.debouncedSearch} searchValue={props.sceneSearch} searchPlaceHolder={} + tags={props.tags} + searchTags={props.searchTags} /> - +
diff --git a/front/src/routes/scene/edit-scene/Settings.jsx b/front/src/routes/scene/edit-scene/Settings.jsx index 955da0d029..ff47c36437 100644 --- a/front/src/routes/scene/edit-scene/Settings.jsx +++ b/front/src/routes/scene/edit-scene/Settings.jsx @@ -89,6 +89,9 @@ class Settings extends Component { isMulti options={props.tags && props.tags.map(tag => ({ value: tag.name, label: tag.name }))} onChange={tags => props.setTags(tags.map(tag => tag.value))} + formatCreateLabel={inputValue => ( + + )} />
diff --git a/front/src/routes/scene/index.js b/front/src/routes/scene/index.js index ee6b54fff3..41a899509e 100644 --- a/front/src/routes/scene/index.js +++ b/front/src/routes/scene/index.js @@ -18,6 +18,9 @@ class Scene extends Component { if (this.state.sceneSearch && this.state.sceneSearch.length) { params.search = this.state.sceneSearch; } + if (this.state.sceneTagSearch && this.state.sceneTagSearch.length) { + params.searchTags = this.state.sceneTagSearch.join(','); + } const scenes = await this.props.httpClient.get('/api/v1/scene', params); this.setState({ scenes, @@ -31,12 +34,30 @@ class Scene extends Component { }); } }; + getTags = async () => { + try { + const tags = await this.props.httpClient.get(`/api/v1/tag_scene`); + this.setState({ + tags + }); + } catch (e) { + console.error(e); + } + }; search = async e => { await this.setState({ sceneSearch: e.target.value }); await this.getScenes(); }; + searchTags = async tags => { + console.log(tags); + await this.setState({ + sceneTagSearch: tags + }); + await this.getScenes(); + }; + changeOrderDir = async e => { await this.setState({ getScenesOrderDir: e.target.value @@ -88,6 +109,7 @@ class Scene extends Component { getScenesOrderDir: 'asc', scenes: [], sceneSearch: null, + sceneTagSearch: null, loading: true }; this.debouncedSearch = debounce(this.search.bind(this), 200); @@ -95,9 +117,10 @@ class Scene extends Component { componentWillMount() { this.getScenes(); + this.getTags(); } - render(props, { scenes, loading, getError }) { + render(props, { scenes, loading, getError, tags }) { return ( ); } diff --git a/front/src/routes/scene/style.css b/front/src/routes/scene/style.css index 449c7c8814..f70dc5350b 100644 --- a/front/src/routes/scene/style.css +++ b/front/src/routes/scene/style.css @@ -39,9 +39,14 @@ } .descriptionSceneEllipsis { + flex-grow: 2; overflow: hidden; display: -webkit-box; -webkit-line-clamp: 3; line-clamp: 3; -webkit-box-orient: vertical; } + +.newButton { + min-width: min-content; +} diff --git a/server/lib/scene/scene.get.js b/server/lib/scene/scene.get.js index bf54a01ab1..115a01b24f 100644 --- a/server/lib/scene/scene.get.js +++ b/server/lib/scene/scene.get.js @@ -1,4 +1,5 @@ const { Op } = require('sequelize'); +const Sequelize = require('sequelize'); const db = require('../../models'); const DEFAULT_OPTIONS = { @@ -46,30 +47,27 @@ async function get(options) { })), }; } - - const scenes = await db.Scene.findAll(queryParams); - - let scenesPlain = scenes.map((scene) => scene.get({ plain: true })); - if (optionsWithDefault.search) { - scenesPlain = scenesPlain.filter((scene) => { - if (scene.name.toLowerCase().includes(optionsWithDefault.search.toLowerCase())) { - return scene; - } - const tagsFound = scene.tags.find((tag) => { - if (tag.name.toLowerCase().includes(optionsWithDefault.search.toLowerCase())) { - return true; - } - return false; - }); - if (tagsFound) { - return scene; - } - return null; + queryParams.where = Sequelize.where(Sequelize.fn('lower', Sequelize.col('t_scene.name')), { + [Op.like]: `%${optionsWithDefault.search}%`, + }); + } + + if (optionsWithDefault.searchTags) { + const tags = await db.TagScene.findAll({ + fields: 'scene_id', + where: { + [Op.or]: optionsWithDefault.searchTags.split(',').map((tag) => ({ name: { [Op.like]: `%${tag}%` } })), + }, }); + queryParams.where = { + [Op.or]: tags.map((tag) => tag.get({ plain: true })).map((tag) => ({ id: tag.scene_id })), + }; } - return scenesPlain; + const scenes = await db.Scene.findAll(queryParams); + + return scenes.map((scene) => scene.get({ plain: true })); } module.exports = {