suggest package update (#253)

* #246 prepare pkg shape detect if needs to update

* #246 optimize package card usage

---------

Co-authored-by: neil <neil@neils-MacBook-Pro.local>
This commit is contained in:
Neil 2023-03-03 15:56:52 +08:00 committed by GitHub
parent ba7be4230d
commit 0c467b08aa
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 74 additions and 59 deletions

View file

@ -0,0 +1,28 @@
<script lang="ts">
import '$appcss';
import PackageCard from '@tea/ui/package-card/package-card.svelte';
import { t } from '$libs/translations';
import type { GUIPackage } from '$libs/types';
import { PackageStates } from '$libs/types';
export let pkg: GUIPackage;
export let onClick: () => void;
const getCTALabel = (state: PackageStates): string => {
return {
[PackageStates.AVAILABLE]: $t("package.install-label").toUpperCase(),
[PackageStates.INSTALLED]: $t("package.installed-label").toUpperCase(),
[PackageStates.INSTALLING]: $t("package.installing-label").toUpperCase(),
[PackageStates.UNINSTALLED]: $t("package.reinstall-label").toUpperCase(),
[PackageStates.NEEDS_UPDATE]: $t("package.needs-update-label").toUpperCase(),
}[state];
};
</script>
<PackageCard
{pkg}
link={`/packages/${pkg.slug}`}
ctaLabel={getCTALabel(pkg.state)}
onClickCTA={onClick}
/>

View file

@ -4,7 +4,7 @@
import type { GUIPackage } from '$libs/types';
import { PackageStates } from '$libs/types';
import Preloader from '@tea/ui/Preloader/Preloader.svelte';
import PackageCard from '@tea/ui/package-card/package-card.svelte';
import Package from "./package.svelte";
import { packagesStore } from '$libs/stores';
import { installPackage } from '@native';
@ -15,15 +15,6 @@
let packages: GUIPackage[] = [];
const getCTALabel = (state: PackageStates): string => {
return {
[PackageStates.AVAILABLE]: $t("package.install-label").toUpperCase(),
[PackageStates.INSTALLED]: $t("package.installed-label").toUpperCase(),
[PackageStates.INSTALLING]: $t("package.installing-label").toUpperCase(),
[PackageStates.UNINSTALLED]: $t("package.reinstall-label").toUpperCase(),
}[state];
};
packagesStore.subscribe((ps) => {
packages = category ?
ps.filter((p) => (p.categories || []).includes(category)) :
@ -39,11 +30,9 @@
{#if packages.length > 0}
{#each packages as pkg}
<div class={pkg.state === PackageStates.INSTALLING ? 'animate-pulse' : ''}>
<PackageCard
<Package
{pkg}
link={`/packages/${pkg.slug}`}
ctaLabel={getCTALabel(pkg.state)}
onClickCTA={async () => {
onClick={async () => {
try {
pkg.state = PackageStates.INSTALLING;
await installPackage(pkg.full_name);

View file

@ -5,7 +5,7 @@
import SortingButtons from './sorting-buttons.svelte';
import type { GUIPackage } from '$libs/types';
import { PackageStates } from '$libs/types';
import PackageCard from '@tea/ui/package-card/package-card.svelte';
import Package from "$components/packages/package.svelte";
import SearchInput from '@tea/ui/search-input/search-input.svelte';
import Preloader from '@tea/ui/Preloader/Preloader.svelte';
@ -50,15 +50,6 @@
setPackages(packages);
};
const getCTALabel = (state: PackageStates): string => {
return {
[PackageStates.AVAILABLE]: $t("package.install-label").toUpperCase(),
[PackageStates.INSTALLED]: $t("package.installed-label").toUpperCase(),
[PackageStates.INSTALLING]: $t("package.installing-label").toUpperCase(),
[PackageStates.UNINSTALLED]: $t("package.reinstall-label").toUpperCase(),
}[state];
};
packagesStore.subscribe(setPackages);
</script>
@ -77,11 +68,9 @@
{#if packages.length > 0}
{#each packages as pkg}
<div class={pkg.state === PackageStates.INSTALLING ? 'animate-pulse' : ''}>
<PackageCard
<Package
{pkg}
link={`/packages/${pkg.slug}`}
ctaLabel={getCTALabel(pkg.state)}
onClickCTA={async () => {
onClick={async () => {
try {
pkg.state = PackageStates.INSTALLING;
await installPackage(pkg.full_name);

View file

@ -1,9 +1,8 @@
<script lang="ts">
import { searchStore } from '$libs/stores';
import { t } from '$libs/translations';
import type { GUIPackage } from '$libs/types';
import Preloader from '@tea/ui/Preloader/Preloader.svelte';
import PackageCard from '@tea/ui/package-card/package-card.svelte';
import Package from "$components/packages/package.svelte";
import { PackageStates } from '$libs/types';
import Posts from '@tea/ui/posts/posts.svelte';
@ -39,15 +38,6 @@
searchStore.searching.subscribe((v) => (loading = v));
const getCTALabel = (state: PackageStates): string => {
return {
[PackageStates.AVAILABLE]: $t("package.install-label").toUpperCase(),
[PackageStates.INSTALLED]: $t("package.installed-label").toUpperCase(),
[PackageStates.INSTALLING]: $t("package.installing-label").toUpperCase(),
[PackageStates.UNINSTALLED]: $t("package.reinstall-label").toUpperCase(),
}[state];
};
const onClose = () => {
term = '';
};
@ -74,11 +64,9 @@
{#if packages.length > 0}
{#each packages as pkg}
<div class={pkg.state === PackageStates.INSTALLING ? 'animate-pulse' : ''}>
<PackageCard
<Package
{pkg}
link={`/packages/${pkg.slug}`}
ctaLabel={getCTALabel(pkg.state)}
onClickCTA={async () => {
onClick={async () => {
try {
pkg.state = PackageStates.INSTALLING;
await installPackage(pkg.full_name);

View file

@ -1,11 +1,10 @@
<script lang="ts">
import '$appcss';
import { t } from '$libs/translations';
import type { GUIPackage } from '$libs/types';
import type { Package } from '@tea/ui/types';
import { PackageStates } from '$libs/types';
import Preloader from '@tea/ui/Preloader/Preloader.svelte';
import PackageCard from '@tea/ui/package-card/package-card.svelte';
import PackageCard from "$components/packages/package.svelte";
import { onMount } from 'svelte';
import { installPackage } from '@native';
import { packagesStore } from '$libs/stores';
@ -14,15 +13,6 @@
let packages: GUIPackage[] = [];
const getCTALabel = (state: PackageStates): string => {
return {
[PackageStates.AVAILABLE]: $t("package.install-label").toUpperCase(),
[PackageStates.INSTALLED]: $t("package.installed-label").toUpperCase(),
[PackageStates.INSTALLING]: $t("package.installing-label").toUpperCase(),
[PackageStates.UNINSTALLED]: $t("package.reinstall-label").toUpperCase(),
}[state];
};
onMount(async () => {
if (!packages.length) {
const matches = await packagesStore.search(pkg.desc, 4);
@ -40,9 +30,7 @@
<div class={pkg.state === PackageStates.INSTALLING ? 'animate-pulse' : ''}>
<PackageCard
{pkg}
link={`/packages/${pkg.slug}`}
ctaLabel={getCTALabel(pkg.state)}
onClickCTA={async () => {
onClick={async () => {
try {
pkg.state = PackageStates.INSTALLING;
await installPackage(pkg.full_name);

View file

@ -32,6 +32,9 @@ export async function getPackages(): Promise<GUIPackage[]> {
// sorts all packages from highest -> lowest
installedPackages.sort((a, b) => semverCompare(b.version, a.version));
// NOTE: its not ideal to get bottles or set package states here maybe do it async in the package store init
// --- it has noticeable slowness
return (packages || []).map((pkg) => {
const installedVersions = installedPackages
.filter((p) => p.full_name === pkg.full_name)

View file

@ -1,10 +1,12 @@
import { writable } from "svelte/store";
import type { GUIPackage } from "../types";
import { PackageStates } from "../types";
import { getPackages } from "@native";
import Fuse from "fuse.js";
import { getPackage } from "@native";
import { getPackage, getPackageBottles } from "@native";
import { getReadme, getContributors, getRepoAsPackage } from "$libs/github";
import semverCompare from "semver/functions/compare";
export default function initPackagesStore() {
let initialized = false;
@ -19,6 +21,12 @@ export default function initPackagesStore() {
packagesIndex = new Fuse(pkgs, {
keys: ["name", "full_name", "desc", "categories"]
});
pkgs.forEach((pkg) => {
if (pkg.state === PackageStates.INSTALLED) {
syncPackageBottlesAndState(pkg.full_name);
}
});
});
}
@ -67,6 +75,25 @@ To read more about this package go to [${guiPkg.homepage}](${guiPkg.homepage}).
updatePackageProp(guiPkg.full_name!, updatedPackage);
};
const syncPackageBottlesAndState = async (pkgName: string) => {
const bottles = await getPackageBottles(pkgName);
const pkg = packages.find((p) => p.full_name === pkgName);
const availableVersions = bottles
.map(({ version }) => version)
.sort((a, b) => semverCompare(b, a));
const installedVersions = pkg?.installed_versions?.sort((a, b) => semverCompare(b, a)) || [];
updatePackageProp(pkgName, {
available_versions: availableVersions,
state:
availableVersions[0] === installedVersions[0]
? PackageStates.INSTALLED
: PackageStates.NEEDS_UPDATE
});
};
return {
packages,
subscribe,

View file

@ -258,6 +258,7 @@
"installed-label": "installed",
"installing-label": "installing",
"reinstall-label": "re-install",
"needs-update-label": "update",
"my-installs-title": "my installs",
"check-for-updates": "check for updates",
"details": "details"

View file

@ -9,13 +9,15 @@ export enum PackageStates {
AVAILABLE,
INSTALLED,
INSTALLING,
UNINSTALLED
UNINSTALLED,
NEEDS_UPDATE
}
export type GUIPackage = Package & {
state: PackageStates;
installed_versions?: string[];
synced?: boolean;
available_versions?: string[];
};
export type Course = {