mindroot 7.7.0__py3-none-any.whl → 8.2.0__py3-none-any.whl
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.
Potentially problematic release.
This version of mindroot might be problematic. Click here for more details.
- mindroot/coreplugins/admin/plugin_manager.py +126 -3
- mindroot/coreplugins/admin/plugin_manager_backup.py +615 -0
- mindroot/coreplugins/admin/router.py +3 -1
- mindroot/coreplugins/admin/server_router.py +8 -1
- mindroot/coreplugins/admin/static/js/plugin-advanced-install.js +83 -12
- mindroot/coreplugins/admin/static/js/plugin-index-browser.js +138 -10
- mindroot/coreplugins/admin/static/js/plugin-install-dialog.js +345 -0
- mindroot/coreplugins/admin/static/js/server-control.js +68 -6
- mindroot/coreplugins/agent/agent.py +4 -0
- mindroot/coreplugins/chat/models.py +0 -1
- mindroot/coreplugins/chat/router.py +31 -0
- mindroot/coreplugins/chat/services.py +24 -0
- mindroot/coreplugins/chat/static/css/dark.css +35 -0
- mindroot/coreplugins/chat/static/css/default.css +35 -0
- mindroot/coreplugins/chat/static/js/chatform.js +185 -0
- mindroot/coreplugins/env_manager/__init__.py +3 -0
- mindroot/coreplugins/env_manager/inject/admin.jinja2 +16 -0
- mindroot/coreplugins/env_manager/mod.py +228 -0
- mindroot/coreplugins/env_manager/router.py +40 -0
- mindroot/coreplugins/env_manager/static/css/env-manager.css +263 -0
- mindroot/coreplugins/env_manager/static/js/env-manager.js +380 -0
- mindroot/coreplugins/home/router.py +33 -2
- mindroot/coreplugins/home/static/css/enhanced.css +111 -5
- mindroot/coreplugins/home/templates/home.jinja2 +7 -4
- mindroot/lib/chatlog.py +5 -1
- mindroot/lib/streamcmd.py +139 -0
- mindroot/lib/templates.py +13 -2
- mindroot/server.py +12 -25
- mindroot-8.2.0.dist-info/METADATA +15 -0
- {mindroot-7.7.0.dist-info → mindroot-8.2.0.dist-info}/RECORD +34 -25
- {mindroot-7.7.0.dist-info → mindroot-8.2.0.dist-info}/WHEEL +1 -1
- mindroot-7.7.0.dist-info/METADATA +0 -310
- {mindroot-7.7.0.dist-info → mindroot-8.2.0.dist-info}/entry_points.txt +0 -0
- {mindroot-7.7.0.dist-info → mindroot-8.2.0.dist-info}/licenses/LICENSE +0 -0
- {mindroot-7.7.0.dist-info → mindroot-8.2.0.dist-info}/top_level.txt +0 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { html, css } from './lit-core.min.js';
|
|
2
2
|
import { PluginBase } from './plugin-base.js';
|
|
3
|
+
import './plugin-install-dialog.js';
|
|
3
4
|
|
|
4
5
|
export class PluginAdvancedInstall extends PluginBase {
|
|
5
6
|
static properties = {
|
|
@@ -75,6 +76,23 @@ export class PluginAdvancedInstall extends PluginBase {
|
|
|
75
76
|
this.showGitHubModal = false;
|
|
76
77
|
}
|
|
77
78
|
|
|
79
|
+
firstUpdated() {
|
|
80
|
+
super.firstUpdated();
|
|
81
|
+
// Create the install dialog if it doesn't exist
|
|
82
|
+
if (!this.installDialog) {
|
|
83
|
+
this.installDialog = document.createElement('plugin-install-dialog');
|
|
84
|
+
document.body.appendChild(this.installDialog);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
disconnectedCallback() {
|
|
89
|
+
super.disconnectedCallback();
|
|
90
|
+
// Remove the dialog when component is removed
|
|
91
|
+
if (this.installDialog && document.body.contains(this.installDialog)) {
|
|
92
|
+
document.body.removeChild(this.installDialog);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
78
96
|
openGitHubModal() {
|
|
79
97
|
const modal = this.shadowRoot.querySelector('#github-install-modal');
|
|
80
98
|
modal.showModal();
|
|
@@ -94,30 +112,83 @@ export class PluginAdvancedInstall extends PluginBase {
|
|
|
94
112
|
return;
|
|
95
113
|
}
|
|
96
114
|
|
|
115
|
+
// Extract repo name from URL
|
|
116
|
+
const repoName = githubUrl.split('/').pop();
|
|
117
|
+
|
|
97
118
|
try {
|
|
98
|
-
|
|
99
|
-
plugin: 'test',
|
|
100
|
-
url: githubUrl
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
alert('Plugin installed successfully from GitHub');
|
|
119
|
+
// Close the modal
|
|
104
120
|
this.closeGitHubModal();
|
|
105
|
-
|
|
121
|
+
|
|
122
|
+
// Open the installation dialog
|
|
123
|
+
this.installDialog.open(repoName || 'GitHub Plugin', 'GitHub');
|
|
124
|
+
|
|
125
|
+
// Show initial message
|
|
126
|
+
this.installDialog.addOutput(`Starting installation of ${repoName} from GitHub...`, 'info');
|
|
127
|
+
|
|
128
|
+
try {
|
|
129
|
+
// Use the existing GitHub installation endpoint which handles the download and extraction
|
|
130
|
+
await this.apiCall('/plugin-manager/install-x-github-plugin', 'POST', {
|
|
131
|
+
plugin: repoName || 'plugin',
|
|
132
|
+
url: githubUrl
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// Show success message
|
|
136
|
+
this.installDialog.addOutput(`Plugin ${repoName} installed successfully from GitHub`, 'success');
|
|
137
|
+
this.installDialog.setComplete(false);
|
|
138
|
+
|
|
139
|
+
// Notify parent components to refresh their lists
|
|
140
|
+
this.dispatch('plugin-installed');
|
|
141
|
+
} catch (error) {
|
|
142
|
+
// Show error message
|
|
143
|
+
this.installDialog.addOutput(`Failed to install plugin from GitHub: ${error.message}`, 'error');
|
|
144
|
+
this.installDialog.setComplete(true);
|
|
145
|
+
}
|
|
106
146
|
} catch (error) {
|
|
107
|
-
|
|
147
|
+
this.installDialog.addOutput(`Failed to install plugin from GitHub: ${error.message}`, 'error');
|
|
148
|
+
this.installDialog.setComplete(true);
|
|
108
149
|
}
|
|
109
150
|
}
|
|
110
151
|
|
|
111
152
|
async handleScanDirectory() {
|
|
112
153
|
const directory = prompt('Enter the directory path to scan for plugins:');
|
|
113
154
|
if (!directory) return;
|
|
155
|
+
|
|
156
|
+
// Open the installation dialog
|
|
157
|
+
this.installDialog.open('Directory Scan', 'Local Directory');
|
|
158
|
+
this.installDialog.addOutput(`Scanning directory: ${directory}`, 'info');
|
|
114
159
|
|
|
115
160
|
try {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
161
|
+
// Make the API call
|
|
162
|
+
const response = await this.apiCall('/plugin-manager/scan-directory', 'POST', { directory });
|
|
163
|
+
|
|
164
|
+
if (response.success) {
|
|
165
|
+
this.installDialog.addOutput(response.message, 'success');
|
|
166
|
+
|
|
167
|
+
// If plugins were found, list them
|
|
168
|
+
if (response.plugins && response.plugins.length > 0) {
|
|
169
|
+
this.installDialog.addOutput('Found plugins:', 'info');
|
|
170
|
+
response.plugins.forEach(plugin => {
|
|
171
|
+
this.installDialog.addOutput(`- ${plugin.name}: ${plugin.description || 'No description'}`, 'info');
|
|
172
|
+
});
|
|
173
|
+
} else {
|
|
174
|
+
this.installDialog.addOutput('No plugins found in directory.', 'warning');
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
this.installDialog.setComplete(false);
|
|
178
|
+
this.dispatch('plugins-scanned');
|
|
179
|
+
} else {
|
|
180
|
+
this.installDialog.addOutput(`Scan failed: ${response.message}`, 'error');
|
|
181
|
+
this.installDialog.setComplete(true);
|
|
182
|
+
}
|
|
119
183
|
} catch (error) {
|
|
120
|
-
|
|
184
|
+
this.installDialog.addOutput(`Failed to scan directory: ${error.message}`, 'error');
|
|
185
|
+
|
|
186
|
+
// If there's a detailed error message, show it
|
|
187
|
+
if (error.response && error.response.data && error.response.data.message) {
|
|
188
|
+
this.installDialog.addOutput(error.response.data.message, 'error');
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
this.installDialog.setComplete(true);
|
|
121
192
|
}
|
|
122
193
|
}
|
|
123
194
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { html, css } from './lit-core.min.js';
|
|
2
2
|
import { PluginBase } from './plugin-base.js';
|
|
3
|
+
import './plugin-install-dialog.js';
|
|
3
4
|
|
|
4
5
|
export class PluginIndexBrowser extends PluginBase {
|
|
5
6
|
static properties = {
|
|
@@ -104,27 +105,154 @@ export class PluginIndexBrowser extends PluginBase {
|
|
|
104
105
|
}
|
|
105
106
|
}
|
|
106
107
|
|
|
108
|
+
firstUpdated() {
|
|
109
|
+
super.firstUpdated();
|
|
110
|
+
// Create the install dialog if it doesn't exist
|
|
111
|
+
if (!this.installDialog) {
|
|
112
|
+
this.installDialog = document.createElement('plugin-install-dialog');
|
|
113
|
+
document.body.appendChild(this.installDialog);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
disconnectedCallback() {
|
|
118
|
+
super.disconnectedCallback();
|
|
119
|
+
// Remove the dialog when component is removed
|
|
120
|
+
if (this.installDialog && document.body.contains(this.installDialog)) {
|
|
121
|
+
document.body.removeChild(this.installDialog);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
107
125
|
async handleInstall(plugin) {
|
|
108
126
|
if (plugin.source === 'github') {
|
|
109
127
|
try {
|
|
110
128
|
console.log('Installing plugin from GitHub:', {plugin})
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
129
|
+
|
|
130
|
+
// Open the installation dialog
|
|
131
|
+
this.installDialog.open(plugin.name, 'GitHub');
|
|
132
|
+
|
|
133
|
+
// Connect to SSE endpoint for streaming GitHub installation
|
|
134
|
+
// Build URL with properly encoded parameters
|
|
135
|
+
const params = new URLSearchParams();
|
|
136
|
+
params.append('plugin', plugin.name);
|
|
137
|
+
params.append('source', 'github');
|
|
138
|
+
params.append('source_path', plugin.github_url);
|
|
139
|
+
|
|
140
|
+
const eventSource = new EventSource(`/plugin-manager/stream-install-plugin?${params.toString()}`);
|
|
141
|
+
|
|
142
|
+
// Debug
|
|
143
|
+
console.log(`Connected to SSE endpoint: /plugin-manager/stream-install-plugin?${params.toString()}`);
|
|
144
|
+
|
|
145
|
+
eventSource.addEventListener('message', (event) => {
|
|
146
|
+
console.log('SSE message event:', event.data);
|
|
147
|
+
this.installDialog.addOutput(event.data, 'info');
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
eventSource.addEventListener('error', (event) => {
|
|
151
|
+
console.log('SSE error event:', event.data);
|
|
152
|
+
this.installDialog.addOutput(event.data, 'error');
|
|
114
153
|
});
|
|
115
|
-
|
|
154
|
+
|
|
155
|
+
eventSource.addEventListener('warning', (event) => {
|
|
156
|
+
console.log('SSE warning event:', event.data);
|
|
157
|
+
this.installDialog.addOutput(event.data, 'warning');
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
eventSource.addEventListener('complete', (event) => {
|
|
161
|
+
console.log('SSE complete event:', event.data);
|
|
162
|
+
this.installDialog.addOutput(event.data, 'success');
|
|
163
|
+
this.installDialog.setComplete(false);
|
|
164
|
+
eventSource.close();
|
|
165
|
+
// Dispatch event for parent components to refresh their lists
|
|
166
|
+
this.dispatch('plugin-installed', { plugin });
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
eventSource.onerror = () => {
|
|
170
|
+
console.log('SSE connection error');
|
|
171
|
+
eventSource.close();
|
|
172
|
+
this.installDialog.setComplete(true);
|
|
173
|
+
};
|
|
174
|
+
} catch (error) {
|
|
175
|
+
this.installDialog.addOutput(`Failed to install plugin from GitHub: ${error.message}`, 'error');
|
|
176
|
+
this.installDialog.setComplete(true);
|
|
177
|
+
}
|
|
178
|
+
} else if (plugin.source === 'local') {
|
|
179
|
+
try {
|
|
180
|
+
// Open the installation dialog
|
|
181
|
+
this.installDialog.open(plugin.name, 'Local');
|
|
182
|
+
|
|
183
|
+
// Use the existing local installation endpoint
|
|
184
|
+
try {
|
|
185
|
+
this.installDialog.addOutput(`Starting installation of ${plugin.name} from local path...`, 'info');
|
|
186
|
+
|
|
187
|
+
// Make the API call to install the plugin
|
|
188
|
+
await this.apiCall('/plugin-manager/install-local-plugin', 'POST', {
|
|
189
|
+
plugin: plugin.name
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
// Show success message
|
|
193
|
+
this.installDialog.addOutput(`Plugin ${plugin.name} installed successfully from local path`, 'success');
|
|
194
|
+
this.installDialog.setComplete(false);
|
|
195
|
+
|
|
196
|
+
// Notify parent components to refresh their lists
|
|
197
|
+
this.dispatch('plugin-installed', { plugin });
|
|
198
|
+
} catch (error) {
|
|
199
|
+
// Show error message
|
|
200
|
+
this.installDialog.addOutput(`Failed to install plugin from local path: ${error.message}`, 'error');
|
|
201
|
+
this.installDialog.setComplete(true);
|
|
202
|
+
}
|
|
116
203
|
} catch (error) {
|
|
117
|
-
|
|
204
|
+
this.installDialog.addOutput(`Failed to install plugin ${plugin.name}: ${error.message}`, 'error');
|
|
205
|
+
this.installDialog.setComplete(true);
|
|
118
206
|
}
|
|
119
207
|
} else {
|
|
208
|
+
// For PyPI packages, use the streaming approach
|
|
120
209
|
try {
|
|
121
|
-
|
|
122
|
-
|
|
210
|
+
// Open the installation dialog
|
|
211
|
+
this.installDialog.open(plugin.name, 'PyPI');
|
|
212
|
+
|
|
213
|
+
// Connect to SSE endpoint
|
|
214
|
+
// Build URL with properly encoded parameters
|
|
215
|
+
const params = new URLSearchParams();
|
|
216
|
+
params.append('plugin', plugin.name);
|
|
217
|
+
params.append('source', 'pypi');
|
|
218
|
+
|
|
219
|
+
const eventSource = new EventSource(`/plugin-manager/stream-install-plugin?${params.toString()}`);
|
|
220
|
+
|
|
221
|
+
// Debug
|
|
222
|
+
console.log(`Connected to SSE endpoint: /plugin-manager/stream-install-plugin?${params.toString()}`);
|
|
223
|
+
|
|
224
|
+
eventSource.addEventListener('message', (event) => {
|
|
225
|
+
console.log('SSE message event:', event.data);
|
|
226
|
+
this.installDialog.addOutput(event.data, 'info');
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
eventSource.addEventListener('error', (event) => {
|
|
230
|
+
console.log('SSE error event:', event.data);
|
|
231
|
+
this.installDialog.addOutput(event.data, 'error');
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
eventSource.addEventListener('warning', (event) => {
|
|
235
|
+
console.log('SSE warning event:', event.data);
|
|
236
|
+
this.installDialog.addOutput(event.data, 'warning');
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
eventSource.addEventListener('complete', (event) => {
|
|
240
|
+
console.log('SSE complete event:', event.data);
|
|
241
|
+
this.installDialog.addOutput(event.data, 'success');
|
|
242
|
+
this.installDialog.setComplete(false);
|
|
243
|
+
eventSource.close();
|
|
244
|
+
// Dispatch event for parent components to refresh their lists
|
|
245
|
+
this.dispatch('plugin-installed', { plugin });
|
|
123
246
|
});
|
|
124
|
-
|
|
125
|
-
|
|
247
|
+
|
|
248
|
+
eventSource.onerror = () => {
|
|
249
|
+
console.log('SSE connection error');
|
|
250
|
+
eventSource.close();
|
|
251
|
+
this.installDialog.setComplete(true);
|
|
252
|
+
};
|
|
126
253
|
} catch (error) {
|
|
127
|
-
|
|
254
|
+
this.installDialog.addOutput(`Failed to install plugin ${plugin.name}: ${error.message}`, 'error');
|
|
255
|
+
this.installDialog.setComplete(true);
|
|
128
256
|
}
|
|
129
257
|
}
|
|
130
258
|
}
|
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
import { html, css } from './lit-core.min.js';
|
|
2
|
+
import { BaseEl } from './base.js';
|
|
3
|
+
|
|
4
|
+
export class PluginInstallDialog extends BaseEl {
|
|
5
|
+
static properties = {
|
|
6
|
+
isOpen: { type: Boolean },
|
|
7
|
+
pluginName: { type: String },
|
|
8
|
+
installSource: { type: String },
|
|
9
|
+
output: { type: Array },
|
|
10
|
+
isComplete: { type: Boolean },
|
|
11
|
+
hasError: { type: Boolean },
|
|
12
|
+
autoClose: { type: Boolean }
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
static styles = css`
|
|
16
|
+
.dialog-backdrop {
|
|
17
|
+
position: fixed;
|
|
18
|
+
top: 0;
|
|
19
|
+
left: 0;
|
|
20
|
+
width: 100%;
|
|
21
|
+
height: 100%;
|
|
22
|
+
background: rgba(0, 0, 0, 0.7);
|
|
23
|
+
display: flex;
|
|
24
|
+
justify-content: center;
|
|
25
|
+
align-items: center;
|
|
26
|
+
z-index: 1000;
|
|
27
|
+
opacity: 0;
|
|
28
|
+
pointer-events: none;
|
|
29
|
+
transition: opacity 0.3s ease;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.dialog-backdrop.open {
|
|
33
|
+
opacity: 1;
|
|
34
|
+
pointer-events: auto;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.dialog {
|
|
38
|
+
background: rgb(15, 15, 30);
|
|
39
|
+
border-radius: 8px;
|
|
40
|
+
width: 95%;
|
|
41
|
+
max-width: 1200px;
|
|
42
|
+
max-height: 80vh;
|
|
43
|
+
display: flex;
|
|
44
|
+
flex-direction: column;
|
|
45
|
+
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);
|
|
46
|
+
transform: translateY(20px);
|
|
47
|
+
transition: transform 0.3s ease;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.dialog-backdrop.open .dialog {
|
|
51
|
+
transform: translateY(0);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.dialog-header {
|
|
55
|
+
padding: 1rem;
|
|
56
|
+
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
|
57
|
+
display: flex;
|
|
58
|
+
justify-content: space-between;
|
|
59
|
+
align-items: center;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.dialog-title {
|
|
63
|
+
font-size: 1.2rem;
|
|
64
|
+
font-weight: 500;
|
|
65
|
+
display: flex;
|
|
66
|
+
align-items: center;
|
|
67
|
+
gap: 0.5rem;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.dialog-title .material-icons {
|
|
71
|
+
font-size: 1.2rem;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.close-button {
|
|
75
|
+
background: none;
|
|
76
|
+
border: none;
|
|
77
|
+
color: rgba(255, 255, 255, 0.7);
|
|
78
|
+
cursor: pointer;
|
|
79
|
+
font-size: 1.5rem;
|
|
80
|
+
padding: 0;
|
|
81
|
+
display: flex;
|
|
82
|
+
align-items: center;
|
|
83
|
+
justify-content: center;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.close-button:hover {
|
|
87
|
+
color: white;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.dialog-content {
|
|
91
|
+
padding: 1rem;
|
|
92
|
+
overflow-y: auto;
|
|
93
|
+
flex: 1;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.terminal {
|
|
97
|
+
background: rgb(10, 10, 20);
|
|
98
|
+
border-radius: 4px;
|
|
99
|
+
padding: 1rem;
|
|
100
|
+
font-family: monospace;
|
|
101
|
+
/* white-space: pre-wrap; */
|
|
102
|
+
font-size: 0.9rem;
|
|
103
|
+
overflow-x: auto;
|
|
104
|
+
color: #f0f0f0;
|
|
105
|
+
height: 300px;
|
|
106
|
+
overflow-y: auto;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.terminal-line {
|
|
110
|
+
margin: 0;
|
|
111
|
+
line-height: 1.4;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.terminal-line.error {
|
|
115
|
+
color: #ff6b6b;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.terminal-line.warning {
|
|
119
|
+
color: #feca57;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.terminal-line.success {
|
|
123
|
+
color: #1dd1a1;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
.terminal-line.warning {
|
|
128
|
+
color: #feca57;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
.dialog-footer {
|
|
133
|
+
padding: 1rem;
|
|
134
|
+
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
|
135
|
+
display: flex;
|
|
136
|
+
justify-content: flex-end;
|
|
137
|
+
gap: 0.5rem;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.status {
|
|
141
|
+
display: flex;
|
|
142
|
+
align-items: center;
|
|
143
|
+
gap: 0.5rem;
|
|
144
|
+
margin-right: auto;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.status.success {
|
|
148
|
+
color: #1dd1a1;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.status.error {
|
|
152
|
+
color: #ff6b6b;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.status.in-progress {
|
|
156
|
+
color: #feca57;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.spinner {
|
|
160
|
+
border: 2px solid rgba(255, 255, 255, 0.1);
|
|
161
|
+
border-top: 2px solid #feca57;
|
|
162
|
+
border-radius: 50%;
|
|
163
|
+
width: 16px;
|
|
164
|
+
height: 16px;
|
|
165
|
+
animation: spin 1s linear infinite;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
@keyframes spin {
|
|
169
|
+
0% { transform: rotate(0deg); }
|
|
170
|
+
100% { transform: rotate(360deg); }
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
button {
|
|
174
|
+
background: #2a2a40;
|
|
175
|
+
color: white;
|
|
176
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
177
|
+
padding: 0.5rem 1rem;
|
|
178
|
+
border-radius: 4px;
|
|
179
|
+
cursor: pointer;
|
|
180
|
+
transition: background 0.2s;
|
|
181
|
+
display: flex;
|
|
182
|
+
align-items: center;
|
|
183
|
+
gap: 0.5rem;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
button:hover {
|
|
187
|
+
background: #3a3a50;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
button:disabled {
|
|
191
|
+
opacity: 0.5;
|
|
192
|
+
cursor: not-allowed;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
button.primary {
|
|
196
|
+
background: #2e86de;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
button.primary:hover {
|
|
200
|
+
background: #54a0ff;
|
|
201
|
+
}
|
|
202
|
+
`;
|
|
203
|
+
|
|
204
|
+
constructor() {
|
|
205
|
+
super();
|
|
206
|
+
this.isOpen = false;
|
|
207
|
+
this.pluginName = '';
|
|
208
|
+
this.installSource = '';
|
|
209
|
+
this.output = [];
|
|
210
|
+
this.isComplete = false;
|
|
211
|
+
this.hasError = false;
|
|
212
|
+
this.autoClose = true;
|
|
213
|
+
this.autoCloseTimer = null;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
connectedCallback() {
|
|
217
|
+
super.connectedCallback();
|
|
218
|
+
// Listen for ESC key to close dialog
|
|
219
|
+
this.handleKeyDown = (e) => {
|
|
220
|
+
if (e.key === 'Escape' && this.isOpen) {
|
|
221
|
+
this.close();
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
window.addEventListener('keydown', this.handleKeyDown);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
disconnectedCallback() {
|
|
228
|
+
super.disconnectedCallback();
|
|
229
|
+
window.removeEventListener('keydown', this.handleKeyDown);
|
|
230
|
+
this.clearAutoCloseTimer();
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
open(pluginName, installSource) {
|
|
234
|
+
this.pluginName = pluginName;
|
|
235
|
+
this.installSource = installSource;
|
|
236
|
+
this.output = [];
|
|
237
|
+
this.isComplete = false;
|
|
238
|
+
this.hasError = false;
|
|
239
|
+
this.isOpen = true;
|
|
240
|
+
this.clearAutoCloseTimer();
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
close() {
|
|
244
|
+
this.isOpen = false;
|
|
245
|
+
this.clearAutoCloseTimer();
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
clearAutoCloseTimer() {
|
|
249
|
+
if (this.autoCloseTimer) {
|
|
250
|
+
clearTimeout(this.autoCloseTimer);
|
|
251
|
+
this.autoCloseTimer = null;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
addOutput(line, type = 'info') {
|
|
256
|
+
// Skip completely empty lines
|
|
257
|
+
if (!line || line.trim() === '') {
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// Debug
|
|
262
|
+
console.log(`Adding output: ${type} - ${JSON.stringify(line)}`);
|
|
263
|
+
|
|
264
|
+
// Add the line to the output array
|
|
265
|
+
this.output = [...this.output, { text: line, type }];
|
|
266
|
+
// Scroll to bottom
|
|
267
|
+
setTimeout(() => {
|
|
268
|
+
const terminal = this.shadowRoot.querySelector('.terminal');
|
|
269
|
+
if (terminal) {
|
|
270
|
+
terminal.scrollTop = terminal.scrollHeight;
|
|
271
|
+
}
|
|
272
|
+
}, 0);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
setComplete(hasError = false) {
|
|
276
|
+
// Check if there are any actual errors (not just warnings)
|
|
277
|
+
const hasActualErrors = this.output.some(line => line.type === 'error');
|
|
278
|
+
console.log(`setComplete: hasError=${hasError}, hasActualErrors=${hasActualErrors}, output count=${this.output.length}`);
|
|
279
|
+
// Add a final status message
|
|
280
|
+
if (hasError) {
|
|
281
|
+
this.addOutput('Installation failed. See errors above.', 'error');
|
|
282
|
+
} else {
|
|
283
|
+
this.addOutput('✓ Installation completed successfully!', 'success');
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
this.isComplete = true;
|
|
287
|
+
this.hasError = hasError || hasActualErrors;
|
|
288
|
+
|
|
289
|
+
// Auto close after 2 seconds if no error and autoClose is enabled
|
|
290
|
+
if (false && !this.hasError && this.autoClose) {
|
|
291
|
+
this.autoCloseTimer = setTimeout(() => {
|
|
292
|
+
this.close();
|
|
293
|
+
}, 2000);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
handleBackdropClick(e) {
|
|
298
|
+
// Close only if clicking directly on the backdrop, not its children
|
|
299
|
+
if (e.target === e.currentTarget) {
|
|
300
|
+
this.close();
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
_render() {
|
|
305
|
+
return html`
|
|
306
|
+
<div class="dialog-backdrop ${this.isOpen ? 'open' : ''}"
|
|
307
|
+
@click=${this.handleBackdropClick}>
|
|
308
|
+
<div class="dialog">
|
|
309
|
+
<div class="dialog-header">
|
|
310
|
+
<div class="dialog-title">
|
|
311
|
+
<span class="material-icons">extension</span>
|
|
312
|
+
Installing ${this.pluginName || 'Plugin'}
|
|
313
|
+
</div>
|
|
314
|
+
<button class="close-button" @click=${this.close}>
|
|
315
|
+
<span class="material-icons">close</span>
|
|
316
|
+
</button>
|
|
317
|
+
</div>
|
|
318
|
+
<div class="dialog-content">
|
|
319
|
+
<div class="terminal">
|
|
320
|
+
${this.output.map(line => html`
|
|
321
|
+
<div class="terminal-line ${line.type}">${line.text}</div>
|
|
322
|
+
`)}
|
|
323
|
+
</div>
|
|
324
|
+
</div>
|
|
325
|
+
<div class="dialog-footer">
|
|
326
|
+
<div class="status ${this.isComplete ? (this.hasError ? 'error' : 'success') : 'in-progress'}">
|
|
327
|
+
${this.isComplete
|
|
328
|
+
? html`<span class="material-icons">${this.hasError ? 'error' : 'check_circle'}</span>
|
|
329
|
+
<span>${this.hasError ? 'Installation failed' : 'Installation complete'}</span>`
|
|
330
|
+
: html`<div class="spinner"></div>
|
|
331
|
+
<span>Installing...</span>`
|
|
332
|
+
}
|
|
333
|
+
</div>
|
|
334
|
+
<button @click=${this.close}>
|
|
335
|
+
<span class="material-icons">close</span>
|
|
336
|
+
Close
|
|
337
|
+
</button>
|
|
338
|
+
</div>
|
|
339
|
+
</div>
|
|
340
|
+
</div>
|
|
341
|
+
`;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
customElements.define('plugin-install-dialog', PluginInstallDialog);
|