mirror of
https://github.com/ivabus/gui
synced 2025-04-23 14:07:14 +03:00
error notifications (#456)
This commit is contained in:
parent
328c6e2bf6
commit
af59c02cae
9 changed files with 86 additions and 54 deletions
|
@ -5,7 +5,7 @@
|
|||
import Button from "@tea/ui/button/button.svelte";
|
||||
import semverCompare from "semver/functions/compare";
|
||||
|
||||
import { PackageStates, type GUIPackage } from "$libs/types";
|
||||
import type { GUIPackage } from "$libs/types";
|
||||
import { packagesStore } from "$libs/stores";
|
||||
import { shellOpenExternal } from "@native";
|
||||
import InstallButton from "$components/install-button/install-button.svelte";
|
||||
|
@ -20,9 +20,6 @@
|
|||
installing = true;
|
||||
await packagesStore.installPkg(pkg, version);
|
||||
installing = false;
|
||||
packagesStore.updatePackage(pkg.full_name, {
|
||||
state: PackageStates.INSTALLED
|
||||
});
|
||||
};
|
||||
|
||||
const prune = async () => {
|
||||
|
|
|
@ -2,21 +2,13 @@
|
|||
import "$appcss";
|
||||
|
||||
import type { GUIPackage } from "$libs/types";
|
||||
import { packagesStore, notificationStore } from "$libs/stores";
|
||||
import { packagesStore } from "$libs/stores";
|
||||
import { onMount } from "svelte";
|
||||
import PackageCard from "$components/package-card/package-card.svelte";
|
||||
import { findAvailableVersions } from "$libs/packages/pkg-utils";
|
||||
|
||||
export let tab = "all";
|
||||
export let pkg: GUIPackage;
|
||||
export let onClick: (version: string) => void;
|
||||
|
||||
const onClickCTA = async (version: string) => {
|
||||
await onClick(version);
|
||||
notificationStore.add({
|
||||
message: `Package ${pkg.full_name} v${version || pkg.version} has been installed.`
|
||||
});
|
||||
};
|
||||
|
||||
onMount(() => {
|
||||
packagesStore.fetchPackageBottles(pkg.full_name);
|
||||
|
@ -28,7 +20,7 @@
|
|||
availableVersions={findAvailableVersions(pkg)}
|
||||
link="/packages/{pkg.slug}?tab={tab}"
|
||||
progessLoading={pkg.install_progress_percentage}
|
||||
{onClickCTA}
|
||||
onClickCTA={(version) => packagesStore.installPkg(pkg, version)}
|
||||
onUninstall={async () => {
|
||||
packagesStore.uninstallPkg(pkg);
|
||||
}}
|
||||
|
|
|
@ -87,11 +87,7 @@
|
|||
{#each packages as pkg, index}
|
||||
{#if index < limit}
|
||||
<div class="card z-1 p-1" class:animate-puls={pkg.state === PackageStates.INSTALLING}>
|
||||
<Package
|
||||
tab={packageFilter}
|
||||
{pkg}
|
||||
onClick={(version) => packagesStore.installPkg(pkg, version)}
|
||||
/>
|
||||
<Package tab={packageFilter} {pkg} />
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
|
|
|
@ -85,14 +85,10 @@ export async function getPackageReviews(full_name: string): Promise<Review[]> {
|
|||
}
|
||||
|
||||
export async function installPackage(pkg: GUIPackage, version?: string) {
|
||||
try {
|
||||
const latestVersion = pkg.version;
|
||||
const specificVersion = version || latestVersion;
|
||||
log.info(`installing package: ${pkg.name} version: ${specificVersion}`);
|
||||
await installPackageCommand(pkg.full_name + (specificVersion ? `@${specificVersion}` : ""));
|
||||
} catch (error) {
|
||||
log.error("installPackage:", error);
|
||||
}
|
||||
const latestVersion = pkg.version;
|
||||
const specificVersion = version || latestVersion;
|
||||
log.info(`installing package: ${pkg.name} version: ${specificVersion}`);
|
||||
await installPackageCommand(pkg.full_name + (specificVersion ? `@${specificVersion}` : ""));
|
||||
}
|
||||
|
||||
export async function getTopPackages(): Promise<GUIPackage[]> {
|
||||
|
|
|
@ -2,5 +2,7 @@ const { ipcRenderer } = window.require("electron");
|
|||
|
||||
export async function installPackageCommand(full_name: string) {
|
||||
const res = await ipcRenderer.invoke("install-package", { full_name });
|
||||
console.log("install:", res);
|
||||
if (res instanceof Error) {
|
||||
throw res;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,11 +15,12 @@ import {
|
|||
} from "@native";
|
||||
|
||||
import { getReadme, getContributors, getRepoAsPackage } from "$libs/github";
|
||||
import type { Package } from "@tea/ui/types";
|
||||
import { NotificationType, type Package } from "@tea/ui/types";
|
||||
import { trackInstall, trackInstallFailed } from "$libs/analytics";
|
||||
import { addInstalledVersion } from "$libs/packages/pkg-utils";
|
||||
import withDebounce from "$libs/utils/debounce";
|
||||
import { trimGithubSlug } from "$libs/github";
|
||||
import { notificationStore } from "$libs/stores";
|
||||
|
||||
const log = window.require("electron-log");
|
||||
|
||||
|
@ -136,6 +137,9 @@ To read more about this package go to [${guiPkg.homepage}](${guiPkg.homepage}).
|
|||
|
||||
const installPkg = async (pkg: GUIPackage, version?: string) => {
|
||||
let fakeTimer: NodeJS.Timer | null = null;
|
||||
const originalState = pkg.state;
|
||||
const versionToInstall = version || pkg.version;
|
||||
|
||||
try {
|
||||
const state: PackageStates =
|
||||
pkg.state === PackageStates.NEEDS_UPDATE
|
||||
|
@ -148,7 +152,6 @@ To read more about this package go to [${guiPkg.homepage}](${guiPkg.homepage}).
|
|||
updatePackage(pkg.full_name, { install_progress_percentage: progress });
|
||||
});
|
||||
|
||||
const versionToInstall = version || pkg.version;
|
||||
await installPackage(pkg, versionToInstall);
|
||||
trackInstall(pkg.full_name);
|
||||
|
||||
|
@ -156,10 +159,22 @@ To read more about this package go to [${guiPkg.homepage}](${guiPkg.homepage}).
|
|||
state: PackageStates.INSTALLED,
|
||||
installed_versions: addInstalledVersion(pkg.installed_versions, versionToInstall)
|
||||
});
|
||||
|
||||
notificationStore.add({
|
||||
message: `Package ${pkg.full_name} v${versionToInstall} has been installed.`
|
||||
});
|
||||
} catch (error) {
|
||||
let message = "Unknown Error";
|
||||
if (error instanceof Error) message = error.message;
|
||||
trackInstallFailed(pkg.full_name, message || "unknown");
|
||||
|
||||
//FIXME: probably need a refresh package state function instead of this
|
||||
updatePackage(pkg.full_name, { state: originalState });
|
||||
|
||||
notificationStore.add({
|
||||
message: `Package ${pkg.full_name} v${versionToInstall} failed to install.`,
|
||||
type: NotificationType.ERROR
|
||||
});
|
||||
} finally {
|
||||
fakeTimer && clearTimeout(fakeTimer);
|
||||
updatePackage(pkg.full_name, { install_progress_percentage: 100 });
|
||||
|
|
|
@ -1,24 +1,25 @@
|
|||
<script lang="ts">
|
||||
import '$appcss';
|
||||
import { t } from '$libs/translations';
|
||||
import "$appcss";
|
||||
import { t } from "$libs/translations";
|
||||
|
||||
import { page } from '$app/stores';
|
||||
import { page } from "$app/stores";
|
||||
// import PageHeader from '$components/page-header/page-header.svelte';
|
||||
import PackageBanner from '$components/package-banner/package-banner.svelte';
|
||||
import PackageBanner from "$components/package-banner/package-banner.svelte";
|
||||
// import SuggestedPackages from '$components/suggested-packages/suggested-packages.svelte';
|
||||
import Tabs from '@tea/ui/tabs/tabs.svelte';
|
||||
import type { Tab } from '@tea/ui/types';
|
||||
import Bottles from '@tea/ui/bottles/bottles.svelte';
|
||||
import PackageMetas from '@tea/ui/package-metas/package-metas.svelte';
|
||||
import Markdown from '@tea/ui/markdown/markdown.svelte';
|
||||
import Tabs from "@tea/ui/tabs/tabs.svelte";
|
||||
import type { Tab } from "@tea/ui/types";
|
||||
import Bottles from "@tea/ui/bottles/bottles.svelte";
|
||||
import PackageMetas from "@tea/ui/package-metas/package-metas.svelte";
|
||||
import Markdown from "@tea/ui/markdown/markdown.svelte";
|
||||
// import PackageSnippets from '@tea/ui/package-snippets/package-snippets.svelte';
|
||||
import Preloader from '@tea/ui/Preloader/Preloader.svelte';
|
||||
import Preloader from "@tea/ui/Preloader/Preloader.svelte";
|
||||
|
||||
/** @type {import('./$types').PageData} */
|
||||
export let data: { slug:string, content:string, title:string };
|
||||
export let data: { slug: string; content: string; title: string };
|
||||
|
||||
import { packagesStore } from '$libs/stores';
|
||||
import { onMount } from 'svelte';
|
||||
import { packagesStore } from "$libs/stores";
|
||||
import { onMount } from "svelte";
|
||||
import NotificationBar from "$components/notification-bar/notification-bar.svelte";
|
||||
|
||||
const { packageList } = packagesStore;
|
||||
|
||||
|
@ -27,10 +28,10 @@
|
|||
// let reviews: Review[];
|
||||
$: bottles = pkg?.bottles || [];
|
||||
$: versions = [...new Set(bottles.map((b) => b.version))];
|
||||
$: readme = pkg?.readme_md || '';
|
||||
$: readme = pkg?.readme_md || "";
|
||||
|
||||
$: tabs = [
|
||||
readme !== '' && {
|
||||
readme !== "" && {
|
||||
label: $t("common.details"),
|
||||
component: Markdown,
|
||||
props: { pkg, source: readme }
|
||||
|
@ -50,17 +51,23 @@
|
|||
|
||||
onMount(() => {
|
||||
packagesStore.syncPackageData(pkg);
|
||||
})
|
||||
});
|
||||
</script>
|
||||
<header class="mx-16 py-5 mb-10 text-gray border border-x-0 border-t-0">
|
||||
|
||||
<header class="text-gray mx-16 mb-4 border border-x-0 border-t-0 py-5">
|
||||
<a class="hover:text-white hover:opacity-80" href="/">{$t("common.home")}</a>
|
||||
>
|
||||
{#if tab !== "all"}
|
||||
<a class="hover:text-white hover:opacity-80" href="/?tab={tab || "all"}">{$t(`tags.${tab}`) || "all"}</a>
|
||||
<a class="hover:text-white hover:opacity-80" href="/?tab={tab || 'all'}"
|
||||
>{$t(`tags.${tab}`) || "all"}</a
|
||||
>
|
||||
>
|
||||
{/if}
|
||||
<span class="text-white">{pkg?.full_name}</span>
|
||||
</header>
|
||||
<div class="mx-16 mb-4">
|
||||
<NotificationBar />
|
||||
</div>
|
||||
{#if pkg}
|
||||
<div class="px-16">
|
||||
<section>
|
||||
|
@ -94,5 +101,5 @@
|
|||
{/if} -->
|
||||
</div>
|
||||
{:else}
|
||||
<Preloader/>
|
||||
<Preloader />
|
||||
{/if}
|
||||
|
|
|
@ -1,20 +1,28 @@
|
|||
<script lang="ts">
|
||||
import "../app.css";
|
||||
|
||||
// import { NotificationType } from "../types";
|
||||
import { NotificationType } from "../types";
|
||||
import type { Notification } from "../types";
|
||||
|
||||
export let notification: Notification;
|
||||
|
||||
export let onClose: () => void;
|
||||
|
||||
const styles = {
|
||||
[NotificationType.MESSAGE]: "message-notification",
|
||||
[NotificationType.ERROR]: "error-notification",
|
||||
[NotificationType.ACTION_BANNER]: "action-banner-notification"
|
||||
};
|
||||
|
||||
const notificationClass = styles[notification.type];
|
||||
</script>
|
||||
|
||||
<div class=" flex w-full items-center justify-between bg-accent px-4 py-2">
|
||||
<div class="text-white">{notification.message}</div>
|
||||
<div class="flex w-full items-center justify-between px-4 py-2 {notificationClass}">
|
||||
<div>{notification.message}</div>
|
||||
<div class="flex items-center gap-4">
|
||||
{#if notification.callback}
|
||||
<button
|
||||
class="h-10 w-32 rounded-sm bg-white text-accent"
|
||||
class="h-10 w-32 rounded-sm bg-white"
|
||||
on:click={() => {
|
||||
if (notification.callback) {
|
||||
notification.callback();
|
||||
|
@ -25,3 +33,21 @@
|
|||
<button class="icon-tea-x-btn mt-1 text-xs" on:click={onClose} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
/* FIXME: is there a better way to integrate this with tailwind? */
|
||||
.error-notification {
|
||||
background-color: #ff4100;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.message-notification {
|
||||
background-color: #8000ff;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.alert-notification {
|
||||
background-color: #8000ff;
|
||||
color: #ffffff;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -117,7 +117,8 @@ export interface ListActionItem {
|
|||
|
||||
export enum NotificationType {
|
||||
MESSAGE,
|
||||
ACTION_BANNER
|
||||
ACTION_BANNER,
|
||||
ERROR
|
||||
}
|
||||
export interface Notification {
|
||||
id: string;
|
||||
|
|
Loading…
Reference in a new issue