mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-12-29 12:33:49 +03:00
Can remove repository if it's missing
This commit is contained in:
parent
6530284a80
commit
be89f303d2
@ -100,6 +100,16 @@ export class ProjectService {
|
||||
return await invoke('delete_project', { id });
|
||||
}
|
||||
|
||||
async deleteProjectByPath(path: string): Promise<boolean> {
|
||||
try {
|
||||
await invoke('delete_project_by_path', { path });
|
||||
return true;
|
||||
} catch (error) {
|
||||
// Will only fail if no project matches the path given
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async promptForDirectory(): Promise<string | undefined> {
|
||||
const selectedPath = open({ directory: true, recursive: true, defaultPath: this.homeDir });
|
||||
if (selectedPath) {
|
||||
|
19
apps/desktop/src/lib/components/ErrorBoundaryActions.svelte
Normal file
19
apps/desktop/src/lib/components/ErrorBoundaryActions.svelte
Normal file
@ -0,0 +1,19 @@
|
||||
<script lang="ts">
|
||||
import InexistentRepo from './errorBoundaryActions/InexistentRepo.svelte';
|
||||
import { getKnownError, KnownErrorType } from '$lib/utils/errors';
|
||||
|
||||
interface Props {
|
||||
error: unknown;
|
||||
}
|
||||
|
||||
const { error }: Props = $props();
|
||||
let knownError = $derived(getKnownError(error));
|
||||
</script>
|
||||
|
||||
{#if knownError}
|
||||
<div>
|
||||
{#if knownError.type === KnownErrorType.FailedToOpenRepoInexistent}
|
||||
<InexistentRepo error={knownError} />
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
@ -1,5 +1,6 @@
|
||||
<script lang="ts">
|
||||
import DecorativeSplitView from './DecorativeSplitView.svelte';
|
||||
import ErrorBoundaryActions from './ErrorBoundaryActions.svelte';
|
||||
import ProjectSwitcher from './ProjectSwitcher.svelte';
|
||||
import loadErrorSvg from '$lib/assets/illustrations/load-error.svg?raw';
|
||||
import Icon from '@gitbutler/ui/Icon.svelte';
|
||||
@ -18,6 +19,8 @@
|
||||
{error ? error : 'An unknown error occurred'}
|
||||
</div>
|
||||
|
||||
<ErrorBoundaryActions {error} />
|
||||
|
||||
<div class="problem__switcher">
|
||||
<ProjectSwitcher />
|
||||
</div>
|
||||
|
@ -0,0 +1,60 @@
|
||||
<script lang="ts">
|
||||
import { ProjectService } from '$lib/backend/projects';
|
||||
import { getContext } from '$lib/utils/context';
|
||||
import Button from '@gitbutler/ui/Button.svelte';
|
||||
import type { FailedToOpenRepoInexistentError } from '$lib/utils/errors';
|
||||
|
||||
const projectService = getContext(ProjectService);
|
||||
|
||||
interface Props {
|
||||
error: FailedToOpenRepoInexistentError;
|
||||
}
|
||||
const { error }: Props = $props();
|
||||
|
||||
let deleteSucceeded: boolean | undefined = $state(undefined);
|
||||
|
||||
async function stopTracking() {
|
||||
deleteSucceeded = await projectService.deleteProjectByPath(error.path);
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="container">
|
||||
{#if deleteSucceeded === undefined}
|
||||
<p class="text-12 text-body text-bold">
|
||||
Do you want to stop tracking the repo under this path?:
|
||||
</p>
|
||||
<p class="text-12 text-body repo-path">{error.path}</p>
|
||||
<div class="button-container">
|
||||
<Button style="error" onclick={stopTracking}>Remove</Button>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if deleteSucceeded === true}
|
||||
<p class="text-12 text-body text-bold">
|
||||
Repo removed successfully
|
||||
</p>
|
||||
{/if}
|
||||
|
||||
{#if deleteSucceeded === false}
|
||||
<p class="text-12 text-body text-bold">
|
||||
Failed to remove repo
|
||||
</p>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style lang="postcss">
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.repo-path {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.button-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
51
apps/desktop/src/lib/utils/errors.ts
Normal file
51
apps/desktop/src/lib/utils/errors.ts
Normal file
@ -0,0 +1,51 @@
|
||||
const FAILED_TO_OPEN_REPO_INEXISTENT_PATTERN =
|
||||
/^Could not open repository at '(.+)' as it does not exist$/;
|
||||
|
||||
export enum KnownErrorType {
|
||||
FailedToOpenRepoInexistent = 'FailedToOpenRepoInexistent'
|
||||
}
|
||||
|
||||
interface BaseKnownError {
|
||||
type: KnownErrorType;
|
||||
}
|
||||
|
||||
export interface FailedToOpenRepoInexistentError extends BaseKnownError {
|
||||
type: KnownErrorType.FailedToOpenRepoInexistent;
|
||||
path: string;
|
||||
}
|
||||
|
||||
export type KnownError = FailedToOpenRepoInexistentError;
|
||||
|
||||
|
||||
export function getErrorMessage(something: unknown): string | null {
|
||||
if (something instanceof Error) return something.message;
|
||||
if (typeof something === 'string') return something;
|
||||
return null;
|
||||
}
|
||||
|
||||
export function getErrorType(something: unknown): KnownErrorType | null {
|
||||
const message = getErrorMessage(something);
|
||||
if (!message) return null;
|
||||
if (FAILED_TO_OPEN_REPO_INEXISTENT_PATTERN.test(message)) {
|
||||
return KnownErrorType.FailedToOpenRepoInexistent;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function getKnownError(something: unknown): KnownError | null {
|
||||
const type = getErrorType(something);
|
||||
if (!type) return null;
|
||||
const message = getErrorMessage(something);
|
||||
if (!message) return null;
|
||||
|
||||
switch (type) {
|
||||
case KnownErrorType.FailedToOpenRepoInexistent: {
|
||||
const match = message.match(FAILED_TO_OPEN_REPO_INEXISTENT_PATTERN);
|
||||
if (!match) return null;
|
||||
return {
|
||||
type,
|
||||
path: match[1] ?? ''
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -146,6 +146,7 @@ fn main() {
|
||||
projects::commands::get_project,
|
||||
projects::commands::update_project,
|
||||
projects::commands::delete_project,
|
||||
projects::commands::delete_project_by_path,
|
||||
projects::commands::list_projects,
|
||||
projects::commands::set_project_active,
|
||||
projects::commands::open_project_in_window,
|
||||
|
@ -91,6 +91,22 @@ pub mod commands {
|
||||
pub fn delete_project(projects: State<'_, Controller>, id: ProjectId) -> Result<(), Error> {
|
||||
projects.delete(id).map_err(Into::into)
|
||||
}
|
||||
|
||||
#[tauri::command(async)]
|
||||
#[instrument(skip(projects), err(Debug))]
|
||||
pub fn delete_project_by_path(
|
||||
projects: State<'_, Controller>,
|
||||
path: &path::Path,
|
||||
) -> Result<(), Error> {
|
||||
let project = projects
|
||||
.list()
|
||||
.context("failed to list projects")?
|
||||
.into_iter()
|
||||
.find(|project| project.path == path)
|
||||
.ok_or_else(|| anyhow::anyhow!("project not found"))?;
|
||||
|
||||
projects.delete(project.id).map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, serde::Serialize)]
|
||||
|
Loading…
Reference in New Issue
Block a user