Switch to internally managed roles, adapt frontend

This commit is contained in:
2025-10-07 02:04:35 +02:00
parent dc0ec5c635
commit 90729736ca
11 changed files with 248 additions and 351 deletions

View File

@@ -1,4 +1,4 @@
import { type Me } from "common/the_api";
import { type User } from "common/the_api";
import { identity } from "effect";
import { useLayoutEffect, useState } from "react";
@@ -10,14 +10,14 @@ export const mapProp = <const K extends string, T>(prop: K, action: Update<T>) =
};
export interface Store {
readonly user: Me | null;
readonly user: User | null;
}
let store: Store = Object.freeze<Store>({
user: null,
});
export function setUser(action: Update<Me | null>) {
export function setUser(action: Update<User | null>) {
set(mapProp("user", action));
}

View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="uuid-f8d4d392-7c12-4bd9-baff-66fbf7814b91" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18">
<path d="m3.802,14.032c.388.242,1.033.511,1.715.511.621,0,1.198-.18,1.676-.487,0,0,.001,0,.002-.001l1.805-1.128v4.073c-.286,0-.574-.078-.824-.234l-4.374-2.734Z" fill="#225086"/>
<path d="m7.853,1.507L.353,9.967c-.579.654-.428,1.642.323,2.111,0,0,2.776,1.735,3.126,1.954.388.242,1.033.511,1.715.511.621,0,1.198-.18,1.676-.487,0,0,.001,0,.002-.001l1.805-1.128-4.364-2.728,4.365-4.924V1s0,0,0,0c-.424,0-.847.169-1.147.507Z" fill="#6df"/>
<polygon points="4.636 10.199 4.688 10.231 9 12.927 9.001 12.927 9.001 12.927 9.001 5.276 9 5.275 4.636 10.199" fill="#cbf8ff"/>
<path d="m17.324,12.078c.751-.469.902-1.457.323-2.111l-4.921-5.551c-.397-.185-.842-.291-1.313-.291-.925,0-1.752.399-2.302,1.026l-.109.123h0s4.364,4.924,4.364,4.924h0s0,0,0,0l-4.365,2.728v4.073c.287,0,.573-.078.823-.234l7.5-4.688Z" fill="#074793"/>
<path d="m9.001,1v4.275s.109-.123.109-.123c.55-.627,1.377-1.026,2.302-1.026.472,0,.916.107,1.313.291l-2.579-2.909c-.299-.338-.723-.507-1.146-.507Z" fill="#0294e4"/>
<polygon points="13.365 10.199 13.365 10.199 13.365 10.199 9.001 5.276 9.001 12.926 13.365 10.199" fill="#96bcc2"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -1,13 +1,8 @@
import { API_URL_PREFIX } from "@/client";
import { buttonVariants } from "@/components/ui/button";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import microsoftEntraId from "@/icons/microsoft-entra-id.svg";
export function Login() {
const internalUrl = `${API_URL_PREFIX}/login`;
const externalUrl = `${API_URL_PREFIX}/login?external`;
return (
<div className="w-full h-full flex items-center justify-center">
<Card>
@@ -16,22 +11,8 @@ export function Login() {
<CardDescription>Zaloguj się, aby kontynuować</CardDescription>
</CardHeader>
<CardContent className="flex flex-col gap-2 content-stretch max-w-sm">
<div
className="text-sm text-stone-500 dark:text-stone-400"
>
Użyj emaila i hasła, konta Microsoft lub konta Google.
</div>
<a className={buttonVariants()} href={externalUrl}>
Konto zewnętrzne
</a>
<div
className="text-sm text-stone-500 dark:text-stone-400 mt-4"
>
Użyj konta firmowego.
</div>
<a className={buttonVariants()} href={internalUrl}>
<img src={microsoftEntraId} />
<div>Konto firmowe</div>
<a className={buttonVariants()} href={`${API_URL_PREFIX}/login`}>
Zaloguj się
</a>
</CardContent>
</Card>

View File

@@ -326,7 +326,8 @@ function AttachmentForm(props: AttachmentForm.Props) {
continue;
}
const data = yield* Body.bytes(file);
// NOTE Apparently, file.bytes is not a thing in this context
const data = new Uint8Array(yield* Body.arrayBuffer(file));
const exit = yield* Effect.exit(client.createAttachment({
pieceId: props.pieceId,
@@ -340,7 +341,7 @@ function AttachmentForm(props: AttachmentForm.Props) {
continue;
}
const attachment = yield* denormalizeSystemInformation(exit.exitValue);
const attachment = yield* denormalizeSystemInformation(exit.value);
props.setAttachments((prev) => {
const next = [...prev, attachment];

View File

@@ -2,7 +2,7 @@ import { client } from "@/client";
import { Button, buttonVariants } from "@/components/ui/button";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
import { setUser, useStore } from "@/hooks/useStore";
import { Effect, pipe } from "effect";
import { Effect, Option, pipe } from "effect";
import { LogOut, Settings, User } from "lucide-react";
import { useEffect } from "react";
import { Link, Outlet, useNavigate } from "react-router-dom";
@@ -53,7 +53,7 @@ export function Root() {
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button type="button" variant="outline">
<User />{user.displayName}
<User />{Option.getOrElse(user.displayName, () => user.userId)}
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">

View File

@@ -37,8 +37,8 @@ export function created({ createdAt, createdBy }: DenormalizedSystemInformation)
if (Option.isSome(createdBy)) {
nodes.push(<br />);
if (createdBy.value !== null) {
nodes.push(`przez ${createdBy.value.displayName}`);
if (Option.isSome(createdBy.value.displayName)) {
nodes.push(`przez ${createdBy.value.displayName.value}`);
} else {
nodes.push("przez nieznanego użytkownika");
}
@@ -53,8 +53,8 @@ export function modified({ modifiedAt, modifiedBy }: DenormalizedSystemInformati
if (Option.isNone(modifiedBy)) {
return "\u2014";
} else {
if (modifiedBy.value !== null) {
return `przez ${modifiedBy.value.displayName}`;
if (Option.isSome(modifiedBy.value.displayName)) {
return `przez ${modifiedBy.value.displayName.value}`;
} else {
return "przez nieznanego użytkownika";
}
@@ -65,8 +65,8 @@ export function modified({ modifiedAt, modifiedBy }: DenormalizedSystemInformati
if (Option.isSome(modifiedBy)) {
nodes.push(<br />);
if (modifiedBy.value !== null) {
nodes.push(`przez ${modifiedBy.value.displayName}`);
if (Option.isSome(modifiedBy.value.displayName)) {
nodes.push(`przez ${modifiedBy.value.displayName.value}`);
} else {
nodes.push("przez nieznanego użytkownika");
}