Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shell 138 improve standalone #326

Merged
merged 5 commits into from
Oct 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/boot/app/app-loader-functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ import {
useUserRight,
useUserRights,
getUserRight,
getUserRights
getUserRights,
useAuthenticated
} from '../../store/account';
import { getApp, getAppContext, useApp, useAppContext } from '../../store/app';
import {
Expand Down Expand Up @@ -122,6 +123,8 @@ export const getAppFunctions = (pkg: CarbonioModule): Record<string, Function> =
getActionsFactory,
useActionFactory,
getActionFactory,
// AUTH
useAuthenticated,
// ACCOUNTS
useUserAccount,
getUserAccount,
Expand Down
4 changes: 3 additions & 1 deletion src/boot/app/shared-libraries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import React from 'react';
import * as ReduxJSToolkit from '@reduxjs/toolkit';
import * as ZappUI from '@zextras/carbonio-design-system';
import * as Preview from '@zextras/carbonio-ui-preview';
import * as Darkreader from 'darkreader';
import * as Lodash from 'lodash';
import * as Moment from 'moment';
import * as ReactDOM from 'react-dom';
Expand All @@ -31,7 +32,8 @@ export function injectSharedLibraries(): void {
'@reduxjs/toolkit': ReduxJSToolkit,
'@zextras/carbonio-shell-ui': {},
'@zextras/carbonio-design-system': ZappUI,
'@zextras/carbonio-ui-preview': Preview
'@zextras/carbonio-ui-preview': Preview,
darkreader: Darkreader
};
window.__ZAPP_HMR_EXPORT__ = {};
}
Expand Down
10 changes: 5 additions & 5 deletions src/boot/bootstrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ import { ContextBridge } from './context-bridge';
import { Loader } from './loader';
import ShellI18nextProvider from './shell-i18n-provider';
import { ThemeProvider } from './theme-provider';
import { BASENAME, IS_STANDALONE } from '../constants';
import { BASENAME, IS_FOCUS_MODE } from '../constants';
import { NotificationPermissionChecker } from '../notification/NotificationPermissionChecker';
import ShellView from '../shell/shell-view';
import { useAppStore } from '../store/app';

