appclean 1.9.0 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/npm-publish.yml +61 -0
- package/DEVELOPMENT.md +84 -0
- package/GUI_IMPLEMENTATION_STATUS.md +143 -0
- package/MD_Files/INDEX.md +51 -0
- package/PHASE2_COMPLETION.md +281 -0
- package/PHASE3_COMPLETION.md +364 -0
- package/README.md +411 -91
- package/RELEASE_GUIDE.md +236 -0
- package/assets/logo.svg +34 -0
- package/dist/core/appUpdateChecker.js +12 -16
- package/dist/core/appUpdateChecker.js.map +1 -1
- package/dist/core/detector.js +14 -18
- package/dist/core/detector.js.map +1 -1
- package/dist/core/duplicateFileFinder.js +12 -19
- package/dist/core/duplicateFileFinder.js.map +1 -1
- package/dist/core/orphanedDependencyDetector.js +19 -26
- package/dist/core/orphanedDependencyDetector.js.map +1 -1
- package/dist/core/performanceOptimizer.js +6 -10
- package/dist/core/performanceOptimizer.js.map +1 -1
- package/dist/core/permissionHandler.js +21 -25
- package/dist/core/permissionHandler.js.map +1 -1
- package/dist/core/pluginSystem.js +9 -13
- package/dist/core/pluginSystem.js.map +1 -1
- package/dist/core/removalRecorder.js +12 -19
- package/dist/core/removalRecorder.js.map +1 -1
- package/dist/core/remover.js +59 -66
- package/dist/core/remover.js.map +1 -1
- package/dist/core/reportGenerator.d.ts +1 -1
- package/dist/core/reportGenerator.d.ts.map +1 -1
- package/dist/core/reportGenerator.js +27 -34
- package/dist/core/reportGenerator.js.map +1 -1
- package/dist/core/scheduledCleanup.js +23 -30
- package/dist/core/scheduledCleanup.js.map +1 -1
- package/dist/core/serviceFileDetector.js +24 -31
- package/dist/core/serviceFileDetector.js.map +1 -1
- package/dist/core/verificationModule.js +10 -14
- package/dist/core/verificationModule.js.map +1 -1
- package/dist/index.js +118 -156
- package/dist/index.js.map +1 -1
- package/dist/managers/brewManager.js +30 -37
- package/dist/managers/brewManager.js.map +1 -1
- package/dist/managers/customManager.js +23 -30
- package/dist/managers/customManager.js.map +1 -1
- package/dist/managers/linuxManager.js +29 -36
- package/dist/managers/linuxManager.js.map +1 -1
- package/dist/managers/npmManager.js +27 -34
- package/dist/managers/npmManager.js.map +1 -1
- package/dist/types/index.js +1 -2
- package/dist/ui/client/api/client.d.ts +24 -0
- package/dist/ui/client/api/client.d.ts.map +1 -0
- package/dist/ui/client/api/client.js +100 -0
- package/dist/ui/client/api/client.js.map +1 -0
- package/dist/ui/client/app.d.ts +7 -0
- package/dist/ui/client/app.d.ts.map +1 -0
- package/dist/ui/client/app.js +75 -0
- package/dist/ui/client/app.js.map +1 -0
- package/dist/ui/client/index.html +107 -0
- package/dist/ui/client/pages/appDetails.d.ts +8 -0
- package/dist/ui/client/pages/appDetails.d.ts.map +1 -0
- package/dist/ui/client/pages/appDetails.js +287 -0
- package/dist/ui/client/pages/appDetails.js.map +1 -0
- package/dist/ui/client/pages/appSearch.d.ts +2 -0
- package/dist/ui/client/pages/appSearch.d.ts.map +1 -0
- package/dist/ui/client/pages/appSearch.js +221 -0
- package/dist/ui/client/pages/appSearch.js.map +1 -0
- package/dist/ui/client/pages/dashboard.d.ts +2 -0
- package/dist/ui/client/pages/dashboard.d.ts.map +1 -0
- package/dist/ui/client/pages/dashboard.js +175 -0
- package/dist/ui/client/pages/dashboard.js.map +1 -0
- package/dist/ui/client/pages/settings.d.ts +7 -0
- package/dist/ui/client/pages/settings.d.ts.map +1 -0
- package/dist/ui/client/pages/settings.js +279 -0
- package/dist/ui/client/pages/settings.js.map +1 -0
- package/dist/ui/client/state/appStore.d.ts +38 -0
- package/dist/ui/client/state/appStore.d.ts.map +1 -0
- package/dist/ui/client/state/appStore.js +130 -0
- package/dist/ui/client/state/appStore.js.map +1 -0
- package/dist/ui/client/state/dashboardStore.d.ts +31 -0
- package/dist/ui/client/state/dashboardStore.d.ts.map +1 -0
- package/dist/ui/client/state/dashboardStore.js +76 -0
- package/dist/ui/client/state/dashboardStore.js.map +1 -0
- package/dist/ui/client/state/uiStore.d.ts +43 -0
- package/dist/ui/client/state/uiStore.d.ts.map +1 -0
- package/dist/ui/client/state/uiStore.js +109 -0
- package/dist/ui/client/state/uiStore.js.map +1 -0
- package/dist/ui/client/styles/animations.css +349 -0
- package/dist/ui/client/styles/base.css +214 -0
- package/dist/ui/client/styles/components.css +400 -0
- package/dist/ui/client/styles/layout.css +224 -0
- package/dist/ui/client/styles/variables.css +140 -0
- package/dist/ui/client/utils/events.d.ts +19 -0
- package/dist/ui/client/utils/events.d.ts.map +1 -0
- package/dist/ui/client/utils/events.js +54 -0
- package/dist/ui/client/utils/events.js.map +1 -0
- package/dist/ui/client/utils/formatting.d.ts +11 -0
- package/dist/ui/client/utils/formatting.d.ts.map +1 -0
- package/dist/ui/client/utils/formatting.js +104 -0
- package/dist/ui/client/utils/formatting.js.map +1 -0
- package/dist/ui/client/utils/router.d.ts +25 -0
- package/dist/ui/client/utils/router.d.ts.map +1 -0
- package/dist/ui/client/utils/router.js +90 -0
- package/dist/ui/client/utils/router.js.map +1 -0
- package/dist/ui/guiServer.d.ts +11 -5
- package/dist/ui/guiServer.d.ts.map +1 -1
- package/dist/ui/guiServer.js +180 -501
- package/dist/ui/guiServer.js.map +1 -1
- package/dist/ui/menu.js +18 -27
- package/dist/ui/menu.js.map +1 -1
- package/dist/ui/prompts.js +34 -47
- package/dist/ui/prompts.js.map +1 -1
- package/dist/ui/server/middleware/errorHandler.d.ts +19 -0
- package/dist/ui/server/middleware/errorHandler.d.ts.map +1 -0
- package/dist/ui/server/middleware/errorHandler.js +100 -0
- package/dist/ui/server/middleware/errorHandler.js.map +1 -0
- package/dist/ui/server/routes/apps.d.ts +8 -0
- package/dist/ui/server/routes/apps.d.ts.map +1 -0
- package/dist/ui/server/routes/apps.js +74 -0
- package/dist/ui/server/routes/apps.js.map +1 -0
- package/dist/ui/server/routes/dashboard.d.ts +4 -0
- package/dist/ui/server/routes/dashboard.d.ts.map +1 -0
- package/dist/ui/server/routes/dashboard.js +57 -0
- package/dist/ui/server/routes/dashboard.js.map +1 -0
- package/dist/ui/server/routes/settings.d.ts +6 -0
- package/dist/ui/server/routes/settings.d.ts.map +1 -0
- package/dist/ui/server/routes/settings.js +31 -0
- package/dist/ui/server/routes/settings.js.map +1 -0
- package/dist/ui/server/services/appService.d.ts +45 -0
- package/dist/ui/server/services/appService.d.ts.map +1 -0
- package/dist/ui/server/services/appService.js +114 -0
- package/dist/ui/server/services/appService.js.map +1 -0
- package/dist/ui/server/services/removalService.d.ts +24 -0
- package/dist/ui/server/services/removalService.d.ts.map +1 -0
- package/dist/ui/server/services/removalService.js +83 -0
- package/dist/ui/server/services/removalService.js.map +1 -0
- package/dist/utils/filesystem.js +32 -49
- package/dist/utils/filesystem.js.map +1 -1
- package/dist/utils/logger.js +9 -18
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/platform.js +10 -22
- package/dist/utils/platform.js.map +1 -1
- package/dist/utils/upgrade.d.ts +2 -1
- package/dist/utils/upgrade.d.ts.map +1 -1
- package/dist/utils/upgrade.js +24 -15
- package/dist/utils/upgrade.js.map +1 -1
- package/package.json +4 -2
- package/scripts/publish-npm.sh +64 -0
- package/src/core/appUpdateChecker.ts +1 -1
- package/src/core/detector.ts +6 -6
- package/src/core/duplicateFileFinder.ts +1 -1
- package/src/core/orphanedDependencyDetector.ts +2 -2
- package/src/core/performanceOptimizer.ts +1 -1
- package/src/core/permissionHandler.ts +2 -2
- package/src/core/pluginSystem.ts +1 -1
- package/src/core/removalRecorder.ts +2 -2
- package/src/core/remover.ts +11 -11
- package/src/core/reportGenerator.ts +2 -2
- package/src/core/scheduledCleanup.ts +2 -2
- package/src/core/serviceFileDetector.ts +2 -2
- package/src/core/verificationModule.ts +2 -2
- package/src/index.ts +8 -8
- package/src/managers/brewManager.ts +3 -3
- package/src/managers/customManager.ts +2 -2
- package/src/managers/linuxManager.ts +3 -3
- package/src/managers/npmManager.ts +3 -3
- package/src/ui/client/api/client.ts +168 -0
- package/src/ui/client/app.ts +125 -0
- package/src/ui/client/index.html +107 -0
- package/src/ui/client/pages/appDetails.ts +356 -0
- package/src/ui/client/pages/appSearch.ts +283 -0
- package/src/ui/client/pages/dashboard.ts +211 -0
- package/src/ui/client/pages/settings.ts +342 -0
- package/src/ui/client/state/appStore.ts +181 -0
- package/src/ui/client/state/dashboardStore.ts +123 -0
- package/src/ui/client/state/uiStore.ts +166 -0
- package/src/ui/client/styles/animations.css +349 -0
- package/src/ui/client/styles/base.css +214 -0
- package/src/ui/client/styles/components.css +400 -0
- package/src/ui/client/styles/layout.css +224 -0
- package/src/ui/client/styles/variables.css +140 -0
- package/src/ui/client/utils/events.ts +74 -0
- package/src/ui/client/utils/formatting.ts +157 -0
- package/src/ui/client/utils/router.ts +161 -0
- package/src/ui/guiServer.ts +245 -498
- package/src/ui/prompts.ts +1 -1
- package/src/ui/server/middleware/errorHandler.ts +174 -0
- package/src/ui/server/routes/apps.ts +132 -0
- package/src/ui/server/routes/dashboard.ts +93 -0
- package/src/ui/server/routes/settings.ts +63 -0
- package/src/ui/server/services/appService.ts +184 -0
- package/src/ui/server/services/removalService.ts +138 -0
- package/src/utils/upgrade.ts +19 -2
- package/tsconfig.json +3 -2
- package/INDEX.md +0 -165
- /package/{ACTION_CHECKLIST.md → MD_Files/ACTION_CHECKLIST.md} +0 -0
- /package/{APPCLEAN_SUMMARY.md → MD_Files/APPCLEAN_SUMMARY.md} +0 -0
- /package/{CHANGELOG.md → MD_Files/CHANGELOG.md} +0 -0
- /package/{CODE_OF_CONDUCT.md → MD_Files/CODE_OF_CONDUCT.md} +0 -0
- /package/{CODE_REVIEW_REPORT.md → MD_Files/CODE_REVIEW_REPORT.md} +0 -0
- /package/{COMMUNITY_POSTS.md → MD_Files/COMMUNITY_POSTS.md} +0 -0
- /package/{DEPLOYMENT_GUIDE.md → MD_Files/DEPLOYMENT_GUIDE.md} +0 -0
- /package/{DEPLOYMENT_STATUS.md → MD_Files/DEPLOYMENT_STATUS.md} +0 -0
- /package/{EXECUTIVE_REPORT.md → MD_Files/EXECUTIVE_REPORT.md} +0 -0
- /package/{GITHUB_OPTIMIZATION.md → MD_Files/GITHUB_OPTIMIZATION.md} +0 -0
- /package/{MARKETING_SUMMARY.md → MD_Files/MARKETING_SUMMARY.md} +0 -0
- /package/{NPM_PACKAGE_OPTIMIZATION.md → MD_Files/NPM_PACKAGE_OPTIMIZATION.md} +0 -0
- /package/{NPM_PUBLISH.md → MD_Files/NPM_PUBLISH.md} +0 -0
- /package/{PROJECT_SUMMARY.txt → MD_Files/PROJECT_SUMMARY.txt} +0 -0
- /package/{PUBLICATION_SUCCESS_REPORT.md → MD_Files/PUBLICATION_SUCCESS_REPORT.md} +0 -0
- /package/{QUICKSTART.md → MD_Files/QUICKSTART.md} +0 -0
- /package/{SETUP_GITHUB.md → MD_Files/SETUP_GITHUB.md} +0 -0
- /package/{TESTING_SUMMARY.md → MD_Files/TESTING_SUMMARY.md} +0 -0
- /package/{setup-github.sh → MD_Files/setup-github.sh} +0 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { dashboardStore } from '../state/dashboardStore.js';
|
|
2
|
+
import { formatBytes, formatPercent, formatRelativeTime } from '../utils/formatting.js';
|
|
3
|
+
export function renderDashboard() {
|
|
4
|
+
const container = document.getElementById('page-container');
|
|
5
|
+
if (!container)
|
|
6
|
+
return;
|
|
7
|
+
container.innerHTML = `
|
|
8
|
+
<div class="loading-state" style="text-align: center; padding: 60px 20px;">
|
|
9
|
+
<div class="spinner-lg spinner"></div>
|
|
10
|
+
<p class="text-center text-muted mt-4">Loading dashboard...</p>
|
|
11
|
+
</div>
|
|
12
|
+
`;
|
|
13
|
+
dashboardStore.refreshStats(true).then(() => {
|
|
14
|
+
const state = dashboardStore.getState();
|
|
15
|
+
const stats = state.stats;
|
|
16
|
+
const error = state.error;
|
|
17
|
+
if (error) {
|
|
18
|
+
container.innerHTML = `
|
|
19
|
+
<div class="alert alert-danger" style="margin: 20px;">
|
|
20
|
+
<h3 style="margin-top: 0;">⚠️ Error Loading Dashboard</h3>
|
|
21
|
+
<p>${escapeHtml(error)}</p>
|
|
22
|
+
<button class="btn btn-primary btn-sm" onclick="window.location.reload()">Retry</button>
|
|
23
|
+
</div>
|
|
24
|
+
`;
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
if (!stats) {
|
|
28
|
+
container.innerHTML = `
|
|
29
|
+
<div class="alert alert-warning" style="margin: 20px;">
|
|
30
|
+
<h3 style="margin-top: 0;">⏳ Initializing</h3>
|
|
31
|
+
<p>Dashboard is loading. Please wait...</p>
|
|
32
|
+
</div>
|
|
33
|
+
`;
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
renderDashboardContent(container, stats);
|
|
37
|
+
dashboardStore.subscribe((newState) => {
|
|
38
|
+
if (newState.stats) {
|
|
39
|
+
renderDashboardContent(container, newState.stats);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
}).catch((error) => {
|
|
43
|
+
console.error('Dashboard error:', error);
|
|
44
|
+
container.innerHTML = `
|
|
45
|
+
<div class="alert alert-danger" style="margin: 20px;">
|
|
46
|
+
<h3 style="margin-top: 0;">❌ Failed to Load Dashboard</h3>
|
|
47
|
+
<p>An unexpected error occurred. Please check the console for details.</p>
|
|
48
|
+
<button class="btn btn-primary btn-sm" onclick="window.location.reload()">Reload Page</button>
|
|
49
|
+
</div>
|
|
50
|
+
`;
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
function renderDashboardContent(container, stats) {
|
|
54
|
+
container.innerHTML = `
|
|
55
|
+
<div class="dashboard-page fade-in">
|
|
56
|
+
<!-- Header -->
|
|
57
|
+
<div class="page-header mb-8">
|
|
58
|
+
<h1 class="text-3xl font-bold">📊 Dashboard</h1>
|
|
59
|
+
<p class="text-secondary mt-2">System overview and app management</p>
|
|
60
|
+
</div>
|
|
61
|
+
|
|
62
|
+
<!-- Stats Grid -->
|
|
63
|
+
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-8">
|
|
64
|
+
${renderStatCard('📦 Installed Apps', stats.totalApps.toString(), 'Total applications detected')}
|
|
65
|
+
${renderStatCard('💾 Total Space Used', formatBytes(stats.totalSpaceUsed), 'Size of all app files')}
|
|
66
|
+
${renderStatCard('🗑️ Removed (Session)', stats.sessionAppsRemoved.toString(), 'Apps removed this session')}
|
|
67
|
+
${renderStatCard('📉 Space Freed', formatBytes(stats.sessionSpaceFreed), 'Total space recovered')}
|
|
68
|
+
</div>
|
|
69
|
+
|
|
70
|
+
<!-- System Health -->
|
|
71
|
+
<div class="card mb-8">
|
|
72
|
+
<div class="card-header">
|
|
73
|
+
<h2 class="text-xl font-bold">💻 System Health</h2>
|
|
74
|
+
</div>
|
|
75
|
+
<div class="card-body">
|
|
76
|
+
<div class="health-gauge mb-4">
|
|
77
|
+
<div class="flex-between mb-2">
|
|
78
|
+
<span class="text-sm font-medium">Disk Usage</span>
|
|
79
|
+
<span class="text-sm font-bold">${formatPercent(stats.diskUsagePercent)}</span>
|
|
80
|
+
</div>
|
|
81
|
+
<div class="progress-bar" style="height: 8px; background: #e5e7eb; border-radius: 4px; overflow: hidden;">
|
|
82
|
+
<div style="
|
|
83
|
+
height: 100%;
|
|
84
|
+
width: ${stats.diskUsagePercent}%;
|
|
85
|
+
background: ${getDiskUsageColor(stats.diskUsagePercent)};
|
|
86
|
+
transition: width 0.3s ease;
|
|
87
|
+
"></div>
|
|
88
|
+
</div>
|
|
89
|
+
</div>
|
|
90
|
+
<p class="text-sm text-muted">
|
|
91
|
+
${stats.diskUsagePercent < 80
|
|
92
|
+
? '✅ Disk usage is healthy'
|
|
93
|
+
: stats.diskUsagePercent < 90
|
|
94
|
+
? '⚠️ Disk usage is getting high'
|
|
95
|
+
: '🔴 Disk usage is critical'}
|
|
96
|
+
</p>
|
|
97
|
+
</div>
|
|
98
|
+
</div>
|
|
99
|
+
|
|
100
|
+
<!-- Recent Activity -->
|
|
101
|
+
<div class="card">
|
|
102
|
+
<div class="card-header">
|
|
103
|
+
<h2 class="text-xl font-bold">📜 Recent Activity</h2>
|
|
104
|
+
</div>
|
|
105
|
+
<div class="card-body">
|
|
106
|
+
${stats.recentlyRemoved.length > 0
|
|
107
|
+
? `
|
|
108
|
+
<div class="activity-list">
|
|
109
|
+
${stats.recentlyRemoved
|
|
110
|
+
.slice(0, 10)
|
|
111
|
+
.map((removal) => `
|
|
112
|
+
<div class="activity-item flex-between p-3 border-b border-color last:border-0" style="padding: 12px 0;">
|
|
113
|
+
<div class="activity-info">
|
|
114
|
+
<p class="text-sm font-medium">${escapeHtml(removal.appName)}</p>
|
|
115
|
+
<p class="text-xs text-muted">Removed ${formatRelativeTime(removal.timestamp)}</p>
|
|
116
|
+
</div>
|
|
117
|
+
<div class="activity-stats text-right">
|
|
118
|
+
<p class="text-sm font-bold text-success">${formatBytes(removal.freedSpace)}</p>
|
|
119
|
+
<p class="text-xs text-muted">${removal.filesRemoved} files</p>
|
|
120
|
+
</div>
|
|
121
|
+
</div>
|
|
122
|
+
`)
|
|
123
|
+
.join('')}
|
|
124
|
+
</div>
|
|
125
|
+
`
|
|
126
|
+
: `
|
|
127
|
+
<p class="text-muted text-center py-8">
|
|
128
|
+
No apps removed yet. Start by searching for apps to remove.
|
|
129
|
+
</p>
|
|
130
|
+
`}
|
|
131
|
+
</div>
|
|
132
|
+
</div>
|
|
133
|
+
|
|
134
|
+
<!-- Quick Actions -->
|
|
135
|
+
<div class="mt-8 grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
136
|
+
<button class="btn btn-primary btn-lg w-full" onclick="window.location.hash = '#/apps'">
|
|
137
|
+
<span>🔍 Find & Remove Apps</span>
|
|
138
|
+
</button>
|
|
139
|
+
<button class="btn btn-secondary btn-lg w-full" onclick="window.location.hash = '#/settings'">
|
|
140
|
+
<span>⚙️ Settings</span>
|
|
141
|
+
</button>
|
|
142
|
+
</div>
|
|
143
|
+
</div>
|
|
144
|
+
`;
|
|
145
|
+
window.scrollTo(0, 0);
|
|
146
|
+
}
|
|
147
|
+
function renderStatCard(label, value, description) {
|
|
148
|
+
return `
|
|
149
|
+
<div class="card">
|
|
150
|
+
<div class="card-body">
|
|
151
|
+
<p class="text-muted text-sm mb-2">${escapeHtml(label)}</p>
|
|
152
|
+
<p class="text-2xl font-bold text-primary mb-1">${escapeHtml(value)}</p>
|
|
153
|
+
<p class="text-xs text-muted">${escapeHtml(description)}</p>
|
|
154
|
+
</div>
|
|
155
|
+
</div>
|
|
156
|
+
`;
|
|
157
|
+
}
|
|
158
|
+
function getDiskUsageColor(percent) {
|
|
159
|
+
if (percent < 50)
|
|
160
|
+
return '#10b981';
|
|
161
|
+
if (percent < 80)
|
|
162
|
+
return '#f59e0b';
|
|
163
|
+
return '#ef4444';
|
|
164
|
+
}
|
|
165
|
+
function escapeHtml(text) {
|
|
166
|
+
const map = {
|
|
167
|
+
'&': '&',
|
|
168
|
+
'<': '<',
|
|
169
|
+
'>': '>',
|
|
170
|
+
'"': '"',
|
|
171
|
+
"'": ''',
|
|
172
|
+
};
|
|
173
|
+
return text.replace(/[&<>"']/g, (m) => map[m]);
|
|
174
|
+
}
|
|
175
|
+
//# sourceMappingURL=dashboard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../../../../src/ui/client/pages/dashboard.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../../../src/ui/client/pages/settings.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,iBAAiB,EAAE,OAAO,CAAC;CAC5B;AAKD,wBAAgB,cAAc,IAAI,IAAI,CAgBrC"}
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import { apiClient } from '../api/client.js';
|
|
2
|
+
import { uiStore } from '../state/uiStore.js';
|
|
3
|
+
export function renderSettings() {
|
|
4
|
+
const container = document.getElementById('page-container');
|
|
5
|
+
if (!container)
|
|
6
|
+
return;
|
|
7
|
+
container.innerHTML = `
|
|
8
|
+
<div class="loading-state" style="text-align: center; padding: 60px 20px;">
|
|
9
|
+
<div class="spinner-lg spinner"></div>
|
|
10
|
+
<p class="text-center text-muted mt-4">Loading settings...</p>
|
|
11
|
+
</div>
|
|
12
|
+
`;
|
|
13
|
+
loadVersionInfo().then((versionInfo) => {
|
|
14
|
+
renderSettingsContent(container, versionInfo);
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
async function loadVersionInfo() {
|
|
18
|
+
try {
|
|
19
|
+
return await apiClient.get('/api/version');
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
return {
|
|
23
|
+
current: 'unknown',
|
|
24
|
+
latest: 'unknown',
|
|
25
|
+
isUpdateAvailable: false,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function renderSettingsContent(container, versionInfo) {
|
|
30
|
+
const currentTheme = uiStore.getState().theme;
|
|
31
|
+
container.innerHTML = `
|
|
32
|
+
<div class="settings-page">
|
|
33
|
+
<!-- Header -->
|
|
34
|
+
<div class="page-header mb-8">
|
|
35
|
+
<h1 class="text-3xl font-bold">⚙️ Settings</h1>
|
|
36
|
+
<p class="text-secondary mt-2">Configure AppClean</p>
|
|
37
|
+
</div>
|
|
38
|
+
|
|
39
|
+
<!-- Version & Updates Section -->
|
|
40
|
+
<div class="card mb-6">
|
|
41
|
+
<div class="card-header">
|
|
42
|
+
<h2 class="text-xl font-bold">📦 Version & Updates</h2>
|
|
43
|
+
</div>
|
|
44
|
+
<div class="card-body">
|
|
45
|
+
<div class="version-info p-4 bg-secondary rounded mb-4">
|
|
46
|
+
<div class="flex-between mb-3">
|
|
47
|
+
<span class="text-sm font-medium">Current Version</span>
|
|
48
|
+
<span class="text-lg font-bold text-primary">v${escapeHtml(versionInfo.current)}</span>
|
|
49
|
+
</div>
|
|
50
|
+
<div class="flex-between">
|
|
51
|
+
<span class="text-sm font-medium">Latest Version</span>
|
|
52
|
+
<span class="text-lg font-bold ${versionInfo.isUpdateAvailable ? 'text-warning' : 'text-success'}">
|
|
53
|
+
v${escapeHtml(versionInfo.latest)}
|
|
54
|
+
</span>
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
|
|
58
|
+
${versionInfo.isUpdateAvailable
|
|
59
|
+
? `
|
|
60
|
+
<div class="alert alert-warning mb-4">
|
|
61
|
+
<span>A new version of AppClean is available!</span>
|
|
62
|
+
</div>
|
|
63
|
+
<div class="flex gap-2">
|
|
64
|
+
<button class="btn btn-primary flex-1" id="upgrade-btn">
|
|
65
|
+
🚀 Upgrade Now
|
|
66
|
+
</button>
|
|
67
|
+
<button class="btn btn-secondary flex-1" id="check-update-btn">
|
|
68
|
+
🔄 Check Again
|
|
69
|
+
</button>
|
|
70
|
+
</div>
|
|
71
|
+
`
|
|
72
|
+
: `
|
|
73
|
+
<div class="alert alert-success mb-4">
|
|
74
|
+
<span>✓ You're running the latest version!</span>
|
|
75
|
+
</div>
|
|
76
|
+
<button class="btn btn-secondary w-full" id="check-update-btn">
|
|
77
|
+
🔄 Check for Updates
|
|
78
|
+
</button>
|
|
79
|
+
`}
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
|
|
83
|
+
<!-- Theme Section -->
|
|
84
|
+
<div class="card mb-6">
|
|
85
|
+
<div class="card-header">
|
|
86
|
+
<h2 class="text-xl font-bold">🎨 Appearance</h2>
|
|
87
|
+
</div>
|
|
88
|
+
<div class="card-body">
|
|
89
|
+
<div class="flex-between items-center p-3 border border-color rounded mb-4">
|
|
90
|
+
<div>
|
|
91
|
+
<p class="font-medium">Dark Mode</p>
|
|
92
|
+
<p class="text-sm text-muted">Switch between light and dark themes</p>
|
|
93
|
+
</div>
|
|
94
|
+
<button
|
|
95
|
+
class="btn btn-sm ${currentTheme === 'dark' ? 'btn-primary' : 'btn-secondary'}"
|
|
96
|
+
id="theme-toggle-btn"
|
|
97
|
+
>
|
|
98
|
+
${currentTheme === 'dark' ? '🌙 Dark' : '☀️ Light'}
|
|
99
|
+
</button>
|
|
100
|
+
</div>
|
|
101
|
+
</div>
|
|
102
|
+
</div>
|
|
103
|
+
|
|
104
|
+
<!-- About Section -->
|
|
105
|
+
<div class="card mb-6">
|
|
106
|
+
<div class="card-header">
|
|
107
|
+
<h2 class="text-xl font-bold">ℹ️ About</h2>
|
|
108
|
+
</div>
|
|
109
|
+
<div class="card-body">
|
|
110
|
+
<div class="space-y-4">
|
|
111
|
+
<div>
|
|
112
|
+
<p class="text-sm font-medium mb-2">AppClean</p>
|
|
113
|
+
<p class="text-sm text-muted">
|
|
114
|
+
Intelligently find and safely remove applications with all their artifacts.
|
|
115
|
+
</p>
|
|
116
|
+
</div>
|
|
117
|
+
|
|
118
|
+
<div>
|
|
119
|
+
<p class="text-sm font-medium mb-2">Links</p>
|
|
120
|
+
<div class="flex gap-2">
|
|
121
|
+
<a
|
|
122
|
+
href="https://github.com/praveenkay/AppClean"
|
|
123
|
+
target="_blank"
|
|
124
|
+
rel="noopener"
|
|
125
|
+
class="btn btn-sm btn-ghost"
|
|
126
|
+
>
|
|
127
|
+
💻 GitHub
|
|
128
|
+
</a>
|
|
129
|
+
<a
|
|
130
|
+
href="https://github.com/praveenkay/AppClean/issues"
|
|
131
|
+
target="_blank"
|
|
132
|
+
rel="noopener"
|
|
133
|
+
class="btn btn-sm btn-ghost"
|
|
134
|
+
>
|
|
135
|
+
🐛 Report Issue
|
|
136
|
+
</a>
|
|
137
|
+
</div>
|
|
138
|
+
</div>
|
|
139
|
+
</div>
|
|
140
|
+
</div>
|
|
141
|
+
</div>
|
|
142
|
+
|
|
143
|
+
<!-- Danger Zone -->
|
|
144
|
+
<div class="card" style="border-color: var(--color-danger);">
|
|
145
|
+
<div class="card-header" style="background: var(--color-danger-light);">
|
|
146
|
+
<h2 class="text-xl font-bold text-danger">⚠️ Danger Zone</h2>
|
|
147
|
+
</div>
|
|
148
|
+
<div class="card-body">
|
|
149
|
+
<p class="text-sm text-muted mb-4">
|
|
150
|
+
Uninstall AppClean from your system. This action cannot be undone.
|
|
151
|
+
</p>
|
|
152
|
+
<button class="btn btn-danger w-full" id="uninstall-btn">
|
|
153
|
+
🗑️ Uninstall AppClean
|
|
154
|
+
</button>
|
|
155
|
+
</div>
|
|
156
|
+
</div>
|
|
157
|
+
</div>
|
|
158
|
+
`;
|
|
159
|
+
setupSettingsListeners();
|
|
160
|
+
window.scrollTo(0, 0);
|
|
161
|
+
}
|
|
162
|
+
function setupSettingsListeners() {
|
|
163
|
+
const upgradeBtn = document.getElementById('upgrade-btn');
|
|
164
|
+
const checkUpdateBtn = document.getElementById('check-update-btn');
|
|
165
|
+
const themeToggleBtn = document.getElementById('theme-toggle-btn');
|
|
166
|
+
const uninstallBtn = document.getElementById('uninstall-btn');
|
|
167
|
+
if (upgradeBtn) {
|
|
168
|
+
upgradeBtn.addEventListener('click', async () => {
|
|
169
|
+
upgradeBtn.disabled = true;
|
|
170
|
+
upgradeBtn.textContent = '⏳ Upgrading...';
|
|
171
|
+
try {
|
|
172
|
+
const result = await apiClient.post('/api/upgrade', {});
|
|
173
|
+
if (result.success) {
|
|
174
|
+
uiStore.showSuccess(result.message);
|
|
175
|
+
setTimeout(() => {
|
|
176
|
+
window.location.reload();
|
|
177
|
+
}, 2000);
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
uiStore.showError(result.message);
|
|
181
|
+
upgradeBtn.disabled = false;
|
|
182
|
+
upgradeBtn.textContent = '🚀 Upgrade Now';
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
catch (error) {
|
|
186
|
+
uiStore.showError(`Upgrade failed: ${error.message}`);
|
|
187
|
+
upgradeBtn.disabled = false;
|
|
188
|
+
upgradeBtn.textContent = '🚀 Upgrade Now';
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
if (checkUpdateBtn) {
|
|
193
|
+
checkUpdateBtn.addEventListener('click', async () => {
|
|
194
|
+
checkUpdateBtn.disabled = true;
|
|
195
|
+
checkUpdateBtn.textContent = '⏳ Checking...';
|
|
196
|
+
try {
|
|
197
|
+
const versionInfo = await apiClient.get('/api/version');
|
|
198
|
+
if (versionInfo.isUpdateAvailable) {
|
|
199
|
+
uiStore.showWarning(`Update available: v${versionInfo.latest} (current: v${versionInfo.current})`);
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
uiStore.showSuccess('You are running the latest version!');
|
|
203
|
+
}
|
|
204
|
+
setTimeout(() => {
|
|
205
|
+
window.location.reload();
|
|
206
|
+
}, 1500);
|
|
207
|
+
}
|
|
208
|
+
catch (error) {
|
|
209
|
+
uiStore.showError(`Failed to check updates: ${error.message}`);
|
|
210
|
+
checkUpdateBtn.disabled = false;
|
|
211
|
+
checkUpdateBtn.textContent = '🔄 Check Again';
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
if (themeToggleBtn) {
|
|
216
|
+
themeToggleBtn.addEventListener('click', () => {
|
|
217
|
+
uiStore.toggleTheme();
|
|
218
|
+
const newTheme = uiStore.getState().theme;
|
|
219
|
+
themeToggleBtn.className = `btn btn-sm ${newTheme === 'dark' ? 'btn-primary' : 'btn-secondary'}`;
|
|
220
|
+
themeToggleBtn.textContent = newTheme === 'dark' ? '🌙 Dark' : '☀️ Light';
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
if (uninstallBtn) {
|
|
224
|
+
uninstallBtn.addEventListener('click', () => {
|
|
225
|
+
const confirmed = confirm('Are you sure you want to uninstall AppClean?\n\nThis action cannot be undone.');
|
|
226
|
+
if (!confirmed)
|
|
227
|
+
return;
|
|
228
|
+
const doubleConfirmed = confirm('This will permanently remove AppClean from your system.\n\nType "YES" in the next dialog to confirm.');
|
|
229
|
+
if (!doubleConfirmed)
|
|
230
|
+
return;
|
|
231
|
+
uninstall();
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
async function uninstall() {
|
|
236
|
+
const uninstallBtn = document.getElementById('uninstall-btn');
|
|
237
|
+
if (uninstallBtn) {
|
|
238
|
+
uninstallBtn.disabled = true;
|
|
239
|
+
uninstallBtn.textContent = '⏳ Uninstalling...';
|
|
240
|
+
}
|
|
241
|
+
uiStore.setProcessing(true);
|
|
242
|
+
try {
|
|
243
|
+
const result = await apiClient.post('/api/uninstall', {});
|
|
244
|
+
if (result.success) {
|
|
245
|
+
uiStore.showSuccess(result.message);
|
|
246
|
+
setTimeout(() => {
|
|
247
|
+
window.close();
|
|
248
|
+
}, 2000);
|
|
249
|
+
}
|
|
250
|
+
else {
|
|
251
|
+
uiStore.showError(result.message);
|
|
252
|
+
if (uninstallBtn) {
|
|
253
|
+
uninstallBtn.disabled = false;
|
|
254
|
+
uninstallBtn.textContent = '🗑️ Uninstall AppClean';
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
catch (error) {
|
|
259
|
+
uiStore.showError(`Uninstall failed: ${error.message}`);
|
|
260
|
+
if (uninstallBtn) {
|
|
261
|
+
uninstallBtn.disabled = false;
|
|
262
|
+
uninstallBtn.textContent = '🗑️ Uninstall AppClean';
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
finally {
|
|
266
|
+
uiStore.setProcessing(false);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
function escapeHtml(text) {
|
|
270
|
+
const map = {
|
|
271
|
+
'&': '&',
|
|
272
|
+
'<': '<',
|
|
273
|
+
'>': '>',
|
|
274
|
+
'"': '"',
|
|
275
|
+
"'": ''',
|
|
276
|
+
};
|
|
277
|
+
return String(text).replace(/[&<>"']/g, (m) => map[m]);
|
|
278
|
+
}
|
|
279
|
+
//# sourceMappingURL=settings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settings.js","sourceRoot":"","sources":["../../../../src/ui/client/pages/settings.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Store } from '../utils/events.js';
|
|
2
|
+
export interface InstalledApp {
|
|
3
|
+
name: string;
|
|
4
|
+
version: string;
|
|
5
|
+
installMethod: string;
|
|
6
|
+
mainPath: string;
|
|
7
|
+
installedDate?: string;
|
|
8
|
+
size?: number;
|
|
9
|
+
}
|
|
10
|
+
export interface SearchOptions {
|
|
11
|
+
query: string;
|
|
12
|
+
installMethod?: string;
|
|
13
|
+
sortBy?: 'name' | 'size' | 'date';
|
|
14
|
+
}
|
|
15
|
+
export interface AppStoreState {
|
|
16
|
+
apps: InstalledApp[];
|
|
17
|
+
searchOptions: SearchOptions;
|
|
18
|
+
selectedApp: InstalledApp | null;
|
|
19
|
+
isLoading: boolean;
|
|
20
|
+
error: string | null;
|
|
21
|
+
total: number;
|
|
22
|
+
page: number;
|
|
23
|
+
pageSize: number;
|
|
24
|
+
}
|
|
25
|
+
export declare class AppStore extends Store<AppStoreState> {
|
|
26
|
+
constructor();
|
|
27
|
+
loadApps(): Promise<void>;
|
|
28
|
+
searchApps(options: Partial<SearchOptions>): Promise<void>;
|
|
29
|
+
setSearchQuery(query: string): void;
|
|
30
|
+
setInstallMethodFilter(method?: string): void;
|
|
31
|
+
setSortBy(sortBy: 'name' | 'size' | 'date'): void;
|
|
32
|
+
selectApp(app: InstalledApp): void;
|
|
33
|
+
clearSelection(): void;
|
|
34
|
+
loadNextPage(): Promise<void>;
|
|
35
|
+
clearError(): void;
|
|
36
|
+
}
|
|
37
|
+
export declare const appStore: AppStore;
|
|
38
|
+
//# sourceMappingURL=appStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"appStore.d.ts","sourceRoot":"","sources":["../../../../src/ui/client/state/appStore.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE3C,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;CACnC;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,YAAY,EAAE,CAAC;IACrB,aAAa,EAAE,aAAa,CAAC;IAC7B,WAAW,EAAE,YAAY,GAAG,IAAI,CAAC;IACjC,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAiBD,qBAAa,QAAS,SAAQ,KAAK,CAAC,aAAa,CAAC;;IAM1C,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IA0BzB,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAkChE,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAKnC,sBAAsB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;IAK7C,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI;IAKjD,SAAS,CAAC,GAAG,EAAE,YAAY,GAAG,IAAI;IAKlC,cAAc,IAAI,IAAI;IAKhB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAoCnC,UAAU,IAAI,IAAI;CAGnB;AAGD,eAAO,MAAM,QAAQ,UAAiB,CAAC"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { Store } from '../utils/events.js';
|
|
2
|
+
const INITIAL_STATE = {
|
|
3
|
+
apps: [],
|
|
4
|
+
searchOptions: {
|
|
5
|
+
query: '',
|
|
6
|
+
installMethod: undefined,
|
|
7
|
+
sortBy: 'name',
|
|
8
|
+
},
|
|
9
|
+
selectedApp: null,
|
|
10
|
+
isLoading: false,
|
|
11
|
+
error: null,
|
|
12
|
+
total: 0,
|
|
13
|
+
page: 1,
|
|
14
|
+
pageSize: 50,
|
|
15
|
+
};
|
|
16
|
+
export class AppStore extends Store {
|
|
17
|
+
constructor() {
|
|
18
|
+
super(INITIAL_STATE);
|
|
19
|
+
}
|
|
20
|
+
async loadApps() {
|
|
21
|
+
this.setState({ isLoading: true, error: null });
|
|
22
|
+
try {
|
|
23
|
+
const response = await fetch('/api/apps/list');
|
|
24
|
+
if (!response.ok)
|
|
25
|
+
throw new Error('Failed to load apps');
|
|
26
|
+
const json = await response.json();
|
|
27
|
+
const data = json.data || json;
|
|
28
|
+
this.setState({
|
|
29
|
+
apps: data.apps || [],
|
|
30
|
+
total: data.total || 0,
|
|
31
|
+
page: data.page || 1,
|
|
32
|
+
isLoading: false,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
const errorMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
37
|
+
console.error('Failed to load apps:', errorMsg);
|
|
38
|
+
this.setState({
|
|
39
|
+
error: errorMsg,
|
|
40
|
+
isLoading: false,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
async searchApps(options) {
|
|
45
|
+
const searchOptions = { ...this.state.searchOptions, ...options };
|
|
46
|
+
this.setState({ searchOptions, isLoading: true, error: null, page: 1 });
|
|
47
|
+
try {
|
|
48
|
+
const params = new URLSearchParams();
|
|
49
|
+
if (searchOptions.query)
|
|
50
|
+
params.append('q', searchOptions.query);
|
|
51
|
+
if (searchOptions.installMethod)
|
|
52
|
+
params.append('method', searchOptions.installMethod);
|
|
53
|
+
if (searchOptions.sortBy)
|
|
54
|
+
params.append('sort', searchOptions.sortBy);
|
|
55
|
+
params.append('limit', String(this.state.pageSize));
|
|
56
|
+
params.append('offset', '0');
|
|
57
|
+
const response = await fetch(`/api/apps/search?${params}`);
|
|
58
|
+
if (!response.ok)
|
|
59
|
+
throw new Error('Failed to search apps');
|
|
60
|
+
const json = await response.json();
|
|
61
|
+
const data = json.data || json;
|
|
62
|
+
this.setState({
|
|
63
|
+
apps: data.apps || [],
|
|
64
|
+
total: data.count || 0,
|
|
65
|
+
isLoading: false,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
const errorMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
70
|
+
console.error('Failed to search apps:', errorMsg);
|
|
71
|
+
this.setState({
|
|
72
|
+
error: errorMsg,
|
|
73
|
+
isLoading: false,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
setSearchQuery(query) {
|
|
78
|
+
this.searchApps({ query });
|
|
79
|
+
}
|
|
80
|
+
setInstallMethodFilter(method) {
|
|
81
|
+
this.searchApps({ installMethod: method });
|
|
82
|
+
}
|
|
83
|
+
setSortBy(sortBy) {
|
|
84
|
+
this.searchApps({ sortBy });
|
|
85
|
+
}
|
|
86
|
+
selectApp(app) {
|
|
87
|
+
this.setState({ selectedApp: app });
|
|
88
|
+
}
|
|
89
|
+
clearSelection() {
|
|
90
|
+
this.setState({ selectedApp: null });
|
|
91
|
+
}
|
|
92
|
+
async loadNextPage() {
|
|
93
|
+
const nextPage = this.state.page + 1;
|
|
94
|
+
const offset = (nextPage - 1) * this.state.pageSize;
|
|
95
|
+
this.setState({ isLoading: true });
|
|
96
|
+
try {
|
|
97
|
+
const params = new URLSearchParams();
|
|
98
|
+
if (this.state.searchOptions.query)
|
|
99
|
+
params.append('q', this.state.searchOptions.query);
|
|
100
|
+
if (this.state.searchOptions.installMethod) {
|
|
101
|
+
params.append('method', this.state.searchOptions.installMethod);
|
|
102
|
+
}
|
|
103
|
+
params.append('limit', String(this.state.pageSize));
|
|
104
|
+
params.append('offset', String(offset));
|
|
105
|
+
const response = await fetch(`/api/apps/search?${params}`);
|
|
106
|
+
if (!response.ok)
|
|
107
|
+
throw new Error('Failed to load more apps');
|
|
108
|
+
const json = await response.json();
|
|
109
|
+
const data = json.data || json;
|
|
110
|
+
this.setState({
|
|
111
|
+
apps: [...this.state.apps, ...(data.apps || [])],
|
|
112
|
+
page: nextPage,
|
|
113
|
+
isLoading: false,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
const errorMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
118
|
+
console.error('Failed to load next page:', errorMsg);
|
|
119
|
+
this.setState({
|
|
120
|
+
error: errorMsg,
|
|
121
|
+
isLoading: false,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
clearError() {
|
|
126
|
+
this.setState({ error: null });
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
export const appStore = new AppStore();
|
|
130
|
+
//# sourceMappingURL=appStore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"appStore.js","sourceRoot":"","sources":["../../../../src/ui/client/state/appStore.ts"],"names":[],"mappings":"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"}
|