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..d04671645 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({ @@ -261,4 +236,4 @@ const reducer = combineReducers({ router: routerReducer, }) -export default (initialState = {}) => createStore(reducer, initialState) +export default (initialState = {}) => createStore(reducer, initialState) \ No newline at end of file