add delete all data

This commit is contained in:
Nikita Galaiko 2023-05-08 09:49:10 +02:00
parent b3aff720df
commit ed3ed7e84b
8 changed files with 264 additions and 174 deletions

View File

@ -500,4 +500,12 @@ impl App {
Ok(())
}
pub fn delete_all_data(&self) -> Result<()> {
self.deltas_searcher.delete_all_data().context("failed to delete search data")?;
for project in self.list_projects()? {
self.delete_project(&project.id).context("failed to delete project")?;
}
Ok(())
}
}

View File

@ -30,6 +30,17 @@ impl MetaStorage {
}
}
pub fn delete_all(&self) -> Result<()> {
let filepath = self
.storage
.local_data_dir()
.join("indexes")
.join(format!("v{}", CURRENT_VERSION))
.join("meta");
fs::remove_dir_all(filepath)?;
Ok(())
}
pub fn get(&self, project_id: &str, session_hash: &str) -> Result<Option<u64>> {
let filepath = Path::new("indexes")
.join(format!("v{}", CURRENT_VERSION))
@ -130,6 +141,18 @@ impl Deltas {
Ok(())
}
pub fn delete_all_data(&self) -> Result<()> {
self.meta_storage
.delete_all()
.context("Could not delete meta data")?;
let mut writer = self.writer.lock().unwrap();
writer
.delete_all_documents()
.context("Could not delete all documents")?;
writer.commit().context("Could not commit")?;
Ok(())
}
pub fn index_session(
&self,
repository: &app::gb_repository::Repository,

View File

@ -429,6 +429,14 @@ async fn git_commit(
Ok(())
}
#[timed(duration(printer = "debug!"))]
#[tauri::command(async)]
async fn delete_all_data(handle: tauri::AppHandle) -> Result<(), Error> {
let app = handle.state::<app::App>();
app.delete_all_data().context("failed to delete all data")?;
Ok(())
}
fn main() {
let tauri_context = generate_context!();
@ -560,6 +568,7 @@ fn main() {
git_stage,
git_unstage,
git_wd_diff,
delete_all_data,
])
.build(tauri_context)
.expect("Failed to build tauri app")

View File

@ -16,6 +16,10 @@ impl Storage {
}
}
pub fn local_data_dir(&self) -> &Path {
&self.local_data_dir
}
pub fn read<P: AsRef<Path>>(&self, path: P) -> Result<Option<String>> {
let file_path = self.local_data_dir.join(path);
if !file_path.exists() {

View File

@ -10,3 +10,7 @@ export type { Project } from './projects';
export * as searchResults from './search';
export { type SearchResult } from './search';
export * as files from './files';
import { invoke } from '$lib/ipc';
export const deleteAllData = () => invoke<void>('delete_all_data');

View File

@ -1,7 +1,9 @@
<script lang="ts">
import type { LoginToken, CloudApi, users } from '$lib/api';
import { toasts, log } from '$lib';
import { derived, writable } from '@square/svelte-store';
import { open } from '@tauri-apps/api/shell';
import Button from './Button';
export let user: Awaited<ReturnType<typeof users.CurrentUser>>;
export let api: Awaited<ReturnType<typeof CloudApi>>;
@ -19,15 +21,25 @@
});
};
let signUpOrLoginLoading = false;
const onSignUpOrLoginClick = () => {
Promise.resolve()
.then(() => (signUpOrLoginLoading = true))
.then(api.login.token.create)
.then(token.set)
.catch((e) => {
log.error(e);
toasts.error('Something went wrong');
})
.finally(() => (signUpOrLoginLoading = false));
};
const token = writable<LoginToken | null>(null);
const authUrl = derived(token, ($token) => $token?.url as string);
</script>
<div>
{#if $user}
<button class="text-zinc-400 hover:text-red-400 hover:underline" on:click={() => user.delete()}
>Log out</button
>
<Button kind="plain" color="destructive" on:click={user.delete}>Log out</Button>
{:else if $token !== null}
{#await Promise.all([open($token.url), pollForUser($token.token)])}
<div>Log in in your system browser</div>
@ -37,9 +49,8 @@
if you are not redirected automatically, you can
</p>
{:else}
<button
class="rounded bg-blue-400 py-1 px-3 text-white"
on:click={() => api.login.token.create().then(token.set)}>Sign up or Log in</button
>
<Button loading={signUpOrLoginLoading} color="primary" on:click={onSignUpOrLoginClick}>
Sign up or Log in
</Button>
{/if}
</div>

View File

@ -13,6 +13,7 @@
export let data: LayoutData;
const { user, posthog, projects, sentry, events, hotkeys } = data;
$: console.log($user);
const project = derived([page, projects], ([page, projects]) =>
projects?.find((project) => project.id === page.params.projectId)
@ -66,7 +67,7 @@
<div class="mr-6">
<Link href="/users/">
{#await user.load() then}
{#if $user}
{#if $user !== null}
{#if $user.picture}
<img class="inline-block h-5 w-5 rounded-full" src={$user.picture} alt="Avatar" />
{/if}

View File

@ -1,7 +1,9 @@
<script lang="ts">
import { Button, Login } from '$lib/components';
import { Button, Dialog, Login } from '$lib/components';
import type { PageData } from './$types';
import { log, toasts } from '$lib';
import { deleteAllData } from '$lib/api';
import { goto } from '$app/navigation';
export let data: PageData;
const { user, api } = data;
@ -61,179 +63,207 @@
pictureChanged = false;
saving = false;
};
let isDeleting = false;
let deleteConfirmationDialog: Dialog;
const onDeleteClicked = () =>
Promise.resolve()
.then(() => (isDeleting = true))
.then(() => deleteAllData())
.then(() => user.delete())
.then(() => toasts.success('All data deleted'))
.catch((e) => {
log.error(e);
toasts.error('Failed to delete project');
})
.then(() => deleteConfirmationDialog.close())
.then(() => goto('/', { replaceState: true, invalidateAll: true }))
.finally(() => (isDeleting = false));
</script>
<div class="mx-auto p-4">
<div class="mx-auto max-w-xl p-4">
{#if $user}
<div class="flex flex-col gap-6 text-zinc-100">
<header class="flex items-center justify-between">
<div class="flex flex-col">
<h2 class="text-2xl font-medium">GitButler Cloud Account</h2>
<div class="">Your online account details on gitbutler.com</div>
<div class="mx-auto max-w-xl p-8">
{#if $user}
<div class="flex flex-col gap-6 text-zinc-100">
<header class="flex items-center justify-between">
<div class="flex flex-col">
<h2 class="text-2xl font-medium">GitButler Cloud Account</h2>
<div class="">Your online account details on gitbutler.com</div>
</div>
<Login {user} {api} />
</header>
<form
on:submit={onSubmit}
class="user-form flex flex-row items-start justify-between gap-12 rounded-lg py-2"
>
<fields id="right" class="flex flex-col items-center gap-2 pt-6">
{#if $user.picture}
<img
class="h-28 w-28 rounded-full border-zinc-300"
src={userPicture}
alt="Your avatar"
/>
{/if}
<label
title="Edit profile photo"
for="picture"
class="font-sm -mt-6 -ml-16 cursor-default rounded-lg border border-zinc-600 bg-zinc-800 px-2 text-center text-zinc-300 hover:bg-zinc-900 hover:text-zinc-50"
>
Edit
<input
on:change={onPictureChange}
type="file"
id="picture"
name="picture"
accept={fileTypes.join('')}
class="hidden"
/>
</label>
</fields>
<fields id="left" class="flex flex-1 flex-col gap-3">
<div class="flex flex-col gap-1">
<label for="name" class="text-zinc-400">Name</label>
<input
autocomplete="off"
autocorrect="off"
spellcheck="false"
id="name"
name="name"
bind:value={userNameInput}
type="text"
class="w-full rounded border border-zinc-600 bg-zinc-700 px-4 py-2 text-zinc-300"
placeholder="Name can't be empty"
required
/>
</div>
<Login {user} {api} />
</header>
<form
on:submit={onSubmit}
class="user-form flex flex-row items-start justify-between gap-12 rounded-lg py-2"
>
<fields id="right" class="flex flex-col items-center gap-2 pt-6">
{#if $user.picture}
<img
class="h-28 w-28 rounded-full border-zinc-300"
src={userPicture}
alt="Your avatar"
/>
{/if}
<div class="flex flex-col gap-1">
<label for="email" class="text-zinc-400">Email</label>
<input
autocomplete="off"
autocorrect="off"
spellcheck="false"
disabled
id="email"
name="email"
bind:value={$user.email}
type="text"
class="w-full rounded border border-zinc-600 bg-zinc-700 px-4 py-2 text-zinc-300"
/>
</div>
<label
title="Edit profile photo"
for="picture"
class="font-sm -mt-6 -ml-16 cursor-default rounded-lg border border-zinc-600 bg-zinc-800 px-2 text-center text-zinc-300 hover:bg-zinc-900 hover:text-zinc-50"
>
Edit
<input
on:change={onPictureChange}
type="file"
id="picture"
name="picture"
accept={fileTypes.join('')}
class="hidden"
/>
</label>
</fields>
<footer class="flex justify-end pt-4">
<Button disabled={!canTriggerUpdate} loading={saving} color="primary" type="submit">
Update profile
</Button>
</footer>
</fields>
</form>
</div>
{:else}
<div class="flex flex-col items-center justify-items-center space-y-6 text-white">
<div class="text-4xl font-bold text-white">Connect to GitButler Cloud</div>
<div>Sign up or log in to GitButler Cloud for more tools and features:</div>
<ul class="space-y-2 pb-4 text-zinc-400">
<li class="flex flex-row space-x-3">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="white"
class="h-6 w-6"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M12 16.5V9.75m0 0l3 3m-3-3l-3 3M6.75 19.5a4.5 4.5 0 01-1.41-8.775 5.25 5.25 0 0110.233-2.33 3 3 0 013.758 3.848A3.752 3.752 0 0118 19.5H6.75z"
/>
</svg>
<span>Backup everything you do in any of your projects</span>
</li>
<li class="flex flex-row space-x-3">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="white"
class="h-6 w-6"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M7.5 21L3 16.5m0 0L7.5 12M3 16.5h13.5m0-13.5L21 7.5m0 0L16.5 12M21 7.5H7.5"
/>
</svg>
<fields id="left" class="flex flex-1 flex-col gap-3">
<div class="flex flex-col gap-1">
<label for="name" class="text-zinc-400">Name</label>
<input
autocomplete="off"
autocorrect="off"
spellcheck="false"
id="name"
name="name"
bind:value={userNameInput}
type="text"
class="w-full rounded border border-zinc-600 bg-zinc-700 px-4 py-2 text-zinc-300"
placeholder="Name can't be empty"
required
/>
</div>
<div class="flex flex-col gap-1">
<label for="email" class="text-zinc-400">Email</label>
<input
autocomplete="off"
autocorrect="off"
spellcheck="false"
disabled
id="email"
name="email"
bind:value={$user.email}
type="text"
class="w-full rounded border border-zinc-600 bg-zinc-700 px-4 py-2 text-zinc-300"
/>
</div>
<footer class="flex justify-end pt-4">
<Button disabled={!canTriggerUpdate} loading={saving} color="primary" type="submit">
Update profile
</Button>
</footer>
</fields>
</form>
<span>Sync your data across devices</span>
</li>
<li class="flex flex-row space-x-3">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="white"
class="h-6 w-6"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L10.582 16.07a4.5 4.5 0 01-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 011.13-1.897l8.932-8.931zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0115.75 21H5.25A2.25 2.25 0 013 18.75V8.25A2.25 2.25 0 015.25 6H10"
/>
</svg>
<span>AI commit message automated suggestions</span>
</li>
</ul>
<div class="mt-8 text-center">
<Login {user} {api} />
</div>
{:else}
<div class="flex flex-col items-center justify-items-center space-y-6 text-white">
<div class="text-4xl font-bold text-white">Connect to GitButler Cloud</div>
<div>Sign up or log in to GitButler Cloud for more tools and features:</div>
<ul class="space-y-2 pb-4 text-zinc-400">
<li class="flex flex-row space-x-3">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="white"
class="h-6 w-6"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M12 16.5V9.75m0 0l3 3m-3-3l-3 3M6.75 19.5a4.5 4.5 0 01-1.41-8.775 5.25 5.25 0 0110.233-2.33 3 3 0 013.758 3.848A3.752 3.752 0 0118 19.5H6.75z"
/>
</svg>
<span>Backup everything you do in any of your projects</span>
</li>
<li class="flex flex-row space-x-3">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="white"
class="h-6 w-6"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M7.5 21L3 16.5m0 0L7.5 12M3 16.5h13.5m0-13.5L21 7.5m0 0L16.5 12M21 7.5H7.5"
/>
</svg>
<span>Sync your data across devices</span>
</li>
<li class="flex flex-row space-x-3">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="white"
class="h-6 w-6"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L10.582 16.07a4.5 4.5 0 01-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 011.13-1.897l8.932-8.931zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0115.75 21H5.25A2.25 2.25 0 013 18.75V8.25A2.25 2.25 0 015.25 6H10"
/>
</svg>
<span>AI commit message automated suggestions</span>
</li>
</ul>
<div class="mt-8 text-center">
<Login {user} {api} />
</div>
<div class="text-center text-zinc-300">
You will still need to give us permission for each project before we transfer any data to
our servers. You can revoke this permission at any time.
</div>
</div>
{/if}
<div class="mt-8 flex flex-col border-t border-zinc-400 pt-4">
<div class="mt-4">
<a
class="flex flex-col gap-2 rounded border border-zinc-700 bg-card-default p-3 text-zinc-400 shadow transition duration-150 ease-out hover:bg-card-active hover:ease-in"
href="mailto:hello@gitbutler.com?subject=Feedback or question!"
>
<h2 class="text-lg text-zinc-300">Get Support</h2>
<div class="text-zinc-500">If you have an issue or any questions, please email us.</div>
</a>
</div>
<div class="mt-4">
<a
class="flex flex-col gap-2 rounded border border-zinc-700 bg-card-default p-3 text-zinc-400 shadow transition duration-150 ease-out hover:bg-card-active hover:ease-in"
href="https://discord.gg/wDKZCPEjXC"
target="_blank"
rel="noreferrer"
>
<h2 class="text-lg text-zinc-300">Join our Discord</h2>
<div class="text-zinc-500">Share feedback, request, or ask questions</div>
</a>
<div class="text-center text-zinc-300">
You will still need to give us permission for each project before we transfer any data to
our servers. You can revoke this permission at any time.
</div>
</div>
{/if}
<div class="mt-8 flex flex-col gap-4 border-t border-zinc-400 pt-4">
<a
class="flex flex-col gap-2 rounded border border-zinc-700 bg-card-default p-3 text-zinc-400 shadow transition duration-150 ease-out hover:bg-card-active hover:ease-in"
href="mailto:hello@gitbutler.com?subject=Feedback or question!"
>
<h2 class="text-lg text-zinc-300">Get Support</h2>
<div class="text-zinc-500">If you have an issue or any questions, please email us.</div>
</a>
<a
class="flex flex-col gap-2 rounded border border-zinc-700 bg-card-default p-3 text-zinc-400 shadow transition duration-150 ease-out hover:bg-card-active hover:ease-in"
href="https://discord.gg/wDKZCPEjXC"
target="_blank"
rel="noreferrer"
>
<h2 class="text-lg text-zinc-300">Join our Discord</h2>
<div class="text-zinc-500">Share feedback, request, or ask questions</div>
</a>
</div>
<div class="mt-8 flex flex-col gap-4 border-t border-zinc-400 pt-4">
<Button color="destructive" kind="outlined" on:click={() => deleteConfirmationDialog.show()}>
Delete all data
</Button>
</div>
</div>
<Dialog bind:this={deleteConfirmationDialog}>
<svelte:fragment slot="title">Delete all local data?</svelte:fragment>
<p>Are you sure you want to delete all local data? This cant be undone.</p>
<svelte:fragment slot="controls" let:close>
<Button kind="outlined" on:click={close}>Cancel</Button>
<Button color="destructive" loading={isDeleting} on:click={onDeleteClicked}>Delete</Button>
</svelte:fragment>
</Dialog>