Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/frontend/src/lib/components/modals/Modals.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { nonNullish } from '@dfinity/utils';
import AuthConfigModal from '$lib/components/modals/auth/AuthConfigModal.svelte';
import UserDetailsModal from '$lib/components/modals/auth/UserDetailsModal.svelte';
import AutomationKeysConfigModal from '$lib/components/modals/automation/AutomationKeysConfigModal.svelte';
import CreateAutomationModal from '$lib/components/modals/automation/CreateAutomationModal.svelte';
import ApplyChangeModal from '$lib/components/modals/changes/ApplyChangeModal.svelte';
import RejectChangeModal from '$lib/components/modals/changes/RejectChangeModal.svelte';
Expand Down Expand Up @@ -168,3 +169,7 @@
{#if modal?.type === 'create_automation' && nonNullish(modal.detail)}
<CreateAutomationModal detail={modal.detail} onclose={close} />
{/if}

{#if modal?.type === 'edit_automation_keys_config' && nonNullish(modal.detail)}
<AutomationKeysConfigModal detail={modal.detail} onclose={close} />
{/if}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<script lang="ts">
import AutomationKeysConfigForm from '$lib/components/satellites/automation/settings/AutomationKeysConfigForm.svelte';
import Modal from '$lib/components/ui/Modal.svelte';
import SpinnerModal from '$lib/components/ui/SpinnerModal.svelte';
import { authIdentity } from '$lib/derived/auth.derived';
import { updateAutomationKeysConfig } from '$lib/services/satellite/automation/automation.config.edit.services';
import { wizardBusy } from '$lib/stores/app/busy.store';
import { i18n } from '$lib/stores/app/i18n.store';
import type { AddAccessKeyScope } from '$lib/types/access-keys';
import type { JunoModalAutomationConfigDetail, JunoModalDetail } from '$lib/types/modal';

interface Props {
detail: JunoModalDetail;
onclose: () => void;
}

let { detail: d, onclose }: Props = $props();

let detail = $derived(d as JunoModalAutomationConfigDetail);

let satellite = $derived(detail.satellite);
let automationConfig = $derived(detail.automationConfig);
let providerConfig = $derived(detail.providerConfig);

let scope = $state<Omit<AddAccessKeyScope, 'admin'> | undefined>(undefined);
let maxTimeToLive = $state<bigint | undefined>(undefined);

let step: 'init' | 'in_progress' | 'ready' | 'error' = $state('init');

const handleSubmit = async ($event: SubmitEvent) => {
$event.preventDefault();

wizardBusy.start();
step = 'in_progress';

const { success } = await updateAutomationKeysConfig({
satellite,
identity: $authIdentity,
automationConfig,
providerConfig,
maxTimeToLive,
scope
});

wizardBusy.stop();

if (success !== 'ok') {
step = 'init';
return;
}

step = 'ready';
};
</script>

<Modal {onclose}>
{#if step === 'ready'}
<div class="msg">
<p>{$i18n.core.configuration_applied}</p>
<button onclick={onclose}>{$i18n.core.close}</button>
</div>
{:else if step === 'in_progress'}
<SpinnerModal>
<p>{$i18n.core.updating_configuration}</p>
</SpinnerModal>
{:else}
<AutomationKeysConfigForm
config={providerConfig}
onsubmit={handleSubmit}
bind:scope
bind:maxTimeToLive
/>
{/if}
</Modal>

<style lang="scss">
@use '../../../styles/mixins/overlay';

.msg {
@include overlay.message;
}
</style>
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import SpinnerParagraph from '$lib/components/ui/SpinnerParagraph.svelte';
import Warning from '$lib/components/ui/Warning.svelte';
import { authIdentity } from '$lib/derived/auth.derived';
import { satelliteAuthConfig } from '$lib/derived/satellite/satellite-configs.derived';
import { getRuleUser } from '$lib/services/satellite/collection/collection.services';
import { loadSatelliteConfig } from '$lib/services/satellite/satellite-config.services';
import { i18n } from '$lib/stores/app/i18n.store';
Expand Down Expand Up @@ -37,8 +36,6 @@
});
};

$inspect($satelliteAuthConfig);

