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

Staging #537

Merged
merged 2 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions backend/src/main/kotlin/no/bekk/routes/UploadCSVRouting.kt
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,12 @@ fun List<AnswersCSVDump>.toCsv(): String {
val stringWriter = StringWriter()
stringWriter.append("questionId,answer,answer_type,answer_unit,answer_updated,answer_actor,comment,comment_updated,comment_actor,context_id,context_name,table_id,team_id\n")
this.forEach {
stringWriter.append("${it.questionId},${it.answer},${it.answerType},${it.answerUnit},${it.answerUpdated},${it.answerActor},${it.comment},${it.commentUpdated},${it.commentActor},${it.contextId},${it.contextName},${it.tableName},${it.teamId}\n")
stringWriter.append("\"${it.questionId}\",\"${it.answer}\",\"${it.answerType}\",\"${it.answerUnit}\",\"${it.answerUpdated}\",\"${it.answerActor}\",\"${it.comment}\",\"${it.commentUpdated}\",\"${it.commentActor}\",\"${it.contextId}\",\"${it.contextName}\",\"${it.tableName}\",\"${it.teamId}\"\n")
}

return stringWriter.toString()
}


fun mapRowToAnswersCSVDump(rs: ResultSet): AnswersCSVDump {
return AnswersCSVDump(
questionId = rs.getString("question_id"),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,42 +1,51 @@
import { Box, FormControl, FormLabel, Select, Skeleton } from '@kvib/react';
import { useFetchTeamTableContexts } from '../../hooks/useFetchTeamTableContexts';
import { FormControl, FormLabel, Select, Skeleton } from '@kvib/react';
import { useFetchAllContexts } from '../../hooks/useFetchAllContexts';
import { Context } from '../../hooks/useFetchTeamContexts';

export function CopyContextDropdown({
tableId,
teamId,
copyContext,
setCopyContext,
}: {
tableId: string;
teamId: string;
copyContext: string | null;
setCopyContext: (context: string) => void;
}) {
const { data: contexts, isLoading: contextsIsLoading } =
useFetchTeamTableContexts(teamId, tableId);
useFetchAllContexts();

const contextsForTable: Context[] =
contexts?.filter((context) => context.tableId === tableId) ?? [];

if (!contexts || contexts.length === 0) {
return null;
}
return (
<Box marginBottom="1rem">
<FormLabel htmlFor="select">
<FormControl>
<FormLabel
style={{
fontSize: 'small',
fontWeight: 'bold',
}}
>
Kopier svar fra eksisterende skjema
</FormLabel>
<FormControl>
<Skeleton isLoaded={!contextsIsLoading}>
<Select
id="select"
placeholder="Velg skjema"
onChange={(e) => setCopyContext(e.target.value)}
bgColor="white"
borderColor="gray.200"
value={copyContext ?? undefined}
>
{contexts?.map((context) => (
<option key={context.id} value={context.id}>
{context.name}
</option>
))}
</Select>
</Skeleton>
</FormControl>
</Box>
<Skeleton isLoaded={!contextsIsLoading}>
<Select
id="select"
placeholder="Velg skjema"
onChange={(e) => setCopyContext(e.target.value)}
bgColor="white"
borderColor="gray.200"
value={copyContext ?? undefined}
>
{contextsForTable?.map((context) => (
<option key={context.id} value={context.id}>
{context.name}
</option>
))}
</Select>
</Skeleton>
</FormControl>
);
}
28 changes: 28 additions & 0 deletions frontend/beCompliant/src/hooks/useFetchAllContexts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { useQuery } from '@tanstack/react-query';
import { apiConfig } from '../api/apiConfig';
import { axiosFetch } from '../api/Fetch';
import { Context } from './useFetchTeamContexts';
import { useFetchUserinfo } from './useFetchUserinfo';

export function useFetchAllContexts() {
const { data: userinfo } = useFetchUserinfo();
const teams: string[] = userinfo?.groups.map((group) => group.id) ?? [];

return useQuery({
queryKey: ['allContexts'],
queryFn: async () => {
const promises: Promise<Context[]>[] = [];
for (const team of teams) {
promises.push(
axiosFetch<Context[]>({
url: apiConfig.contexts.forTeam.url(team),
}).then((response) => response.data)
);
}
return (await Promise.all(promises)).reduce((acc, val) => {
return acc.concat(val);
}, []);
},
enabled: !!teams.length,
});
}
17 changes: 1 addition & 16 deletions frontend/beCompliant/src/pages/CreateContextPage.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { useNavigate, useSearchParams } from 'react-router-dom';
import { LockedCreateContextPage } from './LockedCreateContextPage';
import { UnlockedCreateContextPage } from './UnlockedCreateContextPage';
import { useFetchUserinfo } from '../hooks/useFetchUserinfo';
import { useFetchTables } from '../hooks/useFetchTables';
import { Center, Heading, Icon } from '@kvib/react';
import { useSubmitContext } from '../hooks/useSubmitContext';
Expand Down Expand Up @@ -29,19 +28,13 @@ export const CreateContextPage = () => {

const { mutate: submitContext, isPending: isLoading } = useSubmitContext();

const {
data: userinfo,
isPending: isUserinfoLoading,
isError: isUserinfoError,
} = useFetchUserinfo();

const {
data: tablesData,
isPending: tablesIsPending,
error: tablesError,
} = useFetchTables();

if (isUserinfoError || tablesError) {
if (tablesError) {
return (
<Center height="70svh" flexDirection="column" gap="4">
<Icon icon="error" size={64} weight={600} />
Expand Down Expand Up @@ -90,10 +83,6 @@ export const CreateContextPage = () => {

return locked ? (
<LockedCreateContextPage
userinfo={{
data: userinfo,
isPending: isUserinfoLoading,
}}
tablesData={{
data: tablesData,
isPending: tablesIsPending,
Expand All @@ -107,10 +96,6 @@ export const CreateContextPage = () => {
/>
) : (
<UnlockedCreateContextPage
userinfo={{
data: userinfo,
isPending: isUserinfoLoading,
}}
tablesData={{
data: tablesData,
isPending: tablesIsPending,
Expand Down
171 changes: 95 additions & 76 deletions frontend/beCompliant/src/pages/LockedCreateContextPage.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
import { UserInfo } from '../hooks/useFetchUserinfo';
import { useFetchUserinfo } from '../hooks/useFetchUserinfo';
import {
Box,
Button,
Center,
Flex,
FormControl,
FormLabel,
Heading,
Icon,
Select,
Skeleton,
Spinner,
Stack,
Text,
} from '@kvib/react';
import { Form } from 'react-router-dom';
import { FormEvent, useCallback } from 'react';
import { Table } from '../api/types';
import { CopyContextDropdown } from '../components/createContextPage/CopyContextDropdown';
import { useSearchParams } from 'react-router-dom';

type Props = {
userinfo: { data: UserInfo | undefined; isPending: boolean };
tablesData: { data: Table[] | undefined; isPending: boolean };
handleSumbit: (event: FormEvent<HTMLFormElement>) => void;
isLoading: boolean;
Expand All @@ -28,7 +29,6 @@ type Props = {
};

export const LockedCreateContextPage = ({
userinfo,
tablesData,
handleSumbit,
isLoading,
Expand All @@ -37,9 +37,16 @@ export const LockedCreateContextPage = ({
name,
teamId,
}: Props) => {
const teamDisplayName = userinfo.data?.groups.find(
const {
data: userinfo,
isPending: isUserinfoLoading,
isError: isUserinfoError,
} = useFetchUserinfo();

const teamDisplayName = userinfo?.groups.find(
(group) => group.id === teamId
)?.displayName;

const [search, setSearch] = useSearchParams();
const tableId = search.get('tableId');
const copyContext = search.get('copyContext');
Expand All @@ -52,81 +59,93 @@ export const LockedCreateContextPage = ({
[search, setSearch]
);

if (isUserinfoError) {
return (
<Center height="70svh" flexDirection="column" gap="4">
<Icon icon="error" size={64} weight={600} />
<Heading size="md">Noe gikk galt, prøv gjerne igjen</Heading>
</Center>
);
}

return (
<Stack
direction="column"
alignItems="center"
justifyContent="center"
marginTop="8rem"
>
<Form style={{ width: '40ch' }} onSubmit={handleSumbit}>
<Text fontSize="3xl" fontWeight="bold" mb="32px">
Opprett sikkerhetsskjema
</Text>
<Text fontSize="sm" mb="15px">
Velg hvilket sikkerhetsskjema du skal fylle ut for:
</Text>
<Flex gap="20px">
<Flex flexDirection="column" gap="10px">
<Text fontSize="sm" fontWeight="bold">
Funksjon:
</Text>
<Text fontSize="sm" fontWeight="bold">
Team:
</Text>
</Flex>
<Flex flexDirection="column" gap="10px">
<Text fontSize="sm">{name}</Text>
<Skeleton isLoaded={!userinfo.isPending}>
<Text fontSize="sm">
{teamDisplayName ?? '<Ingen team funnet>'}
<Stack alignItems="center" justifyContent="center" marginTop="8rem">
<Stack>
<Stack gap="16px" mb="2rem">
<Text fontSize="3xl" fontWeight="bold" mb="1rem">
Opprett sikkerhetsskjema
</Text>
<Text fontSize="sm">
Velg hvilket sikkerhetsskjema du skal fylle ut for:
</Text>
<Flex gap="20px">
<Stack gap="10px">
<Text fontSize="sm" fontWeight="bold">
Funksjon:
</Text>
</Skeleton>
<Text fontSize="sm" fontWeight="bold">
Team:
</Text>
</Stack>
<Stack gap="10px">
<Text fontSize="sm">{name}</Text>
<Skeleton isLoaded={!isUserinfoLoading}>
<Text fontSize="sm">
{teamDisplayName ?? '<Ingen team funnet>'}
</Text>
</Skeleton>
</Stack>
</Flex>
</Flex>
</Stack>

<Box marginBottom="50px" mt="40px">
<Text fontWeight="bold" fontSize="sm" mb="10px">
Velg sikkerhetsskjema du ønsker å opprette
</Text>
<FormControl>
<Skeleton isLoaded={!tablesData.isPending}>
<Select
id="tableSelect"
onChange={(e) => setTableId(e.target.value)}
placeholder="Velg skjema"
required
w="fit-content"
bgColor="white"
borderColor="gray.200"
value={tableId ?? undefined}
<form onSubmit={handleSumbit}>
<Stack gap="1rem">
<FormControl isRequired={true}>
<FormLabel
style={{
fontSize: 'small',
fontWeight: 'bold',
}}
>
{tablesData?.data?.map((table) => (
<option key={table.id} value={table.id}>
{table.name}
</option>
))}
</Select>
</Skeleton>
</FormControl>
</Box>
{tableId && tableId.trim() && teamId && teamId.trim() && (
<CopyContextDropdown
tableId={tableId}
teamId={teamId}
copyContext={copyContext}
setCopyContext={setCopyContext}
/>
)}
<Button
type="submit"
variant="primary"
colorScheme="blue"
disabled={isButtonDisabled}
>
{isLoading ? <Spinner size="sm" /> : 'Opprett skjema'}
</Button>
</Form>
Velg sikkerhetsskjema du ønsker å opprette
</FormLabel>
<Skeleton isLoaded={!tablesData.isPending}>
<Select
id="tableSelect"
onChange={(e) => setTableId(e.target.value)}
placeholder="Velg skjema"
required
w="fit-content"
bgColor="white"
borderColor="gray.200"
value={tableId ?? undefined}
>
{tablesData?.data?.map((table) => (
<option key={table.id} value={table.id}>
{table.name}
</option>
))}
</Select>
</Skeleton>
</FormControl>
{tableId && tableId.trim() && teamId && teamId.trim() && (
<CopyContextDropdown
tableId={tableId}
copyContext={copyContext}
setCopyContext={setCopyContext}
/>
)}
<Button
type="submit"
variant="primary"
colorScheme="blue"
disabled={isButtonDisabled}
>
{isLoading ? <Spinner size="sm" /> : 'Opprett skjema'}
</Button>
</Stack>
</form>
</Stack>
</Stack>
);
};
Loading
Loading