Skip to content

Commit

Permalink
Add send debug info user menu button
Browse files Browse the repository at this point in the history
  • Loading branch information
cskrov committed Nov 1, 2024
1 parent 7c704ae commit db46ae2
Show file tree
Hide file tree
Showing 10 changed files with 511 additions and 90 deletions.
8 changes: 1 addition & 7 deletions frontend/src/components/app/app.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import { AppErrorBoundary } from '@app/components/app/error-boundary';
import { StaticDataLoader } from '@app/components/app/static-data-context';
import { NavHeader } from '@app/components/header/header';
import { Toasts } from '@app/components/toast/toasts';
import { VersionCheckerStatus } from '@app/components/version-checker/version-checker-status';
import { reduxStore } from '@app/redux/configure-store';
import { StrictMode } from 'react';
import { Provider } from 'react-redux';
Expand All @@ -13,14 +10,11 @@ import { Router } from './router';
export const App = () => (
<StrictMode>
<AppErrorBoundary>
<GlobalStyles />
<Provider store={reduxStore}>
<StaticDataLoader>
<BrowserRouter>
<GlobalStyles />
<NavHeader />
<Router />
<Toasts />
<VersionCheckerStatus />
</BrowserRouter>
</StaticDataLoader>
</Provider>
Expand Down
160 changes: 87 additions & 73 deletions frontend/src/components/app/router.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { NotFoundPage } from '@app/components/app/not-found-page';
import { ProtectedRoute } from '@app/components/app/protected-route';
import { NavHeader } from '@app/components/header/header';
import { ModalEnum } from '@app/components/svarbrev/row/row';
import { Toasts } from '@app/components/toast/toasts';
import { VersionCheckerStatus } from '@app/components/version-checker/version-checker-status';
import { AccessRightsPage } from '@app/pages/access-rights/access-rights';
import { AdminPage } from '@app/pages/admin/admin';
import { AnkebehandlingPage } from '@app/pages/ankebehandling/ankebehandling';
Expand All @@ -22,92 +25,103 @@ import { SvarbrevPage } from '@app/pages/svarbrev/svarbrev';
import { ToppteksterPage } from '@app/pages/topptekster/topptekster';
import { TrygderettsankebehandlingPage } from '@app/pages/trygderettsankebehandling/trygderettsankebehandling';
import { Role } from '@app/types/bruker';
import { Route, Routes as Switch } from 'react-router-dom';
import { Outlet, Route, Routes as Switch } from 'react-router-dom';

export const Router = () => (
<Switch>
<Route path="/" element={<LandingPage />} />

<Route element={<ProtectedRoute roles={[Role.KABAL_SAKSBEHANDLING, Role.KABAL_ROL]} />}>
<Route path="oppgaver" element={<OppgaverPage />} />
<Route path="mineoppgaver" element={<MineOppgaverPage />} />
<Route path="klagebehandling/:oppgaveId" element={<KlagebehandlingPage />} />
<Route path="ankebehandling/:oppgaveId" element={<AnkebehandlingPage />} />
<Route path="trygderettsankebehandling/:oppgaveId" element={<TrygderettsankebehandlingPage />} />
<Route path="behandling-etter-tr-opphevet/:oppgaveId" element={<BehandlingEtterTrOpphevetPage />} />
</Route>
<Route element={<AppWrapper />}>
<Route path="/" element={<LandingPage />} />

<Route element={<ProtectedRoute roles={[Role.KABAL_SAKSBEHANDLING, Role.KABAL_ROL]} />}>
<Route path="oppgaver" element={<OppgaverPage />} />
<Route path="mineoppgaver" element={<MineOppgaverPage />} />
<Route path="klagebehandling/:oppgaveId" element={<KlagebehandlingPage />} />
<Route path="ankebehandling/:oppgaveId" element={<AnkebehandlingPage />} />
<Route path="trygderettsankebehandling/:oppgaveId" element={<TrygderettsankebehandlingPage />} />
<Route path="behandling-etter-tr-opphevet/:oppgaveId" element={<BehandlingEtterTrOpphevetPage />} />
</Route>

<Route element={<ProtectedRoute roles={[Role.KABAL_INNSYN_EGEN_ENHET, Role.KABAL_KROL]} />}>
<Route path="oppgavestyring" element={<OppgavestyringPage />} />
</Route>
<Route element={<ProtectedRoute roles={[Role.KABAL_INNSYN_EGEN_ENHET, Role.KABAL_KROL]} />}>
<Route path="oppgavestyring" element={<OppgavestyringPage />} />
</Route>

<Route element={<ProtectedRoute roles={[Role.KABAL_SAKSBEHANDLING, Role.KABAL_OPPGAVESTYRING_ALLE_ENHETER]} />}>
<Route path="sok" element={<SearchPage />} />
</Route>
<Route element={<ProtectedRoute roles={[Role.KABAL_SAKSBEHANDLING, Role.KABAL_OPPGAVESTYRING_ALLE_ENHETER]} />}>
<Route path="sok" element={<SearchPage />} />
</Route>

<Route element={<ProtectedRoute roles={[Role.KABAL_MALTEKSTREDIGERING]} />}>
<Route
path="maltekstseksjoner/:lang/:id/versjoner/:maltekstseksjonVersionId/tekster/:textId"
element={<MaltekstseksjonerPage />}
/>
<Route
path="maltekstseksjoner/:lang/:id/versjoner/:maltekstseksjonVersionId"
element={<MaltekstseksjonerPage />}
/>
<Route path="maltekstseksjoner/:lang/:id" element={<MaltekstseksjonerPage />} />
<Route path="maltekstseksjoner/:lang" element={<MaltekstseksjonerPage />} />
<Route path="maltekstseksjoner" element={<MaltekstseksjonerPage />} />

<Route path="maltekster/:lang/:id/versjoner/:versionId" element={<MalteksterPage />} />
<Route path="maltekster/:lang/:id" element={<MalteksterPage />} />
<Route path="maltekster/:lang" element={<MalteksterPage />} />
<Route path="maltekster" element={<MalteksterPage />} />

<Route path="redigerbare-maltekster/:lang/:id/versjoner/:versionId" element={<RedigerbareMalteksterPage />} />
<Route path="redigerbare-maltekster/:lang/:id" element={<RedigerbareMalteksterPage />} />
<Route path="redigerbare-maltekster/:lang" element={<RedigerbareMalteksterPage />} />
<Route path="redigerbare-maltekster" element={<RedigerbareMalteksterPage />} />

<Route path="topptekster/:lang/:id/versjoner/:versionId" element={<ToppteksterPage />} />
<Route path="topptekster/:lang/:id" element={<ToppteksterPage />} />
<Route path="topptekster/:lang" element={<ToppteksterPage />} />
<Route path="topptekster" element={<ToppteksterPage />} />

<Route path="bunntekster/:lang/:id/versjoner/:versionId" element={<BunnteksterPage />} />
<Route path="bunntekster/:lang/:id" element={<BunnteksterPage />} />
<Route path="bunntekster/:lang" element={<BunnteksterPage />} />
<Route path="bunntekster" element={<BunnteksterPage />} />
</Route>
<Route element={<ProtectedRoute roles={[Role.KABAL_MALTEKSTREDIGERING]} />}>
<Route
path="maltekstseksjoner/:lang/:id/versjoner/:maltekstseksjonVersionId/tekster/:textId"
element={<MaltekstseksjonerPage />}
/>
<Route
path="maltekstseksjoner/:lang/:id/versjoner/:maltekstseksjonVersionId"
element={<MaltekstseksjonerPage />}
/>
<Route path="maltekstseksjoner/:lang/:id" element={<MaltekstseksjonerPage />} />
<Route path="maltekstseksjoner/:lang" element={<MaltekstseksjonerPage />} />
<Route path="maltekstseksjoner" element={<MaltekstseksjonerPage />} />

<Route path="maltekster/:lang/:id/versjoner/:versionId" element={<MalteksterPage />} />
<Route path="maltekster/:lang/:id" element={<MalteksterPage />} />
<Route path="maltekster/:lang" element={<MalteksterPage />} />
<Route path="maltekster" element={<MalteksterPage />} />

<Route path="redigerbare-maltekster/:lang/:id/versjoner/:versionId" element={<RedigerbareMalteksterPage />} />
<Route path="redigerbare-maltekster/:lang/:id" element={<RedigerbareMalteksterPage />} />
<Route path="redigerbare-maltekster/:lang" element={<RedigerbareMalteksterPage />} />
<Route path="redigerbare-maltekster" element={<RedigerbareMalteksterPage />} />

<Route path="topptekster/:lang/:id/versjoner/:versionId" element={<ToppteksterPage />} />
<Route path="topptekster/:lang/:id" element={<ToppteksterPage />} />
<Route path="topptekster/:lang" element={<ToppteksterPage />} />
<Route path="topptekster" element={<ToppteksterPage />} />

<Route path="bunntekster/:lang/:id/versjoner/:versionId" element={<BunnteksterPage />} />
<Route path="bunntekster/:lang/:id" element={<BunnteksterPage />} />
<Route path="bunntekster/:lang" element={<BunnteksterPage />} />
<Route path="bunntekster" element={<BunnteksterPage />} />
</Route>

<Route element={<ProtectedRoute roles={[Role.KABAL_FAGTEKSTREDIGERING]} />}>
<Route path="gode-formuleringer/:lang/:id/versjoner/:versionId" element={<GodeFormuleringerPage />} />
<Route path="gode-formuleringer/:lang/:id" element={<GodeFormuleringerPage />} />
<Route path="gode-formuleringer/:lang" element={<GodeFormuleringerPage />} />
<Route path="gode-formuleringer" element={<GodeFormuleringerPage />} />
<Route element={<ProtectedRoute roles={[Role.KABAL_FAGTEKSTREDIGERING]} />}>
<Route path="gode-formuleringer/:lang/:id/versjoner/:versionId" element={<GodeFormuleringerPage />} />
<Route path="gode-formuleringer/:lang/:id" element={<GodeFormuleringerPage />} />
<Route path="gode-formuleringer/:lang" element={<GodeFormuleringerPage />} />
<Route path="gode-formuleringer" element={<GodeFormuleringerPage />} />

<Route path="regelverk/:id/versjoner/:versionId" element={<RegelverkPage />} />
<Route path="regelverk/:id" element={<RegelverkPage />} />
<Route path="regelverk" element={<RegelverkPage />} />
</Route>
<Route path="regelverk/:id/versjoner/:versionId" element={<RegelverkPage />} />
<Route path="regelverk/:id" element={<RegelverkPage />} />
<Route path="regelverk" element={<RegelverkPage />} />
</Route>

<Route element={<ProtectedRoute roles={[Role.KABAL_SVARBREVINNSTILLINGER]} />}>
<Route path="svarbrev">
<Route index element={<SvarbrevPage />} />
<Route path=":id" element={<SvarbrevPage modal={ModalEnum.PREVIEW} />} />
<Route path=":id/historikk" element={<SvarbrevPage modal={ModalEnum.HISTORY} />} />
<Route element={<ProtectedRoute roles={[Role.KABAL_SVARBREVINNSTILLINGER]} />}>
<Route path="svarbrev">
<Route index element={<SvarbrevPage />} />
<Route path=":id" element={<SvarbrevPage modal={ModalEnum.PREVIEW} />} />
<Route path=":id/historikk" element={<SvarbrevPage modal={ModalEnum.HISTORY} />} />
</Route>
</Route>
</Route>

<Route element={<ProtectedRoute roles={[Role.KABAL_TILGANGSSTYRING_EGEN_ENHET]} />}>
<Route path="tilgangsstyring" element={<AccessRightsPage />} />
</Route>
<Route element={<ProtectedRoute roles={[Role.KABAL_TILGANGSSTYRING_EGEN_ENHET]} />}>
<Route path="tilgangsstyring" element={<AccessRightsPage />} />
</Route>

<Route element={<ProtectedRoute roles={[Role.KABAL_ADMIN]} />}>
<Route path="admin" element={<AdminPage />} />
</Route>
<Route element={<ProtectedRoute roles={[Role.KABAL_ADMIN]} />}>
<Route path="admin" element={<AdminPage />} />
</Route>

<Route path="innstillinger" element={<SettingsPage />} />
<Route path="innstillinger" element={<SettingsPage />} />

<Route path="*" element={<NotFoundPage />} />
<Route path="*" element={<NotFoundPage />} />
</Route>
</Switch>
);

const AppWrapper = () => (
<>
<NavHeader />
<Outlet />
<Toasts />
<VersionCheckerStatus />
</>
);
158 changes: 158 additions & 0 deletions frontend/src/components/header/user-menu/debug.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import { toast } from '@app/components/toast/store';
import { ENVIRONMENT } from '@app/environment';
import { useOppgave } from '@app/hooks/oppgavebehandling/use-oppgave';
import { useSmartEditorActiveDocument } from '@app/hooks/settings/use-setting';
import { useGetDocumentsQuery } from '@app/redux-api/oppgaver/queries/documents';
import { useUtfall, useYtelserAll } from '@app/simple-api-state/use-kodeverk';
import { user } from '@app/static-data/static-data';
import type { INavEmployee } from '@app/types/bruker';
import { SaksTypeEnum } from '@app/types/kodeverk';
import { BugIcon } from '@navikt/aksel-icons';
import { Button, Dropdown, Tooltip } from '@navikt/ds-react';
import { skipToken } from '@reduxjs/toolkit/query';
import { useCallback } from 'react';
import { useParams } from 'react-router-dom';

export const DebugButton = () => {
const { oppgaveId } = useParams();

if (oppgaveId !== undefined) {
return <BehandlingDebug />;
}

return <SimpleDebug />;
};

export const SimpleDebug = () => {
const reporter = useReporter();

const onClick: React.MouseEventHandler<HTMLElement> = useCallback(async () => {
const body = JSON.stringify(
{
reporter: await reporter,
url: window.location.href,
version: ENVIRONMENT.version,
},
null,
2,
);

sendDebugInfo(body);
}, [reporter]);

return (
<Dropdown.Menu.List.Item as={SendButton} onClick={onClick}>
Send teknisk informasjon
</Dropdown.Menu.List.Item>
);
};

export const BehandlingDebug = () => {
const reporter = useReporter();
const { data: oppgave } = useOppgave();
const { data: documents } = useGetDocumentsQuery(oppgave?.id ?? skipToken);
const { value: selectedTab = null } = useSmartEditorActiveDocument();
const { data: utfallList = [] } = useUtfall();

const onClick: React.MouseEventHandler<HTMLElement> = useCallback(async () => {
if (oppgave === undefined) {
console.error('No behandling loaded');
return;
}

const medunderskriver = oppgave.medunderskriver.employee;
const rol = oppgave.typeId !== SaksTypeEnum.ANKE_I_TRYGDERETTEN ? oppgave.rol : null;

const body = JSON.stringify(
{
reporter: await reporter,
url: window.location.href,
version: ENVIRONMENT.version,
data: {
type: 'behandling',
behandlingId: oppgave.id,
utfall: utfallList.find((u) => u.id === oppgave.resultat.utfallId)?.navn ?? oppgave.resultat.utfallId,
ekstraUtfall: oppgave.resultat.extraUtfallIdSet.map((id) => utfallList.find((u) => u.id === id)?.navn ?? id),
medunderskriver: employeeToUser(medunderskriver),
muFlowState: oppgave.medunderskriver.flowState,
rol: employeeToUser(rol?.employee),
rolFlowState: rol?.flowState ?? null,
selectedTab,
documents: documents
?.filter((d) => !d.isSmartDokument)
.map(({ id, tittel, type, templateId }) => ({ id, title: tittel, type, templateId })),
smartDocuments: documents
?.filter((d) => d.isSmartDokument)
.map(({ id, tittel, type, templateId }) => ({ id, title: tittel, type, templateId })),
},
},
null,
2,
);

sendDebugInfo(body);
}, [oppgave, documents, selectedTab, reporter, utfallList]);

return (
<Dropdown.Menu.List.Item as={SendButton} onClick={onClick}>
Send teknisk informasjon
</Dropdown.Menu.List.Item>
);
};

const sendDebugInfo = async (body: string) => {
try {
const res = await fetch('/debug', { method: 'POST', body, headers: { 'Content-Type': 'application/json' } });

if (!res.ok) {
throw new Error(await res.text());
}

toast.success('Teknisk informasjon er sendt til Team Klage');
} catch (error) {
console.error('Failed to send debug info to Team Klage', error instanceof Error ? error.message : error);
toast.error(
'Klarte ikke sende teknisk informasjon til Team Klage. Teknisk informasjon er kopiert til utklippstavlen din.',
);
navigator.clipboard.writeText(body);
}
};

const useReporter = async () => {
const { data: ytelser } = useYtelserAll();

if (ytelser === undefined) {
return user;
}

const { tildelteYtelser, ...rest } = await user;

return {
...rest,
tildelteYtelser: tildelteYtelser.map((id) => {
const ytelse = ytelser.find((y) => y.id === id);

if (ytelse === undefined) {
return `Unknown ytelse (\`${id}\`)`;
}

return `${ytelse.navn} (${ytelse.id})`;
}),
};
};

interface SendButtonProps {
onClick: () => void;
children?: React.ReactNode;
}

const SendButton = ({ onClick, children }: SendButtonProps) => (
<Tooltip content="Sender teknisk informasjon om saken direkte til Team Klage.">
<Button variant="tertiary" size="small" onClick={onClick} icon={<BugIcon aria-hidden />}>
{children}
</Button>
</Tooltip>
);

const employeeToUser = (employee: INavEmployee | null = null) =>
employee === null ? null : { name: employee.navn, navIdent: employee.navIdent };
2 changes: 2 additions & 0 deletions frontend/src/components/header/user-menu/dropdown.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { DebugButton } from '@app/components/header/user-menu/debug';
import { ENVIRONMENT } from '@app/environment';
import { pushEvent } from '@app/observability';
import { CogIcon, CogRotationIcon, LeaveIcon } from '@navikt/aksel-icons';
Expand Down Expand Up @@ -33,6 +34,7 @@ export const UserDropdown = (): JSX.Element | null => {
>
{null}
</Dropdown.Menu.List.Item>
<DebugButton />
</Dropdown.Menu.List>
</Menu>
);
Expand Down
Loading

0 comments on commit db46ae2

Please sign in to comment.