mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-12-20 16:11:46 +03:00
Show toast when failing to open external link
- toast contains url - can be copied or clicked
This commit is contained in:
parent
80dab85ae2
commit
232ea42256
@ -7,11 +7,11 @@
|
|||||||
import TimeAgo from '$lib/components/TimeAgo.svelte';
|
import TimeAgo from '$lib/components/TimeAgo.svelte';
|
||||||
import { draggable } from '$lib/dragging/draggable';
|
import { draggable } from '$lib/dragging/draggable';
|
||||||
import { draggableCommit, nonDraggable } from '$lib/dragging/draggables';
|
import { draggableCommit, nonDraggable } from '$lib/dragging/draggables';
|
||||||
|
import { openExternalUrl } from '$lib/utils/url';
|
||||||
import { filesToFileTree } from '$lib/vbranches/filetree';
|
import { filesToFileTree } from '$lib/vbranches/filetree';
|
||||||
import { Ownership } from '$lib/vbranches/ownership';
|
import { Ownership } from '$lib/vbranches/ownership';
|
||||||
import { listRemoteCommitFiles } from '$lib/vbranches/remoteCommits';
|
import { listRemoteCommitFiles } from '$lib/vbranches/remoteCommits';
|
||||||
import { LocalFile, RemoteCommit, Commit, RemoteFile } from '$lib/vbranches/types';
|
import { LocalFile, RemoteCommit, Commit, RemoteFile } from '$lib/vbranches/types';
|
||||||
import { open } from '@tauri-apps/api/shell';
|
|
||||||
import { writable, type Writable } from 'svelte/store';
|
import { writable, type Writable } from 'svelte/store';
|
||||||
import { slide } from 'svelte/transition';
|
import { slide } from 'svelte/transition';
|
||||||
|
|
||||||
@ -122,7 +122,7 @@
|
|||||||
kind="outlined"
|
kind="outlined"
|
||||||
icon="open-link"
|
icon="open-link"
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
if (commitUrl) open(commitUrl);
|
if (commitUrl) openExternalUrl(commitUrl);
|
||||||
}}>Open commit</Button
|
}}>Open commit</Button
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
@ -52,9 +52,7 @@
|
|||||||
{#if title}
|
{#if title}
|
||||||
<div class="info-message__title text-base-13 text-semibold">{title}</div>
|
<div class="info-message__title text-base-13 text-semibold">{title}</div>
|
||||||
{/if}
|
{/if}
|
||||||
<div class="info-message__text text-base-body-12">
|
<div class="info-message__text text-base-body-12"><slot /></div>
|
||||||
<slot />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{#if primary || secondary}
|
{#if primary || secondary}
|
||||||
<div class="info-message__actions">
|
<div class="info-message__actions">
|
||||||
@ -88,6 +86,9 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: var(--space-12);
|
gap: var(--space-12);
|
||||||
}
|
}
|
||||||
|
.info-message__text {
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
.info-message__content {
|
.info-message__content {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Icon from '$lib/components/Icon.svelte';
|
import Icon from '$lib/components/Icon.svelte';
|
||||||
import { open } from '@tauri-apps/api/shell';
|
import { openExternalUrl } from '$lib/utils/url';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
|
|
||||||
let classes = '';
|
let classes = '';
|
||||||
@ -32,9 +32,9 @@
|
|||||||
class:disabled
|
class:disabled
|
||||||
on:click={(e) => {
|
on:click={(e) => {
|
||||||
if (href && isExternal) {
|
if (href && isExternal) {
|
||||||
open(href);
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
openExternalUrl(href);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -4,7 +4,14 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import InfoMessage from '$lib/components/InfoMessage.svelte';
|
import InfoMessage from '$lib/components/InfoMessage.svelte';
|
||||||
import { dismissToast, toastStore } from '$lib/notifications/toasts';
|
import { dismissToast, toastStore } from '$lib/notifications/toasts';
|
||||||
|
import { marked } from 'marked';
|
||||||
import { slide } from 'svelte/transition';
|
import { slide } from 'svelte/transition';
|
||||||
|
|
||||||
|
var renderer = new marked.Renderer();
|
||||||
|
renderer.link = function (href, title, text) {
|
||||||
|
if (!title) title = text;
|
||||||
|
return '<a target="_blank" href="' + href + '" title="' + title + '">' + text + '</a>';
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="toast-controller">
|
<div class="toast-controller">
|
||||||
@ -15,7 +22,7 @@
|
|||||||
style={toast.style ?? 'neutral'}
|
style={toast.style ?? 'neutral'}
|
||||||
secondary="Dismiss"
|
secondary="Dismiss"
|
||||||
on:secondary={() => dismissToast(toast.id)}
|
on:secondary={() => dismissToast(toast.id)}
|
||||||
shadow>{toast.message}</InfoMessage
|
shadow>{@html marked.parse(toast.message, { renderer })}</InfoMessage
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
|
@ -3,7 +3,7 @@ import { resetSentry, setSentryUser } from '$lib/analytics/sentry';
|
|||||||
import { getCloudApiClient, type User } from '$lib/backend/cloud';
|
import { getCloudApiClient, type User } from '$lib/backend/cloud';
|
||||||
import { invoke } from '$lib/backend/ipc';
|
import { invoke } from '$lib/backend/ipc';
|
||||||
import { sleep } from '$lib/utils/sleep';
|
import { sleep } from '$lib/utils/sleep';
|
||||||
import { open } from '@tauri-apps/api/shell';
|
import { openExternalUrl } from '$lib/utils/url';
|
||||||
import { BehaviorSubject, Observable, Subject, merge, shareReplay } from 'rxjs';
|
import { BehaviorSubject, Observable, Subject, merge, shareReplay } from 'rxjs';
|
||||||
|
|
||||||
export class UserService {
|
export class UserService {
|
||||||
@ -49,7 +49,7 @@ export class UserService {
|
|||||||
this.loading$.next(true);
|
this.loading$.next(true);
|
||||||
try {
|
try {
|
||||||
const token = await this.cloud.login.token.create();
|
const token = await this.cloud.login.token.create();
|
||||||
open(token.url);
|
openExternalUrl(token.url);
|
||||||
|
|
||||||
// Assumed min time for login flow
|
// Assumed min time for login flow
|
||||||
await sleep(4000);
|
await sleep(4000);
|
||||||
|
19
gitbutler-ui/src/lib/utils/url.ts
Normal file
19
gitbutler-ui/src/lib/utils/url.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { showToast } from '$lib/notifications/toasts';
|
||||||
|
import { posthog } from 'posthog-js';
|
||||||
|
|
||||||
|
export function openExternalUrl(href: string) {
|
||||||
|
try {
|
||||||
|
open(href);
|
||||||
|
} catch (e) {
|
||||||
|
if (typeof e == 'string' || e instanceof String) {
|
||||||
|
// TODO: Remove if/when we've resolved all external URL problems.
|
||||||
|
posthog.capture('Link Error', { href, message: e });
|
||||||
|
|
||||||
|
const message = 'Failed to open link in external browser: <br />' + href;
|
||||||
|
showToast({ title: 'External URL error', message, style: 'error' });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rethrowing for sentry and posthog
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@
|
|||||||
import '../styles/main.postcss';
|
import '../styles/main.postcss';
|
||||||
|
|
||||||
import ShareIssueModal from '$lib/components/ShareIssueModal.svelte';
|
import ShareIssueModal from '$lib/components/ShareIssueModal.svelte';
|
||||||
|
import ToastController from '$lib/notifications/ToastController.svelte';
|
||||||
import { SETTINGS_CONTEXT, loadUserSettings } from '$lib/settings/userSettings';
|
import { SETTINGS_CONTEXT, loadUserSettings } from '$lib/settings/userSettings';
|
||||||
import * as events from '$lib/utils/events';
|
import * as events from '$lib/utils/events';
|
||||||
import * as hotkeys from '$lib/utils/hotkeys';
|
import * as hotkeys from '$lib/utils/hotkeys';
|
||||||
@ -49,3 +50,4 @@
|
|||||||
</div>
|
</div>
|
||||||
<Toaster />
|
<Toaster />
|
||||||
<ShareIssueModal bind:this={shareIssueModal} user={$user$} {cloud} />
|
<ShareIssueModal bind:this={shareIssueModal} user={$user$} {cloud} />
|
||||||
|
<ToastController />
|
||||||
|
Loading…
Reference in New Issue
Block a user