diff --git a/i18n/en.pot b/i18n/en.pot index 9ee746c..7b3986b 100644 --- a/i18n/en.pot +++ b/i18n/en.pot @@ -5,8 +5,8 @@ msgstr "" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -"POT-Creation-Date: 2023-08-15T11:06:27.074Z\n" -"PO-Revision-Date: 2023-08-15T11:06:27.074Z\n" +"POT-Creation-Date: 2023-10-24T20:42:29.340Z\n" +"PO-Revision-Date: 2023-10-24T20:42:29.340Z\n" msgid "Field {{field}} cannot be blank" msgstr "" @@ -38,6 +38,9 @@ msgstr "" msgid "Name *" msgstr "" +msgid "Description" +msgstr "" + msgid "Icon" msgstr "" @@ -371,6 +374,9 @@ msgstr "" msgid "First load can take a couple of minutes, please wait..." msgstr "" +msgid "Loading the user configuration..." +msgstr "" + msgid "Create" msgstr "" diff --git a/i18n/es.po b/i18n/es.po index 305f4e3..347eade 100644 --- a/i18n/es.po +++ b/i18n/es.po @@ -1,7 +1,7 @@ msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" -"POT-Creation-Date: 2023-08-15T11:06:27.074Z\n" +"POT-Creation-Date: 2023-10-24T20:42:29.340Z\n" "PO-Revision-Date: 2018-10-25T09:02:35.143Z\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -38,6 +38,9 @@ msgstr "" msgid "Name *" msgstr "" +msgid "Description" +msgstr "" + msgid "Icon" msgstr "" @@ -370,6 +373,9 @@ msgstr "" msgid "First load can take a couple of minutes, please wait..." msgstr "" +msgid "Loading the user configuration..." +msgstr "" + msgid "Create" msgstr "" diff --git a/src/data/entities/JSONAction.ts b/src/data/entities/JSONAction.ts index 86a4269..485c785 100644 --- a/src/data/entities/JSONAction.ts +++ b/src/data/entities/JSONAction.ts @@ -4,6 +4,7 @@ export interface JSONAction { _version: number; id: string; name: TranslatableText; + description: TranslatableText; icon: string; iconLocation: string; backgroundColor: string; diff --git a/src/data/repositories/ActionDefaultRepository.ts b/src/data/repositories/ActionDefaultRepository.ts index f8f927e..9b61e76 100644 --- a/src/data/repositories/ActionDefaultRepository.ts +++ b/src/data/repositories/ActionDefaultRepository.ts @@ -1,7 +1,7 @@ import FileSaver from "file-saver"; import JSZip from "jszip"; import _ from "lodash"; -import { defaultAction, isValidActionType, Action } from "../../domain/entities/Action"; +import { defaultAction, isValidActionType, Action, defaultTranslatableModel } from "../../domain/entities/Action"; import { TranslatableText } from "../../domain/entities/TranslatableText"; import { validateUserPermission } from "../../domain/entities/User"; import { ActionRepository } from "../../domain/repositories/ActionRepository"; @@ -60,8 +60,8 @@ export class ActionDefaultRepository implements ActionRepository { } public async get(key: string): Promise { - const dataStoreModel = await this.storageClient.getObjectInCollection(Namespaces.ACTIONS, key); - + const actions = (await this.storageClient.getObject(Namespaces.ACTIONS)) ?? []; + const dataStoreModel = _(actions).find(action => action.id === key); if (!dataStoreModel) return undefined; const domainModel = await this.buildDomainModel(dataStoreModel); @@ -168,6 +168,7 @@ export class ActionDefaultRepository implements ActionRepository { _version: model._version, id: model.id, name: model.name, + description: model.description, icon: model.icon, iconLocation: model.iconLocation, backgroundColor: model.backgroundColor, @@ -202,6 +203,7 @@ export class ActionDefaultRepository implements ActionRepository { return { ...rest, + description: model.description ?? defaultTranslatableModel("description"), installed: await this.instanceRepository.isAppInstalledByUrl(model.dhisLaunchUrl), editable: validateUserPermission(model, "write", currentUser), compatible: validateDhisVersion(model, instanceVersion), diff --git a/src/domain/entities/Action.ts b/src/domain/entities/Action.ts index bc465d1..d5850e6 100644 --- a/src/domain/entities/Action.ts +++ b/src/domain/entities/Action.ts @@ -12,11 +12,18 @@ export const ActionTypeModel = Schema.oneOf([ // Schema.exact("widget"), ]); +export const defaultTranslatableModel = (type: string) => ({ + key: `action-${type}`, + referenceValue: "", + translations: {}, +}); + export const ActionModel = Schema.extend( BaseMetadataModel, Schema.object({ id: Schema.string, name: TranslatableTextModel, + description: Schema.optionalSafe(TranslatableTextModel, defaultTranslatableModel("description")), icon: Schema.string, iconLocation: Schema.optionalSafe(Schema.string, ""), backgroundColor: Schema.optionalSafe(Schema.string, ""), @@ -76,7 +83,8 @@ export const actionValidations: ModelValidation[] = [ export const defaultAction: PartialAction = { id: "", - name: { key: "action-name", referenceValue: "", translations: {} }, + name: defaultTranslatableModel("name"), + description: defaultTranslatableModel("description"), icon: "", iconLocation: "", backgroundColor: "#276696", @@ -102,9 +110,9 @@ export const getPageActions = ( } else if (user) { return currentPageActions .filter(action => { - const actionUsers = action.userAccesses?.map(userAccess => userAccess.id); - const actionUserGroups = action.userGroupAccesses?.map(userGroupAccess => userGroupAccess.id); - const userGroupIds = user.userGroups?.map(userGroup => userGroup.id); + const actionUsers = action.userAccesses?.map(userAccess => userAccess.id) ?? []; + const actionUserGroups = action.userGroupAccesses?.map(userGroupAccess => userGroupAccess.id) ?? []; + const userGroupIds = user.userGroups.map(userGroup => userGroup.id); const hasUserAccess = actionUsers.includes(user.id); const hasUserGroupAccess = _.intersection(actionUserGroups, userGroupIds).length > 0; diff --git a/src/domain/helpers/ActionHelpers.ts b/src/domain/helpers/ActionHelpers.ts index 2aff824..e96aea7 100644 --- a/src/domain/helpers/ActionHelpers.ts +++ b/src/domain/helpers/ActionHelpers.ts @@ -5,6 +5,7 @@ export const updateTranslation = ( action: PartialAction, key: string, value: string, + modelType: "name" | "description", language?: string ): PartialAction => { const translate = (text: TranslatableText): TranslatableText => { @@ -17,6 +18,7 @@ export const updateTranslation = ( return { ...action, - name: translate(action.name), + name: modelType === "name" ? translate(action.name) : action.name, + description: modelType === "description" ? translate(action.description) : action.description, }; }; diff --git a/src/webapp/components/action-creation-wizard/steps/GeneralInfoStep.tsx b/src/webapp/components/action-creation-wizard/steps/GeneralInfoStep.tsx index 7486b40..70ea1c1 100644 --- a/src/webapp/components/action-creation-wizard/steps/GeneralInfoStep.tsx +++ b/src/webapp/components/action-creation-wizard/steps/GeneralInfoStep.tsx @@ -51,8 +51,8 @@ export const GeneralInfoStep: React.FC = ({ actio ); const onChangeTranslation = useCallback( - (text: TranslatableText, value: string) => { - onChange(action => updateTranslation(action, text.key, value)); + (text: TranslatableText, value: string, type: "name" | "description") => { + onChange(action => updateTranslation(action, text.key, value, type)); }, [onChange] ); @@ -94,12 +94,23 @@ export const GeneralInfoStep: React.FC = ({ actio fullWidth={true} label={i18n.t("Name *")} value={action.name.referenceValue} - onChange={event => onChangeTranslation(action.name, event.target.value)} + onChange={event => onChangeTranslation(action.name, event.target.value, "name")} error={!!errors["name"]} helperText={errors["name"]} /> + + onChangeTranslation(action.description, event.target.value, "description")} + error={!!errors["description"]} + helperText={errors["description"]} + /> + +

{i18n.t("Icon")}

diff --git a/src/webapp/components/additional-components/AdditionalComponents.tsx b/src/webapp/components/additional-components/AdditionalComponents.tsx index 0ff3e4a..5d2f8d7 100644 --- a/src/webapp/components/additional-components/AdditionalComponents.tsx +++ b/src/webapp/components/additional-components/AdditionalComponents.tsx @@ -44,6 +44,7 @@ export const AdditionalComponents: React.FC<{ }; const name = translate(action.name); + const description = translate(action.description); return ( : undefined} iconLocation={action?.iconLocation} + description={description} backgroundColor={action?.backgroundColor} fontColor={action?.fontColor} textAlignment={action?.textAlignment} diff --git a/src/webapp/components/card-board/BigCard.tsx b/src/webapp/components/card-board/BigCard.tsx index 0176c77..6f208ab 100644 --- a/src/webapp/components/card-board/BigCard.tsx +++ b/src/webapp/components/card-board/BigCard.tsx @@ -6,6 +6,7 @@ import { CardProgress, CardProgressText } from "./CardProgress"; const BaseCard: React.FC = ({ className, label, + description, icon, iconLocation, backgroundColor, @@ -33,6 +34,7 @@ const BaseCard: React.FC = ({ {icon && iconLocation === "top" ? {icon} : null} {label} {icon && (!iconLocation || iconLocation === "bottom") ? {icon} : null} + {description ?

{description}

: null} {progress !== undefined ? {`${normalizedProgress}%`} : null} {progress !== undefined ? : null} @@ -60,6 +62,7 @@ export interface BigCardProps { onClick?: (event: React.MouseEvent) => void; onContextMenu?: (event: React.MouseEvent) => void; disabled?: boolean; + description?: string; icon?: ReactNode; iconLocation?: string; backgroundColor?: string; @@ -82,8 +85,9 @@ const BigCardIcon = styled.span` img, svg { + height: 72px; max-height: 10vw; - max-width: 18vh; + // max-width: 18vh; margin: 0; user-drag: none; }