const load = async () => {
await Promise.all([loadConfig(), loadRule()]);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<script lang="ts">
import type { SatelliteDid } from '$declarations';
import GitHubConfigGuard from '$lib/components/satellites/automation/guards/GitHubConfigGuard.svelte';
import AutomationKeysSettings from '$lib/components/satellites/automation/settings/AutomationKeysSettings.svelte';
import type { Satellite } from '$lib/types/satellite';

interface Props {
satellite: Satellite;
}

let { satellite }: Props = $props();
</script>

<GitHubConfigGuard {satellite}>
{#snippet content(config: SatelliteDid.OpenIdAutomationProviderConfig)}
<AutomationKeysSettings {config} {satellite} />
{/snippet}
</GitHubConfigGuard>
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<script lang="ts">
import type { Snippet } from 'svelte';
import { fade } from 'svelte/transition';
import type { SatelliteDid } from '$declarations';
import AutomationNew from '$lib/components/satellites/automation/AutomationNew.svelte';
import NoAutomation from '$lib/components/satellites/automation/NoAutomation.svelte';
import SpinnerParagraph from '$lib/components/ui/SpinnerParagraph.svelte';
import { githubConfig } from '$lib/derived/satellite/github.derived';
import { i18n } from '$lib/stores/app/i18n.store';
import type { Satellite } from '$lib/types/satellite';

interface Props {
satellite: Satellite;
content: Snippet<[SatelliteDid.OpenIdAutomationProviderConfig]>;
}

let { content, satellite }: Props = $props();
</script>

{#if $githubConfig === undefined}
<SpinnerParagraph>{$i18n.core.loading_config}</SpinnerParagraph>
{:else if $githubConfig === null}
<div in:fade>
<NoAutomation />

<AutomationNew {satellite} />
</div>
{:else}
<div in:fade>
{@render content($githubConfig)}
</div>
{/if}
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
<script lang="ts">
import { fromNullable, nonNullish, notEmptyString } from '@dfinity/utils';
import { onMount } from 'svelte';
import type { SatelliteDid } from '$declarations';
import Input from '$lib/components/ui/Input.svelte';
import Value from '$lib/components/ui/Value.svelte';
import { AUTOMATION_DEFAULT_MAX_SESSION_TIME_TO_LIVE } from '$lib/constants/automation.constants';
import {
AN_HOUR_NS,
FIFTEEN_MINUTES_NS,
FIVE_MINUTES_NS,
FORTY_FIVE_MINUTES_NS,
TEN_MINUTES_NS,
THIRTY_MINUTES_NS,
TWO_MINUTES_NS
} from '$lib/constants/duration.constants';
import { isBusy } from '$lib/derived/app/busy.derived';
import { i18n } from '$lib/stores/app/i18n.store';
import type { AddAccessKeyScope } from '$lib/types/access-keys';

interface Props {
config: SatelliteDid.OpenIdAutomationProviderConfig;
onsubmit: ($event: SubmitEvent) => Promise<void>;
scope: Omit<AddAccessKeyScope, 'admin'> | undefined;
maxTimeToLive: bigint | undefined;
}

let { onsubmit, config, scope = $bindable(), maxTimeToLive = $bindable() }: Props = $props();

// svelte-ignore state_referenced_locally
let controller = $state(fromNullable(config?.controller));
let controllerScope = $state(fromNullable(controller?.scope ?? []));

// Scope
let scopeInput = $state(
nonNullish(controllerScope) && 'Submit' in controllerScope ? 'submit' : 'write'
);

$effect(() => {
scope = notEmptyString(scopeInput) ? scopeInput : 'write';
});

// Max time to live
let maxTimeToLiveInput = $state(
Number(
fromNullable(controller?.max_time_to_live ?? []) ??
AUTOMATION_DEFAULT_MAX_SESSION_TIME_TO_LIVE
)
);

$effect(() => {
maxTimeToLive = BigInt(maxTimeToLiveInput);
});

let customMaxTimeToLive = $state(false);
onMount(() => {
// Only evaluated onMount as we do not want to toggle between input or select
// if the dev enters one of the values.
customMaxTimeToLive =
nonNullish(maxTimeToLiveInput) &&
BigInt(maxTimeToLiveInput) !== TWO_MINUTES_NS &&
BigInt(maxTimeToLiveInput) !== FIVE_MINUTES_NS &&
BigInt(maxTimeToLiveInput) !== TEN_MINUTES_NS &&
BigInt(maxTimeToLiveInput) !== FIFTEEN_MINUTES_NS &&
BigInt(maxTimeToLiveInput) !== THIRTY_MINUTES_NS &&
BigInt(maxTimeToLiveInput) !== FORTY_FIVE_MINUTES_NS &&
BigInt(maxTimeToLiveInput) !== AN_HOUR_NS;
});
</script>

<h2>{$i18n.automation.keys}</h2>

<p>
{$i18n.automation.edit_automation_keys}
</p>

<form class="content" {onsubmit}>
<div class="container">
<div>
<Value>
{#snippet label()}
{$i18n.controllers.scope}
{/snippet}

<select name="scope" bind:value={scope}>
<option value="submit">{$i18n.controllers.submit}</option>
<option value="write">{$i18n.controllers.write}</option>
</select>
</Value>
</div>

<div>
<Value>
{#snippet label()}
{$i18n.authentication.session_duration}{#if customMaxTimeToLive}
({$i18n.authentication.in_nanoseconds}){/if}
{/snippet}

{#if customMaxTimeToLive}
<Input
name="maxTimeToLive"
inputType="number"
placeholder=""
bind:value={maxTimeToLiveInput}
/>
{:else}
<select name="maxTimeToLive" bind:value={maxTimeToLiveInput}>
<option value={Number(TWO_MINUTES_NS)}> {$i18n.core.two_minutes} </option>
<option value={Number(FIVE_MINUTES_NS)}> {$i18n.core.five_minutes} </option>
<option value={Number(TEN_MINUTES_NS)}> {$i18n.core.ten_minutes} </option>
<option value={Number(FIFTEEN_MINUTES_NS)}> {$i18n.core.fifteen_minutes} </option>
<option value={Number(THIRTY_MINUTES_NS)}> {$i18n.core.thirty_minutes} </option>
<option value={Number(FORTY_FIVE_MINUTES_NS)}> {$i18n.core.forty_five_minutes} </option>
<option value={Number(AN_HOUR_NS)}> {$i18n.core.an_hour} </option>
</select>
{/if}
</Value>
</div>
</div>

<button disabled={$isBusy} type="submit">
{$i18n.core.submit}
</button>
</form>
Loading