Skip to content

Commit

Permalink
Merge pull request #459 from dolittle/improve-ms-pages
Browse files Browse the repository at this point in the history
Improve ms pages
  • Loading branch information
N00bG1rl authored Aug 25, 2023
2 parents 7bc4f3a + f85de7e commit dce1b6b
Show file tree
Hide file tree
Showing 15 changed files with 94 additions and 111 deletions.
6 changes: 6 additions & 0 deletions Source/DesignSystem/atoms/LoadingSpinner/LoadingSpinner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,9 @@ export const LoadingSpinner = (props: CircularProgressProps) =>
<Box sx={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: 1, p: 2 }}>
<CircularProgress {...props} />
</Box>;

// TODO: Move this to a separate component.
export const FullPageLoadingSpinner = (props: CircularProgressProps) =>
<Box sx={{ width: 1, height: 1, position: 'absolute', top: 0, left: 0, zIndex: '9999', backgroundColor: '#191A2150' }}>
<LoadingSpinner {...props} />
</Box>;
2 changes: 1 addition & 1 deletion Source/DesignSystem/atoms/LoadingSpinner/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Dolittle. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

export { LoadingSpinner } from './LoadingSpinner';
export { FullPageLoadingSpinner, LoadingSpinner } from './LoadingSpinner';
2 changes: 1 addition & 1 deletion Source/DesignSystem/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export * from './atoms/Forms';
export { Icon, IconProps } from './atoms/Icon';
export { IconButton, IconButtonProps } from './atoms/IconButton';
export { Link, LinkProps } from './atoms/Link';
export { LoadingSpinner } from './atoms/LoadingSpinner';
export { FullPageLoadingSpinner, LoadingSpinner } from './atoms/LoadingSpinner';
export { MaintenanceMessageBuilding } from './atoms/MaintenanceMessage';
export { StatusIndicator, StatusIndicatorProps } from './atoms/StatusIndicator';
export { Summary } from './atoms/Metrics';
Expand Down
11 changes: 6 additions & 5 deletions Source/DesignSystem/templates/Layout/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@

import React from 'react';

import { Box, Grid, SxProps, Toolbar } from '@mui/material';
import { Box, Grid, SxProps } from '@mui/material';

import { NavigationBar, NavigationBarProps, SidePanel, SidePanelProps, Breadcrumbs, BreadcrumbsProps } from '@dolittle/design-system';
import { NavigationBar, NavigationBarProps, SidePanel, SidePanelProps } from '@dolittle/design-system';

