From 5cb31f859d1fa2695988397088daac89ef8e422b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roger=20Boixader=20G=C3=BCell?= Date: Thu, 25 Jan 2024 18:28:37 +0100 Subject: [PATCH 1/2] Feat: Add possibility to translate the workflow texts --- CHANGELOG.md | 4 + e2e/cypress/integration/gmi-type-content.js | 6 +- e2e/vite_example/package-lock.json | 8 +- .../guillotina_react_app/__init__.py | 6 +- .../guillotina_react_app/workflow.py | 91 +++++++++++++++++++ .../guillotina_react_app/requirements.txt | 2 +- .../components/behaviors/iworkflow.js | 45 ++++++++- .../components/fields/renderField.js | 1 - 8 files changed, 151 insertions(+), 12 deletions(-) create mode 100644 guillotina_example/guillotina_react_app/guillotina_react_app/workflow.py diff --git a/CHANGELOG.md b/CHANGELOG.md index f002a60..6c1f3f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +0.26.0 +------ +- Feat: Add possibility to translate the workflow texts + 0.25.2 ------ - feat: use label property to render info in search inputs and to sort elements diff --git a/e2e/cypress/integration/gmi-type-content.js b/e2e/cypress/integration/gmi-type-content.js index c99c423..b959b2a 100644 --- a/e2e/cypress/integration/gmi-type-content.js +++ b/e2e/cypress/integration/gmi-type-content.js @@ -269,15 +269,15 @@ LOGIN_TYPES.forEach((loginType) => { ) // Modify workflow - cy.findByText(/Current state: private/) + cy.findByText(/Current state: Private/) cy.findByText('Publish').click() cy.findByText('Confirm').click() cy.get(NOTIFICATION_SELECTOR).should('contain', `Great status changed!`) - cy.findByText(/Current state: public/) + cy.findByText(/Current state: Public/) cy.findByText('Retire').click() cy.findByText('Confirm').click() cy.get(NOTIFICATION_SELECTOR).should('contain', `Great status changed!`) - cy.findByText(/Current state: private/) + cy.findByText(/Current state: Private/) // Upload multiple image cy.get(`[data-test='formMultiimageOrderedAttachmentTest']`).within(() => { diff --git a/e2e/vite_example/package-lock.json b/e2e/vite_example/package-lock.json index 496cd68..0a82001 100644 --- a/e2e/vite_example/package-lock.json +++ b/e2e/vite_example/package-lock.json @@ -30,7 +30,7 @@ }, "../..": { "name": "@guillotinaweb/react-gmi", - "version": "0.24.0", + "version": "0.26.0", "license": "MIT", "dependencies": { "brace": "0.11.1", @@ -38,15 +38,18 @@ "jwt-decode": "3.1.2", "prop-types": "15.7.2", "react-beautiful-dnd": "13.1.1", + "react-intl": "6.5.5", "react-useportal": "1.0.19", "uuid": "9.0.1" }, "devDependencies": { "@babel/cli": "7.12.10", "@babel/core": "7.12.10", + "@formatjs/cli": "^6.2.4", "@testing-library/jest-dom": "5.11.6", "@testing-library/react": "11.2.2", "@testing-library/user-event": "12.6.0", + "babel-plugin-formatjs": "^10.5.10", "husky": "4.3.6", "microbundle": "0.13.0", "prettier": "2.2.1", @@ -4946,9 +4949,11 @@ "requires": { "@babel/cli": "7.12.10", "@babel/core": "7.12.10", + "@formatjs/cli": "^6.2.4", "@testing-library/jest-dom": "5.11.6", "@testing-library/react": "11.2.2", "@testing-library/user-event": "12.6.0", + "babel-plugin-formatjs": "^10.5.10", "brace": "0.11.1", "bulma": "0.9.4", "husky": "4.3.6", @@ -4957,6 +4962,7 @@ "prettier": "2.2.1", "prop-types": "15.7.2", "react-beautiful-dnd": "13.1.1", + "react-intl": "6.5.5", "react-useportal": "1.0.19", "sass": "1.69.5", "serialize-javascript": "5.0.1", diff --git a/guillotina_example/guillotina_react_app/guillotina_react_app/__init__.py b/guillotina_example/guillotina_react_app/guillotina_react_app/__init__.py index 902576d..22b8cfb 100644 --- a/guillotina_example/guillotina_react_app/guillotina_react_app/__init__.py +++ b/guillotina_example/guillotina_react_app/guillotina_react_app/__init__.py @@ -1,12 +1,13 @@ from guillotina import configure - +from guillotina_react_app.workflow import guillotina_basic_with_translations app_settings = { "commands": { "populate": "guillotina_react_app.commands.populate.PopulateData", }, + "workflows": {"guillotina_basic_with_translations": guillotina_basic_with_translations}, "workflows_content": { - "guillotina_react_app.gmi.interface.IGMI": "guillotina_basic", + "guillotina_react_app.gmi.interface.IGMI": "guillotina_basic_with_translations", "guillotina_react_app.gmi.interface.IGMIBehaviors": "guillotina_simple", }, } @@ -21,3 +22,4 @@ def includeme(root): configure.scan("guillotina_react_app.vocabularies") configure.scan("guillotina_react_app.gmi") configure.scan("guillotina_react_app.gmi_behaviors") + configure.scan("guillotina_react_app.workflow") diff --git a/guillotina_example/guillotina_react_app/guillotina_react_app/workflow.py b/guillotina_example/guillotina_react_app/guillotina_react_app/workflow.py new file mode 100644 index 0000000..ef9858d --- /dev/null +++ b/guillotina_example/guillotina_react_app/guillotina_react_app/workflow.py @@ -0,0 +1,91 @@ +guillotina_basic_with_translations = { + "initial_state": "private", + "states": { + "private": { + "metadata": { + "title": "Private", + "translated_title": { + "en": "Private", + "ca": "Privat", + "es": "Privado", + }, + }, + "actions": { + "publish": { + "title": "Publish", + "metadata": { + "translated_title": { + "en": "Publish", + "ca": "Publicar", + "es": "Publicar", + }, + }, + "to": "public", + "check_permission": "guillotina.ReviewContent", + } + }, + "set_permission": { + "roleperm": [ + { + "setting": "Deny", + "role": "guillotina.Anonymous", + "permission": "guillotina.ViewContent", + }, + { + "setting": "Deny", + "role": "guillotina.Anonymous", + "permission": "guillotina.AccessContent", + }, + { + "setting": "Deny", + "role": "guillotina.Anonymous", + "permission": "guillotina.SearchContent", + }, + ] + }, + }, + "public": { + "metadata": { + "title": "Public", + "translated_title": { + "en": "Public", + "ca": "Públic", + "es": "Público", + }, + }, + "actions": { + "retire": { + "title": "Retire", + "metadata": { + "translated_title": { + "en": "Retire", + "ca": "Retirar", + "es": "Retirar", + }, + }, + "to": "private", + "check_permission": "guillotina.ReviewContent", + }, + }, + "set_permission": { + "roleperm": [ + { + "setting": "AllowSingle", + "role": "guillotina.Anonymous", + "permission": "guillotina.ViewContent", + }, + { + "setting": "AllowSingle", + "role": "guillotina.Anonymous", + "permission": "guillotina.AccessContent", + }, + { + "setting": "AllowSingle", + "role": "guillotina.Anonymous", + "permission": "guillotina.SearchContent", + }, + ] + }, + }, + }, +} diff --git a/guillotina_example/guillotina_react_app/requirements.txt b/guillotina_example/guillotina_react_app/requirements.txt index b92ac68..ebec2f1 100644 --- a/guillotina_example/guillotina_react_app/requirements.txt +++ b/guillotina_example/guillotina_react_app/requirements.txt @@ -1,2 +1,2 @@ -guillotina==7.0.0 +guillotina==7.0.2 pillow==9.5 \ No newline at end of file diff --git a/src/guillo-gmi/components/behaviors/iworkflow.js b/src/guillo-gmi/components/behaviors/iworkflow.js index aab7c61..44d82d1 100644 --- a/src/guillo-gmi/components/behaviors/iworkflow.js +++ b/src/guillo-gmi/components/behaviors/iworkflow.js @@ -4,7 +4,8 @@ import { Confirm } from '../modal' import { useCrudContext } from '../../hooks/useCrudContext' import { ItemModel } from '../../models' import { defineMessages, useIntl } from 'react-intl' - +import { useVocabulary } from '../../hooks/useVocabulary' +import { get } from '../../lib/utils' const messages = defineMessages({ status_changed_ok: { id: 'status_changed_ok', @@ -36,6 +37,7 @@ export function IWorkflow() { const [definition, setDefinition] = React.useState(undefined) const [workflowAction, setWorkflowAction] = React.useState(null) const model = new ItemModel(Ctx.context) + const vocabulary = useVocabulary('workflow_states') const currentState = model.item['guillotina.contrib.workflows.interfaces.IWorkflowBehavior'][ 'review_state' @@ -72,6 +74,35 @@ export function IWorkflow() { Ctx.refresh() setWorkflowAction(null) } + const getStateTitle = () => { + console.log('getStateTitle', vocabulary) + if (vocabulary.data?.items?.length > 0) { + const vocabularyValue = vocabulary.data.items.find( + (item) => item.token === currentState + ) + console.log('state title', vocabularyValue, intl.locale) + if (vocabularyValue) { + const translatedValue = get( + vocabularyValue, + `title.translated_title.${intl.locale}`, + null + ) + if (translatedValue !== null) { + return translatedValue + } + const titleValue = get( + vocabularyValue, + `title.title.${intl.locale}`, + null + ) + if (titleValue !== null) { + return titleValue + } + } + } + return currentState + } + console.log('Workflow log') if (definition === undefined) return null return ( @@ -92,10 +123,12 @@ export function IWorkflow() { className="has-text-weight-bold" data-test={`textInfoStatus-${currentState}`} > - {intl.formatMessage(messages.current_state, { state: currentState })} + {intl.formatMessage(messages.current_state, { + state: getStateTitle(), + })} - {modifyContent && ( + {modifyContent && definition.transitions.length > 0 && (
- {transition.title} + {get( + transition, + `metadata.translated_title.${intl.locale}`, + transition.title + )} ) })} diff --git a/src/guillo-gmi/components/fields/renderField.js b/src/guillo-gmi/components/fields/renderField.js index 5f50380..cda62af 100644 --- a/src/guillo-gmi/components/fields/renderField.js +++ b/src/guillo-gmi/components/fields/renderField.js @@ -105,7 +105,6 @@ export const SearchRenderField = ({ schema, value, modifyContent }) => { }, [value]) const getRenderValue = () => { - console.log('get render values', value, valuesLabels) if (value === undefined) { if (modifyContent) { return DEFAULT_VALUE_EDITABLE_FIELD From 076fa5780a6d625abdf2982104670fe921496f92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roger=20Boixader=20G=C3=BCell?= Date: Thu, 25 Jan 2024 18:36:27 +0100 Subject: [PATCH 2/2] chore: delete logs and language vite exaple --- e2e/vite_example/src/App.tsx | 6 +++++- package.json | 2 +- src/guillo-gmi/components/behaviors/iworkflow.js | 4 +--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/e2e/vite_example/src/App.tsx b/e2e/vite_example/src/App.tsx index 8d1de09..e910708 100644 --- a/e2e/vite_example/src/App.tsx +++ b/e2e/vite_example/src/App.tsx @@ -132,7 +132,11 @@ function App() { {isLogged && ( { - console.log('getStateTitle', vocabulary) if (vocabulary.data?.items?.length > 0) { const vocabularyValue = vocabulary.data.items.find( (item) => item.token === currentState ) - console.log('state title', vocabularyValue, intl.locale) if (vocabularyValue) { const translatedValue = get( vocabularyValue, @@ -102,7 +100,7 @@ export function IWorkflow() { } return currentState } - console.log('Workflow log') + if (definition === undefined) return null return (