mirror of
https://github.com/multica-ai/multica.git
synced 2026-07-05 13:29:44 +02:00
Adds avatar_url column to workspace, threads it through the API +
WorkspaceAvatar component, and adds a click-to-upload editor in the
workspace settings tab. Mirrors the squad avatar pattern (migration 086);
UI strings use "logo" while the schema/code uses avatar_url for codebase
consistency with user.avatar_url and squad.avatar_url.
- migration 093: ALTER TABLE workspace ADD COLUMN avatar_url TEXT
- UpdateWorkspace SQL + handler accept avatar_url (auth gated to
owner/admin at the router via RequireWorkspaceRoleFromURL)
- WorkspaceAvatar renders <img> when avatar_url is set, falls back to
the initial-letter span otherwise
- workspace-tab.tsx adds a 16x16 click-to-upload logo editor at the
top of the general settings card, using useFileUpload + accept=
image/png,image/jpeg,image/webp (server stores under workspaces/{id}/)
- en + zh-Hans settings i18n strings added
Co-authored-by: Matt Voska <voska@users.noreply.github.com>
48 lines
1.6 KiB
TypeScript
48 lines
1.6 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import type { Workspace } from "../types";
|
|
import { paths } from "./paths";
|
|
import { resolvePostAuthDestination } from "./resolve";
|
|
|
|
function makeWs(slug: string): Workspace {
|
|
return {
|
|
id: `id-${slug}`,
|
|
name: slug,
|
|
slug,
|
|
description: null,
|
|
context: null,
|
|
settings: {},
|
|
repos: [],
|
|
issue_prefix: slug.toUpperCase(),
|
|
avatar_url: null,
|
|
created_at: "",
|
|
updated_at: "",
|
|
};
|
|
}
|
|
|
|
describe("resolvePostAuthDestination", () => {
|
|
it("!onboarded → /onboarding (even with a workspace)", () => {
|
|
// V3 invariant: onboarded_at is the single source of truth for
|
|
// workspace access. A user holding workspaces but flagged !onboarded
|
|
// (rare mid-flow state: closed app between Step 2 and Step 3) gets
|
|
// routed to /onboarding so they can finish; the layout hard gate
|
|
// would redirect them anyway.
|
|
const ws = [makeWs("acme")];
|
|
expect(resolvePostAuthDestination(ws, false)).toBe(paths.onboarding());
|
|
expect(resolvePostAuthDestination([], false)).toBe(paths.onboarding());
|
|
});
|
|
|
|
it("onboarded + workspace[0] → /<first.slug>/issues", () => {
|
|
const ws = [makeWs("acme"), makeWs("beta")];
|
|
expect(resolvePostAuthDestination(ws, true)).toBe(
|
|
paths.workspace("acme").issues(),
|
|
);
|
|
});
|
|
|
|
it("onboarded + no workspace → /workspaces/new", () => {
|
|
// Already-onboarded user without any workspace — usually a returning
|
|
// user whose last workspace got deleted or who left it. They skip
|
|
// re-onboarding and go straight to workspace creation.
|
|
expect(resolvePostAuthDestination([], true)).toBe(paths.newWorkspace());
|
|
});
|
|
});
|