mirror of
https://github.com/appwrite/console.git
synced 2026-06-06 19:27:48 +00:00
update: remove unnecessary responsibility from createPolicy.
This commit is contained in:
@@ -1,5 +1,3 @@
|
||||
import { ID } from '@appwrite.io/console';
|
||||
|
||||
export type UserBackupPolicy = {
|
||||
id?: string;
|
||||
label: string;
|
||||
@@ -17,7 +15,6 @@ export type UserBackupPolicy = {
|
||||
|
||||
export const cronExpression = (policy: UserBackupPolicy) => {
|
||||
const now = new Date();
|
||||
if (!policy.id) policy.id = ID.unique();
|
||||
|
||||
if (policy.plainTextFrequency === 'hourly') {
|
||||
const utcMinute = now.getUTCMinutes();
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
let showCustomId = false;
|
||||
let showPlanUpgradeAlert = true;
|
||||
|
||||
const createPolicies = async () => {
|
||||
const createPolicies = async (resourceId: string) => {
|
||||
if (!totalPolicies.length) return;
|
||||
|
||||
const totalPoliciesPromise = totalPolicies.map((policy) => {
|
||||
@@ -36,7 +36,7 @@
|
||||
policy.retained,
|
||||
policy.schedule,
|
||||
policy.label,
|
||||
id
|
||||
resourceId
|
||||
);
|
||||
});
|
||||
|
||||
@@ -45,8 +45,9 @@
|
||||
|
||||
const create = async () => {
|
||||
try {
|
||||
const database = await sdk.forProject.databases.create(id ? id : ID.unique(), name);
|
||||
await createPolicies();
|
||||
const databaseId = id ? id : ID.unique();
|
||||
const database = await sdk.forProject.databases.create(databaseId, name);
|
||||
await createPolicies(databaseId);
|
||||
|
||||
showCreate = false;
|
||||
dispatch('created', database);
|
||||
@@ -85,7 +86,7 @@
|
||||
{#if !showCustomId}
|
||||
<div>
|
||||
<Pill button on:click={() => (showCustomId = !showCustomId)}
|
||||
><span class="icon-pencil" aria-hidden="true" /><span class="text">
|
||||
><span class="icon-pencil" aria-hidden="true" /><span class="text">
|
||||
Database ID
|
||||
</span></Pill>
|
||||
</div>
|
||||
@@ -105,9 +106,9 @@
|
||||
{/if}
|
||||
{:else}
|
||||
<CreatePolicy
|
||||
isModal={false}
|
||||
title="Backup policies"
|
||||
bind:totalPolicies
|
||||
isShowing={showCreate}
|
||||
title="Backup policies"
|
||||
subtitle="Protect your data and ensure quick recovery by adding backup policies." />
|
||||
{/if}
|
||||
</FormList>
|
||||
|
||||
+57
-1
@@ -21,9 +21,12 @@
|
||||
import { app } from '$lib/stores/app';
|
||||
import { onMount } from 'svelte';
|
||||
import { feedback } from '$lib/stores/feedback';
|
||||
import { cronExpression, type UserBackupPolicy } from '$lib/helpers/backups';
|
||||
|
||||
let showCreatePolicy = false;
|
||||
let policyCreateError: string;
|
||||
let showCreateManualBackup = false;
|
||||
let totalPolicies: UserBackupPolicy[] = [];
|
||||
let isDisabled = isSelfHosted || (isCloud && $organization?.billingPlan === BillingPlan.FREE);
|
||||
|
||||
export let data: PageData;
|
||||
@@ -82,6 +85,46 @@
|
||||
}
|
||||
};
|
||||
|
||||
const createPolicies = async () => {
|
||||
const totalPoliciesPromise = totalPolicies.map((policy) => {
|
||||
cronExpression(policy);
|
||||
|
||||
return sdk.forProject.backups.createPolicy(
|
||||
policy.id,
|
||||
['databases'],
|
||||
policy.retained,
|
||||
policy.schedule,
|
||||
policy.label,
|
||||
data.database.$id
|
||||
);
|
||||
});
|
||||
|
||||
try {
|
||||
await Promise.all(totalPoliciesPromise);
|
||||
|
||||
const message =
|
||||
totalPolicies.length > 1
|
||||
? `Backup policies have been created`
|
||||
: `<b>${totalPolicies[0].label}</b> policy has been created`;
|
||||
|
||||
addNotification({
|
||||
isHtml: true,
|
||||
type: 'success',
|
||||
message
|
||||
});
|
||||
|
||||
invalidate(Dependencies.BACKUPS);
|
||||
} catch (err) {
|
||||
addNotification({
|
||||
type: 'error',
|
||||
message: err.message
|
||||
});
|
||||
} finally {
|
||||
totalPolicies = [];
|
||||
showCreatePolicy = false;
|
||||
}
|
||||
};
|
||||
|
||||
onMount(() => {
|
||||
return sdk.forConsole.client.subscribe('console', (response) => {
|
||||
if (response.events.includes('archives.*') || response.events.includes('policies.*')) {
|
||||
@@ -165,7 +208,20 @@
|
||||
</div>
|
||||
</Container>
|
||||
|
||||
<CreatePolicy bind:showCreate={showCreatePolicy} />
|
||||
<Modal
|
||||
title="Create backup policy"
|
||||
size="big"
|
||||
onSubmit={createPolicies}
|
||||
bind:show={showCreatePolicy}
|
||||
bind:error={policyCreateError}>
|
||||
|
||||
<CreatePolicy bind:totalPolicies isShowing={showCreatePolicy} />
|
||||
|
||||
<svelte:fragment slot="footer">
|
||||
<Button secondary on:click={() => (showCreatePolicy = false)}>Cancel</Button>
|
||||
<Button submit disabled={!totalPolicies.length}>Create</Button>
|
||||
</svelte:fragment>
|
||||
</Modal>
|
||||
|
||||
<Modal
|
||||
title="Create manual backup"
|
||||
|
||||
+164
-434
@@ -1,34 +1,15 @@
|
||||
<script lang="ts">
|
||||
import { Modal } from '$lib/components';
|
||||
import {
|
||||
Button,
|
||||
FormList,
|
||||
Helper,
|
||||
InputCheckbox,
|
||||
InputSelect,
|
||||
InputText,
|
||||
InputTime
|
||||
} from '$lib/elements/forms';
|
||||
import { Button, FormList, Helper, InputCheckbox, InputSelect, InputText, InputTime } from '$lib/elements/forms';
|
||||
import { ID } from '@appwrite.io/console';
|
||||
import { capitalize } from '$lib/helpers/string';
|
||||
import { backupRetainingOptions, database } from '../store';
|
||||
import { backupRetainingOptions } from '../store';
|
||||
import { policyPricing, presetPolicies } from './store';
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import { addNotification } from '$lib/stores/notifications';
|
||||
import { invalidate } from '$app/navigation';
|
||||
import { Dependencies } from '$lib/constants';
|
||||
import {
|
||||
backupFrequencies,
|
||||
backupPolicyDescription,
|
||||
cronExpression,
|
||||
type UserBackupPolicy
|
||||
} from '$lib/helpers/backups';
|
||||
|
||||
export let isModal = true;
|
||||
export let showCreate = false;
|
||||
import { backupFrequencies, backupPolicyDescription, type UserBackupPolicy } from '$lib/helpers/backups';
|
||||
|
||||
export let isShowing: boolean;
|
||||
export let title: string | undefined = undefined;
|
||||
export let subtitle: string | undefined = undefined;
|
||||
|
||||
export let totalPolicies: UserBackupPolicy[] = [];
|
||||
|
||||
let showCustomPolicy = false;
|
||||
@@ -37,9 +18,11 @@
|
||||
$: totalPolicies = [
|
||||
...listOfCustomPolicies,
|
||||
...$presetPolicies.filter((policy) => policy.checked)
|
||||
];
|
||||
].map((policy) => {
|
||||
if (!policy.id) policy.id = ID.unique();
|
||||
return policy;
|
||||
});
|
||||
|
||||
let error: string;
|
||||
let policyInEdit = null;
|
||||
let policyRetention = 30;
|
||||
let selectedTime = '00:00';
|
||||
@@ -49,7 +32,6 @@
|
||||
let monthlyBackupFrequency = 'end';
|
||||
|
||||
const resetFormVariables = () => {
|
||||
error = null;
|
||||
policyInEdit = null;
|
||||
policyRetention = 30;
|
||||
selectedTime = '00:00';
|
||||
@@ -58,47 +40,6 @@
|
||||
monthlyBackupFrequency = 'end';
|
||||
};
|
||||
|
||||
export const createPolicies = async () => {
|
||||
const totalPoliciesPromise = totalPolicies.map((policy) => {
|
||||
cronExpression(policy);
|
||||
|
||||
return sdk.forProject.backups.createPolicy(
|
||||
policy.id,
|
||||
['databases'],
|
||||
policy.retained,
|
||||
policy.schedule,
|
||||
policy.label,
|
||||
$database.$id
|
||||
);
|
||||
});
|
||||
|
||||
try {
|
||||
await Promise.all(totalPoliciesPromise);
|
||||
|
||||
const message =
|
||||
totalPolicies.length > 1
|
||||
? `Backup policies have been created`
|
||||
: `<b>${totalPolicies[0].label}</b> has been created`;
|
||||
|
||||
addNotification({
|
||||
isHtml: true,
|
||||
type: 'success',
|
||||
message
|
||||
});
|
||||
|
||||
showCreate = false;
|
||||
resetFormVariables();
|
||||
totalPolicies = [];
|
||||
listOfCustomPolicies = [];
|
||||
invalidate(Dependencies.BACKUPS);
|
||||
} catch (err) {
|
||||
addNotification({
|
||||
type: 'error',
|
||||
message: err.message
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleSavePolicy = () => {
|
||||
const userBackupPolicy = {
|
||||
default: false,
|
||||
@@ -118,7 +59,16 @@
|
||||
};
|
||||
|
||||
const markPolicyChecked = (event: Event, policy: UserBackupPolicy) => {
|
||||
policy.checked = (event.target as HTMLInputElement).checked;
|
||||
const isChecked = (event.target as HTMLInputElement).checked;
|
||||
|
||||
presetPolicies.update((all) => {
|
||||
return all.map((p) => {
|
||||
if (p.label === policy.label) {
|
||||
return { ...p, checked: isChecked };
|
||||
}
|
||||
return p;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$: customPolicyDescription = (policy: UserBackupPolicy) => {
|
||||
@@ -138,7 +88,7 @@
|
||||
customPolicySection?.scrollIntoView({ behavior: 'auto' });
|
||||
}
|
||||
|
||||
$: if (!showCreate) {
|
||||
$: if (isShowing) {
|
||||
resetFormVariables();
|
||||
showCustomPolicy = false;
|
||||
listOfCustomPolicies = [];
|
||||
@@ -151,53 +101,59 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if isModal}
|
||||
<Modal
|
||||
title="Create backup policy"
|
||||
size="big"
|
||||
bind:show={showCreate}
|
||||
onSubmit={createPolicies}
|
||||
bind:error>
|
||||
<FormList>
|
||||
<div class="u-flex-vertical u-gap-12">
|
||||
<div class="grid-1-1 u-gap-12">
|
||||
{#each $presetPolicies as policy, index (index)}
|
||||
<div class="card policy-default-custom-card">
|
||||
<div class="u-flex u-gap-8 body-text-2">
|
||||
<InputCheckbox
|
||||
id={index.toString()}
|
||||
on:change={(event) => markPolicyChecked(event, policy)} />
|
||||
<div class="u-flex-vertical u-gap-16">
|
||||
{#if title || subtitle}
|
||||
<div class="body-text-2">
|
||||
{#if title}
|
||||
<h3 class="u-bold">{title}</h3>
|
||||
{/if}
|
||||
|
||||
<div class="u-flex-vertical u-gap-4">
|
||||
<div class="u-flex u-gap-4">
|
||||
{#if subtitle}
|
||||
<span>{subtitle}</span>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<FormList>
|
||||
<div class="u-flex-vertical u-gap-12">
|
||||
<div class="grid-1-1 u-gap-12">
|
||||
{#each $presetPolicies as policy, index (index)}
|
||||
<div class="card policy-default-custom-card">
|
||||
<div class="u-flex u-gap-8 body-text-2">
|
||||
<InputCheckbox
|
||||
id={index.toString()}
|
||||
on:change={(event) => markPolicyChecked(event, policy)} />
|
||||
|
||||
<div class="u-flex-vertical u-gap-4">
|
||||
<div class="u-flex u-gap-4">
|
||||
<h3 class="u-bold">{policy.label}</h3>
|
||||
<span class="inline-tag">$20.00</span>
|
||||
</div>
|
||||
|
||||
{policy.description}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
{#if listOfCustomPolicies.length}
|
||||
<div class="u-flex-vertical u-gap-8">
|
||||
{#each listOfCustomPolicies as policy}
|
||||
<div class="card policy-default-custom-card">
|
||||
<div class="u-flex-vertical u-gap-4 body-text-2">
|
||||
<div class="u-flex u-main-space-between">
|
||||
<div class="u-flex u-cross-center u-gap-4">
|
||||
<h3 class="u-bold">{policy.label}</h3>
|
||||
<span class="inline-tag">$20.00</span>
|
||||
</div>
|
||||
|
||||
{policy.description}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
{#if listOfCustomPolicies.length}
|
||||
<div class="u-flex-vertical u-gap-8">
|
||||
{#each listOfCustomPolicies as policy}
|
||||
<div class="card policy-default-custom-card">
|
||||
<div class="u-flex-vertical u-gap-4 body-text-2">
|
||||
<div class="u-flex u-main-space-between">
|
||||
<div class="u-flex u-cross-center u-gap-4">
|
||||
<h3 class="u-bold">{policy.label}</h3>
|
||||
<span class="inline-tag">$20.00</span>
|
||||
</div>
|
||||
|
||||
<div class="u-flex u-gap-8">
|
||||
<Button
|
||||
text
|
||||
noMargin
|
||||
class="icon-pencil height-fit-content"
|
||||
on:click={() => {
|
||||
<div class="u-flex u-gap-8">
|
||||
<Button
|
||||
text
|
||||
noMargin
|
||||
class="icon-pencil height-fit-content"
|
||||
on:click={() => {
|
||||
policyInEdit = policy.id;
|
||||
backupPolicyName = policy.label;
|
||||
policyRetention = policy.retained;
|
||||
@@ -214,320 +170,95 @@
|
||||
];
|
||||
}} />
|
||||
|
||||
<Button
|
||||
text
|
||||
noMargin
|
||||
class="icon-trash height-fit-content"
|
||||
on:click={() => {
|
||||
<Button
|
||||
text
|
||||
noMargin
|
||||
class="icon-trash height-fit-content"
|
||||
on:click={() => {
|
||||
listOfCustomPolicies = [
|
||||
...listOfCustomPolicies.filter(
|
||||
(p) => policy.id !== p.id
|
||||
)
|
||||
];
|
||||
}} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span>{customPolicyDescription(policy)}</span>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if showCustomPolicy || policyInEdit}
|
||||
<section
|
||||
bind:this={customPolicySection}
|
||||
class="modal is-inner-modal u-width-full-line">
|
||||
<div class="modal-form">
|
||||
<div class="u-flex-vertical u-gap-24">
|
||||
<div class="u-flex-vertical u-gap-4">
|
||||
<InputSelect
|
||||
label="Frequency"
|
||||
id="policyFrequency"
|
||||
placeholder="Select runtime"
|
||||
bind:value={policyFrequency}
|
||||
options={['hourly', 'daily', 'weekly', 'monthly'].map(
|
||||
(freq) => ({
|
||||
value: freq,
|
||||
label: freq.charAt(0).toUpperCase() + freq.slice(1)
|
||||
})
|
||||
)}
|
||||
required />
|
||||
{#if policyFrequency === 'hourly'}
|
||||
<span>{formPolicyDescription()}</span>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
{#if policyFrequency !== 'hourly'}
|
||||
<div class="u-flex-vertical u-gap-8">
|
||||
<div class="u-flex u-gap-8 time-holder">
|
||||
{#if policyFrequency === 'monthly'}
|
||||
<InputSelect
|
||||
id="monthly"
|
||||
label="Monthly Timing"
|
||||
bind:value={monthlyBackupFrequency}
|
||||
placeholder="End of month (28th)"
|
||||
fullWidth
|
||||
options={backupFrequencies[policyFrequency]} />
|
||||
{/if}
|
||||
|
||||
<div
|
||||
class:u-margin-block-start-4={policyFrequency ===
|
||||
'monthly'}>
|
||||
<InputTime
|
||||
id="time"
|
||||
bind:value={selectedTime}
|
||||
label={['daily', 'weekly'].includes(
|
||||
policyFrequency
|
||||
)
|
||||
? 'Timing'
|
||||
: ''} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span>{formPolicyDescription()}</span>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="u-flex-vertical u-gap-8">
|
||||
<InputSelect
|
||||
fullWidth
|
||||
id="retention"
|
||||
label="Keep for"
|
||||
placeholder="3 months"
|
||||
bind:value={policyRetention}
|
||||
options={backupRetainingOptions} />
|
||||
<span>
|
||||
{#if policyRetention === 365 * 100}
|
||||
Every backup created under this policy will be retained <b
|
||||
>forever</b
|
||||
>.
|
||||
{:else}
|
||||
Every backup created under this policy will be retained
|
||||
for <b>
|
||||
{backupRetainingOptions.find(
|
||||
(option) => option.value === policyRetention
|
||||
)?.label ?? '3 months'}
|
||||
</b> before being automatically deleted.
|
||||
{/if}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<InputText
|
||||
id="name"
|
||||
label="Policy name"
|
||||
placeholder="{capitalize(policyFrequency)} backup"
|
||||
autofocus
|
||||
bind:value={backupPolicyName}
|
||||
required />
|
||||
|
||||
{#if policyNameError}
|
||||
<Helper type="warning">This field is required</Helper>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="u-main-end u-flex u-gap-8">
|
||||
<Button
|
||||
text
|
||||
on:click={() => {
|
||||
showCustomPolicy = false;
|
||||
}}
|
||||
>Cancel
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
secondary
|
||||
on:click={() => {
|
||||
if (!backupPolicyName) {
|
||||
policyNameError = true;
|
||||
return;
|
||||
}
|
||||
|
||||
policyNameError = false;
|
||||
handleSavePolicy();
|
||||
}}>
|
||||
{policyInEdit ? 'Update' : 'Save'}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{:else}
|
||||
<div class="u-flex u-main-space-between u-padding-inline-4 u-width-full-line">
|
||||
<button
|
||||
class="custom-policy-text"
|
||||
on:click={() => (showCustomPolicy = true)}
|
||||
>Custom policy
|
||||
</button>
|
||||
<span>Total: ${totalPolicies.length * policyPricing}.00</span>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</FormList>
|
||||
|
||||
<svelte:fragment slot="footer">
|
||||
<Button secondary on:click={() => (showCreate = false)}>Cancel</Button>
|
||||
<Button submit disabled={!totalPolicies.length}>Create</Button>
|
||||
</svelte:fragment>
|
||||
</Modal>
|
||||
{:else}
|
||||
<div class="u-flex-vertical u-gap-16">
|
||||
{#if title || subtitle}
|
||||
<div class="body-text-2">
|
||||
{#if title}
|
||||
<h3 class="u-bold">{title}</h3>
|
||||
{/if}
|
||||
|
||||
{#if subtitle}
|
||||
<span>{subtitle}</span>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<FormList>
|
||||
<div class="u-flex-vertical u-gap-12">
|
||||
<div class="grid-1-1 u-gap-12">
|
||||
{#each $presetPolicies as policy, index (index)}
|
||||
<div class="card policy-default-custom-card">
|
||||
<div class="u-flex u-gap-8 body-text-2">
|
||||
<InputCheckbox
|
||||
id={index.toString()}
|
||||
on:change={(event) => markPolicyChecked(event, policy)} />
|
||||
|
||||
<div class="u-flex-vertical u-gap-4">
|
||||
<div class="u-flex u-gap-4">
|
||||
<h3 class="u-bold">{policy.label}</h3>
|
||||
<span class="inline-tag">$20.00</span>
|
||||
</div>
|
||||
|
||||
{policy.description}
|
||||
</div>
|
||||
<span>{customPolicyDescription(policy)}</span>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if listOfCustomPolicies.length}
|
||||
<div class="u-flex-vertical u-gap-8">
|
||||
{#each listOfCustomPolicies as policy}
|
||||
<div class="card policy-default-custom-card">
|
||||
<div class="u-flex-vertical u-gap-4 body-text-2">
|
||||
<div class="u-flex u-main-space-between">
|
||||
<h3 class="body-text-2 u-bold">{policy.label}</h3>
|
||||
|
||||
<div class="u-flex u-gap-8">
|
||||
<Button
|
||||
text
|
||||
noMargin
|
||||
class="icon-pencil height-fit-content"
|
||||
on:click={() => {
|
||||
policyInEdit = policy.id;
|
||||
backupPolicyName = policy.label;
|
||||
policyRetention = policy.retained;
|
||||
selectedTime = policy.selectedTime;
|
||||
policyFrequency = policy.plainTextFrequency;
|
||||
monthlyBackupFrequency =
|
||||
policy.monthlyBackupFrequency;
|
||||
|
||||
// do not show in the list can cause confusion.
|
||||
listOfCustomPolicies = [
|
||||
...listOfCustomPolicies.filter(
|
||||
(p) => policy.id !== p.id
|
||||
)
|
||||
];
|
||||
}} />
|
||||
|
||||
<Button
|
||||
text
|
||||
noMargin
|
||||
class="icon-trash height-fit-content"
|
||||
on:click={() => {
|
||||
listOfCustomPolicies = [
|
||||
...listOfCustomPolicies.filter(
|
||||
(p) => policy.id !== p.id
|
||||
)
|
||||
];
|
||||
}} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span>{customPolicyDescription(policy)}</span>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if showCustomPolicy || policyInEdit}
|
||||
<section
|
||||
bind:this={customPolicySection}
|
||||
class="modal is-inner-modal u-width-full-line">
|
||||
<div class="modal-form">
|
||||
<div class="u-flex-vertical u-gap-24">
|
||||
<div class="u-flex-vertical u-gap-4">
|
||||
<InputSelect
|
||||
label="Frequency"
|
||||
id="policyFrequency"
|
||||
placeholder="Select runtime"
|
||||
bind:value={policyFrequency}
|
||||
options={['hourly', 'daily', 'weekly', 'monthly'].map(
|
||||
{#if showCustomPolicy || policyInEdit}
|
||||
<section
|
||||
bind:this={customPolicySection}
|
||||
class="modal is-inner-modal u-width-full-line">
|
||||
<div class="modal-form">
|
||||
<div class="u-flex-vertical u-gap-24">
|
||||
<div class="u-flex-vertical u-gap-4">
|
||||
<InputSelect
|
||||
label="Frequency"
|
||||
id="policyFrequency"
|
||||
placeholder="Select runtime"
|
||||
bind:value={policyFrequency}
|
||||
options={['hourly', 'daily', 'weekly', 'monthly'].map(
|
||||
(freq) => ({
|
||||
value: freq,
|
||||
label: freq.charAt(0).toUpperCase() + freq.slice(1)
|
||||
})
|
||||
)}
|
||||
required />
|
||||
{#if policyFrequency === 'hourly'}
|
||||
<span>{formPolicyDescription()}</span>
|
||||
{/if}
|
||||
</div>
|
||||
required />
|
||||
{#if policyFrequency === 'hourly'}
|
||||
<span>{formPolicyDescription()}</span>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
{#if policyFrequency !== 'hourly'}
|
||||
<div class="u-flex-vertical u-gap-8">
|
||||
<div class="u-flex u-gap-8 time-holder">
|
||||
{#if policyFrequency === 'monthly'}
|
||||
<InputSelect
|
||||
id="monthly"
|
||||
label="Monthly Timing"
|
||||
bind:value={monthlyBackupFrequency}
|
||||
placeholder="End of month (28th)"
|
||||
fullWidth
|
||||
options={backupFrequencies[policyFrequency]} />
|
||||
{/if}
|
||||
{#if policyFrequency !== 'hourly'}
|
||||
<div class="u-flex-vertical u-gap-8">
|
||||
<div class="u-flex u-gap-8 time-holder">
|
||||
{#if policyFrequency === 'monthly'}
|
||||
<InputSelect
|
||||
id="monthly"
|
||||
label="Monthly Timing"
|
||||
bind:value={monthlyBackupFrequency}
|
||||
placeholder="End of month (28th)"
|
||||
fullWidth
|
||||
options={backupFrequencies[policyFrequency]} />
|
||||
{/if}
|
||||
|
||||
<div
|
||||
class:u-margin-block-start-4={policyFrequency ===
|
||||
<div
|
||||
class:u-margin-block-start-4={policyFrequency ===
|
||||
'monthly'}>
|
||||
<InputTime
|
||||
id="time"
|
||||
bind:value={selectedTime}
|
||||
label={['daily', 'weekly'].includes(
|
||||
<InputTime
|
||||
id="time"
|
||||
bind:value={selectedTime}
|
||||
label={['daily', 'weekly'].includes(
|
||||
policyFrequency
|
||||
)
|
||||
? 'Timing'
|
||||
: ''} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span>{formPolicyDescription()}</span>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="u-flex-vertical u-gap-8">
|
||||
<InputSelect
|
||||
fullWidth
|
||||
id="retention"
|
||||
label="Keep for"
|
||||
placeholder="3 months"
|
||||
bind:value={policyRetention}
|
||||
options={backupRetainingOptions} />
|
||||
<span>
|
||||
<span>{formPolicyDescription()}</span>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="u-flex-vertical u-gap-8">
|
||||
<InputSelect
|
||||
fullWidth
|
||||
id="retention"
|
||||
label="Keep for"
|
||||
placeholder="3 months"
|
||||
bind:value={policyRetention}
|
||||
options={backupRetainingOptions} />
|
||||
<span>
|
||||
{#if policyRetention === 365 * 100}
|
||||
Every backup created under this policy will be retained <b
|
||||
>forever</b
|
||||
>.
|
||||
>forever</b
|
||||
>.
|
||||
{:else}
|
||||
Every backup created under this policy will be retained
|
||||
for <b>
|
||||
@@ -537,34 +268,34 @@
|
||||
</b> before being automatically deleted.
|
||||
{/if}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<InputText
|
||||
id="name"
|
||||
label="Policy name"
|
||||
placeholder="{capitalize(policyFrequency)} backup"
|
||||
autofocus
|
||||
bind:value={backupPolicyName}
|
||||
required />
|
||||
<div>
|
||||
<InputText
|
||||
id="name"
|
||||
label="Policy name"
|
||||
placeholder="{capitalize(policyFrequency)} backup"
|
||||
autofocus
|
||||
bind:value={backupPolicyName}
|
||||
required />
|
||||
|
||||
{#if policyNameError}
|
||||
<Helper type="warning">This field is required</Helper>
|
||||
{/if}
|
||||
</div>
|
||||
{#if policyNameError}
|
||||
<Helper type="warning">This field is required</Helper>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="u-main-end u-flex u-gap-8">
|
||||
<Button
|
||||
text
|
||||
on:click={() => {
|
||||
<div class="u-main-end u-flex u-gap-8">
|
||||
<Button
|
||||
text
|
||||
on:click={() => {
|
||||
showCustomPolicy = false;
|
||||
}}
|
||||
>Cancel
|
||||
</Button>
|
||||
>Cancel
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
secondary
|
||||
on:click={() => {
|
||||
<Button
|
||||
secondary
|
||||
on:click={() => {
|
||||
if (!backupPolicyName) {
|
||||
policyNameError = true;
|
||||
return;
|
||||
@@ -573,26 +304,25 @@
|
||||
policyNameError = false;
|
||||
handleSavePolicy();
|
||||
}}>
|
||||
{policyInEdit ? 'Update' : 'Save'}
|
||||
</Button>
|
||||
</div>
|
||||
{policyInEdit ? 'Update' : 'Save'}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{:else}
|
||||
<div class="u-flex u-main-space-between u-padding-inline-4 u-width-full-line">
|
||||
<button
|
||||
class="custom-policy-text"
|
||||
on:click={() => (showCustomPolicy = true)}
|
||||
>Custom policy
|
||||
</button>
|
||||
<span>Total: ${totalPolicies.length * policyPricing}.00</span>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</FormList>
|
||||
</div>
|
||||
{/if}
|
||||
</section>
|
||||
{:else}
|
||||
<div class="u-flex u-main-space-between u-padding-inline-4 u-width-full-line">
|
||||
<button
|
||||
class="custom-policy-text"
|
||||
on:click={() => (showCustomPolicy = true)}
|
||||
>Custom policy
|
||||
</button>
|
||||
<span>Total: ${totalPolicies.length * policyPricing}.00</span>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</FormList>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.card {
|
||||
|
||||
Reference in New Issue
Block a user