mirror of
https://gitee.com/spark-store-project/spark-store
synced 2026-04-26 01:10:16 +08:00
feat: enhance application type definitions and improve app management logic
This commit is contained in:
@@ -4,6 +4,8 @@ import readline from 'node:readline';
|
||||
import { promisify } from 'node:util';
|
||||
import pino from 'pino';
|
||||
|
||||
import { InstalledAppInfo } from '../../typedefinition';
|
||||
|
||||
const logger = pino({ 'name': 'install-manager' });
|
||||
|
||||
type InstallTask = {
|
||||
@@ -66,7 +68,7 @@ const runCommandCapture = async (execCommand: string, execParams: string[]) => {
|
||||
};
|
||||
|
||||
const parseInstalledList = (output: string) => {
|
||||
const apps: Array<{ pkgname: string; version: string; arch: string; flags: string; raw: string }> = [];
|
||||
const apps: Array<InstalledAppInfo> = [];
|
||||
const lines = output.split('\n');
|
||||
for (const line of lines) {
|
||||
const trimmed = line.trim();
|
||||
|
||||
7
electron/typedefinition.ts
Normal file
7
electron/typedefinition.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export interface InstalledAppInfo {
|
||||
pkgname: string;
|
||||
version: string;
|
||||
arch: string;
|
||||
flags: string;
|
||||
raw: string;
|
||||
}
|
||||
@@ -23,6 +23,7 @@
|
||||
"scripts": {
|
||||
"dev": "vite --mode debug | pino-pretty",
|
||||
"build": "vue-tsc --noEmit && vite build --mode production && electron-builder --config electron-builder.yml",
|
||||
"build:vite": "vue-tsc --noEmit && vite build --mode production",
|
||||
"build:rpm": "vue-tsc --noEmit && vite build --mode production && electron-builder --config electron-builder.yml --linux rpm",
|
||||
"build:deb": "vue-tsc --noEmit && vite build --mode production && electron-builder --config electron-builder.yml --linux deb",
|
||||
"preview": "vite preview --mode debug"
|
||||
|
||||
74
src/App.vue
74
src/App.vue
@@ -59,7 +59,7 @@ import UninstallConfirmModal from './components/UninstallConfirmModal.vue';
|
||||
import { APM_STORE_BASE_URL, currentApp, currentAppIsInstalled } from './global/storeConfig';
|
||||
import { downloads } from './global/downloadStatus';
|
||||
import { handleInstall, handleRetry, handleUpgrade } from './modeuls/processInstall';
|
||||
import type { App, AppJson, DownloadItem } from './global/typedefinition';
|
||||
import type { App, AppJson, DownloadItem, UpdateAppItem, InstalledAppInfo } from './global/typedefinition';
|
||||
import type { Ref } from 'vue';
|
||||
|
||||
const logger = pino();
|
||||
@@ -267,7 +267,7 @@ const toggleAllUpgrades = () => {
|
||||
}));
|
||||
};
|
||||
|
||||
const upgradeSingleApp = (app: App) => {
|
||||
const upgradeSingleApp = (app: UpdateAppItem) => {
|
||||
if (!app?.pkgname) return;
|
||||
const target = apps.value.find(a => a.pkgname === app.pkgname);
|
||||
if (target) {
|
||||
@@ -275,7 +275,25 @@ const upgradeSingleApp = (app: App) => {
|
||||
} else {
|
||||
// If we can't find it in the list (e.g. category not loaded?), use the info we have
|
||||
// But handleUpgrade expects App. Let's try to construct minimal App
|
||||
handleUpgrade(app);
|
||||
let minimalApp: App = {
|
||||
name: app.pkgname,
|
||||
pkgname: app.pkgname,
|
||||
version: app.newVersion || '',
|
||||
category: 'unknown',
|
||||
tags: '',
|
||||
more: '',
|
||||
filename: '',
|
||||
torrent_address: '',
|
||||
author: '',
|
||||
contributor: '',
|
||||
website: '',
|
||||
update: '',
|
||||
size: '',
|
||||
img_urls: [],
|
||||
icons: '',
|
||||
currentStatus: 'installed'
|
||||
}
|
||||
handleUpgrade(minimalApp);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -306,14 +324,38 @@ const refreshInstalledApps = async () => {
|
||||
return;
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
installedApps.value = (result.apps || []).map((app: any) => ({
|
||||
...app,
|
||||
// Normalize if Main process returns different casing
|
||||
name: app.name || app.Name || app.pkgname,
|
||||
pkgname: app.pkgname || app.Pkgname,
|
||||
version: app.version || app.Version,
|
||||
removing: false
|
||||
}));
|
||||
installedApps.value = []
|
||||
for (const app of result.apps) {
|
||||
let appInfo = apps.value.find(a => a.pkgname === app.pkgname);
|
||||
if (appInfo) {
|
||||
appInfo.flags = app.flags;
|
||||
appInfo.arch = app.arch;
|
||||
appInfo.currentStatus = 'installed';
|
||||
} else {
|
||||
// 如果在当前应用列表中找不到该应用,创建一个最小的 App 对象
|
||||
appInfo = {
|
||||
name: app.name || app.pkgname,
|
||||
pkgname: app.pkgname,
|
||||
version: app.version,
|
||||
category: 'unknown',
|
||||
tags: '',
|
||||
more: '',
|
||||
filename: '',
|
||||
torrent_address: '',
|
||||
author: '',
|
||||
contributor: '',
|
||||
website: '',
|
||||
update: '',
|
||||
size: '',
|
||||
img_urls: [],
|
||||
icons: '',
|
||||
currentStatus: 'installed',
|
||||
arch: app.arch,
|
||||
flags: app.flags
|
||||
};
|
||||
}
|
||||
installedApps.value.push(appInfo);
|
||||
}
|
||||
} catch (error: any) {
|
||||
installedApps.value = [];
|
||||
installedError.value = error?.message || '读取已安装应用失败';
|
||||
@@ -322,16 +364,9 @@ const refreshInstalledApps = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
const requestUninstall = (app: App | {pkgname: string, [key:string]: any}) => {
|
||||
const requestUninstall = (app: App) => {
|
||||
let target = null;
|
||||
if (!('pkgname' in app) && 'Pkgname' in app) {
|
||||
// @ts-ignore
|
||||
target = apps.value.find(a => a.pkgname === app.Pkgname);
|
||||
} else if (!app?.pkgname) {
|
||||
// try to find by some other way or failed
|
||||
} else {
|
||||
target = apps.value.find(a => a.pkgname === app.pkgname) || app;
|
||||
}
|
||||
|
||||
if (target) {
|
||||
uninstallTargetApp.value = target as App;
|
||||
@@ -553,6 +588,7 @@ const loadApps = async () => {
|
||||
img_urls: typeof appJson.img_urls === 'string' ? JSON.parse(appJson.img_urls) : appJson.img_urls,
|
||||
icons: appJson.icons,
|
||||
category: category,
|
||||
currentStatus: 'not-installed',
|
||||
};
|
||||
apps.value.push(normalizedApp);
|
||||
});
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import AppCard from './AppCard.vue';
|
||||
import type { App } from '@/global/typedefinition';
|
||||
import type { App } from '../global/typedefinition';
|
||||
|
||||
defineProps<{
|
||||
apps: App[];
|
||||
|
||||
@@ -61,9 +61,9 @@
|
||||
</div>
|
||||
<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"
|
||||
:disabled="app.removing" @click="$emit('uninstall', app)">
|
||||
:disabled="app.currentStatus === 'not-installed'" @click="$emit('uninstall', app)">
|
||||
<i class="fas fa-trash"></i>
|
||||
{{ app.removing ? '卸载中…' : '卸载' }}
|
||||
卸载
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -74,7 +74,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { App } from '@/global/typedefinition';
|
||||
import { App } from '../global/typedefinition';
|
||||
|
||||
defineProps<{
|
||||
show: boolean;
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, watch, nextTick, onUnmounted } from 'vue';
|
||||
import type { App } from '@/global/typedefinition';
|
||||
import type { App } from '../global/typedefinition';
|
||||
|
||||
const props = defineProps<{
|
||||
show: boolean;
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { UpdateAppItem } from '@/global/typedefinition';
|
||||
import type { UpdateAppItem } from '../global/typedefinition';
|
||||
|
||||
defineProps<{
|
||||
show: boolean;
|
||||
|
||||
@@ -86,6 +86,9 @@ export interface App {
|
||||
icons: string;
|
||||
category: string; // Frontend added
|
||||
installed?: boolean; // Frontend state
|
||||
flags?: string; // Tags in apm packages manager, e.g. "automatic" for dependencies
|
||||
arch?: string; // Architecture, e.g. "amd64", "arm64"
|
||||
currentStatus: 'not-installed' | 'installed'; // Current installation status
|
||||
}
|
||||
|
||||
export interface UpdateAppItem {
|
||||
@@ -95,3 +98,13 @@ export interface UpdateAppItem {
|
||||
selected?: boolean;
|
||||
upgrading?: boolean;
|
||||
}
|
||||
|
||||
|
||||
/**************Below are type from main process ********************/
|
||||
export interface InstalledAppInfo {
|
||||
pkgname: string;
|
||||
version: string;
|
||||
arch: string;
|
||||
flags: string;
|
||||
raw: string;
|
||||
}
|
||||
Reference in New Issue
Block a user