mirror of
https://gitee.com/spark-store-project/spark-store
synced 2026-05-30 01:31:06 +08:00
fix(installed-apps): restore open and detail actions
This commit is contained in:
@@ -123,6 +123,8 @@
|
||||
:apm-available="apmAvailable"
|
||||
@close="closeInstalledModal"
|
||||
@refresh="refreshInstalledApps"
|
||||
@open-app="openDownloadedApp($event.pkgname, $event.origin)"
|
||||
@open-detail="openDetail"
|
||||
@uninstall="uninstallInstalledApp"
|
||||
@switch-origin="handleSwitchOrigin"
|
||||
/>
|
||||
|
||||
@@ -1,7 +1,29 @@
|
||||
import { render, screen } from "@testing-library/vue";
|
||||
import { fireEvent, render, screen } from "@testing-library/vue";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import InstalledAppsModal from "@/components/InstalledAppsModal.vue";
|
||||
import type { App } from "@/global/typedefinition";
|
||||
|
||||
const createApp = (overrides: Partial<App> = {}): App => ({
|
||||
name: "Spark Notes",
|
||||
pkgname: "spark-notes",
|
||||
version: "1.0.0",
|
||||
filename: "spark-notes.deb",
|
||||
torrent_address: "",
|
||||
author: "",
|
||||
contributor: "",
|
||||
website: "",
|
||||
update: "",
|
||||
size: "1 MB",
|
||||
more: "",
|
||||
tags: "",
|
||||
img_urls: [],
|
||||
icons: "",
|
||||
category: "office",
|
||||
origin: "spark",
|
||||
currentStatus: "installed",
|
||||
...overrides,
|
||||
});
|
||||
|
||||
describe("InstalledAppsModal", () => {
|
||||
it("keeps scroll chaining inside the modal list", () => {
|
||||
@@ -22,4 +44,95 @@ describe("InstalledAppsModal", () => {
|
||||
|
||||
expect(scrollContainer?.className).toContain("overscroll-contain");
|
||||
});
|
||||
|
||||
it("renders open and detail actions for a store-backed installed app", () => {
|
||||
render(InstalledAppsModal, {
|
||||
props: {
|
||||
show: true,
|
||||
apps: [createApp()],
|
||||
loading: false,
|
||||
error: "",
|
||||
activeOrigin: "spark",
|
||||
storeFilter: "both",
|
||||
apmAvailable: true,
|
||||
},
|
||||
});
|
||||
|
||||
expect(screen.getByRole("button", { name: "打开" })).toBeTruthy();
|
||||
expect(screen.getByRole("button", { name: "查看详情" })).toBeTruthy();
|
||||
});
|
||||
|
||||
it("emits open-app when clicking 打开", async () => {
|
||||
const rendered = render(InstalledAppsModal, {
|
||||
props: {
|
||||
show: true,
|
||||
apps: [createApp()],
|
||||
loading: false,
|
||||
error: "",
|
||||
activeOrigin: "spark",
|
||||
storeFilter: "both",
|
||||
apmAvailable: true,
|
||||
},
|
||||
});
|
||||
|
||||
await fireEvent.click(screen.getByRole("button", { name: "打开" }));
|
||||
|
||||
expect(rendered.emitted("open-app")).toHaveLength(1);
|
||||
expect(rendered.emitted("open-app")?.[0]?.[0]).toMatchObject({
|
||||
pkgname: "spark-notes",
|
||||
});
|
||||
});
|
||||
|
||||
it("emits open-detail when clicking 查看详情", async () => {
|
||||
const rendered = render(InstalledAppsModal, {
|
||||
props: {
|
||||
show: true,
|
||||
apps: [createApp()],
|
||||
loading: false,
|
||||
error: "",
|
||||
activeOrigin: "spark",
|
||||
storeFilter: "both",
|
||||
apmAvailable: true,
|
||||
},
|
||||
});
|
||||
|
||||
await fireEvent.click(screen.getByRole("button", { name: "查看详情" }));
|
||||
|
||||
expect(rendered.emitted("open-detail")).toHaveLength(1);
|
||||
expect(rendered.emitted("open-detail")?.[0]?.[0]).toMatchObject({
|
||||
pkgname: "spark-notes",
|
||||
});
|
||||
});
|
||||
|
||||
it("shows 查看详情 for metadata-rich unknown-category apps", () => {
|
||||
render(InstalledAppsModal, {
|
||||
props: {
|
||||
show: true,
|
||||
apps: [createApp({ category: "unknown", more: "Has store metadata" })],
|
||||
loading: false,
|
||||
error: "",
|
||||
activeOrigin: "spark",
|
||||
storeFilter: "both",
|
||||
apmAvailable: true,
|
||||
},
|
||||
});
|
||||
|
||||
expect(screen.getByRole("button", { name: "查看详情" })).toBeTruthy();
|
||||
});
|
||||
|
||||
it("hides 查看详情 for unknown-category apps", () => {
|
||||
render(InstalledAppsModal, {
|
||||
props: {
|
||||
show: true,
|
||||
apps: [createApp({ category: "unknown" })],
|
||||
loading: false,
|
||||
error: "",
|
||||
activeOrigin: "spark",
|
||||
storeFilter: "both",
|
||||
apmAvailable: true,
|
||||
},
|
||||
});
|
||||
|
||||
expect(screen.queryByRole("button", { name: "查看详情" })).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -146,6 +146,23 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="inline-flex items-center gap-2 rounded-2xl border border-slate-300/70 px-4 py-2 text-sm font-semibold text-slate-700 transition hover:bg-slate-50 dark:border-slate-700 dark:text-slate-200 dark:hover:bg-slate-800"
|
||||
@click="$emit('open-app', app)"
|
||||
>
|
||||
<i class="fas fa-play"></i>
|
||||
打开
|
||||
</button>
|
||||
<button
|
||||
v-if="canOpenDetail(app)"
|
||||
type="button"
|
||||
class="inline-flex items-center gap-2 rounded-2xl border border-brand/30 px-4 py-2 text-sm font-semibold text-brand transition hover:bg-brand/10"
|
||||
@click="$emit('open-detail', app)"
|
||||
>
|
||||
<i class="fas fa-circle-info"></i>
|
||||
查看详情
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="inline-flex items-center gap-2 rounded-2xl border border-rose-300/60 px-4 py-2 text-sm font-semibold text-rose-600 transition hover:bg-rose-50 disabled:opacity-50"
|
||||
@@ -178,6 +195,16 @@ const getIconUrl = (app: App) => {
|
||||
return `${APM_STORE_BASE_URL}/${finalArch}/${app.category}/${app.pkgname}/icon.png`;
|
||||
};
|
||||
|
||||
const canOpenDetail = (app: App) => {
|
||||
return (
|
||||
app.category !== "unknown" ||
|
||||
Boolean(app.more) ||
|
||||
Boolean(app.website) ||
|
||||
Boolean(app.author) ||
|
||||
(app.img_urls?.length ?? 0) > 0
|
||||
);
|
||||
};
|
||||
|
||||
defineProps<{
|
||||
show: boolean;
|
||||
apps: App[];
|
||||
@@ -193,6 +220,8 @@ defineEmits<{
|
||||
(e: "refresh"): void;
|
||||
(e: "uninstall", app: App): void;
|
||||
(e: "switch-origin", origin: "apm" | "spark"): void;
|
||||
(e: "open-app", app: App): void;
|
||||
(e: "open-detail", app: App): void;
|
||||
}>();
|
||||
|
||||
const onOverlayWheel = (e: WheelEvent) => {
|
||||
|
||||
Reference in New Issue
Block a user