Skip to content

Commit a13a400

Browse files
authored
Merge pull request #2317 from appwrite/feat-add-delete-archive-projects
2 parents 2b3cd7a + c3f3008 commit a13a400

1 file changed

Lines changed: 97 additions & 5 deletions

File tree

src/lib/components/archiveProject.svelte

Lines changed: 97 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<script lang="ts">
2-
import { Button } from '$lib/elements/forms';
3-
import { DropList, GridItem1, CardContainer } from '$lib/components';
2+
import { Button, InputText } from '$lib/elements/forms';
3+
import { DropList, GridItem1, CardContainer, Modal } from '$lib/components';
4+
import { Submit, trackEvent, trackError } from '$lib/actions/analytics';
45
import {
56
Badge,
67
Icon,
@@ -9,7 +10,8 @@
910
Accordion,
1011
ActionMenu,
1112
Popover,
12-
Layout
13+
Layout,
14+
Divider
1315
} from '@appwrite.io/pink-svelte';
1416
import {
1517
IconAndroid,
@@ -21,7 +23,8 @@
2123
IconInfo,
2224
IconDotsHorizontal,
2325
IconInboxIn,
24-
IconSwitchHorizontal
26+
IconSwitchHorizontal,
27+
IconTrash
2528
} from '@appwrite.io/pink-icons-svelte';
2629
import { getPlatformInfo } from '$lib/helpers/platform';
2730
import { Status, type Models } from '@appwrite.io/console';
@@ -33,7 +36,7 @@
3336
import { addNotification } from '$lib/stores/notifications';
3437
import { invalidate } from '$app/navigation';
3538
import { Dependencies } from '$lib/constants';
36-
import { Modal } from '$lib/components';
39+
3740
import { isSmallViewport } from '$lib/stores/viewport';
3841
import { isCloud } from '$lib/system';
3942
import { regions as regionsStore } from '$lib/stores/organization';
@@ -53,6 +56,17 @@
5356
let readOnlyInfoOpen = $state<Record<string, boolean>>({});
5457
let showUnarchiveModal = $state(false);
5558
let projectToUnarchive = $state<Models.Project | null>(null);
59+
let showDeleteModal = $state(false);
60+
let projectToDelete = $state<Models.Project | null>(null);
61+
let deleteProjectName = $state<string | null>(null);
62+
let deleteError = $state<string | null>(null);
63+
64+
function resetDeleteState() {
65+
showDeleteModal = false;
66+
projectToDelete = null;
67+
deleteProjectName = null;
68+
deleteError = null;
69+
}
5670
5771
function filterPlatforms(platforms: { name: string; icon: string }[]) {
5872
return platforms.filter(
@@ -103,6 +117,12 @@
103117
showUnarchiveModal = true;
104118
}
105119
120+
function handleDeleteProject(project: Models.Project) {
121+
projectToDelete = project;
122+
deleteProjectName = null;
123+
showDeleteModal = true;
124+
}
125+
106126
// Confirm unarchive action
107127
async function confirmUnarchive() {
108128
if (!projectToUnarchive) return;
@@ -141,6 +161,29 @@
141161
projectToUnarchive = null;
142162
}
143163
164+
async function confirmDelete() {
165+
if (!projectToDelete) return;
166+
167+
try {
168+
await sdk.forConsoleIn(projectToDelete.region).projects.delete({
169+
projectId: projectToDelete.$id
170+
});
171+
172+
await invalidate(Dependencies.ORGANIZATION);
173+
174+
trackEvent(Submit.ProjectDelete);
175+
addNotification({
176+
type: 'success',
177+
message: `${projectToDelete.name} has been deleted`
178+
});
179+
180+
resetDeleteState();
181+
} catch (error) {
182+
deleteError = error.message;
183+
trackError(error, Submit.ProjectDelete);
184+
}
185+
}
186+
144187
function findRegion(project: Models.Project) {
145188
return $regionsStore.regions.find((region) => region.$id === project.region);
146189
}
@@ -226,6 +269,14 @@
226269
leadingIcon={IconSwitchHorizontal}
227270
on:click={() => handleMigrateProject(project)}
228271
>Migrate project</ActionMenu.Item.Button>
272+
<div class="action-menu-divider">
273+
<Divider />
274+
</div>
275+
<ActionMenu.Item.Button
276+
status="danger"
277+
leadingIcon={IconTrash}
278+
on:click={() => handleDeleteProject(project)}
279+
>Delete project</ActionMenu.Item.Button>
229280
</ActionMenu.Root>
230281
</Popover>
231282
</div>
@@ -275,10 +326,51 @@
275326
</svelte:fragment>
276327
</Modal>
277328

329+
<!-- Delete Confirmation Modal -->
330+
<Modal
331+
size="s"
332+
bind:show={showDeleteModal}
333+
title="Delete project"
334+
onSubmit={confirmDelete}
335+
bind:error={deleteError}>
336+
<svelte:fragment slot="description">
337+
The archived project <strong>{projectToDelete?.name}</strong> will be deleted along with all
338+
of its metadata, stats, and other resources.
339+
<b>This action is irreversible.</b>
340+
</svelte:fragment>
341+
342+
<InputText
343+
label={`Enter "${projectToDelete?.name}" to continue`}
344+
placeholder="Enter name"
345+
id="delete-project-name"
346+
autofocus
347+
required
348+
bind:value={deleteProjectName} />
349+
350+
<svelte:fragment slot="footer">
351+
<Button
352+
text
353+
on:click={() => {
354+
resetDeleteState();
355+
}}>Cancel</Button>
356+
<Button
357+
submissionLoader
358+
submit
359+
disabled={(deleteProjectName ?? '') !== projectToDelete?.name}>
360+
Delete
361+
</Button>
362+
</svelte:fragment>
363+
</Modal>
364+
278365
<style>
279366
.archive-projects-margin-top {
280367
margin-top: 36px;
281368
}
369+
.action-menu-divider {
370+
margin-inline: -1rem;
371+
padding-block-start: 0.25rem;
372+
padding-block-end: 0.25rem;
373+
}
282374
283375
.archive-projects-margin {
284376
margin-top: 16px;

0 commit comments

Comments
 (0)