Compare commits

...

14 Commits

Author SHA1 Message Date
Ali BARIN
321019d36a sample js usage in ts 2023-12-22 12:24:32 +00:00
QAComet
d070e976b0 test(e2e-tests): run only on relevant changes in pull requests (#1495) 2023-12-15 18:51:58 +01:00
Ali BARIN
0caf6bfabb Merge pull request #1494 from automatisch/aut-551
feat: hide notifications page in mation instances
2023-12-15 18:00:08 +01:00
Ali BARIN
b842d7938f feat: hide notifications page in mation instances 2023-12-15 16:28:41 +00:00
Ali BARIN
cebbf84375 Merge pull request #1491 from automatisch/aut-548
feat: apply conditional mation styling
2023-12-15 11:40:12 +01:00
Ali BARIN
8608431490 feat: add conditional mation logo by default 2023-12-14 15:59:37 +00:00
Ali BARIN
78ba18b176 feat: apply conditional mation styling 2023-12-14 14:28:07 +00:00
Ali BARIN
f8c30c8526 Merge pull request #1475 from automatisch/aut-547
feat(queries/getAutomatischInfo): add mation
2023-12-14 11:15:35 +01:00
QAComet
693c9b85a5 test: run UI workflow only on changes outside of backend apps (#1462) 2023-12-14 10:45:15 +01:00
Ali BARIN
70bb7defd1 feat(queries/getAutomatischInfo): add mation 2023-12-12 17:37:27 +00:00
Ali BARIN
160377ca31 Merge pull request #1473 from automatisch/aut-545
docs(salesforce): update connection steps
2023-12-12 18:17:07 +01:00
Ali BARIN
2c0ce77a4e docs(salesforce): update connection steps 2023-12-12 17:08:15 +00:00
Ali BARIN
77fbb0c9da Merge pull request #1470 from automatisch/aut-538
fix(odoo): introduce secure connection option
2023-12-11 16:44:11 +01:00
Ali BARIN
5971425d23 fix(odoo): introduce secure connection option 2023-12-11 15:36:50 +00:00
23 changed files with 248 additions and 34 deletions

View File

@@ -4,6 +4,11 @@ on:
branches: branches:
- main - main
pull_request: pull_request:
paths:
- 'packages/backend/**'
- 'packages/e2e-tests/**'
- 'packages/web/**'
- '!packages/backend/src/apps/**'
workflow_dispatch: workflow_dispatch:
env: env:

View File

@@ -11,7 +11,7 @@ export default {
readOnly: false, readOnly: false,
value: null, value: null,
placeholder: null, placeholder: null,
description: 'Host name of your Odoo Server', description: 'Host name of your Odoo Server (e.g. sub.domain.com without the protocol)',
clickToCopy: false, clickToCopy: false,
}, },
{ {
@@ -25,6 +25,27 @@ export default {
description: 'Port that the host is running on, defaults to 443 (HTTPS)', description: 'Port that the host is running on, defaults to 443 (HTTPS)',
clickToCopy: false, clickToCopy: false,
}, },
{
key: 'secure',
label: 'Secure',
type: 'dropdown' as const,
required: true,
readOnly: false,
value: 'true',
description: 'True if the host communicates via secure protocol.',
variables: false,
clickToCopy: false,
options: [
{
label: 'True',
value: 'true',
},
{
label: 'False',
value: 'false',
},
],
},
{ {
key: 'databaseName', key: 'databaseName',
label: 'Database Name', label: 'Database Name',
@@ -40,7 +61,7 @@ export default {
key: 'email', key: 'email',
label: 'Email Address', label: 'Email Address',
type: 'string' as const, type: 'string' as const,
requires: true, required: true,
readOnly: false, readOnly: false,
value: null, value: null,
placeholder: null, placeholder: null,

View File

@@ -32,8 +32,10 @@ export const asyncMethodCall = async <T = number>($: IGlobalVariable, { method,
export const getClient = ($: IGlobalVariable, { path = 'common' }) => { export const getClient = ($: IGlobalVariable, { path = 'common' }) => {
const host = $.auth.data.host as string; const host = $.auth.data.host as string;
const port = Number($.auth.data.port as string); const port = Number($.auth.data.port as string);
const secure = $.auth.data.secure === 'true';
const createClientFunction = secure ? xmlrpc.createSecureClient : xmlrpc.createClient;
return xmlrpc.createClient( return createClientFunction(
{ {
host, host,
port, port,

View File

@@ -49,6 +49,7 @@ type AppConfig = {
smtpPassword: string; smtpPassword: string;
fromEmail: string; fromEmail: string;
isCloud: boolean; isCloud: boolean;
isMation: boolean;
isSelfHosted: boolean; isSelfHosted: boolean;
paddleVendorId: number; paddleVendorId: number;
paddleVendorAuthCode: string; paddleVendorAuthCode: string;
@@ -127,6 +128,7 @@ const appConfig: AppConfig = {
fromEmail: process.env.FROM_EMAIL, fromEmail: process.env.FROM_EMAIL,
isCloud: process.env.AUTOMATISCH_CLOUD === 'true', isCloud: process.env.AUTOMATISCH_CLOUD === 'true',
isSelfHosted: process.env.AUTOMATISCH_CLOUD !== 'true', isSelfHosted: process.env.AUTOMATISCH_CLOUD !== 'true',
isMation: process.env.MATION === 'true',
paddleVendorId: Number(process.env.PADDLE_VENDOR_ID), paddleVendorId: Number(process.env.PADDLE_VENDOR_ID),
paddleVendorAuthCode: process.env.PADDLE_VENDOR_AUTH_CODE, paddleVendorAuthCode: process.env.PADDLE_VENDOR_AUTH_CODE,
paddlePublicKey: process.env.PADDLE_PUBLIC_KEY, paddlePublicKey: process.env.PADDLE_PUBLIC_KEY,

View File

@@ -9,6 +9,7 @@ describe('graphQL getAutomatischInfo query', () => {
query { query {
getAutomatischInfo { getAutomatischInfo {
isCloud isCloud
isMation
license { license {
id id
name name
@@ -24,6 +25,7 @@ describe('graphQL getAutomatischInfo query', () => {
jest.spyOn(license, 'getLicense').mockResolvedValue(false); jest.spyOn(license, 'getLicense').mockResolvedValue(false);
jest.replaceProperty(appConfig, 'isCloud', false); jest.replaceProperty(appConfig, 'isCloud', false);
jest.replaceProperty(appConfig, 'isMation', false);
}); });
it('should return empty license data', async () => { it('should return empty license data', async () => {
@@ -36,6 +38,7 @@ describe('graphQL getAutomatischInfo query', () => {
data: { data: {
getAutomatischInfo: { getAutomatischInfo: {
isCloud: false, isCloud: false,
isMation: false,
license: { license: {
id: null, id: null,
name: null, name: null,
@@ -77,6 +80,7 @@ describe('graphQL getAutomatischInfo query', () => {
data: { data: {
getAutomatischInfo: { getAutomatischInfo: {
isCloud: true, isCloud: true,
isMation: false,
license: { license: {
expireAt: '2025-08-09T10:56:54.144Z', expireAt: '2025-08-09T10:56:54.144Z',
id: '123123', id: '123123',
@@ -105,6 +109,69 @@ describe('graphQL getAutomatischInfo query', () => {
const expectedResponsePayload = { const expectedResponsePayload = {
data: { data: {
getAutomatischInfo: { getAutomatischInfo: {
isCloud: false,
isMation: false,
license: {
expireAt: '2025-08-09T10:56:54.144Z',
id: '123123',
name: 'Test License',
verified: true,
},
},
},
};
expect(response.body).toEqual(expectedResponsePayload);
});
});
describe('and with mation flag enabled', () => {
beforeEach(async () => {
jest.replaceProperty(appConfig, 'isCloud', false);
jest.replaceProperty(appConfig, 'isMation', true);
});
it('should return all license data', async () => {
const response = await request(app)
.post('/graphql')
.send({ query })
.expect(200);
const expectedResponsePayload = {
data: {
getAutomatischInfo: {
isCloud: false,
isMation: true,
license: {
expireAt: '2025-08-09T10:56:54.144Z',
id: '123123',
name: 'Test License',
verified: true,
},
},
},
};
expect(response.body).toEqual(expectedResponsePayload);
});
});
describe('and with mation flag disabled', () => {
beforeEach(async () => {
jest.replaceProperty(appConfig, 'isCloud', false);
jest.replaceProperty(appConfig, 'isMation', false);
});
it('should return all license data', async () => {
const response = await request(app)
.post('/graphql')
.send({ query })
.expect(200);
const expectedResponsePayload = {
data: {
getAutomatischInfo: {
isMation: false,
isCloud: false, isCloud: false,
license: { license: {
expireAt: '2025-08-09T10:56:54.144Z', expireAt: '2025-08-09T10:56:54.144Z',

View File

@@ -13,6 +13,7 @@ const getAutomatischInfo = async () => {
return { return {
isCloud: appConfig.isCloud, isCloud: appConfig.isCloud,
isMation: appConfig.isMation,
license: computedLicense, license: computedLicense,
}; };
}; };

View File

@@ -0,0 +1,10 @@
import appConfig from '../../config/app';
const getUseJsFile = async () => {
return {
canInvoke: true,
appConfig,
};
};
export default getUseJsFile;

View File

@@ -6,6 +6,7 @@ import getApps from './queries/get-apps';
import getAutomatischInfo from './queries/get-automatisch-info'; import getAutomatischInfo from './queries/get-automatisch-info';
import getBillingAndUsage from './queries/get-billing-and-usage.ee'; import getBillingAndUsage from './queries/get-billing-and-usage.ee';
import getConfig from './queries/get-config.ee'; import getConfig from './queries/get-config.ee';
import getUseJsFile from './queries/get-use-js-file.js';
import getConnectedApps from './queries/get-connected-apps'; import getConnectedApps from './queries/get-connected-apps';
import getCurrentUser from './queries/get-current-user'; import getCurrentUser from './queries/get-current-user';
import getDynamicData from './queries/get-dynamic-data'; import getDynamicData from './queries/get-dynamic-data';
@@ -68,6 +69,7 @@ const queryResolvers = {
healthcheck, healthcheck,
listSamlAuthProviders, listSamlAuthProviders,
testConnection, testConnection,
getUseJsFile,
}; };
export default queryResolvers; export default queryResolvers;

View File

@@ -11,6 +11,7 @@ type Query {
getConnectedApps(name: String): [App] getConnectedApps(name: String): [App]
testConnection(id: String!): Connection testConnection(id: String!): Connection
getFlow(id: String!): Flow getFlow(id: String!): Flow
getUseJsFile: JSONObject
getFlows( getFlows(
limit: Int! limit: Int!
offset: Int! offset: Int!
@@ -646,6 +647,7 @@ type AppHealth {
type GetAutomatischInfo { type GetAutomatischInfo {
isCloud: Boolean isCloud: Boolean
isMation: Boolean
license: License license: License
} }

View File

@@ -2,11 +2,12 @@
"compilerOptions": { "compilerOptions": {
"baseUrl": ".", "baseUrl": ".",
"declaration": true, "declaration": true,
"allowJs": true,
"esModuleInterop": true, "esModuleInterop": true,
"lib": ["es2021"], "lib": ["es2021"],
"module": "commonjs", "module": "commonjs",
"moduleResolution": "node", "moduleResolution": "node",
"noImplicitAny": true, "noImplicitAny": false,
"outDir": "dist", "outDir": "dist",
"paths": { "paths": {
"*": ["../../node_modules/*", "node_modules/*", "src/types/*"] "*": ["../../node_modules/*", "node_modules/*", "src/types/*"]

View File

@@ -12,7 +12,9 @@ connection in Automatisch. If any of the steps are outdated, please let us know!
1. Enter necessary information in the form. 1. Enter necessary information in the form.
1. Check **Enable OAuth Settings** checkbox. 1. Check **Enable OAuth Settings** checkbox.
1. Copy **OAuth Redirect URL** from Automatisch and paste it to the **Callback URL** field. 1. Copy **OAuth Redirect URL** from Automatisch and paste it to the **Callback URL** field.
1. Add any scopes you plan to use in the **Selected OAuth Scopes** section. 1. Add any scopes you plan to use in the **Selected OAuth Scopes** section. We suggest `full` and `refresh_token, offline_access` scopes.
1. Uncheck "Require Proof Key for Code Exchange (PKCE) Extension for Supported Authorization Flows" checkbox.
1. Check "Enable Authorization Code and Credentials Flow" checkbox
1. Click on the **Save** button at the bottom of the page. 1. Click on the **Save** button at the bottom of the page.
1. Acknowledge the information and click on the **Continue** button. 1. Acknowledge the information and click on the **Continue** button.
1. In the **API (Enable OAuth Settings)** section, click the **Manager Consumer Details** button. 1. In the **API (Enable OAuth Settings)** section, click the **Manager Consumer Details** button.

View File

@@ -2,7 +2,7 @@ import styled from '@emotion/styled';
export const LogoImage = styled('img')(() => ({ export const LogoImage = styled('img')(() => ({
maxWidth: 200, maxWidth: 200,
maxHeight: 50, maxHeight: 22,
width: '100%', width: '100%',
height: 'auto', height: 'auto',
})); }));

View File

@@ -0,0 +1,22 @@
import Typography from '@mui/material/Typography';
import * as React from 'react';
import { FormattedMessage } from 'react-intl';
import MationLogo from 'components/MationLogo';
import useAutomatischInfo from 'hooks/useAutomatischInfo';
const DefaultLogo = () => {
const { isMation, loading } = useAutomatischInfo();
if (loading) return <React.Fragment />;
if (isMation) return <MationLogo />;
return (
<Typography variant="h6" component="h1" data-test="typography-logo" noWrap>
<FormattedMessage id="brandText" />
</Typography>
);
};
export default DefaultLogo;

View File

@@ -12,6 +12,7 @@ import * as URLS from 'config/urls';
import useVersion from 'hooks/useVersion'; import useVersion from 'hooks/useVersion';
import AppBar from 'components/AppBar'; import AppBar from 'components/AppBar';
import Drawer from 'components/Drawer'; import Drawer from 'components/Drawer';
import useAutomatischInfo from 'hooks/useAutomatischInfo';
type PublicLayoutProps = { type PublicLayoutProps = {
children: React.ReactNode; children: React.ReactNode;
@@ -38,19 +39,36 @@ const drawerLinks = [
}, },
]; ];
const generateDrawerBottomLinks = ({ notificationBadgeContent = 0 }) => [ type GenerateDrawerBottomLinksOptions = {
{ isMation: boolean;
Icon: NotificationsIcon, loading: boolean;
primary: 'settingsDrawer.notifications', notificationBadgeContent: number;
to: URLS.UPDATES, };
badgeContent: notificationBadgeContent,
}, const generateDrawerBottomLinks = ({
]; isMation,
loading,
notificationBadgeContent = 0,
}: GenerateDrawerBottomLinksOptions) => {
if (loading || isMation) {
return [];
}
return [
{
Icon: NotificationsIcon,
primary: 'settingsDrawer.notifications',
to: URLS.UPDATES,
badgeContent: notificationBadgeContent,
},
];
};
export default function PublicLayout({ export default function PublicLayout({
children, children,
}: PublicLayoutProps): React.ReactElement { }: PublicLayoutProps): React.ReactElement {
const version = useVersion(); const version = useVersion();
const { isMation, loading } = useAutomatischInfo();
const theme = useTheme(); const theme = useTheme();
const matchSmallScreens = useMediaQuery(theme.breakpoints.down('lg')); const matchSmallScreens = useMediaQuery(theme.breakpoints.down('lg'));
const [isDrawerOpen, setDrawerOpen] = React.useState(!matchSmallScreens); const [isDrawerOpen, setDrawerOpen] = React.useState(!matchSmallScreens);
@@ -60,6 +78,8 @@ export default function PublicLayout({
const drawerBottomLinks = generateDrawerBottomLinks({ const drawerBottomLinks = generateDrawerBottomLinks({
notificationBadgeContent: version.newVersionCount, notificationBadgeContent: version.newVersionCount,
loading,
isMation,
}); });
return ( return (

View File

@@ -1,8 +1,7 @@
import Typography from '@mui/material/Typography';
import * as React from 'react'; import * as React from 'react';
import { FormattedMessage } from 'react-intl';
import CustomLogo from 'components/CustomLogo/index.ee'; import CustomLogo from 'components/CustomLogo/index.ee';
import DefaultLogo from 'components/DefaultLogo';
import useConfig from 'hooks/useConfig'; import useConfig from 'hooks/useConfig';
const Logo = () => { const Logo = () => {
@@ -13,11 +12,7 @@ const Logo = () => {
if (logoSvgData) return <CustomLogo />; if (logoSvgData) return <CustomLogo />;
return ( return <DefaultLogo />;
<Typography variant="h6" component="h1" data-test="typography-logo" noWrap>
<FormattedMessage id="brandText" />
</Typography>
);
}; };
export default Logo; export default Logo;

View File

@@ -0,0 +1,3 @@
<svg width="115" height="22" viewBox="0 0 411 77" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M276.991 15.3555C281.231 15.3555 284.669 11.918 284.669 7.67773C284.669 3.43744 281.231 0 276.991 0C272.751 0 269.313 3.43744 269.313 7.67773C269.313 11.918 272.751 15.3555 276.991 15.3555ZM367.497 50.0315C367.497 41.5346 374.385 34.6464 382.882 34.6464C391.379 34.6464 398.267 41.5346 398.267 50.0315V71.2076H409.851V50.0315C409.851 35.1371 397.777 23.0627 382.882 23.0627C367.988 23.0627 355.914 35.1371 355.914 50.0315V71.2076H367.497V50.0315ZM271.199 71.2071V28.8539H282.783V71.2071H271.199ZM237.933 34.6464V71.2076H249.517V34.6464H259.608V23.0627H249.517V7.67718H237.933V23.0627H227.843V34.6464H237.933ZM176.899 50.0296C176.899 58.5265 183.787 65.4146 192.284 65.4146V76.9983C177.389 76.9983 165.315 64.924 165.315 50.0296C165.315 35.1351 177.389 23.0608 192.284 23.0608C207.178 23.0608 219.252 35.1359 219.252 50.0303L219.253 71.2068H207.669L207.669 50.0303C207.669 41.5334 200.781 34.6445 192.284 34.6445C183.787 34.6445 176.899 41.5326 176.899 50.0296ZM71.0145 50.0315C71.0145 41.5346 77.9026 34.6464 86.3995 34.6464C94.8965 34.6464 101.785 41.5346 101.785 50.0315V71.2071H113.368V50.0315C113.368 41.5346 120.256 34.6464 128.753 34.6464C137.25 34.6464 144.138 41.5346 144.138 50.0315L144.138 71.2071H155.722L155.722 50.0315C155.722 35.1371 143.647 23.0627 128.753 23.0627C120.165 23.0627 112.515 27.0767 107.576 33.3308C102.637 27.0767 94.9873 23.0627 86.3995 23.0627C71.5051 23.0627 59.4308 35.1371 59.4308 50.0315V71.2071H71.0145V50.0315ZM44.0459 65.4162V76.9999H1.69178V65.4162H44.0459ZM292.376 50.0305C292.376 64.925 304.45 76.9993 319.345 76.9993C334.239 76.9993 346.313 64.9257 346.313 50.0313C346.313 35.1369 334.239 23.0618 319.345 23.0618C304.45 23.0618 292.376 35.1361 292.376 50.0305ZM319.345 65.4157C310.848 65.4157 303.96 58.5276 303.96 50.0306C303.96 41.5337 310.848 34.6456 319.345 34.6456C327.842 34.6456 334.729 41.5345 334.729 50.0314C334.729 58.5283 327.842 65.4157 319.345 65.4157Z" fill="#ffffff"/>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -0,0 +1,8 @@
import * as React from 'react';
import { ReactComponent as MationLogoSvg } from './assets/mation-logo.svg';
const MationLogo = () => {
return <MationLogoSvg />;
};
export default MationLogo;

View File

@@ -7,19 +7,20 @@ import * as React from 'react';
import { IJSONObject } from '@automatisch/types'; import { IJSONObject } from '@automatisch/types';
import useConfig from 'hooks/useConfig'; import useConfig from 'hooks/useConfig';
import theme from 'styles/theme'; import useAutomatischInfo from 'hooks/useAutomatischInfo';
import { defaultTheme, mationTheme } from 'styles/theme';
type ThemeProviderProps = { type ThemeProviderProps = {
children: React.ReactNode; children: React.ReactNode;
}; };
const customizeTheme = (defaultTheme: typeof theme, config: IJSONObject) => { const customizeTheme = (theme: typeof defaultTheme, config: IJSONObject) => {
// `clone` is needed so that the new theme reference triggers re-render // `clone` is needed so that the new theme reference triggers re-render
const shallowDefaultTheme = clone(defaultTheme); const shallowDefaultTheme = clone(theme);
for (const key in config) { for (const key in config) {
const value = config[key]; const value = config[key];
const exists = get(defaultTheme, key); const exists = get(theme, key);
if (exists) { if (exists) {
set(shallowDefaultTheme, key, value); set(shallowDefaultTheme, key, value);
@@ -33,18 +34,21 @@ const ThemeProvider = ({
children, children,
...props ...props
}: ThemeProviderProps): React.ReactElement => { }: ThemeProviderProps): React.ReactElement => {
const { config, loading } = useConfig(); const { isMation, loading: automatischInfoLoading } = useAutomatischInfo();
const { config, loading: configLoading } = useConfig();
const customTheme = React.useMemo(() => { const customTheme = React.useMemo(() => {
if (!config) return theme; const installationTheme = isMation ? mationTheme : defaultTheme;
const customTheme = customizeTheme(theme, config); if (configLoading || automatischInfoLoading) return installationTheme;
const customTheme = customizeTheme(installationTheme, config || {});
return customTheme; return customTheme;
}, [config]); }, [configLoading, config, isMation, automatischInfoLoading]);
// TODO: maybe a global loading state for the custom theme? // TODO: maybe a global loading state for the custom theme?
if (loading) return <></>; if (automatischInfoLoading || configLoading) return <></>;
return ( return (
<BaseThemeProvider theme={customTheme} {...props}> <BaseThemeProvider theme={customTheme} {...props}>

View File

@@ -5,11 +5,15 @@ import { GET_AUTOMATISCH_INFO } from 'graphql/queries/get-automatisch-info';
export type AutomatischInfoContextParams = { export type AutomatischInfoContextParams = {
isCloud: boolean; isCloud: boolean;
isMation: boolean;
loading: boolean;
}; };
export const AutomatischInfoContext = export const AutomatischInfoContext =
React.createContext<AutomatischInfoContextParams>({ React.createContext<AutomatischInfoContextParams>({
isCloud: false, isCloud: false,
isMation: false,
loading: true,
}); });
type AutomatischInfoProviderProps = { type AutomatischInfoProviderProps = {
@@ -23,13 +27,15 @@ export const AutomatischInfoProvider = (
const { data, loading } = useQuery(GET_AUTOMATISCH_INFO); const { data, loading } = useQuery(GET_AUTOMATISCH_INFO);
const isCloud = data?.getAutomatischInfo?.isCloud; const isCloud = data?.getAutomatischInfo?.isCloud;
const isMation = data?.getAutomatischInfo?.isMation;
const value = React.useMemo(() => { const value = React.useMemo(() => {
return { return {
isCloud, isCloud,
loading isMation,
loading,
}; };
}, [isCloud, loading]); }, [isCloud, isMation, loading]);
return ( return (
<AutomatischInfoContext.Provider value={value}> <AutomatischInfoContext.Provider value={value}>

View File

@@ -4,6 +4,7 @@ export const GET_AUTOMATISCH_INFO = gql`
query GetAutomatischInfo { query GetAutomatischInfo {
getAutomatischInfo { getAutomatischInfo {
isCloud isCloud
isMation
} }
} }
`; `;

View File

@@ -3,6 +3,8 @@ import { AutomatischInfoContext } from 'contexts/AutomatischInfo';
type UseAutomatischInfoReturn = { type UseAutomatischInfoReturn = {
isCloud: boolean; isCloud: boolean;
isMation: boolean;
loading: boolean;
}; };
export default function useAutomatischInfo(): UseAutomatischInfoReturn { export default function useAutomatischInfo(): UseAutomatischInfoReturn {
@@ -10,5 +12,7 @@ export default function useAutomatischInfo(): UseAutomatischInfoReturn {
return { return {
isCloud: automatischInfoContext.isCloud, isCloud: automatischInfoContext.isCloud,
isMation: automatischInfoContext.isMation,
loading: automatischInfoContext.loading,
}; };
} }

View File

@@ -1,4 +1,5 @@
import * as React from 'react'; import * as React from 'react';
import { useNavigate } from 'react-router-dom';
import Box from '@mui/material/Box'; import Box from '@mui/material/Box';
import Stack from '@mui/material/Stack'; import Stack from '@mui/material/Stack';
@@ -7,6 +8,8 @@ import Container from 'components/Container';
import NotificationCard from 'components/NotificationCard'; import NotificationCard from 'components/NotificationCard';
import PageTitle from 'components/PageTitle'; import PageTitle from 'components/PageTitle';
import useFormatMessage from 'hooks/useFormatMessage'; import useFormatMessage from 'hooks/useFormatMessage';
import useAutomatischInfo from 'hooks/useAutomatischInfo';
import * as URLS from 'config/urls';
interface INotification { interface INotification {
name: string; name: string;
@@ -16,8 +19,19 @@ interface INotification {
} }
export default function Updates(): React.ReactElement { export default function Updates(): React.ReactElement {
const navigate = useNavigate();
const formatMessage = useFormatMessage(); const formatMessage = useFormatMessage();
const { notifications } = useNotifications(); const { notifications } = useNotifications();
const { isMation, loading } = useAutomatischInfo();
React.useEffect(
function redirectToHomepageInMation() {
if (!loading && isMation) {
navigate(URLS.DASHBOARD);
}
},
[loading, isMation]
);
return ( return (
<Box sx={{ py: 3 }}> <Box sx={{ py: 3 }}>

View File

@@ -1,3 +1,5 @@
import { deepmerge } from '@mui/utils';
import type { Theme } from '@mui/material/styles';
import { createTheme, alpha } from '@mui/material/styles'; import { createTheme, alpha } from '@mui/material/styles';
import { cardActionAreaClasses } from '@mui/material/CardActionArea'; import { cardActionAreaClasses } from '@mui/material/CardActionArea';
@@ -6,7 +8,7 @@ export const primaryMainColor = '#0059F7';
export const primaryLightColor = '#4286FF'; export const primaryLightColor = '#4286FF';
export const primaryDarkColor = '#001F52'; export const primaryDarkColor = '#001F52';
const extendedTheme = createTheme({ export const defaultTheme = createTheme({
palette: { palette: {
primary: { primary: {
main: primaryMainColor, main: primaryMainColor,
@@ -280,4 +282,24 @@ const extendedTheme = createTheme({
}, },
}); });
export default extendedTheme; export const mationTheme = createTheme(deepmerge(defaultTheme, {
palette: {
primary: {
main: '#2962FF',
light: '#448AFF',
dark: '#2962FF',
contrastText: '#fff',
},
},
components: {
MuiAppBar: {
styleOverrides: {
root: ({ theme }: { theme: Theme }) => ({
zIndex: theme.zIndex.drawer + 1,
}),
},
},
},
}));
export default defaultTheme;