Skip to content

Commit

Permalink
Custom schema view (#268)
Browse files Browse the repository at this point in the history
* wip

* custom view for schemas

* fix

* fix

* fix
  • Loading branch information
starheim98 authored Jan 29, 2025
1 parent 3187029 commit b59044e
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 46 deletions.
156 changes: 125 additions & 31 deletions frisk.config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,21 @@ import {
} from "@/services/backend";
import { getRegelrettClientId, getregelrettFrontendUrl } from "@/config";
import { object, string, array, type z } from "zod";
import { Button, FormControl, FormLabel, Select } from "@kvib/react";
import {
Button,
Flex,
FormControl,
FormLabel,
IconButton,
Link,
Select,
useDisclosure,
} from "@kvib/react";
import type { useFunction } from "@/hooks/use-function";
import type { useMetadata } from "@/hooks/use-metadata";
import { msalInstance } from "@/services/msal";
import { InteractionRequiredAuthError } from "@azure/msal-browser";
import type { useMetadata } from "@/hooks/use-metadata";
import { DeleteMetadataModal } from "@/components/delete-metadata-modal";

export async function getConfig(): Promise<FriskConfig> {
const schemas = await getSchemasFromRegelrett();
Expand Down Expand Up @@ -74,34 +84,6 @@ export async function getConfig(): Promise<FriskConfig> {
return { displayValue: "Utviklerportalen" };
},
},
...schemas.map(
(schema): InputMetadata => ({
key: schema.id,
type: "text",
displayName: schema.name,
label: "Regelrett skjema",
show: (mode, hasAccess) => mode === "read" && hasAccess,
isRequired: false,
placeholder: "Sett inn skjema",
inheritFromParent: false,
getDisplayValue: async (input) => {
const contextId = input.value;
const searchParams = new URLSearchParams({
redirectBackUrl: window.location.href,
redirectBackTitle: "Funksjonsregisteret",
});
const url = `${getregelrettFrontendUrl()}/context/${contextId}?${searchParams.toString()}`;
return {
displayValue: schema.name,
value: url,
displayOptions: {
type: "url",
isExternal: false,
},
};
},
}),
),
{
key: "dependencies",
type: "select",
Expand All @@ -126,6 +108,41 @@ export async function getConfig(): Promise<FriskConfig> {
placeholder: "Søk etter funksjoner",
inheritFromParent: false,
},
...schemas.map(
(schema): InputMetadata => ({
key: schema.id,
type: "text",
displayName: schema.name,
label: "Regelrett skjema",
show: (mode, hasAccess) => mode === "read" && hasAccess,
isRequired: false,
placeholder: "Sett inn skjema",
inheritFromParent: false,
getDisplayValue: async (input) => {
const contextId = input.value;
const searchParams = new URLSearchParams({
redirectBackUrl: window.location.href,
redirectBackTitle: "Funksjonsregisteret",
});
const url = `${getregelrettFrontendUrl()}/context/${contextId}?${searchParams.toString()}`;
return {
displayValue: "Skjema",
displayOptions: {
type: "custom",
component: (
<SchemaDisplay
key={contextId}
schema={schema}
url={url}
functionId={input.functionId}
metadataId={input.id}
/>
),
},
};
},
}),
),
],

logo: {
Expand Down Expand Up @@ -191,7 +208,12 @@ type GeneralMetadataContent = {
* you can use this function to get the display value. Often used together with inputType: "select" since
* selects has both a value, and a name.
*/
getDisplayValue?: (input: { key: string; value: string }) => Promise<{
getDisplayValue?: (input: {
key: string;
value: string;
functionId: number;
id: number;
}) => Promise<{
displayValue: string;
value?: string;
displayOptions?:
Expand All @@ -204,6 +226,10 @@ type GeneralMetadataContent = {
| {
type: "url";
isExternal: boolean;
}
| {
type: "custom";
component: React.ReactNode;
};
}>;
};
Expand Down Expand Up @@ -320,6 +346,74 @@ function createSchemaComponent(schemas: RegelrettSchema[]) {
};
}

type Schema = {
id: string;
name: string;
};

type SchemaDisplayProps = {
schema: Schema;
url: string;
functionId: number;
metadataId: number;
};

function SchemaDisplay({
schema,
url,
functionId,
metadataId,
}: SchemaDisplayProps) {
const { isOpen, onOpen, onClose } = useDisclosure();

return (
<Flex width="90%" gap={2} alignItems="center">
<Button
colorScheme="blue"
as={Link}
href={url}
isExternal={false}
variant="secondary"
borderRadius="md"
backgroundColor="white"
leftIcon="article"
textDecoration="none"
size="sm"
onClick={(e) => e.stopPropagation()}
overflow="hidden"
fontWeight="medium"
fontSize="sm"
justifyContent="start"
flex="1"
>
{schema.name}
</Button>

<IconButton
aria-label="Delete schema"
icon="delete"
variant="tertiary"
size="sm"
colorScheme="red"
borderRadius="md"
_hover={{ backgroundColor: "red.50" }}
onClick={(e) => {
e.stopPropagation();
onOpen();
}}
/>
<DeleteMetadataModal
onOpen={onOpen}
onClose={onClose}
isOpen={isOpen}
functionId={functionId}
metadataId={metadataId}
displayValue={schema.name}
/>
</Flex>
);
}

const REGELRETT_BACKEND_URL = `${getregelrettFrontendUrl()}/api`;

async function getSchemasFromRegelrett() {
Expand Down
2 changes: 1 addition & 1 deletion src/components/delete-metadata-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export function DeleteMetadataModal({
colorScheme="red"
leftIcon="delete"
onClick={async (e) => {
e.preventDefault();
e.stopPropagation();
removeMetadata.mutateAsync({
id: metadataId,
functionId: functionId,
Expand Down
26 changes: 12 additions & 14 deletions src/components/metadata/metadata-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,23 +58,19 @@ export function MetadataView({ metadata, functionId }: Props) {
) : null}
{displayValues.map((dv, i) => {
const isDisplayValueLoading = dv.isLoading;
const displayValue =
dv.data?.displayValue ?? metadataToDisplay?.[i]?.value;
const metadataDisplayType = dv.data?.displayOptions?.type;
const metadataType = metadata.type;
const metaDataValue = dv.data?.value ?? metadataToDisplay?.[i]?.value;
const metadataId = metadataToDisplay?.[i]?.id;
const isLoading = isCurrentMetadataLoading || isDisplayValueLoading;
const isNoMetadata = !currentMetadata && !isCurrentMetadataLoading;

if (isNoMetadata) return null;

switch (metadataDisplayType) {
switch (dv.data?.displayOptions?.type) {
case "text":
return (
<TextView
key={metaDataValue}
displayValue={displayValue}
displayValue={dv.data.displayValue}
isLoading={isLoading}
/>
);
Expand All @@ -83,8 +79,8 @@ export function MetadataView({ metadata, functionId }: Props) {
<LinkView
key={metaDataValue}
url={metaDataValue}
displayValue={displayValue}
isExternal={dv.data?.displayOptions?.isExternal ?? true}
displayValue={dv.data.displayValue}
isExternal={dv.data.displayOptions.isExternal}
isDeletable={isDeletable}
metadataId={metadataId}
functionId={functionId}
Expand All @@ -96,20 +92,22 @@ export function MetadataView({ metadata, functionId }: Props) {
return (
<PillView
key={metaDataValue}
displayValue={displayValue}
displayValue={dv.data.displayValue}
isLoading={isLoading}
/>
);
case "custom":
return dv.data.displayOptions.component;

case undefined:
switch (metadataType) {
switch (metadata.type) {
case "select":
case "number":
case "text":
return (
<TextView
key={metaDataValue}
displayValue={displayValue}
displayValue={dv.data?.displayValue ?? metaDataValue}
isLoading={isLoading}
/>
);
Expand All @@ -118,7 +116,7 @@ export function MetadataView({ metadata, functionId }: Props) {
<LinkView
key={metaDataValue}
url={metaDataValue}
displayValue={displayValue}
displayValue={dv.data?.displayValue ?? metaDataValue}
isExternal={metadata.isExternal}
isDeletable={isDeletable}
metadataId={metadataId}
Expand All @@ -127,12 +125,12 @@ export function MetadataView({ metadata, functionId }: Props) {
/>
);
default:
metadataType satisfies never;
metadata satisfies never;
console.error("Unsupported data type");
return null;
}
default:
metadataDisplayType satisfies never;
dv.data?.displayOptions satisfies undefined;
console.error("Unsupported data type");
return null;
}
Expand Down

0 comments on commit b59044e

Please sign in to comment.