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

11156 new app status #11364

Merged
merged 41 commits into from
Oct 23, 2023
Merged
Show file tree
Hide file tree
Changes from 38 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
9fe7774
New version of about/overview/administration page
mlqn Sep 29, 2023
2931fb1
Add unit tests for new About page
mlqn Sep 29, 2023
9f34846
Remove extra div
mlqn Sep 29, 2023
a2ce329
Rename Administration to LegacyAdministration and About to Administra…
mlqn Oct 2, 2023
a734949
Fix background image
mlqn Oct 3, 2023
ea806c3
Fix background sizes
mlqn Oct 3, 2023
93f11a9
Replace metadata with appConfig
mlqn Oct 3, 2023
a79b84b
Fix unit tests
mlqn Oct 4, 2023
b540a34
Replace h1 with Heading
mlqn Oct 4, 2023
3b8b996
Merge remote-tracking branch 'origin/master' into 11156-new-app-status
mlqn Oct 11, 2023
7f99009
Add new app status
mlqn Oct 12, 2023
c52835b
Merge remote-tracking branch 'origin/master' into 11156-new-app-status
mlqn Oct 13, 2023
1d5929a
Fix date
mlqn Oct 13, 2023
b3dc46b
Update app status based on new sketches
mlqn Oct 13, 2023
2fa72f8
Update activity based on new sketches
mlqn Oct 13, 2023
e4b84af
Cleanup app status components
mlqn Oct 13, 2023
f7dccfa
Refactoring app status based on new sketches
mlqn Oct 13, 2023
5aa923e
Update app status names
mlqn Oct 13, 2023
3371dab
Merge remote-tracking branch 'origin/master' into 11156-new-app-status
mlqn Oct 14, 2023
b14828c
Revert prettier changes after merging
mlqn Oct 14, 2023
3230e57
Revert prettier changes after merging
mlqn Oct 14, 2023
49c5fdc
Revert prettier changes after merging
mlqn Oct 14, 2023
a810e9d
Add tests for AppStatus
mlqn Oct 14, 2023
724a0e6
Add tests for AppLogs
mlqn Oct 14, 2023
1d7f334
Add environments tests
mlqn Oct 14, 2023
3d50873
Fix block styles
mlqn Oct 15, 2023
a184bcf
Add error handling for app status
mlqn Oct 15, 2023
e53018b
Fix background-image
mlqn Oct 15, 2023
4eeef2d
Replace newAdministration flag with settingsModal
mlqn Oct 15, 2023
aa21d3e
Merge branch 'master' into 11156-new-app-status
framitdavid Oct 20, 2023
bebce28
first PR feedbacks and clean ups
framitdavid Oct 21, 2023
74682b1
removed unused dep
framitdavid Oct 21, 2023
0fd53d1
fixed broken tests
framitdavid Oct 21, 2023
6b535eb
revert prev-commit, let caseing be a css problem not js-problem
framitdavid Oct 21, 2023
431551e
forgotten to remove toUperCase from one test
framitdavid Oct 21, 2023
bd79c5e
PR feedback
framitdavid Oct 21, 2023
7e85b20
add text-key to nb.json
framitdavid Oct 21, 2023
caf8e1f
fixed wrong variant on profileMenu after designsystem update
framitdavid Oct 21, 2023
481cd0a
PR feedback
framitdavid Oct 23, 2023
b96cbdd
changed text
framitdavid Oct 23, 2023
1c43859
Merge branch 'master' into 11156-new-app-status
framitdavid Oct 23, 2023
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
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
Loading