const styles: SxProps = {
'width': '100vw',
'minHeight': 'calc(100vh - 96px)',
'display': 'flex',
'flexDirection': 'column',
Expand Down Expand Up @@ -48,12 +49,12 @@ export type LayoutProps = {
* @returns A {@link Layout} component.
*/
export const Layout = ({ navigationBar, sidePanel, children, sx }: LayoutProps) =>
<Grid container sx={{ flexFlow: 'nowrap' }}>
<Grid container sx={{ width: 'unset', display: 'inline-flex', flexFlow: 'nowrap' }}>
<NavigationBar {...navigationBar} />

{sidePanel && <SidePanel {...sidePanel} />}

<Box component='main' sx={{ ...styles, ...sx }}>
<Grid item component='main' sx={{ ...styles, ...sx }}>
{children}
</Box>
</Grid>
</Grid>;
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@ export type SetupFieldsProps = {
environments: string[];
hasDashedBorder?: boolean;
isDisabled?: boolean;
onEnvironmentSelect?: (environment: string) => void;
};

export const SetupFields = ({ environments, hasDashedBorder, isDisabled }: SetupFieldsProps) => {
export const SetupFields = ({ environments, hasDashedBorder, isDisabled, onEnvironmentSelect }: SetupFieldsProps) => {
const [showEnvironmentInfo, setShowEnvironmentInfo] = useState(false);
const [showEntrypointInfo, setShowEntrypointInfo] = useState(false);

Expand Down Expand Up @@ -59,6 +60,7 @@ export const SetupFields = ({ environments, hasDashedBorder, isDisabled }: Setup
label='Development Environment'
options={environments?.map(env => ({ value: env, displayValue: env })) || []}
onOpen={() => setShowEnvironmentInfo(true)}
onChange={event => onEnvironmentSelect ? onEnvironmentSelect(event.target.value) : null}
disabled={isDisabled}
required
sx={hasDashedBorder ? { '& fieldset': { borderStyle: 'dashed' } } : {}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { Guid } from '@dolittle/rudiments';

import { Typography } from '@mui/material';

import { Button, Form, LoadingSpinner } from '@dolittle/design-system';
import { Button, Form, FullPageLoadingSpinner } from '@dolittle/design-system';

import { saveSimpleMicroservice } from '../../stores/microservice';

Expand All @@ -32,76 +32,73 @@ export const DeployMicroservice = ({ application }: DeployMicroserviceProps) =>
const location = useLocation();
const { enqueueSnackbar } = useSnackbar();

const [isLoading, setIsLoading] = useState(false);
const availableEnvironments = application.environments.map(env => env.name);

// TODO ENV: Show always as 'false' while deploying and display option later in configuration?
//const environmentInfo = application.environments.find(env => env.name === 'Dev')!;
const hasM3ConnectorOption = false; // environmentInfo?.connections?.m3Connector || false;
const [isLoading, setIsLoading] = useState(false);
const [selectedEnvironment, setSelectedEnvironment] = useState(availableEnvironments[0]);

const availableEnvironments = application.environments.map(env => env.name);
const latestRuntimeVersion = getLatestRuntimeInfo().image;
const environmentInfo = application.environments.find(env => env.name === selectedEnvironment);
const hasM3ConnectorOption = environmentInfo?.connections?.m3Connector;

const frag = new URLSearchParams(location.hash.slice(1));

const handleCreateMicroservice = async (values: MicroserviceFormParameters) => {
setIsLoading(true);

// Values from data grid table.
const { microserviceName, developmentEnvironment, headArguments, headImage, headPort, runtimeVersion, isPublic, ingressPath, entrypoint, hasM3Connector } = values;
const microserviceId = Guid.create().toString();
// Convert the head arguments to the format that the form expects.
const headArgumentValues = headArguments.map(arg => arg.value);
const headArgumentValues = values.headArguments.map(arg => arg.value);

const newMicroservice: MicroserviceSimple = {
dolittle: {
applicationId: application.id,
customerId: application.customerId,
microserviceId,
},
name: microserviceName,
name: values.microserviceName,
kind: 'simple',
environment: developmentEnvironment,
environment: values.developmentEnvironment,
extra: {
headImage,
headPort: parseInt(headPort.toString(), 10),
runtimeImage: runtimeVersion,
isPublic,
headImage: values.headImage,
headPort: parseInt(values.headPort.toString(), 10),
runtimeImage: values.runtimeVersion,
isPublic: values.isPublic,
ingress: {
path: '/' + ingressPath,
path: '/' + values.ingressPath,
pathType: 'Prefix',
},
headCommand: {
command: entrypoint.length ? [entrypoint] : [],
command: values.entrypoint.length ? [values.entrypoint] : [],
args: headArgumentValues,
},
connections: {
m3Connector: hasM3Connector,
m3Connector: values.hasM3Connector,
},
},
};

try {
await saveSimpleMicroservice(newMicroservice);
enqueueSnackbar(`Microservice '${microserviceName}' has been deployed.`);
enqueueSnackbar(`Microservice '${values.microserviceName}' has been deployed.`);
const href = `/microservices/application/${application.id}/view/${newMicroservice.dolittle.microserviceId}/${newMicroservice.environment}}`;
navigate(href);
} catch (error: unknown) {
const message = (error instanceof Error) ? error.message : 'Something went wrong when saving microservice.';
enqueueSnackbar(message, { variant: 'error' });
} catch (error) {
enqueueSnackbar('Something went wrong when saving microservice.', { variant: 'error' });
} finally {
setIsLoading(false);
}
};

return (
<>
<Typography variant='h1'>Deploy Base Microservice</Typography>
{isLoading && <FullPageLoadingSpinner />}
<Typography variant='h1' sx={{ mt: 3, mb: 4 }}>Deploy Base Microservice</Typography>

<Form<MicroserviceFormParameters>
initialValues={{
microserviceName: '',
developmentEnvironment: availableEnvironments[0] || '',
runtimeVersion: latestRuntimeVersion,
developmentEnvironment: selectedEnvironment,
runtimeVersion: getLatestRuntimeInfo().image,
headImage: frag.get('head-image') || '', // nginxdemos/hello:latest
headPort: 80,
entrypoint: '',
Expand All @@ -110,19 +107,18 @@ export const DeployMicroservice = ({ application }: DeployMicroserviceProps) =>
ingressPath: '',
hasM3Connector: false,
}}
sx={{ 'mt': 4.5, 'ml': 3, '& .MuiFormControl-root': { my: 1 } }}
sx={{ 'ml': 3, '& .MuiFormControl-root': { my: 1 } }}
onSubmit={handleCreateMicroservice}
>
<SetupFields environments={availableEnvironments} />
<SetupFields environments={availableEnvironments} onEnvironmentSelect={setSelectedEnvironment} />

<ContainerImageFields />

<PublicUrlFields />

{hasM3ConnectorOption && <HasM3ConnectorField />}

{isLoading ?
<LoadingSpinner /> :
<Button variant='filled' label='Deploy microservice' type='submit' startWithIcon='RocketLaunch' sx={{ mt: 1 }} />
}
<Button variant='filled' label='Deploy microservice' type='submit' startWithIcon='RocketLaunch' sx={{ mt: 1 }} />
</Form>
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,30 +14,13 @@ import { EnvironmentVariablesSection } from './environmentSection/environmentVar
export type ConfigurationFilesSectionProps = {
application: HttpResponseApplication;
applicationId: string;
// TODO: Refactor? This is the same as currentMicroservice.id?
microserviceId: string;
currentMicroservice: MicroserviceStore;
};

export const ConfigurationFilesSection = ({ application, applicationId, microserviceId, currentMicroservice }: ConfigurationFilesSectionProps) => (
export const ConfigurationFilesSection = ({ application, applicationId, currentMicroservice }: ConfigurationFilesSectionProps) => (
<>
<SetupSection
application={application}
applicationId={applicationId}
currentMicroservice={currentMicroservice}
microserviceId={microserviceId}
/>

<FilesSection
applicationId={applicationId}
currentMicroservice={currentMicroservice}
microserviceId={microserviceId}
/>

<EnvironmentVariablesSection
applicationId={applicationId}
currentMicroservice={currentMicroservice}
microserviceId={microserviceId}
/>
<SetupSection application={application} currentMicroservice={currentMicroservice} />
<FilesSection applicationId={applicationId} currentMicroservice={currentMicroservice} />
<EnvironmentVariablesSection applicationId={applicationId} currentMicroservice={currentMicroservice} />
</>
);
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,10 @@ export type EnvironmentVariableTableRow = InputEnvironmentVariable & {
export type EnvironmentVariablesProps = {
applicationId: string;
currentMicroservice: MicroserviceStore;
// TODO: Refactor? This is the same as currentMicroservice.id?
microserviceId: string;
};

// TODO: TYPO: Variables = Variable
export const EnvironmentVariablesSection = ({ applicationId, currentMicroservice, microserviceId }: EnvironmentVariablesProps) => {
export const EnvironmentVariablesSection = ({ applicationId, currentMicroservice }: EnvironmentVariablesProps) => {
const { enqueueSnackbar } = useSnackbar();

const [envVariableTableRows, setEnvVariableTableRows] = useState<EnvironmentVariableTableRow[]>([]);
Expand All @@ -61,6 +59,7 @@ export const EnvironmentVariablesSection = ({ applicationId, currentMicroservice
const [disableAddButton, setDisableAddButton] = useState(false);
const [restartInfoBoxIsOpen, setRestartInfoBoxIsOpen] = useState(false);

const microserviceId = currentMicroservice.id;
const microserviceEnvironment = currentMicroservice.environment;
const microserviceName = currentMicroservice.name;

Expand Down Expand Up @@ -247,7 +246,7 @@ export const EnvironmentVariablesSection = ({ applicationId, currentMicroservice
title='No environment variables yet...'
description={`To add your first environment variable, select 'add variable'. Provide a name, value and set its secrecy.`}
label='Add Variable'
handleOnClick={handleEnvVariableAdd} // TODO: Sometimes throws error when clicked
handleOnClick={handleEnvVariableAdd}
/> :
<DataGridWrapper>
<DataGridPro
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,9 @@ const MAX_CONFIGMAP_ENTRY_SIZE = 3145728;
export type FilesSectionProps = {
applicationId: string;
currentMicroservice: MicroserviceStore;
// TODO: Refactor? This is the same as currentMicroservice.id?
microserviceId: string;
};

export const FilesSection = ({ applicationId, currentMicroservice, microserviceId }: FilesSectionProps) => {
export const FilesSection = ({ applicationId, currentMicroservice }: FilesSectionProps) => {
const fileUploadRef = useRef<FileUploadFormRef>(null);
const { enqueueSnackbar } = useSnackbar();

Expand All @@ -44,6 +42,7 @@ export const FilesSection = ({ applicationId, currentMicroservice, microserviceI
const [deleteConfigFileDialogIsOpen, setDeleteConfigFileDialogIsOpen] = useState(false);
const [validateFileDialogIsOpen, setValidateFileDialogIsOpen] = useState({ isOpen: false, file: [] as File[] });

const microserviceId = currentMicroservice.id;
const microserviceEnvironment = currentMicroservice.environment;
const microserviceName = currentMicroservice.name;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import React, { useState } from 'react';
import { useSnackbar } from 'notistack';
import { useNavigate } from 'react-router-dom';

import { Accordion, AlertDialog, Form } from '@dolittle/design-system';
import { Accordion, AlertDialog, Form, FullPageLoadingSpinner } from '@dolittle/design-system';

import { canDeleteMicroservice, deleteMicroservice, MicroserviceStore } from '../../../../stores/microservice';

Expand All @@ -24,21 +24,20 @@ import { getRuntimeNumberFromString } from '../../../../../utils/helpers';

export type SetupSectionProps = {
application: HttpResponseApplication;
applicationId: string;
currentMicroservice: MicroserviceStore;
// TODO: Refactor? This is the same as currentMicroservice.id?
microserviceId: string;
};

export const SetupSection = ({ application, applicationId, currentMicroservice, microserviceId }: SetupSectionProps) => {
export const SetupSection = ({ application, currentMicroservice }: SetupSectionProps) => {
const navigate = useNavigate();
const { enqueueSnackbar } = useSnackbar();

const [deleteDialogIsOpen, setDeleteDialogIsOpen] = useState(false);
const [restartDialogIsOpen, setRestartDialogIsOpen] = useState(false);
const [formIsNotEditable, setFormIsNotEditable] = useState(true);
const [isLoading, setIsLoading] = useState(false);

// TODO ENV: Not sure that I can use currentMicroservice.environment here?
const applicationId = application.id;
const microserviceId = currentMicroservice.id;
const microserviceEnvironment = currentMicroservice.environment;
const microserviceName = currentMicroservice.name;
const microserviceInfo = currentMicroservice.edit?.extra;
Expand All @@ -50,6 +49,7 @@ export const SetupSection = ({ application, applicationId, currentMicroservice,
};

const availableEnvironments = application.environments.map(env => env.name);

const hasPublicUrl = microserviceInfo?.isPublic || false;
const hasM3ConnectorOption = application.environments.find(env => env.name === microserviceEnvironment)?.connections?.m3Connector || false;
// Remove extra slash from ingress path as it is there already with startAdornment.
Expand All @@ -58,6 +58,9 @@ export const SetupSection = ({ application, applicationId, currentMicroservice,
const headArgumentValues = microserviceInfo?.headCommand?.args?.map((arg: string) => ({ value: arg })) || [];

const handleMicroserviceDelete = async () => {
setIsLoading(true);
setDeleteDialogIsOpen(false);

if (!canDelete) {
enqueueSnackbar('Deleting microservice is disabled.', { variant: 'error' });
return;
Expand All @@ -67,16 +70,20 @@ export const SetupSection = ({ application, applicationId, currentMicroservice,

if (!success) {
enqueueSnackbar(`Failed to delete microservice '${microserviceName}'.`, { variant: 'error' });
setIsLoading(false);
return;
}

enqueueSnackbar(`Microservice '${microserviceName}' has been deleted.`);
const href = `/microservices/application/${applicationId}/overview`;
navigate(href);
setIsLoading(false);
};

return (
<>
{isLoading && <FullPageLoadingSpinner />}

<AlertDialog
id='delete-microservice'
title='Delete microservice?'
Expand Down Expand Up @@ -113,15 +120,17 @@ export const SetupSection = ({ application, applicationId, currentMicroservice,
headImage: microserviceInfo?.headImage,
headPort: microserviceInfo?.headPort,
entrypoint: '',
isPublic: microserviceInfo?.isPublic,
isPublic: hasPublicUrl,
headArguments: headArgumentValues,
ingressPath: cleanedIngressPath,
hasM3Connector: hasM3ConnectorOption,
}}
sx={{ '& .MuiFormControl-root': { my: 1 } }}
>
<SetupFields environments={availableEnvironments} hasDashedBorder isDisabled={formIsNotEditable} />

<ContainerImageFields hasDashedBorder isDisabled={formIsNotEditable} />

<PublicUrlFields hasDashedBorder hasPublicUrl={hasPublicUrl} isDisabled={formIsNotEditable} />

{hasM3ConnectorOption && <HasM3ConnectorField isDisabled={formIsNotEditable} />}
Expand Down
Loading

0 comments on commit dce1b6b

Please sign in to comment.