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
43 changes: 18 additions & 25 deletions apps/desktop/src/components/AppUpdater.test.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,28 @@
import AppUpdater from '$components/AppUpdater.svelte';
import { EventContext } from '$lib/analytics/eventContext';
import { PostHogWrapper } from '$lib/analytics/posthog';
import { Tauri } from '$lib/backend/tauri';
import createBackend, { type Update } from '$lib/backend';
import { ShortcutService } from '$lib/shortcuts/shortcutService';
import { getSettingsdServiceMock } from '$lib/testing/mockSettingsdService';
import { UPDATER_SERVICE, UpdaterService } from '$lib/updater/updater';
import { render, screen } from '@testing-library/svelte';
import { expect, test, describe, vi, beforeEach, afterEach } from 'vitest';
import type { Update } from '@tauri-apps/plugin-updater';

describe('AppUpdater', () => {
let updater: UpdaterService;
let context: Map<any, any>;
const tauri = new Tauri();
const shortcuts = new ShortcutService(tauri);
const backend = createBackend();
const shortcuts = new ShortcutService(backend);
const MockSettingsService = getSettingsdServiceMock();
const settingsService = new MockSettingsService();
const eventContext = new EventContext();
const posthog = new PostHogWrapper(settingsService, eventContext);

beforeEach(() => {
vi.useFakeTimers();
updater = new UpdaterService(tauri, posthog, shortcuts);
updater = new UpdaterService(backend, posthog, shortcuts);
context = new Map([[UPDATER_SERVICE._key, updater]]);
vi.spyOn(tauri, 'listen').mockReturnValue(async () => {});
vi.spyOn(backend, 'listen').mockReturnValue(async () => {});
vi.mock('$env/dynamic/public', () => {
return {
env: {
Expand All @@ -39,23 +38,18 @@ describe('AppUpdater', () => {
});

test('should be hidden if no update', async () => {
vi.spyOn(tauri, 'checkUpdate').mockReturnValue(
mockUpdate({
version: '1'
})
);
vi.spyOn(backend, 'checkUpdate').mockReturnValue(mockUpdate(null));

render(AppUpdater, { context });
await vi.advanceTimersToNextTimerAsync();

const updateBanner = screen.queryByTestId('update-banner');
expect(updateBanner).toBeNull();
expect(updateBanner).toBe(null);
});

test('should display download button', async () => {
vi.spyOn(tauri, 'checkUpdate').mockReturnValue(
vi.spyOn(backend, 'checkUpdate').mockReturnValue(
mockUpdate({
available: true,
version: '1',
body: 'release notes'
})
Expand All @@ -68,24 +62,19 @@ describe('AppUpdater', () => {
expect(button).toBeVisible();
});

test('should display up-to-date on manaul check', async () => {
vi.spyOn(tauri, 'checkUpdate').mockReturnValue(
mockUpdate({
available: false
})
);
render(AppUpdater, { context });
test('should display up-to-date on manual check', async () => {
vi.spyOn(backend, 'checkUpdate').mockReturnValue(mockUpdate(null));
const { getByTestId } = render(AppUpdater, { context });
updater.checkForUpdate(true);
await vi.advanceTimersToNextTimerAsync();

const button = screen.getByTestId('got-it');
const button = getByTestId('got-it');
expect(button).toBeVisible();
});

test('should display restart button on install complete', async () => {
vi.spyOn(tauri, 'checkUpdate').mockReturnValue(
vi.spyOn(backend, 'checkUpdate').mockReturnValue(
mockUpdate({
available: true,
version: '2',
body: 'release notes'
})
Expand All @@ -102,7 +91,11 @@ describe('AppUpdater', () => {
});
});

async function mockUpdate(update: Partial<Update>): Promise<Update> {
async function mockUpdate(update: Partial<Update> | null): Promise<Update | null> {
if (update === null) {
return await Promise.resolve(null);
}

return await Promise.resolve({
download: () => {},
install: () => {},
Expand Down
7 changes: 4 additions & 3 deletions apps/desktop/src/components/BranchHeaderContextMenu.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
import { projectAiGenEnabled } from '$lib/config/config';
import { DEFAULT_FORGE_FACTORY } from '$lib/forge/forgeFactory.svelte';
import { STACK_SERVICE } from '$lib/stacks/stackService.svelte';
import { openExternalUrl } from '$lib/utils/url';
import { URL_SERVICE } from '$lib/utils/url';
import { inject } from '@gitbutler/shared/context';
import {
ContextMenu,
Expand Down Expand Up @@ -59,6 +59,7 @@
const stackService = inject(STACK_SERVICE);
const forge = inject(DEFAULT_FORGE_FACTORY);
const promptService = inject(PROMPT_SERVICE);
const urlService = inject(URL_SERVICE);
const [insertBlankCommitInBranch, commitInsertion] = stackService.insertBlankCommit;
const [updateBranchNameMutation] = stackService.updateBranchName;
const [createRef, refCreation] = stackService.createReference;
Expand Down Expand Up @@ -180,7 +181,7 @@
testId={TestId.BranchHeaderContextMenu_OpenInBrowser}
onclick={() => {
const url = forge.current.branch(branchName)?.url;
if (url) openExternalUrl(url);
if (url) urlService.openExternalUrl(url);
close();
}}
/>
Expand Down Expand Up @@ -299,7 +300,7 @@
label="Open PR in browser"
testId={TestId.BranchHeaderContextMenu_OpenPRInBrowser}
onclick={() => {
openExternalUrl(pr.htmlUrl);
urlService.openExternalUrl(pr.htmlUrl);
close();
}}
/>
Expand Down
5 changes: 3 additions & 2 deletions apps/desktop/src/components/BranchList.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import { STACK_SERVICE } from '$lib/stacks/stackService.svelte';
import { combineResults } from '$lib/state/helpers';
import { UI_STATE } from '$lib/state/uiState.svelte';
import { openExternalUrl } from '$lib/utils/url';
import { URL_SERVICE } from '$lib/utils/url';
import { copyToClipboard } from '@gitbutler/shared/clipboard';
import { inject } from '@gitbutler/shared/context';

Expand All @@ -43,6 +43,7 @@
const uiState = inject(UI_STATE);
const modeService = inject(MODE_SERVICE);
const forge = inject(DEFAULT_FORGE_FACTORY);
const urlService = inject(URL_SERVICE);
const intelligentScrollingService = inject(INTELLIGENT_SCROLLING_SERVICE);

const [insertBlankCommitInBranch, commitInsertion] = stackService.insertBlankCommit;
Expand Down Expand Up @@ -264,7 +265,7 @@
disabled={!prUrl}
onclick={() => {
if (prUrl) {
openExternalUrl(prUrl);
urlService.openExternalUrl(prUrl);
}
}}
icon={forge.current.name === 'gitlab' ? 'view-mr-browser' : 'view-pr-browser'}
Expand Down
8 changes: 3 additions & 5 deletions apps/desktop/src/components/CloneForm.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import InfoMessage, { type MessageStyle } from '$components/InfoMessage.svelte';
import Section from '$components/Section.svelte';
import { POSTHOG_WRAPPER } from '$lib/analytics/posthog';
import { invoke } from '$lib/backend/ipc';
import { GIT_SERVICE } from '$lib/git/gitService';
import { PROJECTS_SERVICE } from '$lib/project/projectsService';
import { projectPath } from '$lib/routes/routes.svelte';
import { parseRemoteUrl } from '$lib/url/gitUrl';
Expand All @@ -18,6 +18,7 @@
import { onMount } from 'svelte';

const projectsService = inject(PROJECTS_SERVICE);
const gitService = inject(GIT_SERVICE);
const posthog = inject(POSTHOG_WRAPPER);

let loading = $state(false);
Expand Down Expand Up @@ -84,10 +85,7 @@

const targetDir = await join(targetDirPath, remoteUrl.name);

await invoke('git_clone_repository', {
repositoryUrl,
targetDir
});
await gitService.cloneRepo(repositoryUrl, targetDir);

posthog.capture('Repository Cloned', { protocol: remoteUrl.protocol });
const project = await projectsService.addProject(targetDir);
Expand Down
5 changes: 3 additions & 2 deletions apps/desktop/src/components/CommitContextMenu.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
import { writeClipboard } from '$lib/backend/clipboard';
import { rewrapCommitMessage } from '$lib/config/uiFeatureFlags';
import { STACK_SERVICE } from '$lib/stacks/stackService.svelte';
import { openExternalUrl } from '$lib/utils/url';
import { URL_SERVICE } from '$lib/utils/url';
import { inject } from '@gitbutler/shared/context';
import {
ContextMenu,
Expand All @@ -66,6 +66,7 @@

let { flat, projectId, openId = $bindable(), rightClickTrigger, contextData }: Props = $props();

const urlService = inject(URL_SERVICE);
const stackService = inject(STACK_SERVICE);
const [insertBlankCommitInBranch, commitInsertion] = stackService.insertBlankCommit;
const [createRef, refCreation] = stackService.createReference;
Expand Down Expand Up @@ -164,7 +165,7 @@
<ContextMenuItem
label="Open in browser"
onclick={async () => {
await openExternalUrl(commitUrl);
await urlService.openExternalUrl(commitUrl);
close();
}}
/>
Expand Down
8 changes: 5 additions & 3 deletions apps/desktop/src/components/CommitSigningForm.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
import InfoMessage from '$components/InfoMessage.svelte';
import Section from '$components/Section.svelte';
import SectionCardDisclaimer from '$components/SectionCardDisclaimer.svelte';
import { invoke } from '$lib/backend/ipc';
import { GIT_CONFIG_SERVICE } from '$lib/config/gitConfigService';
import { GIT_SERVICE } from '$lib/git/gitService';
import { inject } from '@gitbutler/shared/context';
import { Button, Link, SectionCard, Select, SelectItem, Textbox, Toggle } from '@gitbutler/ui';

Expand All @@ -12,6 +12,7 @@
const { projectId }: { projectId: string } = $props();

const gitConfig = inject(GIT_CONFIG_SERVICE);
const gitService = inject(GIT_SERVICE);

let signCommits = $state(false);

Expand Down Expand Up @@ -57,8 +58,9 @@
errorMessage = '';
checked = true;
loading = true;
await invoke('check_signing_settings', { projectId: projectId })
.then((_) => {
await gitService
.checkSigningSettings(projectId)
.then(() => {
signCheckResult = true;
})
.catch((err) => {
Expand Down
9 changes: 6 additions & 3 deletions apps/desktop/src/components/DecorativeSplitView.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import AccountLink from '$components/AccountLink.svelte';
import gbLogoSvg from '$lib/assets/gb-logo.svg?raw';
import { USER } from '$lib/user/user';
import { openExternalUrl } from '$lib/utils/url';
import { URL_SERVICE } from '$lib/utils/url';
import { inject } from '@gitbutler/shared/context';
import { Icon } from '@gitbutler/ui';
import { type Snippet } from 'svelte';
Expand All @@ -17,6 +17,7 @@
const { hideDetails, img, children, testId }: Props = $props();
const user = inject(USER);
const urlService = inject(URL_SERVICE);
</script>

<div class="decorative-split-view" data-testid={testId}>
Expand Down Expand Up @@ -51,15 +52,17 @@
<button
type="button"
class="right-side__link"
onclick={async () => await openExternalUrl('https://docs.gitbutler.com/')}
onclick={async () =>
await urlService.openExternalUrl('https://docs.gitbutler.com/')}
>
<Icon name="docs" opacity={0.6} />
<span class="text-14 text-semibold">GitButler docs</span>
</button>
<button
type="button"
class="right-side__link"
onclick={async () => await openExternalUrl('https://discord.com/invite/MmFkmaJ42D')}
onclick={async () =>
await urlService.openExternalUrl('https://discord.com/invite/MmFkmaJ42D')}
>
<Icon name="discord" opacity={0.6} />
<span class="text-14 text-semibold">Join community</span>
Expand Down
5 changes: 3 additions & 2 deletions apps/desktop/src/components/EditMode.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import { SETTINGS } from '$lib/settings/userSettings';
import { USER_SERVICE } from '$lib/user/userService';
import { computeChangeStatus } from '$lib/utils/fileStatus';
import { getEditorUri, openExternalUrl } from '$lib/utils/url';
import { getEditorUri, URL_SERVICE } from '$lib/utils/url';
import { inject } from '@gitbutler/shared/context';

import { Avatar, Badge, Button, FileListItem, InfoButton, Modal } from '@gitbutler/ui';
Expand All @@ -42,6 +42,7 @@
const modeService = inject(MODE_SERVICE);
const userSettings = inject(SETTINGS);
const fileService = inject(FILE_SERVICE);
const urlService = inject(URL_SERVICE);

const userService = inject(USER_SERVICE);
const user = userService.user;
Expand Down Expand Up @@ -208,7 +209,7 @@
schemeId: $userSettings.defaultCodeEditor.schemeIdentifer,
path: [vscodePath(projectPath), file.path]
});
openExternalUrl(path);
urlService.openExternalUrl(path);
}
}

Expand Down
8 changes: 6 additions & 2 deletions apps/desktop/src/components/Feed.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import CliSymLink from '$components/profileSettings/CliSymLink.svelte';
import { ACTION_SERVICE } from '$lib/actions/actionService.svelte';
import laneNewSvg from '$lib/assets/empty-state/lane-new.svg?raw';
import { invoke } from '$lib/backend/ipc';
import { CLI_MANAGER } from '$lib/cli/cli';
import { SETTINGS_SERVICE } from '$lib/config/appSettingsV2';
import { projectAiGenEnabled } from '$lib/config/config';
import { FEED_FACTORY } from '$lib/feed/feed';
Expand All @@ -26,6 +26,9 @@
const settingsService = inject(SETTINGS_SERVICE);
const settingsStore = $derived(settingsService.appSettings);

const cliManager = inject(CLI_MANAGER);
const [instalCLI, installingCLI] = cliManager.install;

const combinedEntries = $derived(feed.combined);
const lastAddedId = $derived(feed.lastAddedId);

Expand Down Expand Up @@ -202,7 +205,8 @@
kind="outline"
icon="play"
size="tag"
onclick={async () => await invoke('install_cli')}>Install But CLI</Button
loading={installingCLI.current.isLoading}
onclick={async () => await instalCLI()}>Install But CLI</Button
>
<span class="clr-text-2">(requires admin)</span>
or
Expand Down
9 changes: 6 additions & 3 deletions apps/desktop/src/components/FileContextMenu.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import { writeClipboard } from '$lib/backend/clipboard';
import { changesToDiffSpec } from '$lib/commits/utils';
import { projectAiExperimentalFeaturesEnabled, projectAiGenEnabled } from '$lib/config/config';
import { FILE_SERVICE } from '$lib/files/fileService';
import { isTreeChange, type TreeChange } from '$lib/hunks/change';
import { platformName } from '$lib/platform/platform';
import { vscodePath } from '$lib/project/project';
Expand All @@ -15,7 +16,7 @@
import { STACK_SERVICE } from '$lib/stacks/stackService.svelte';
import { UI_STATE } from '$lib/state/uiState.svelte';
import { computeChangeStatus } from '$lib/utils/fileStatus';
import { getEditorUri, openExternalUrl, showFileInFolder } from '$lib/utils/url';
import { getEditorUri, URL_SERVICE } from '$lib/utils/url';
import { inject } from '@gitbutler/shared/context';

import {
Expand Down Expand Up @@ -61,6 +62,8 @@
const idSelection = inject(ID_SELECTION);
const aiService = inject(AI_SERVICE);
const actionService = inject(ACTION_SERVICE);
const fileService = inject(FILE_SERVICE);
const urlService = inject(URL_SERVICE);
const [autoCommit, autoCommitting] = actionService.autoCommit;
const [branchChanges, branchingChanges] = actionService.branchChanges;
const [absorbChanges, absorbingChanges] = actionService.absorb;
Expand Down Expand Up @@ -428,7 +431,7 @@
schemeId: $userSettings.defaultCodeEditor.schemeIdentifer,
path: [vscodePath(projectPath), change.path]
});
openExternalUrl(path);
urlService.openExternalUrl(path);
}
}
contextMenu.close();
Expand All @@ -446,7 +449,7 @@
const projectPath = project?.path;
if (projectPath) {
const absPath = await join(projectPath, item.changes[0]!.path);
await showFileInFolder(absPath);
await fileService.showFileInFolder(absPath);
}
contextMenu.close();
}}
Expand Down
Loading
Loading