From a20167dcf14e47fc9d2eb5f82875d1ffa73fff06 Mon Sep 17 00:00:00 2001 From: p3rcypj Date: Tue, 30 Apr 2024 15:58:08 +0000 Subject: [PATCH 1/4] Fix page not found error with not being able to redirect inside section --- public/index.html | 13 ++++---- .../AdditionalComponents.tsx | 21 +++--------- .../components/item-category/ItemCategory.tsx | 2 +- src/webapp/components/item-root/ItemRoot.tsx | 7 +--- src/webapp/contexts/app-context.tsx | 6 +++- src/webapp/pages/home/HomePage.tsx | 33 ++++++++----------- src/webapp/pages/settings/useConfig.ts | 12 +++++-- 7 files changed, 43 insertions(+), 51 deletions(-) diff --git a/public/index.html b/public/index.html index e87e0bb..7486350 100644 --- a/public/index.html +++ b/public/index.html @@ -3,15 +3,16 @@ - diff --git a/src/webapp/components/additional-components/AdditionalComponents.tsx b/src/webapp/components/additional-components/AdditionalComponents.tsx index 806fe1e..a390f50 100644 --- a/src/webapp/components/additional-components/AdditionalComponents.tsx +++ b/src/webapp/components/additional-components/AdditionalComponents.tsx @@ -1,7 +1,6 @@ -import { useConfig } from "../../pages/settings/useConfig"; -import i18n from "@eyeseetea/d2-ui-components/locales"; import React from "react"; -import { LandingNode, updateLandingNodes } from "../../../domain/entities/LandingNode"; +import { useConfig } from "../../pages/settings/useConfig"; +import { LandingNode } from "../../../domain/entities/LandingNode"; import { useAppContext } from "../../contexts/app-context"; import { BigCard } from "../card-board/BigCard"; import { Cardboard } from "../card-board/Cardboard"; @@ -9,6 +8,7 @@ import { LandingParagraph } from "../landing-layout"; import { useAnalytics } from "../../hooks/useAnalytics"; import { Action, getPageActions } from "../../../domain/entities/Action"; import { useSnackbar } from "@eyeseetea/d2-ui-components"; +import i18n from "@eyeseetea/d2-ui-components/locales"; export const AdditionalComponents: React.FC<{ isRoot: boolean; @@ -16,22 +16,11 @@ export const AdditionalComponents: React.FC<{ openPage(page: LandingNode): void; }> = React.memo(props => { const { isRoot, currentPage, openPage } = props; - const { actions, translate, launchAppBaseUrl, landings } = useAppContext(); - const { showAllActions, landingPagePermissions, user } = useConfig(); + const { actions, translate, launchAppBaseUrl, getLandingNodeById } = useAppContext(); + const { showAllActions, user } = useConfig(); const analytics = useAnalytics(); const snackbar = useSnackbar(); - const userLandings = React.useMemo(() => { - return landings && landingPagePermissions && user - ? updateLandingNodes(landings, landingPagePermissions, user) - : undefined; - }, [landingPagePermissions, landings, user]); - - const getLandingNodeById = React.useCallback( - (id: string) => userLandings?.find(landing => landing.id === id), - [userLandings] - ); - const actionHandleClick = React.useCallback( (action: Action) => { switch (action.type) { diff --git a/src/webapp/components/item-category/ItemCategory.tsx b/src/webapp/components/item-category/ItemCategory.tsx index db670a2..ead7462 100644 --- a/src/webapp/components/item-category/ItemCategory.tsx +++ b/src/webapp/components/item-category/ItemCategory.tsx @@ -46,7 +46,7 @@ export const ItemCategory: React.FC<{ {showAdditionalComponents && ( - )}{" "} + )} ); diff --git a/src/webapp/components/item-root/ItemRoot.tsx b/src/webapp/components/item-root/ItemRoot.tsx index 71e9522..144dfd0 100644 --- a/src/webapp/components/item-root/ItemRoot.tsx +++ b/src/webapp/components/item-root/ItemRoot.tsx @@ -32,12 +32,7 @@ export const ItemRoot: React.FC<{ {currentPage.pageRendering === "single" ? ( currentPage.children.map(node => ( - openPage(node)} - currentPage={node} - /> + )) ) : ( diff --git a/src/webapp/contexts/app-context.tsx b/src/webapp/contexts/app-context.tsx index a79f8e9..d6746fe 100644 --- a/src/webapp/contexts/app-context.tsx +++ b/src/webapp/contexts/app-context.tsx @@ -9,10 +9,12 @@ import { cacheImages } from "../utils/image-cache"; import { Instance } from "../../data/entities/Instance"; import { Typography } from "@material-ui/core"; import i18n from "../../locales"; +import { Maybe } from "../../types/utils"; const AppContext = React.createContext(null); export const AppContextProvider: React.FC = ({ children, baseUrl, locale }) => { + const [compositionRoot, setCompositionRoot] = React.useState(); const [actions, setActions] = useState([]); const [landings, setLandings] = useState(); const [hasSettingsAccess, setHasSettingsAccess] = useState(false); @@ -22,7 +24,7 @@ export const AppContextProvider: React.FC = ({ children const [launchAppBaseUrl, setLaunchAppBaseUrl] = useState(""); const translate = buildTranslate(locale); - const [compositionRoot, setCompositionRoot] = React.useState(); + const getLandingNodeById = useCallback((id: string) => landings?.find(landing => landing.id === id), [landings]); React.useEffect(() => { getCompositionRoot(new Instance({ url: baseUrl })).then(compositionRoot => { @@ -66,6 +68,7 @@ export const AppContextProvider: React.FC = ({ children hasSettingsAccess, isAdmin, launchAppBaseUrl, + getLandingNodeById, }} > {children} @@ -112,4 +115,5 @@ export interface AppContextState { hasSettingsAccess: boolean; isAdmin: boolean; launchAppBaseUrl: string; + getLandingNodeById: (id: string) => Maybe; } diff --git a/src/webapp/pages/home/HomePage.tsx b/src/webapp/pages/home/HomePage.tsx index 6d150b1..c05df84 100644 --- a/src/webapp/pages/home/HomePage.tsx +++ b/src/webapp/pages/home/HomePage.tsx @@ -1,12 +1,8 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from "react"; import CircularProgress from "material-ui/CircularProgress"; import styled from "styled-components"; -import { - LandingNode, - getPrimaryRedirectUrl as getPrimaryActionUrl, - updateLandingNodes, -} from "../../../domain/entities/LandingNode"; -import i18n from "../../../locales"; +import { useSnackbar } from "@eyeseetea/d2-ui-components"; +import { LandingNode, getPrimaryRedirectUrl as getPrimaryActionUrl } from "../../../domain/entities/LandingNode"; import { LandingLayout, LandingContent } from "../../components/landing-layout"; import { useAppContext } from "../../contexts/app-context"; import { useNavigate } from "react-router-dom"; @@ -18,29 +14,24 @@ import { goTo } from "../../utils/routes"; import { defaultIcon, defaultTitle } from "../../router/Router"; import { useAnalytics } from "../../hooks/useAnalytics"; import { Maybe } from "../../../types/utils"; +import i18n from "../../../locales"; export const HomePage: React.FC = React.memo(() => { - const { hasSettingsAccess, landings, reload, isLoading, launchAppBaseUrl, translate, compositionRoot } = - useAppContext(); - const { defaultApplication, landingPagePermissions, user } = useConfig(); - - const userLandings = useMemo(() => { - return landings && landingPagePermissions && user - ? updateLandingNodes(landings, landingPagePermissions, user) - : undefined; - }, [landingPagePermissions, landings, user]); + const { hasSettingsAccess, reload, isLoading, launchAppBaseUrl, translate, compositionRoot } = useAppContext(); + const { defaultApplication, userLandings } = useConfig(); const initLandings = useMemo(() => userLandings?.filter(landing => landing.executeOnInit), [userLandings]); const navigate = useNavigate(); const analytics = useAnalytics(); + const snackbar = useSnackbar(); const [history, updateHistory] = useState([]); const [isLoadingLong, setLoadingLong] = useState(false); const [pageType, setPageType] = useState<"userLandings" | "singleLanding">( userLandings && userLandings?.length > 1 ? "userLandings" : "singleLanding" ); - const favicon = useRef(document.head.querySelector('link[rel="icon"]')); + const favicon = useRef(document.head.querySelector('link[rel="shortcut icon"]')); const currentPage = useMemo(() => { return history[0] ?? initLandings?.[0]; @@ -59,10 +50,14 @@ export const HomePage: React.FC = React.memo(() => { const openPage = useCallback( (page: LandingNode) => { - compositionRoot.analytics.sendPageView({ title: page.name.referenceValue, location: undefined }); - updateHistory(history => [page, ...history]); + if (userLandings?.some(landing => landing.id === page.id)) { + compositionRoot.analytics.sendPageView({ title: page.name.referenceValue, location: undefined }); + updateHistory(history => [page, ...history]); + } else { + snackbar.error(i18n.t("You do not have access to this page.")); + } }, - [compositionRoot.analytics] + [compositionRoot.analytics, userLandings, snackbar] ); const goBack = useCallback(() => { diff --git a/src/webapp/pages/settings/useConfig.ts b/src/webapp/pages/settings/useConfig.ts index 4413cf8..4f92c77 100644 --- a/src/webapp/pages/settings/useConfig.ts +++ b/src/webapp/pages/settings/useConfig.ts @@ -1,12 +1,13 @@ -import { useState, useEffect, useCallback } from "react"; +import { useState, useEffect, useCallback, useMemo } from "react"; import { LandingPagePermission, Permission } from "../../../domain/entities/Permission"; import { SharedUpdate } from "../../components/permissions-dialog/PermissionsDialog"; import { useAppContext } from "../../contexts/app-context"; import { User } from "../../../domain/entities/User"; import { Maybe } from "../../../types/utils"; +import { LandingNode, updateLandingNodes } from "../../../domain/entities/LandingNode"; export function useConfig(): useConfigPloc { - const { compositionRoot } = useAppContext(); + const { compositionRoot, landings } = useAppContext(); const [showAllActions, setShowAllActions] = useState(false); const [defaultApplication, setDefaultApplication] = useState(""); const [googleAnalyticsCode, setGoogleAnalyticsCode] = useState>(); @@ -14,6 +15,11 @@ export function useConfig(): useConfigPloc { const [landingPagePermissions, setLandingPagePermissions] = useState(); const [user, setUser] = useState(); + const userLandings = useMemo(() => { + if (!(landings && landingPagePermissions && user)) return undefined; + return updateLandingNodes(landings, landingPagePermissions, user); + }, [landingPagePermissions, landings, user]); + useEffect(() => { compositionRoot.config.getShowAllActions().then(setShowAllActions); compositionRoot.config.getDefaultApplication().then(setDefaultApplication); @@ -89,6 +95,7 @@ export function useConfig(): useConfigPloc { landingPagePermissions, updateLandingPagePermissions, googleAnalyticsCode, + userLandings, }; } @@ -104,4 +111,5 @@ interface useConfigPloc { landingPagePermissions?: LandingPagePermission[]; updateLandingPagePermissions: (sharedUpdate: SharedUpdate, id: string) => Promise; googleAnalyticsCode: Maybe; + userLandings: Maybe; } From 56bf32b6bef1e178d2577963a8eb6f8ef00826f1 Mon Sep 17 00:00:00 2001 From: p3rcypj Date: Thu, 2 May 2024 20:42:44 +0000 Subject: [PATCH 2/4] Update i18n --- i18n/en.pot | 7 +++++-- i18n/es.po | 5 ++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/i18n/en.pot b/i18n/en.pot index 8ae5fb8..147d832 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: 2024-04-23T08:25:26.968Z\n" -"PO-Revision-Date: 2024-04-23T08:25:26.968Z\n" +"POT-Creation-Date: 2024-04-30T15:58:34.129Z\n" +"PO-Revision-Date: 2024-04-30T15:58:34.129Z\n" msgid "Field {{field}} cannot be blank" msgstr "" @@ -410,6 +410,9 @@ msgstr "" msgid "New action" msgstr "" +msgid "You do not have access to this page." +msgstr "" + msgid "First load can take a couple of minutes, please wait..." msgstr "" diff --git a/i18n/es.po b/i18n/es.po index fa2d171..17e5279 100644 --- a/i18n/es.po +++ b/i18n/es.po @@ -1,7 +1,7 @@ msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" -"POT-Creation-Date: 2024-04-23T08:25:26.968Z\n" +"POT-Creation-Date: 2024-04-30T15:58:34.129Z\n" "PO-Revision-Date: 2018-10-25T09:02:35.143Z\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -409,6 +409,9 @@ msgstr "" msgid "New action" msgstr "" +msgid "You do not have access to this page." +msgstr "" + msgid "First load can take a couple of minutes, please wait..." msgstr "" From 215755e800b3ee1dcf7a51df5144f303e05aecf9 Mon Sep 17 00:00:00 2001 From: p3rcypj Date: Thu, 2 May 2024 21:53:38 +0000 Subject: [PATCH 3/4] Fix sections not accessible --- src/domain/entities/LandingNode.ts | 4 ++++ src/webapp/pages/home/HomePage.tsx | 9 +++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/domain/entities/LandingNode.ts b/src/domain/entities/LandingNode.ts index ce53c3e..6515adc 100644 --- a/src/domain/entities/LandingNode.ts +++ b/src/domain/entities/LandingNode.ts @@ -132,4 +132,8 @@ export function getPrimaryRedirectUrl( return redirectUrl; } +export function flattenLandingNodes(nodes: LandingNode[]): LandingNode[] { + return nodes.flatMap(node => [node, ...flattenLandingNodes(node.children)]); +} + type Url = string; diff --git a/src/webapp/pages/home/HomePage.tsx b/src/webapp/pages/home/HomePage.tsx index c05df84..575e69c 100644 --- a/src/webapp/pages/home/HomePage.tsx +++ b/src/webapp/pages/home/HomePage.tsx @@ -2,7 +2,11 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from "react" import CircularProgress from "material-ui/CircularProgress"; import styled from "styled-components"; import { useSnackbar } from "@eyeseetea/d2-ui-components"; -import { LandingNode, getPrimaryRedirectUrl as getPrimaryActionUrl } from "../../../domain/entities/LandingNode"; +import { + LandingNode, + flattenLandingNodes, + getPrimaryRedirectUrl as getPrimaryActionUrl, +} from "../../../domain/entities/LandingNode"; import { LandingLayout, LandingContent } from "../../components/landing-layout"; import { useAppContext } from "../../contexts/app-context"; import { useNavigate } from "react-router-dom"; @@ -50,7 +54,8 @@ export const HomePage: React.FC = React.memo(() => { const openPage = useCallback( (page: LandingNode) => { - if (userLandings?.some(landing => landing.id === page.id)) { + const nodes = userLandings && flattenLandingNodes(userLandings); + if (nodes?.some(landing => landing.id === page.id)) { compositionRoot.analytics.sendPageView({ title: page.name.referenceValue, location: undefined }); updateHistory(history => [page, ...history]); } else { From 0c67d16a7950d96cf22f8911748793191cdc0baa Mon Sep 17 00:00:00 2001 From: Adrian Quintana Date: Sun, 5 May 2024 18:42:27 +0100 Subject: [PATCH 4/4] bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5ef80a7..f835d7a 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "home-page", "description": "Home Page App", - "version": "1.7.0", + "version": "1.7.1", "license": "GPL-3.0", "author": "EyeSeeTea team", "homepage": ".",