Skip to content

Commit

Permalink
Quotas (#143)
Browse files Browse the repository at this point in the history
At long last, the promised land!!  The dashboard actually has something
on it.
  • Loading branch information
spjmurray authored Jan 31, 2025
1 parent 62d5576 commit f953f42
Show file tree
Hide file tree
Showing 42 changed files with 1,734 additions and 345 deletions.
37 changes: 17 additions & 20 deletions src/lib/clients/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,14 @@ function traceContextMiddleware(): Identity.Middleware {
// accessToken is a callback to get the Authorization header. Crucially this
// also has a reference to the full token, so san see when the access token
// has expired and refresh it using the refresh token.
async function accessToken(tokens: InternalToken): Promise<string> {
async function accessToken(tokens: InternalToken, fetchImpl?: typeof fetch): Promise<string> {
if (!tokens) return '';

// TODO: we could get multiple API calls concurrently, at which point
// we are repeating the operation, be nice if we could handle this
// somehow.
if (new Date(Date.now()).toJSON() > tokens.expiry) {
const discovery = await OIDC.discovery();
const discovery = await OIDC.discovery(fetchImpl || fetch);

const form = new URLSearchParams({
grant_type: 'refresh_token',
Expand Down Expand Up @@ -119,62 +119,59 @@ async function accessToken(tokens: InternalToken): Promise<string> {
}

// client gets a new initialized client with auth and any additional middlewares.
export function kubernetes(
tokens: InternalToken,
fetch?: Kubernetes.FetchAPI
): Kubernetes.DefaultApi {
export function kubernetes(tokens: InternalToken, fetchImpl?: typeof fetch): Kubernetes.DefaultApi {
const config = new Kubernetes.Configuration({
basePath: env.PUBLIC_KUBERNETES_HOST,
accessToken: async () => accessToken(tokens),
accessToken: async () => accessToken(tokens, fetchImpl),
middleware: [authenticationMiddleware(), traceContextMiddleware()],
fetchApi: fetch
fetchApi: fetchImpl
});

return new Kubernetes.DefaultApi(config);
}

export function compute(tokens: InternalToken, fetch?: Compute.FetchAPI): Compute.DefaultApi {
export function compute(tokens: InternalToken, fetchImpl?: typeof fetch): Compute.DefaultApi {
const config = new Compute.Configuration({
basePath: env.PUBLIC_COMPUTE_HOST,
accessToken: async () => accessToken(tokens),
accessToken: async () => accessToken(tokens, fetchImpl),
middleware: [authenticationMiddleware(), traceContextMiddleware()],
fetchApi: fetch
fetchApi: fetchImpl
});

return new Compute.DefaultApi(config);
}

export function application(
tokens: InternalToken,
fetch?: Application.FetchAPI
fetchImpl?: typeof fetch
): Application.DefaultApi {
const config = new Application.Configuration({
basePath: env.PUBLIC_APPLICATION_HOST,
accessToken: async () => accessToken(tokens),
accessToken: async () => accessToken(tokens, fetchImpl),
middleware: [authenticationMiddleware(), traceContextMiddleware()],
fetchApi: fetch
fetchApi: fetchImpl
});

return new Application.DefaultApi(config);
}

export function identity(tokens: InternalToken, fetch?: Identity.FetchAPI): Identity.DefaultApi {
export function identity(tokens: InternalToken, fetchImpl?: typeof fetch): Identity.DefaultApi {
const config = new Identity.Configuration({
basePath: env.PUBLIC_OAUTH2_ISSUER,
accessToken: async () => accessToken(tokens),
accessToken: async () => accessToken(tokens, fetchImpl),
middleware: [authenticationMiddleware(), traceContextMiddleware()],
fetchApi: fetch
fetchApi: fetchImpl
});

return new Identity.DefaultApi(config);
}

export function region(tokens: InternalToken, fetch?: Region.FetchAPI): Region.DefaultApi {
export function region(tokens: InternalToken, fetchImpl?: typeof fetch): Region.DefaultApi {
const config = new Region.Configuration({
basePath: env.PUBLIC_REGION_HOST,
accessToken: async () => accessToken(tokens),
accessToken: async () => accessToken(tokens, fetchImpl),
middleware: [authenticationMiddleware(), traceContextMiddleware()],
fetchApi: fetch
fetchApi: fetchImpl
});

return new Region.DefaultApi(config);
Expand Down
28 changes: 28 additions & 0 deletions src/lib/forms/NumberInput.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<script lang="ts">
interface Props {
// Unique element ID.
id: string;
// Value to bind to.
value: number;
// Label to attach describing the input.
label: string;
// Formatting hint.
hint?: string;
min?: number;
max?: number;
}
let { id, value = $bindable(), label, hint = '', min = 0, max }: Props = $props();
</script>

<div class="flex flex-col gap-4">
<div class="flex flex-col gap-1">
<label for={id}>{label}</label>

{#if hint}
<div class="text-xs italic text-surface-500">{hint}</div>
{/if}
</div>

<input {id} class="input shadow-lg" type="number" bind:value {min} {max} />
</div>
2 changes: 1 addition & 1 deletion src/lib/layouts/ShellList.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@
</script>

<!-- In mobile mode show vertical cards, in desktop mode show horizontal table rows -->
<div class="flex flex-col lg:grid lg:grid-cols-[repeat(6,max-content)_auto] gap-4">
<div class="flex flex-col lg:grid lg:grid-cols-[repeat(6,max-content)_auto] lg:auto-rows-fr gap-2">
{@render children?.()}
</div>
4 changes: 2 additions & 2 deletions src/lib/layouts/ShellListItem.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
</script>

<article
class="flex gap-2 lg:gap-8 lg:col-span-full lg:grid lg:grid-cols-subgrid lg:items-center card bg-surface-50-900-token shadow-lg p-4"
class="flex gap-2 lg:gap-4 lg:col-span-full lg:grid lg:grid-cols-subgrid lg:items-center card bg-surface-50-900-token shadow-lg p-4"
>
<div class="flex flex-col gap-4 lg:contents overflow-hidden">
<div class="flex items-center gap-4 lg:contents overflow-hidden">
<iconify-icon {icon} class="text-2xl text-primary-500"></iconify-icon>
<iconify-icon {icon} class="text-4xl text-primary-500"></iconify-icon>

<div class="overflow-hidden text-ellipsis">
{@render main()}
Expand Down
4 changes: 2 additions & 2 deletions src/lib/layouts/ShellListItemHeader.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
</script>

{#snippet header()}
<header class="flex flex-col gap-1 bg-surface-50-900-token">
<header class="flex flex-col gap-1">
{#if project}
<div class="flex gap-2 items-center tex-sm overflow-hidden text-ellipsis whitespace-nowrap">
<iconify-icon icon="mdi:account-group-outline"></iconify-icon>
Expand All @@ -47,7 +47,7 @@
</div>

{#if metadata?.description}
<div class="text-sm italic text-surface-500 bg-surface-50-900-token whitespace-nowrap">
<div class="text-sm italic text-surface-500 whitespace-nowrap">
{metadata.description}
</div>
{/if}
Expand Down
70 changes: 0 additions & 70 deletions src/lib/login/index.ts

This file was deleted.

4 changes: 2 additions & 2 deletions src/lib/oidc/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@ export type DiscoveryInfo = {
};

// Return something that promises to return discovery data.
export function discovery(): Promise<DiscoveryInfo> {
export function discovery(fetchImpl: typeof fetch): Promise<DiscoveryInfo> {
const discoveryURL = `${issuer}/.well-known/openid-configuration`;
const discoveryOptions = {
method: 'GET'
};

return fetch(discoveryURL, discoveryOptions)
return fetchImpl(discoveryURL, discoveryOptions)
.then((response) => response.json())
.catch((error) => console.log(error));
}
Expand Down
8 changes: 8 additions & 0 deletions src/lib/openapi/identity/.openapi-generator/FILES
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ models/Acl.ts
models/AclEndpoint.ts
models/AclOperation.ts
models/AclScopedEndpoints.ts
models/AllocationRead.ts
models/AllocationSpec.ts
models/AllocationWrite.ts
models/AuthMethod.ts
models/Claim.ts
models/CodeChallengeMethod.ts
Expand All @@ -26,9 +29,14 @@ models/OrganizationSpec.ts
models/OrganizationType.ts
models/OrganizationWrite.ts
models/ProjectRead.ts
models/ProjectScopedResourceReadMetadata.ts
models/ProjectSpec.ts
models/ProjectWrite.ts
models/ProviderScope.ts
models/Quota.ts
models/QuotaDetailed.ts
models/QuotasRead.ts
models/QuotasWrite.ts
models/ResourceMetadata.ts
models/ResourceProvisioningStatus.ts
models/ResourceReadMetadata.ts
Expand Down
Loading

0 comments on commit f953f42

Please sign in to comment.