From 94ff387c7242973f59d17c69cc8c48cbdc854aed Mon Sep 17 00:00:00 2001 From: Adama Camara <48602776+acamara2016@users.noreply.github.com> Date: Fri, 23 Sep 2022 11:48:00 -0300 Subject: [PATCH 1/3] added isShown to page props --- .../components/actions/action.props.ts | 12 +- src/frontend/store/store.ts | 265 ++++++++++-------- 2 files changed, 151 insertions(+), 126 deletions(-) diff --git a/src/frontend/components/actions/action.props.ts b/src/frontend/components/actions/action.props.ts index 54cd6421d..5e4a73a58 100644 --- a/src/frontend/components/actions/action.props.ts +++ b/src/frontend/components/actions/action.props.ts @@ -1,5 +1,5 @@ import { Dispatch, SetStateAction } from 'react' -import { ActionJSON, RecordJSON, ResourceJSON } from '../../interfaces' +import { ActionJSON, RecordJSON, ResourceJSON, PageJSON } from '../../interfaces' /** * Props which are passed to all action components @@ -10,23 +10,23 @@ export type ActionProps = { /** * Action object describing the action */ - action: ActionJSON; + action: ActionJSON /** * Object of type: {@link ResourceJSON} */ - resource: ResourceJSON; + resource: ResourceJSON /** * Selected record. Passed for actions with "record" actionType */ - record?: RecordJSON; + record?: RecordJSON /** * Selected records. Passed for actions with "bulk" actionType */ - records?: Array; + records?: Array /** * Sets tag in a header of an action. It is a function taking tag as an argument */ - setTag?: Dispatch>; + setTag?: Dispatch> } diff --git a/src/frontend/store/store.ts b/src/frontend/store/store.ts index faa7185b8..783fe7711 100644 --- a/src/frontend/store/store.ts +++ b/src/frontend/store/store.ts @@ -17,7 +17,8 @@ import { DROP_NOTICE, ADD_NOTICE, ROUTE_CHANGED, - INITIAL_ROUTE } from './actions' + INITIAL_ROUTE, +} from './actions' import { Assets, BrandingOptions, VersionProps } from '../../adminjs-options.interface' import { PageJSON, ResourceJSON } from '../interfaces' @@ -27,199 +28,223 @@ import { Locale } from '../../locale/config' import { NoticeMessage } from '../hoc/with-notice' export type DashboardInState = { - component?: string; + component?: string } export type NoticeMessageInState = NoticeMessage & { - message: string; - id: string; - type: NoticeMessage['type']; - progress: number; + message: string + id: string + type: NoticeMessage['type'] + progress: number } export type Paths = { - rootPath: string; - logoutPath: string; - loginPath: string; - assetsCDN?: string; + rootPath: string + logoutPath: string + loginPath: string + assetsCDN?: string } const resourcesReducer = ( state: Array = [], action: { - type: string; - data: Array; - }, + type: string + data: Array + } ) => { switch (action.type) { - case RESOURCES_INITIALIZE: - return action.data - default: return state + case RESOURCES_INITIALIZE: + return action.data + default: + return state } } const pagesReducer = ( state: Array = [], action: { - type: string; - data: Array; - }, + type: string + data: Array + } ) => { switch (action.type) { - case PAGES_INITIALIZE: - return action.data - default: return state + case PAGES_INITIALIZE: + return action.data + default: + return state } } const localesReducer = ( state: Locale = { language: 'en', translations: {} } as Locale, action: { - type: string; - data: Locale; - }, + type: string + data: Locale + } ) => { switch (action.type) { - case LOCALE_INITIALIZE: - return action.data - default: return state + case LOCALE_INITIALIZE: + return action.data + default: + return state } } -const brandingReducer = (state = {}, action: { - type: string; - data: BrandingOptions; -}) => { +const brandingReducer = ( + state = {}, + action: { + type: string + data: BrandingOptions + } +) => { switch (action.type) { - case BRANDING_INITIALIZE: - return action.data - default: return state + case BRANDING_INITIALIZE: + return action.data + default: + return state } } -const assetsReducer = (state = {}, action: { - type: string; - data: Assets; -}) => { +const assetsReducer = ( + state = {}, + action: { + type: string + data: Assets + } +) => { switch (action.type) { - case ASSETS_INITIALIZE: - return action.data - default: return state + case ASSETS_INITIALIZE: + return action.data + default: + return state } } -const pathsReducer = ( - state: Paths = DEFAULT_PATHS, - action: {type: string; data: Paths}, -): Paths => { +const pathsReducer = (state: Paths = DEFAULT_PATHS, action: { type: string; data: Paths }): Paths => { switch (action.type) { - case PATHS_INITIALIZE: - return action.data - default: return state + case PATHS_INITIALIZE: + return action.data + default: + return state } } -const dashboardReducer = (state = {}, action: { - type: string; - data: DashboardInState; -}): DashboardInState => { +const dashboardReducer = ( + state = {}, + action: { + type: string + data: DashboardInState + } +): DashboardInState => { switch (action.type) { - case DASHBOARD_INITIALIZE: - return action.data - default: return state + case DASHBOARD_INITIALIZE: + return action.data + default: + return state } } const sessionReducer = ( state: CurrentAdmin | null = null, action: { - type: string; - data: CurrentAdmin | null; - }, + type: string + data: CurrentAdmin | null + } ) => { switch (action.type) { - case SESSION_INITIALIZE: - return action.data - default: return state + case SESSION_INITIALIZE: + return action.data + default: + return state } } -const versionsReducer = (state = {}, action: { - type: string; - data: VersionProps; -}) => { +const versionsReducer = ( + state = {}, + action: { + type: string + data: VersionProps + } +) => { switch (action.type) { - case VERSIONS_INITIALIZE: - return { - admin: action.data.admin, - app: action.data.app, - } - default: return state + case VERSIONS_INITIALIZE: + return { + admin: action.data.admin, + app: action.data.app, + } + default: + return state } } export type RouterProps = { - from: Partial>; - to: Partial>; + from: Partial> + to: Partial> } -const routerReducer = (state: RouterProps = { from: {}, to: {} }, action: { - type: string; - data: any; -}) => { +const routerReducer = ( + state: RouterProps = { from: {}, to: {} }, + action: { + type: string + data: any + } +) => { switch (action.type) { - case INITIAL_ROUTE: - return { - ...state, - from: { ...action.data }, - } - case ROUTE_CHANGED: - return { - from: { ...state.to }, - to: { ...action.data }, - } - default: return state + case INITIAL_ROUTE: + return { + ...state, + from: { ...action.data }, + } + case ROUTE_CHANGED: + return { + from: { ...state.to }, + to: { ...action.data }, + } + default: + return state } } type NoticeArgs = { noticeId: string; progress: number } -const noticesReducer = (state: Array = [], action: { - type: string; - data: NoticeMessageInState | NoticeArgs; -}): Array => { - switch (action.type) { - case ADD_NOTICE: { - const notices = [action.data as NoticeMessageInState] - return notices - } - case DROP_NOTICE: { - return state.filter((notice) => notice.id !== (action.data as NoticeArgs).noticeId) - } - case SET_NOTICE_PROGRESS: { - return state.map((notice) => ({ - ...notice, - progress: notice.id === (action.data as NoticeArgs).noticeId - ? action.data.progress - : notice.progress, - })) +const noticesReducer = ( + state: Array = [], + action: { + type: string + data: NoticeMessageInState | NoticeArgs } - default: return state +): Array => { + switch (action.type) { + case ADD_NOTICE: { + const notices = [action.data as NoticeMessageInState] + return notices + } + case DROP_NOTICE: { + return state.filter((notice) => notice.id !== (action.data as NoticeArgs).noticeId) + } + case SET_NOTICE_PROGRESS: { + return state.map((notice) => ({ + ...notice, + progress: notice.id === (action.data as NoticeArgs).noticeId ? action.data.progress : notice.progress, + })) + } + default: + return state } } export type ReduxState = { - resources: Array; - branding: BrandingOptions; - assets: Assets; - paths: Paths; - session: CurrentAdmin | null; - dashboard: DashboardInState; - notices: Array; - versions: VersionProps; - pages: Array; - locale: Locale; - router: RouterProps; + resources: Array + branding: BrandingOptions + assets: Assets + paths: Paths + session: CurrentAdmin | null + dashboard: DashboardInState + notices: Array + versions: VersionProps + pages: Array + locale: Locale + router: RouterProps } const reducer = combineReducers({ From daea8d6b9ee406936432c75afbda93d719f157f5 Mon Sep 17 00:00:00 2001 From: Adama Camara Date: Wed, 28 Sep 2022 15:05:23 -0300 Subject: [PATCH 2/3] added isVisible to page props --- src/adminjs-options.interface.ts | 7 +- .../components/actions/action.props.ts | 14 +- .../interfaces/page-json.interface.ts | 8 + src/frontend/store/pages-to-store.ts | 5 +- src/frontend/store/store.ts | 265 ++++++++---------- 5 files changed, 144 insertions(+), 155 deletions(-) diff --git a/src/adminjs-options.interface.ts b/src/adminjs-options.interface.ts index 33ee9fe86..207bc94ba 100644 --- a/src/adminjs-options.interface.ts +++ b/src/adminjs-options.interface.ts @@ -3,7 +3,7 @@ import { TransformOptions as BabelConfig } from 'babel-core' import BaseResource from './backend/adapters/resource/base-resource' import BaseDatabase from './backend/adapters/database/base-database' -import { PageContext } from './backend/actions/action.interface' +import { IsFunction, PageContext } from './backend/actions/action.interface' import { ResourceOptions } from './backend/decorators/resource/resource-options.interface' import { Locale } from './locale/config' import { CurrentAdmin } from './current-admin.interface' @@ -389,6 +389,11 @@ export type AdminPage = { * Page icon */ icon?: string; + + /** + * Page visibility + */ + isVisible?: boolean | IsFunction } /** diff --git a/src/frontend/components/actions/action.props.ts b/src/frontend/components/actions/action.props.ts index 5e4a73a58..73d998136 100644 --- a/src/frontend/components/actions/action.props.ts +++ b/src/frontend/components/actions/action.props.ts @@ -1,5 +1,5 @@ import { Dispatch, SetStateAction } from 'react' -import { ActionJSON, RecordJSON, ResourceJSON, PageJSON } from '../../interfaces' +import { ActionJSON, RecordJSON, ResourceJSON } from '../../interfaces' /** * Props which are passed to all action components @@ -10,23 +10,23 @@ export type ActionProps = { /** * Action object describing the action */ - action: ActionJSON + action: ActionJSON; /** * Object of type: {@link ResourceJSON} */ - resource: ResourceJSON + resource: ResourceJSON; /** * Selected record. Passed for actions with "record" actionType */ - record?: RecordJSON + record?: RecordJSON; /** * Selected records. Passed for actions with "bulk" actionType */ - records?: Array + records?: Array; /** * Sets tag in a header of an action. It is a function taking tag as an argument */ - setTag?: Dispatch> -} + setTag?: Dispatch>; +} \ No newline at end of file diff --git a/src/frontend/interfaces/page-json.interface.ts b/src/frontend/interfaces/page-json.interface.ts index 491d81b51..ccbc13cb5 100644 --- a/src/frontend/interfaces/page-json.interface.ts +++ b/src/frontend/interfaces/page-json.interface.ts @@ -1,3 +1,6 @@ +import { IsFunction } from 'src/backend' +import { ActionJSON } from './action' + /** * Representing the page in the sidebar * @subcategory Frontend @@ -16,4 +19,9 @@ export interface PageJSON { * Page icon */ icon?: string; + + /** + * Page visibility + */ + isVisible: boolean | IsFunction; } diff --git a/src/frontend/store/pages-to-store.ts b/src/frontend/store/pages-to-store.ts index 844a213a0..7d6c02289 100644 --- a/src/frontend/store/pages-to-store.ts +++ b/src/frontend/store/pages-to-store.ts @@ -2,11 +2,12 @@ import { AdminJSOptions } from '../../adminjs-options.interface' import { PageJSON } from '../interfaces' -const pagesToStore = (pages: AdminJSOptions['pages'] = {}): Array => Object.entries(pages) - .map(([key, adminPage]) => ({ +const pagesToStore = (pages: AdminJSOptions['pages'] = {}): Array => + Object.entries(pages).map(([key, adminPage]) => ({ name: key, component: adminPage.component, icon: adminPage.icon, + isVisible: adminPage.isVisible, })) export default pagesToStore diff --git a/src/frontend/store/store.ts b/src/frontend/store/store.ts index 783fe7711..faa7185b8 100644 --- a/src/frontend/store/store.ts +++ b/src/frontend/store/store.ts @@ -17,8 +17,7 @@ import { DROP_NOTICE, ADD_NOTICE, ROUTE_CHANGED, - INITIAL_ROUTE, -} from './actions' + INITIAL_ROUTE } from './actions' import { Assets, BrandingOptions, VersionProps } from '../../adminjs-options.interface' import { PageJSON, ResourceJSON } from '../interfaces' @@ -28,223 +27,199 @@ import { Locale } from '../../locale/config' import { NoticeMessage } from '../hoc/with-notice' export type DashboardInState = { - component?: string + component?: string; } export type NoticeMessageInState = NoticeMessage & { - message: string - id: string - type: NoticeMessage['type'] - progress: number + message: string; + id: string; + type: NoticeMessage['type']; + progress: number; } export type Paths = { - rootPath: string - logoutPath: string - loginPath: string - assetsCDN?: string + rootPath: string; + logoutPath: string; + loginPath: string; + assetsCDN?: string; } const resourcesReducer = ( state: Array = [], action: { - type: string - data: Array - } + type: string; + data: Array; + }, ) => { switch (action.type) { - case RESOURCES_INITIALIZE: - return action.data - default: - return state + case RESOURCES_INITIALIZE: + return action.data + default: return state } } const pagesReducer = ( state: Array = [], action: { - type: string - data: Array - } + type: string; + data: Array; + }, ) => { switch (action.type) { - case PAGES_INITIALIZE: - return action.data - default: - return state + case PAGES_INITIALIZE: + return action.data + default: return state } } const localesReducer = ( state: Locale = { language: 'en', translations: {} } as Locale, action: { - type: string - data: Locale - } + type: string; + data: Locale; + }, ) => { switch (action.type) { - case LOCALE_INITIALIZE: - return action.data - default: - return state + case LOCALE_INITIALIZE: + return action.data + default: return state } } -const brandingReducer = ( - state = {}, - action: { - type: string - data: BrandingOptions - } -) => { +const brandingReducer = (state = {}, action: { + type: string; + data: BrandingOptions; +}) => { switch (action.type) { - case BRANDING_INITIALIZE: - return action.data - default: - return state + case BRANDING_INITIALIZE: + return action.data + default: return state } } -const assetsReducer = ( - state = {}, - action: { - type: string - data: Assets - } -) => { +const assetsReducer = (state = {}, action: { + type: string; + data: Assets; +}) => { switch (action.type) { - case ASSETS_INITIALIZE: - return action.data - default: - return state + case ASSETS_INITIALIZE: + return action.data + default: return state } } -const pathsReducer = (state: Paths = DEFAULT_PATHS, action: { type: string; data: Paths }): Paths => { +const pathsReducer = ( + state: Paths = DEFAULT_PATHS, + action: {type: string; data: Paths}, +): Paths => { switch (action.type) { - case PATHS_INITIALIZE: - return action.data - default: - return state + case PATHS_INITIALIZE: + return action.data + default: return state } } -const dashboardReducer = ( - state = {}, - action: { - type: string - data: DashboardInState - } -): DashboardInState => { +const dashboardReducer = (state = {}, action: { + type: string; + data: DashboardInState; +}): DashboardInState => { switch (action.type) { - case DASHBOARD_INITIALIZE: - return action.data - default: - return state + case DASHBOARD_INITIALIZE: + return action.data + default: return state } } const sessionReducer = ( state: CurrentAdmin | null = null, action: { - type: string - data: CurrentAdmin | null - } + type: string; + data: CurrentAdmin | null; + }, ) => { switch (action.type) { - case SESSION_INITIALIZE: - return action.data - default: - return state + case SESSION_INITIALIZE: + return action.data + default: return state } } -const versionsReducer = ( - state = {}, - action: { - type: string - data: VersionProps - } -) => { +const versionsReducer = (state = {}, action: { + type: string; + data: VersionProps; +}) => { switch (action.type) { - case VERSIONS_INITIALIZE: - return { - admin: action.data.admin, - app: action.data.app, - } - default: - return state + case VERSIONS_INITIALIZE: + return { + admin: action.data.admin, + app: action.data.app, + } + default: return state } } export type RouterProps = { - from: Partial> - to: Partial> + from: Partial>; + to: Partial>; } -const routerReducer = ( - state: RouterProps = { from: {}, to: {} }, - action: { - type: string - data: any - } -) => { +const routerReducer = (state: RouterProps = { from: {}, to: {} }, action: { + type: string; + data: any; +}) => { switch (action.type) { - case INITIAL_ROUTE: - return { - ...state, - from: { ...action.data }, - } - case ROUTE_CHANGED: - return { - from: { ...state.to }, - to: { ...action.data }, - } - default: - return state + case INITIAL_ROUTE: + return { + ...state, + from: { ...action.data }, + } + case ROUTE_CHANGED: + return { + from: { ...state.to }, + to: { ...action.data }, + } + default: return state } } type NoticeArgs = { noticeId: string; progress: number } -const noticesReducer = ( - state: Array = [], - action: { - type: string - data: NoticeMessageInState | NoticeArgs - } -): Array => { +const noticesReducer = (state: Array = [], action: { + type: string; + data: NoticeMessageInState | NoticeArgs; +}): Array => { switch (action.type) { - case ADD_NOTICE: { - const notices = [action.data as NoticeMessageInState] - return notices - } - case DROP_NOTICE: { - return state.filter((notice) => notice.id !== (action.data as NoticeArgs).noticeId) - } - case SET_NOTICE_PROGRESS: { - return state.map((notice) => ({ - ...notice, - progress: notice.id === (action.data as NoticeArgs).noticeId ? action.data.progress : notice.progress, - })) - } - default: - return state + case ADD_NOTICE: { + const notices = [action.data as NoticeMessageInState] + return notices + } + case DROP_NOTICE: { + return state.filter((notice) => notice.id !== (action.data as NoticeArgs).noticeId) + } + case SET_NOTICE_PROGRESS: { + return state.map((notice) => ({ + ...notice, + progress: notice.id === (action.data as NoticeArgs).noticeId + ? action.data.progress + : notice.progress, + })) + } + default: return state } } export type ReduxState = { - resources: Array - branding: BrandingOptions - assets: Assets - paths: Paths - session: CurrentAdmin | null - dashboard: DashboardInState - notices: Array - versions: VersionProps - pages: Array - locale: Locale - router: RouterProps + resources: Array; + branding: BrandingOptions; + assets: Assets; + paths: Paths; + session: CurrentAdmin | null; + dashboard: DashboardInState; + notices: Array; + versions: VersionProps; + pages: Array; + locale: Locale; + router: RouterProps; } const reducer = combineReducers({ From 0bd62909ba7f02f74dd0a5fe01df58cc28c39be2 Mon Sep 17 00:00:00 2001 From: Adama Camara Date: Sun, 2 Oct 2022 14:52:19 -0300 Subject: [PATCH 3/3] addressed comments --- .../interfaces/page-json.interface.ts | 2 +- src/frontend/store/pages-to-store.ts | 22 ++++++++++++++----- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/frontend/interfaces/page-json.interface.ts b/src/frontend/interfaces/page-json.interface.ts index ccbc13cb5..4bf7e9517 100644 --- a/src/frontend/interfaces/page-json.interface.ts +++ b/src/frontend/interfaces/page-json.interface.ts @@ -23,5 +23,5 @@ export interface PageJSON { /** * Page visibility */ - isVisible: boolean | IsFunction; + isVisible: boolean; } diff --git a/src/frontend/store/pages-to-store.ts b/src/frontend/store/pages-to-store.ts index 7d6c02289..7b9be0656 100644 --- a/src/frontend/store/pages-to-store.ts +++ b/src/frontend/store/pages-to-store.ts @@ -3,11 +3,21 @@ import { AdminJSOptions } from '../../adminjs-options.interface' import { PageJSON } from '../interfaces' const pagesToStore = (pages: AdminJSOptions['pages'] = {}): Array => - Object.entries(pages).map(([key, adminPage]) => ({ - name: key, - component: adminPage.component, - icon: adminPage.icon, - isVisible: adminPage.isVisible, - })) + Object.entries(pages).map(([key, adminPage]) => { + let isVisible = true; + if (adminPage.isVisible) { + if (typeof adminPage.isVisible === 'function') { + isVisible = adminPage.isVisible({ currentAdmin }) + } else { + isVisible = adminPage.isVisible + } + } + return { + name: key, + component: adminPage.component, + icon: adminPage.icon, + isVisible, + } + }); export default pagesToStore