const StandaloneListener = (): null => {
const FocusModeListener = (): null => {
const { route } = useParams<{ route?: string }>();
useEffect(() => {
if (route) useAppStore.setState({ standalone: route });
if (route) useAppStore.setState({ focusMode: route });
}, [route]);
return null;
};
Expand All @@ -44,10 +44,10 @@ const Bootstrapper: FC = () => (
<SnackbarManager>
<ModalManager>
<Loader />
{IS_STANDALONE && (
{IS_FOCUS_MODE && (
<Switch>
<Route path={'/:route'}>
<StandaloneListener />
<FocusModeListener />
</Route>
</Switch>
)}
Expand Down
5 changes: 4 additions & 1 deletion src/boot/loader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { find } from 'lodash';
import { useTranslation } from 'react-i18next';

import { loadApps, unloadAllApps } from './app/load-apps';
import { IS_FOCUS_MODE } from '../constants';
import { getComponents } from '../network/get-components';
import { getInfo } from '../network/get-info';
import { loginConfig } from '../network/login-config';
Expand Down Expand Up @@ -80,7 +81,9 @@ export const Loader = (): React.JSX.Element => {
} else if ('message' in promiseRejectedResult.reason) {
console.error(promiseRejectedResult.reason.message);
}
setOpen(true);
if (!IS_FOCUS_MODE) {
setOpen(true);
}
}
if (isPromiseFulfilledResult(getComponentsPromiseSettledResult)) {
loadApps(Object.values(useAppStore.getState().apps));
Expand Down
6 changes: 3 additions & 3 deletions src/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,10 @@ export const darkReaderDynamicThemeFixes: DynamicThemeFix = {

const base = '/carbonio/';

const standaloneBase = `${base}standalone`;
const focusModeBase = `${base}focus-mode`;

export const IS_STANDALONE = window.location.pathname.startsWith(standaloneBase);
export const BASENAME = IS_STANDALONE ? standaloneBase : base;
export const IS_FOCUS_MODE = window.location.pathname.startsWith(focusModeBase);
export const BASENAME = IS_FOCUS_MODE ? focusModeBase : base;
export const EMAIL_VALIDATION_REGEX =
// eslint-disable-next-line @typescript-eslint/no-unused-vars, max-len, no-control-regex
/(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])/;
Expand Down
4 changes: 2 additions & 2 deletions src/network/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
SoapContext,
SoapResponse
} from '../../types';
import { IS_STANDALONE, SHELL_APP_ID } from '../constants';
import { IS_FOCUS_MODE, SHELL_APP_ID } from '../constants';
import { report } from '../reporting/functions';
import { useAccountStore } from '../store/account';
import { useNetworkStore } from '../store/network';
Expand Down Expand Up @@ -103,7 +103,7 @@ const handleResponse = <R>(api: string, res: SoapResponse<R>): R | ErrorSoapBody
(code) => code === (<ErrorSoapResponse>res).Body.Fault.Detail?.Error?.Code
)
) {
if (IS_STANDALONE) {
if (IS_FOCUS_MODE) {
useAccountStore.setState({ authenticated: false });
} else {
goToLogin();
Expand Down
3 changes: 2 additions & 1 deletion src/shell/app-view-container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@ import { Redirect, Route, Switch, useLocation } from 'react-router-dom';
import styled from 'styled-components';

import AppContextProvider from '../boot/app/app-context-provider';
import { IS_FOCUS_MODE } from '../constants';
import { useAppList, useAppStore, useRoutes } from '../store/app';

const _BoardsRouterContainer = styled(Container)`
flex-grow: 1;
flex-basis: 0;
min-width: 0.0625rem;
max-height: calc(100vh - 3.75rem);
max-height: ${IS_FOCUS_MODE ? '100vh' : 'calc(100vh - 3.75rem)'};
overflow-y: auto;
`;

Expand Down
11 changes: 1 addition & 10 deletions src/shell/shell-primary-bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,7 @@ import styled from 'styled-components';
import BadgeWrap from './badge-wrap';
import { PrimaryAccessoryView, PrimaryBarView } from '../../types';
import AppContextProvider from '../boot/app/app-context-provider';
import {
BOARD_CONTAINER_ZINDEX,
IS_STANDALONE,
PRIMARY_BAR_WIDTH,
SEARCH_APP_ID
} from '../constants';
import { BOARD_CONTAINER_ZINDEX, PRIMARY_BAR_WIDTH, SEARCH_APP_ID } from '../constants';
import { useCurrentRoute } from '../history/hooks';
import { useAppStore } from '../store/app';
import { minimizeBoards, reopenBoards, useBoardStore } from '../store/boards';
Expand Down Expand Up @@ -155,10 +150,6 @@ const ShellPrimaryBar = (): React.JSX.Element | null => {
[accessoryViews]
);

if (IS_STANDALONE && activeRoute?.standalone?.hidePrimaryBar) {
return null;
}

return (
<PrimaryBarContainer
width={PRIMARY_BAR_WIDTH}
Expand Down
80 changes: 26 additions & 54 deletions src/shell/shell-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,8 @@ import ShellHeader from './shell-header';
import ShellPrimaryBar from './shell-primary-bar';
import ShellSecondaryBar from './shell-secondary-bar';
import { ThemeCallbacksContext } from '../boot/theme-provider';
import { IS_STANDALONE } from '../constants';
import { IS_FOCUS_MODE } from '../constants';
import { useDarkReaderResultValue } from '../dark-mode/use-dark-reader-result-value';
import { useCurrentRoute } from '../history/hooks';
import { goToLogin } from '../network/utils';
import { useAccountStore } from '../store/account';
import { ShellUtilityBar } from '../utility-bar/bar';
import { ShellUtilityPanel } from '../utility-bar/panel';

Expand All @@ -48,37 +45,19 @@ function DarkReaderListener(): null {
return null;
}

const useLoginRedirection = (allowUnauthenticated?: boolean): void => {
const auth = useAccountStore((s) => s.authenticated);
useEffect(() => {
if (IS_STANDALONE && !auth && !allowUnauthenticated) {
goToLogin();
}
}, [allowUnauthenticated, auth]);
};

interface ShellComponentProps {
allowUnauthenticated?: boolean;
hideShellHeader?: boolean;
}

const ShellComponent = ({
allowUnauthenticated,
hideShellHeader
}: ShellComponentProps): React.JSX.Element => {
useLoginRedirection(allowUnauthenticated);
return (
<Background>
<DarkReaderListener />
{!(IS_STANDALONE && hideShellHeader) && (
<ShellHeader>
<ShellUtilityBar />
</ShellHeader>
)}
<Row crossAlignment="unset" style={{ position: 'relative', flexGrow: '1' }}>
const ShellComponent = (): React.JSX.Element => (
<Background>
<DarkReaderListener />
{!IS_FOCUS_MODE && (
<ShellHeader>
<ShellUtilityBar />
</ShellHeader>
)}
<Row crossAlignment="unset" style={{ position: 'relative', flexGrow: '1' }}>
{!IS_FOCUS_MODE && (
<Container
orientation="horizontal"
background="gray5"
background={'gray5'}
width="fit"
height="fill"
mainAlignment="flex-start"
Expand All @@ -87,27 +66,20 @@ const ShellComponent = ({
<ShellPrimaryBar />
<ShellSecondaryBar />
</Container>
<AppViewContainer />
<ShellUtilityPanel />
</Row>
<BoardContainer />
</Background>
);
};

const MemoShell = React.memo(ShellComponent);
)}
<AppViewContainer />
<ShellUtilityPanel />
</Row>
<BoardContainer />
</Background>
);

const ShellView = (): React.JSX.Element => {
const activeRoute = useCurrentRoute();
const allowUnauthenticated = activeRoute?.standalone?.allowUnauthenticated;
const hideShellHeader = activeRoute?.standalone?.hideShellHeader;
return (
<ShellContextProvider>
<PreviewManager>
<MemoShell allowUnauthenticated={allowUnauthenticated} hideShellHeader={hideShellHeader} />
</PreviewManager>
</ShellContextProvider>
);
};
const ShellView = (): React.JSX.Element => (
<ShellContextProvider>
<PreviewManager>
<ShellComponent />
</PreviewManager>
</ShellContextProvider>
);

export default ShellView;
15 changes: 11 additions & 4 deletions src/store/account/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import {
AccountSettings
} from '../../../types';

export const useAuthenticated = (): boolean => useAccountStore((s) => s.authenticated);

export const useUserAccount = (): Account => useAccountStore((s) => s.account as Account);
export const useUserAccounts = (): Array<Account> => {
const acct = useAccountStore((s) => s.account);
Expand All @@ -37,10 +39,15 @@ export const useUserSettings = (): AccountSettings => useAccountStore((s) => s.s
export const useUserSetting = <T = void>(...path: Array<string>): string | T =>
useAccountStore((s) => get(s.settings, join(path, '.')));

export const getUserAccount = (): Account => useAccountStore.getState().account as Account;
export const getUserAccounts = (): Array<Account> => [
useAccountStore.getState().account as Account
];
export const getUserAccount = (): Account | undefined => useAccountStore.getState().account;
export const getUserAccounts = (): Array<Account> => {
const { account } = useAccountStore.getState();
const accounts: Account[] = [];
if (account) {
accounts.push(account);
}
return accounts;
};
export const getUserSettings = (): AccountSettings => useAccountStore.getState().settings;
export const getUserSetting = <T = void>(...path: Array<string>): string | T =>
get(useAccountStore.getState().settings, join(path, '.'));
Expand Down
24 changes: 12 additions & 12 deletions src/store/app/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { normalizeApp } from './utils';
import type { AppState, CarbonioModule } from '../../../types';
import { SHELL_APP_ID } from '../../constants';

const STANDALONE_RESPONSE = 'standalone';
const FOCUS_MODE_RESPONSE = 'focus-mode';

function addIfNotPresent<T extends { id: unknown }>(
items: T[],
Expand Down Expand Up @@ -42,7 +42,7 @@ function removeById<T extends { id: unknown }>(items: T[], id: unknown): void {

// extra currying as suggested in https://github.com/pmndrs/zustand/blob/main/docs/guides/typescript.md#basic-usage
export const useAppStore = create<AppState>()((set, get) => ({
standalone: false,
focusMode: false,
apps: {},
appContexts: {},
shell: {
Expand Down Expand Up @@ -114,14 +114,14 @@ export const useAppStore = create<AppState>()((set, get) => ({
},
// add route (id route primaryBar secondaryBar app)
addRoute: (routeData): string => {
const { standalone } = get();
if (standalone && routeData.route !== standalone) {
return STANDALONE_RESPONSE;
const { focusMode } = get();
if (focusMode && (routeData.route !== focusMode || !routeData.focusMode)) {
return FOCUS_MODE_RESPONSE;
}
set(
produce<AppState>((state) => {
state.routes[routeData.id] = routeData;
if (routeData.primaryBar) {
if (routeData.primaryBar && !routeData.focusMode) {
addAndSort(state.views.primaryBar, {
app: routeData.app,
id: routeData.id,
Expand Down Expand Up @@ -199,9 +199,9 @@ export const useAppStore = create<AppState>()((set, get) => ({

// add settings
addSettingsView: (data): string => {
const { standalone } = get();
if (standalone && data.route !== standalone) {
return STANDALONE_RESPONSE;
const { focusMode } = get();
if (focusMode && data.route !== focusMode) {
return FOCUS_MODE_RESPONSE;
}
set(
produce<AppState>((state) => {
Expand All @@ -222,9 +222,9 @@ export const useAppStore = create<AppState>()((set, get) => ({
//
// add search
addSearchView: (data): string => {
const { standalone } = get();
if (standalone && data.route !== standalone) {
return STANDALONE_RESPONSE;
const { focusMode } = get();
if (focusMode && data.route !== focusMode) {
return FOCUS_MODE_RESPONSE;
}
set(
produce<AppState>((state) => {
Expand Down
6 changes: 1 addition & 5 deletions src/store/app/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,7 @@ export const normalizeRoute = (
primaryBar: data.primaryBar ?? app.icon ?? 'CubeOutline',
secondaryBar: data.secondaryBar,
appView: data.appView ?? FallbackView,
standalone: {
hidePrimaryBar: data?.standalone?.hidePrimaryBar,
hideShellHeader: data?.standalone?.hideShellHeader,
allowUnauthenticated: data?.standalone?.allowUnauthenticated
}
focusMode: data.focusMode
};
};

Expand Down
2 changes: 1 addition & 1 deletion src/utility-bar/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const checkRoute = (
view: UtilityView | PrimaryAccessoryView | SecondaryAccessoryView,
activeRoute?: AppRoute
): boolean => {
const activeRouteValues = Object.values(omit(activeRoute, 'standalone') ?? {});
const activeRouteValues = Object.values(omit(activeRoute, 'focusMode') ?? {});
if (view.blacklistRoutes) return !checkList(activeRouteValues, view.blacklistRoutes);
if (view.whitelistRoutes) return checkList(activeRouteValues, view.whitelistRoutes);
return true;
Expand Down
Loading