Skip to content

Commit

Permalink
11156 new app status (#11364)
Browse files Browse the repository at this point in the history
* New version of about/overview/administration page

* Add unit tests for new About page

* Remove extra div

* Rename Administration to LegacyAdministration and About to Administration

* Fix background image

* Fix background sizes

* Replace metadata with appConfig

* Fix unit tests

* Replace h1 with Heading

* Add new app status

* Fix date

* Update app status based on new sketches

* Update activity based on new sketches

* Cleanup app status components

* Refactoring app status based on new sketches

* Update app status names

* Revert prettier changes after merging

* Revert prettier changes after merging

* Revert prettier changes after merging

* Add tests for AppStatus

* Add tests for AppLogs

* Add environments tests

* Fix block styles

* Add error handling for app status

* Fix background-image

* Replace newAdministration flag with settingsModal

* first PR feedbacks and clean ups

* removed unused dep

* fixed broken tests

* revert prev-commit, let caseing be a css problem not js-problem

* forgotten to remove toUperCase from one test

* PR feedback

* add text-key to nb.json

* fixed wrong variant on profileMenu after designsystem update

* PR feedback

* changed text

---------

Co-authored-by: LAPTOP-S0QU96IH\david <david@framit.no>
  • Loading branch information
mlqn and framitdavid authored Oct 23, 2023
1 parent 9fe74bd commit 0e07568
Show file tree
Hide file tree
Showing 34 changed files with 1,114 additions and 172 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion frontend/app-development/config/routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export const routes: IRoute[] = [
activeSubHeaderSelection: TopBarMenu.About,
activeLeftMenuSelection: 'Om appen',
menu: 'about',
subapp: shouldDisplayFeature('newAdministration') ? Administration : LegacyAdministration,
subapp: shouldDisplayFeature('settingsModal') ? Administration : LegacyAdministration,
},
{
path: '/:org/:app/datamodel',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
.administration {
.pageContainer {
background-color: #e6eff8;
position: relative;
}

.administration::before {
.pageContainer::before {
background-image: url('/designer/img/Altinn-studio.svg');
background-position: left -220px;
background-size: 1600px auto;
background-position: center 10px;
background-size: 100% auto;
background-repeat: no-repeat;

content: ' ';
Expand Down Expand Up @@ -36,7 +36,7 @@

.content {
background-color: white;
border-radius: 6px;
border-radius: 4px;
box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.05);
display: flex;
flex-direction: column;
Expand Down Expand Up @@ -77,6 +77,14 @@
padding: var(--fds-spacing-4);
}

.asideBlock {
background-color: #fbfbfc;
border: solid 2px #efefef;
border-radius: 4px;

padding: var(--fds-spacing-4);
}

.divider {
background-color: #efefef;
border: none;
Expand All @@ -86,14 +94,6 @@
width: 100%;
}

/* TODO: remove when all sections are implemented */
.placeholder {
background-color: #fbfbfc;
border: solid 2px #efefef;
border-radius: 6px;
height: 500px;
}

@media (min-width: 960px) {
.content {
flex-direction: row;
Expand All @@ -103,9 +103,3 @@
display: block;
}
}

@media (min-width: 1600px) {
.administration::before {
background-position: center -220px;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ describe('Administration', () => {
startUrl: `${APP_DEVELOPMENT_BASENAME}/${org}/${app}`,
queries: {
...queriesMock,
getEnvironments: jest.fn().mockImplementation(() => Promise.resolve([])),
getOrgList: jest.fn().mockImplementation(() => Promise.resolve({ orgs: [] })),
getAppConfig: jest.fn().mockImplementation(() =>
Promise.resolve({
serviceName: title,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { Heading } from '@digdir/design-system-react';
import { toast } from 'react-toastify';
import { useTranslation } from 'react-i18next';
import { Documentation } from './Documentation';
import { AppEnvironments } from './AppEnvironments';
import { AppLogs } from './AppLogs';
import { Navigation } from './Navigation';

export const Administration = () => {
Expand All @@ -18,24 +20,31 @@ export const Administration = () => {
}

return (
<div className={classes.administration}>
<div className={classes.pageContainer}>
<div className={classes.container}>
<div className={classes.header}>
<Heading size='xlarge'>{appConfigData?.serviceName || app}</Heading>
</div>
<div className={classes.content}>
<main className={classes.main}>
<div className={classes.mainBlock} style={{ height: '500px' }}>
{/* APP STATUS PLACEHOLDER */}
<div className={classes.mainBlock}>
<AppEnvironments />
</div>
<div className={classes.mainBlock}>
<AppLogs />
</div>
<div className={classes.mainBlock}>
<Navigation />
</div>
</main>
<aside className={classes.aside}>
<Documentation />
<div className={classes.asideBlock}>
<Documentation />
</div>
<hr className={classes.divider} />
<div className={classes.placeholder}>{/* NEWS PLACEHOLDER */}</div>
<div className={classes.asideBlock} style={{ height: '500px' }}>
{/* NEWS PLACEHOLDER */}
</div>
</aside>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.appEnvironments {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: var(--fds-spacing-4);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import React from 'react';
import { screen, waitForElementToBeRemoved } from '@testing-library/react';
import { AppEnvironments } from './AppEnvironments';
import { APP_DEVELOPMENT_BASENAME } from 'app-shared/constants';
import { renderWithProviders } from '../../../test/testUtils';
import { queriesMock } from 'app-development/test/mocks';
import { textMock } from '../../../../testing/mocks/i18nMock';

// Test data
const org = 'org';
const app = 'app';

const render = (queries = {}) => {
return renderWithProviders(<AppEnvironments />, {
startUrl: `${APP_DEVELOPMENT_BASENAME}/${org}/${app}`,
queries: {
...queriesMock,
...queries,
},
});
};

describe('AppEnvironments', () => {
it('shows loading spinner when loading required data', () => {
render({
getEnvironments: jest.fn().mockImplementation(() => Promise.resolve([])),
getOrgList: jest.fn().mockImplementation(() => Promise.resolve([])),
});

expect(screen.getByText(textMock('general.loading'))).toBeInTheDocument();
});

it('shows error message if an error occured while fetching required data', async () => {
render({
getEnvironments: jest.fn().mockImplementation(() => Promise.reject()),
getOrgList: jest.fn().mockImplementation(() => Promise.reject()),
});

await waitForElementToBeRemoved(() => screen.queryByTitle(textMock('general.loading')));

expect(screen.getByText(textMock('administration.app_environments_error'))).toBeInTheDocument();
});

it('shows no environments message when organization has no environment', async () => {
render({
getEnvironments: jest.fn().mockImplementation(() => Promise.resolve([])),
getOrgList: jest.fn().mockImplementation(() => Promise.resolve({ orgs: [] })),
});

await waitForElementToBeRemoved(() => screen.queryByTitle(textMock('general.loading')));

expect(
screen.getByRole('heading', { name: textMock('app_publish.no_env_title') }),
).toBeInTheDocument();
expect(screen.getByText(textMock('app_publish.no_env_1'))).toBeInTheDocument();
expect(screen.getByText(textMock('app_publish.no_env_2'))).toBeInTheDocument();
});

it('shows statuses when organization has environments', async () => {
const envName = 'tt02';
const envType = 'test';
render({
getDeployments: jest.fn().mockImplementation(() =>
Promise.resolve({
results: [
{
tagName: '1',
envName,
deployedInEnv: false,
build: {
id: '14381045',
status: 'completed',
result: 'succeeded',
started: '2023-10-03T09:57:31.238Z',
finished: '2023-10-03T09:57:41.29Z',
},
created: '2023-10-03T11:57:31.072013+02:00',
createdBy: 'test',
app,
org,
},
],
}),
),

getEnvironments: jest.fn().mockImplementation(() =>
Promise.resolve([
{
appsUrl: 'http://host.docker.internal:6161',
platformUrl: 'http://host.docker.internal:6161',
hostname: 'host.docker.internal:6161',
appPrefix: 'apps',
platformPrefix: 'platform',
name: envName,
type: envType,
},
]),
),
getOrgList: jest
.fn()
.mockImplementation(() =>
Promise.resolve({ orgs: { [org]: { environments: [envName] } } }),
),
});

await waitForElementToBeRemoved(() => screen.queryByTitle(textMock('general.loading')));

expect(screen.getByRole('heading', { name: envName })).toBeInTheDocument();
expect(screen.getByText(textMock('administration.unavailable'))).toBeInTheDocument();
expect(screen.getByText(textMock('administration.go_to_build_log'))).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams';
import { useEnvironmentsQuery, useOrgListQuery } from 'app-development/hooks/queries';
import { AltinnSpinner } from 'app-shared/components';
import { ICreateAppDeploymentEnvObject } from 'app-development/sharedResources/appDeployment/types';
import { DeployEnvironment } from 'app-shared/types/DeployEnvironment';
import { AppStatus } from './AppStatus';
import { Alert } from '@digdir/design-system-react';
import { NoEnvironmentsAlert } from './NoEnvironmentsAlert';
import classes from './AppEnvironments.module.css';

export const AppEnvironments = () => {
const { org } = useStudioUrlParams();
const { t } = useTranslation();

const {
data: environmentList = [],
isLoading: envIsLoading,
isError: envIsError,
} = useEnvironmentsQuery({ hideDefaultError: true });
const {
data: orgs = { orgs: {} },
isLoading: orgsIsLoading,
isError: orgsIsError,
} = useOrgListQuery({ hideDefaultError: true });

if (envIsLoading || orgsIsLoading) return <AltinnSpinner />;

if (envIsError || orgsIsError)
return <Alert severity='danger'>{t('administration.app_environments_error')}</Alert>;

const selectedOrg = orgs.orgs[org];
const hasNoEnvironments = !(selectedOrg?.environments?.length ?? 0);

if (hasNoEnvironments) {
return <NoEnvironmentsAlert />;
}

const orgEnvironments: ICreateAppDeploymentEnvObject[] = environmentList.filter(
(env: DeployEnvironment) => selectedOrg.environments.includes(env.name),
);

return (
<div className={classes.appEnvironments}>
{orgEnvironments.map((orgEnvironment: DeployEnvironment) => {
return (
<AppStatus
key={orgEnvironment.name}
envName={orgEnvironment.name}
envType={orgEnvironment.type}
/>
);
})}
</div>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
.appLogs {
display: flex;
flex-direction: column;
gap: var(--fds-spacing-4);
justify-content: space-between;

max-height: 275px;
}

.appLogsTitle {
font-weight: unset !important;
}

.logs {
background-color: white;
border-radius: 4px;
display: flex;
flex-direction: column;
gap: var(--fds-spacing-6);
margin: 0;
padding: var(--fds-spacing-4);
padding-left: var(--fds-spacing-8);

overflow: auto;
}

.logTitle {
font-weight: bold;
margin-bottom: var(--fds-spacing-2);
}
Loading

0 comments on commit 0e07568

Please sign in to comment.