fix: validate repository settings wire response
This commit is contained in:
@@ -1,9 +1,20 @@
|
||||
<script lang="ts">
|
||||
import { invalidateAll } from '$app/navigation';
|
||||
import { workspaceApiPath, workspaceRoute } from '$lib/workspace/api/http';
|
||||
import type { RepositorySourceKind } from '$lib/generated/workspace-api';
|
||||
import type { PageProps } from './$types';
|
||||
|
||||
let { data }: PageProps = $props();
|
||||
|
||||
function sourceLabel(kind: RepositorySourceKind): string {
|
||||
if (kind === 'local_path' || kind === 'file') return 'Local';
|
||||
if (kind === 'invalid') return 'Invalid';
|
||||
return 'Remote Git';
|
||||
}
|
||||
|
||||
function supportsRepositoryAccess(kind: RepositorySourceKind): boolean {
|
||||
return kind === 'ssh' || kind === 'http' || kind === 'https';
|
||||
}
|
||||
let showAddRepository = $state(false);
|
||||
let repositoryId = $state('');
|
||||
let displayName = $state('');
|
||||
@@ -122,22 +133,22 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each data.repositories.items as repository (repository.repository_id)}
|
||||
{#each data.repositories.items as repository (repository.id)}
|
||||
<tr>
|
||||
<td>
|
||||
<a class="inline-link" href={workspaceRoute(data.workspaceId, `/repositories/${encodeURIComponent(repository.repository_id)}`)}>
|
||||
<a class="inline-link" href={workspaceRoute(data.workspaceId, `/repositories/${encodeURIComponent(repository.id)}`)}>
|
||||
<strong>{repository.display_name}</strong>
|
||||
</a>
|
||||
<small><code>{repository.repository_id}</code></small>
|
||||
<small><code>{repository.id}</code></small>
|
||||
</td>
|
||||
<td>
|
||||
<span>{repository.source.kind === 'local_path' ? 'Local' : 'Remote Git'}</span>
|
||||
<span>{sourceLabel(repository.source.kind)}</span>
|
||||
<small><code>{repository.source.uri}</code></small>
|
||||
</td>
|
||||
<td>{repository.default_selector ?? '—'}</td>
|
||||
<td>{repository.observed.status}</td>
|
||||
<td>{repository.observed_status}</td>
|
||||
<td>
|
||||
{#if repository.source.kind === 'remote_git'}
|
||||
{#if supportsRepositoryAccess(repository.source.kind)}
|
||||
<a class="inline-link" href={workspaceRoute(data.workspaceId, '/settings/repository-access')}>Configure access</a>
|
||||
{:else}
|
||||
<span class="settings-muted-action">Not required</span>
|
||||
|
||||
@@ -1,34 +1,13 @@
|
||||
import { loadJson, workspaceApiPath } from "$lib/workspace/api/http";
|
||||
import { parseRepositoryListResponse } from "$lib/workspace/api/workspace-model";
|
||||
import type { PageLoad } from "./$types";
|
||||
|
||||
export type RepositorySource = {
|
||||
kind: "local_path" | "remote_git";
|
||||
uri: string;
|
||||
};
|
||||
|
||||
export type RepositorySummary = {
|
||||
repository_id: string;
|
||||
display_name: string;
|
||||
kind: string;
|
||||
provider: string;
|
||||
source: RepositorySource;
|
||||
default_selector?: string | null;
|
||||
observed: {
|
||||
status: string;
|
||||
observed_at?: string | null;
|
||||
};
|
||||
diagnostics: Array<{ code: string; message: string }>;
|
||||
};
|
||||
|
||||
type RepositoryListResponse = {
|
||||
items: RepositorySummary[];
|
||||
diagnostics: Array<{ code: string; message: string }>;
|
||||
};
|
||||
|
||||
export const load: PageLoad = async ({ fetch, params }) => {
|
||||
const repositories = await loadJson<RepositoryListResponse>(
|
||||
const repositories = await loadJson(
|
||||
fetch,
|
||||
workspaceApiPath(params.workspaceId, "/repositories"),
|
||||
undefined,
|
||||
parseRepositoryListResponse,
|
||||
);
|
||||
return {
|
||||
workspaceId: params.workspaceId,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
declare const Deno: {
|
||||
test(name: string, fn: () => void | Promise<void>): void;
|
||||
readTextFile(path: URL): Promise<string>;
|
||||
};
|
||||
|
||||
import {
|
||||
@@ -108,3 +109,45 @@ Deno.test("workspace response requires the permission projection", () => {
|
||||
"permissions must be an object",
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("Repository settings consume the validated shared wire shape", async () => {
|
||||
const [loadSource, pageSource] = await Promise.all([
|
||||
Deno.readTextFile(
|
||||
new URL(
|
||||
"../src/routes/w/[workspaceId]/settings/repositories/+page.ts",
|
||||
import.meta.url,
|
||||
),
|
||||
),
|
||||
Deno.readTextFile(
|
||||
new URL(
|
||||
"../src/routes/w/[workspaceId]/settings/repositories/+page.svelte",
|
||||
import.meta.url,
|
||||
),
|
||||
),
|
||||
]);
|
||||
|
||||
for (
|
||||
const token of [
|
||||
"parseRepositoryListResponse",
|
||||
"repository.id",
|
||||
"repository.observed_status",
|
||||
"sourceLabel(repository.source.kind)",
|
||||
"supportsRepositoryAccess(repository.source.kind)",
|
||||
]
|
||||
) {
|
||||
if (!loadSource.includes(token) && !pageSource.includes(token)) {
|
||||
throw new Error(`Repository settings should include ${token}`);
|
||||
}
|
||||
}
|
||||
for (
|
||||
const staleToken of [
|
||||
"repository.repository_id",
|
||||
"repository.observed.status",
|
||||
"repository.source.kind === 'remote_git'",
|
||||
]
|
||||
) {
|
||||
if (loadSource.includes(staleToken) || pageSource.includes(staleToken)) {
|
||||
throw new Error(`Repository settings must not use ${staleToken}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user