imcp 0.0.12 → 0.0.14
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/dist/core/ConfigurationProvider.d.ts +2 -1
- package/dist/core/ConfigurationProvider.js +20 -24
- package/dist/core/InstallationService.d.ts +17 -0
- package/dist/core/InstallationService.js +127 -61
- package/dist/core/MCPManager.d.ts +1 -0
- package/dist/core/MCPManager.js +3 -0
- package/dist/core/RequirementService.d.ts +4 -4
- package/dist/core/RequirementService.js +11 -7
- package/dist/core/ServerSchemaProvider.d.ts +1 -1
- package/dist/core/ServerSchemaProvider.js +15 -10
- package/dist/core/constants.d.ts +3 -0
- package/dist/core/constants.js +4 -1
- package/dist/core/installers/clients/ClientInstaller.js +58 -40
- package/dist/core/installers/requirements/PipInstaller.js +10 -5
- package/dist/core/onboard/FeedOnboardService.d.ts +35 -0
- package/dist/core/onboard/FeedOnboardService.js +137 -0
- package/dist/core/types.d.ts +6 -1
- package/dist/core/validators/FeedValidator.d.ts +13 -0
- package/dist/core/validators/FeedValidator.js +27 -0
- package/dist/services/ServerService.d.ts +5 -0
- package/dist/services/ServerService.js +15 -0
- package/dist/utils/githubAuth.js +0 -10
- package/dist/utils/githubUtils.d.ts +16 -0
- package/dist/utils/githubUtils.js +55 -39
- package/dist/web/contract/serverContract.d.ts +64 -0
- package/dist/web/contract/serverContract.js +2 -0
- package/dist/web/public/css/detailsWidget.css +157 -32
- package/dist/web/public/css/onboard.css +44 -0
- package/dist/web/public/css/serverDetails.css +35 -19
- package/dist/web/public/index.html +16 -10
- package/dist/web/public/js/detailsWidget.js +43 -40
- package/dist/web/public/js/modal/index.js +58 -0
- package/dist/web/public/js/modal/installHandler.js +227 -0
- package/dist/web/public/js/modal/installModal.js +163 -0
- package/dist/web/public/js/modal/installation.js +281 -0
- package/dist/web/public/js/modal/loadingModal.js +52 -0
- package/dist/web/public/js/modal/loadingUI.js +74 -0
- package/dist/web/public/js/modal/messageQueue.js +112 -0
- package/dist/web/public/js/modal/modalSetup.js +512 -0
- package/dist/web/public/js/modal/modalUI.js +214 -0
- package/dist/web/public/js/modal/modalUtils.js +49 -0
- package/dist/web/public/js/modal/version.js +20 -0
- package/dist/web/public/js/modal/versionUtils.js +20 -0
- package/dist/web/public/js/modal.js +25 -1041
- package/dist/web/public/js/onboard/formProcessor.js +309 -0
- package/dist/web/public/js/onboard/index.js +131 -0
- package/dist/web/public/js/onboard/state.js +32 -0
- package/dist/web/public/js/onboard/templates.js +375 -0
- package/dist/web/public/js/onboard/uiHandlers.js +196 -0
- package/dist/web/public/js/serverCategoryDetails.js +211 -123
- package/dist/web/public/onboard.html +150 -0
- package/dist/web/server.js +25 -0
- package/package.json +3 -4
- package/src/core/ConfigurationProvider.ts +37 -29
- package/src/core/InstallationService.ts +176 -62
- package/src/core/MCPManager.ts +4 -0
- package/src/core/RequirementService.ts +12 -8
- package/src/core/ServerSchemaLoader.ts +48 -0
- package/src/core/ServerSchemaProvider.ts +137 -0
- package/src/core/constants.ts +4 -1
- package/src/core/installers/clients/ClientInstaller.ts +66 -49
- package/src/core/installers/requirements/PipInstaller.ts +10 -5
- package/src/core/types.ts +6 -1
- package/src/services/ServerService.ts +15 -0
- package/src/utils/githubAuth.ts +14 -27
- package/src/utils/githubUtils.ts +84 -47
- package/src/web/public/css/detailsWidget.css +235 -0
- package/src/web/public/css/serverDetails.css +126 -0
- package/src/web/public/index.html +16 -10
- package/src/web/public/js/detailsWidget.js +264 -0
- package/src/web/public/js/modal/index.js +58 -0
- package/src/web/public/js/modal/installModal.js +163 -0
- package/src/web/public/js/modal/installation.js +281 -0
- package/src/web/public/js/modal/loadingModal.js +52 -0
- package/src/web/public/js/modal/messageQueue.js +112 -0
- package/src/web/public/js/modal/modalSetup.js +512 -0
- package/src/web/public/js/modal/modalUtils.js +49 -0
- package/src/web/public/js/modal/versionUtils.js +20 -0
- package/src/web/public/js/modal.js +25 -1041
- package/src/web/public/js/serverCategoryDetails.js +211 -123
- package/src/web/server.ts +31 -0
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
.details-widget {
|
|
2
|
+
transition: all 0.3s ease-in-out;
|
|
3
|
+
width: 100%;
|
|
4
|
+
max-width: 100%;
|
|
5
|
+
box-sizing: border-box;
|
|
6
|
+
margin: 0;
|
|
7
|
+
padding: 0;
|
|
8
|
+
display: block;
|
|
9
|
+
overflow: hidden;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.tools-list {
|
|
13
|
+
width: 100%;
|
|
14
|
+
max-width: 100%;
|
|
15
|
+
margin: 0;
|
|
16
|
+
padding: 0.1rem;
|
|
17
|
+
box-sizing: border-box;
|
|
18
|
+
overflow: hidden;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.tool-card {
|
|
22
|
+
width: 100%;
|
|
23
|
+
margin-bottom: -1px;
|
|
24
|
+
border-radius: 0;
|
|
25
|
+
box-sizing: border-box;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.tool-card:first-child {
|
|
29
|
+
border-top-left-radius: 6px;
|
|
30
|
+
border-top-right-radius: 6px;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.tool-card:last-child {
|
|
34
|
+
border-bottom-left-radius: 6px;
|
|
35
|
+
border-bottom-right-radius: 6px;
|
|
36
|
+
margin-bottom: 0;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.tool-card {
|
|
40
|
+
transition: all 0.3s ease-out;
|
|
41
|
+
border: 1px solid #e5e7eb;
|
|
42
|
+
padding: 0.5rem;
|
|
43
|
+
background-color: white;
|
|
44
|
+
position: relative;
|
|
45
|
+
z-index: 1;
|
|
46
|
+
font-size: 0.9rem;
|
|
47
|
+
width: 100%;
|
|
48
|
+
box-sizing: border-box;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.tool-card .text-gray-600 {
|
|
52
|
+
font-size: 0.75rem;
|
|
53
|
+
line-height: 1.3;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.tool-card.active {
|
|
57
|
+
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.12);
|
|
58
|
+
border-color: transparent;
|
|
59
|
+
background-color: #f8fafc;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.tool-card:hover {
|
|
63
|
+
transform: translateY(-1px);
|
|
64
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.tool-card-header {
|
|
68
|
+
position: relative;
|
|
69
|
+
padding-right: 2rem;
|
|
70
|
+
width: 100%;
|
|
71
|
+
box-sizing: border-box;
|
|
72
|
+
cursor: pointer;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.tool-card-header::after {
|
|
76
|
+
content: '';
|
|
77
|
+
position: absolute;
|
|
78
|
+
right: 1rem;
|
|
79
|
+
top: 50%;
|
|
80
|
+
transform: translateY(-50%);
|
|
81
|
+
width: 12px;
|
|
82
|
+
height: 12px;
|
|
83
|
+
border-right: 2px solid #64748b;
|
|
84
|
+
border-bottom: 2px solid #64748b;
|
|
85
|
+
transform-origin: 75% 75%;
|
|
86
|
+
transition: transform 0.3s ease;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.tool-card.active .tool-card-header::after {
|
|
90
|
+
transform: translateY(-50%) rotate(45deg);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.tool-details {
|
|
94
|
+
max-height: 0;
|
|
95
|
+
opacity: 0;
|
|
96
|
+
overflow: hidden;
|
|
97
|
+
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
|
|
98
|
+
background-color: #f9fafb;
|
|
99
|
+
border-radius: 6px;
|
|
100
|
+
width: 100%;
|
|
101
|
+
max-width: 100%;
|
|
102
|
+
box-sizing: border-box;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.tool-details.visible {
|
|
106
|
+
max-height: 2000px;
|
|
107
|
+
opacity: 1;
|
|
108
|
+
padding: 0.1rem;
|
|
109
|
+
margin-top: 0.5rem;
|
|
110
|
+
border-top: 1px solid #e5e7eb;
|
|
111
|
+
width: 100%;
|
|
112
|
+
max-width: 100%;
|
|
113
|
+
box-sizing: border-box;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.property-item {
|
|
117
|
+
margin-bottom: 0.15rem;
|
|
118
|
+
padding: 0.5rem;
|
|
119
|
+
border-left: 2px solid #e5e7eb;
|
|
120
|
+
transition: all 0.2s ease;
|
|
121
|
+
font-size: 0.8rem;
|
|
122
|
+
background-color: white;
|
|
123
|
+
border-radius: 4px;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.property-item:hover {
|
|
127
|
+
border-left-color: #3b82f6;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.property-header {
|
|
131
|
+
margin-bottom: 0.25rem;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.property-title {
|
|
135
|
+
display: flex;
|
|
136
|
+
align-items: center;
|
|
137
|
+
gap: 0.5rem;
|
|
138
|
+
flex-wrap: wrap;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.property-name {
|
|
142
|
+
font-weight: 600;
|
|
143
|
+
color: #1e293b;
|
|
144
|
+
font-size: 0.85rem;
|
|
145
|
+
background-color: #f8fafc;
|
|
146
|
+
padding: 0.2rem 0.4rem;
|
|
147
|
+
border-radius: 4px;
|
|
148
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
|
149
|
+
display: inline-block;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.property-type {
|
|
153
|
+
color: #64748b;
|
|
154
|
+
font-size: 0.65rem;
|
|
155
|
+
padding: 0.1rem 0.3rem;
|
|
156
|
+
background: #f1f5f9;
|
|
157
|
+
border-radius: 3px;
|
|
158
|
+
font-family: 'Courier New', monospace;
|
|
159
|
+
margin-left: 0.3rem;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.property-desc {
|
|
163
|
+
color: #6b7280;
|
|
164
|
+
font-size: 0.7rem;
|
|
165
|
+
margin-left: 0.5rem;
|
|
166
|
+
display: inline-block;
|
|
167
|
+
font-style: italic;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.property-default {
|
|
171
|
+
font-size: 0.75rem;
|
|
172
|
+
color: #6b7280;
|
|
173
|
+
margin-top: 0.15rem;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.property-default code {
|
|
177
|
+
background: #f1f5f9;
|
|
178
|
+
padding: 0.2rem 0.4rem;
|
|
179
|
+
border-radius: 4px;
|
|
180
|
+
font-family: 'Courier New', monospace;
|
|
181
|
+
font-size: 0.85rem;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.required-fields {
|
|
185
|
+
border-left: 2px solid #64748b;
|
|
186
|
+
padding: 0.25rem 0.5rem;
|
|
187
|
+
margin-bottom: 0.5rem;
|
|
188
|
+
font-size: 0.8rem;
|
|
189
|
+
border-radius: 2px;
|
|
190
|
+
color: #64748b;
|
|
191
|
+
}
|
|
192
|
+
.required-star {
|
|
193
|
+
color: #dc2626;
|
|
194
|
+
margin-left: 2px;
|
|
195
|
+
font-weight: bold;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
/* Ensure proper container behavior for the widget */
|
|
200
|
+
.details-widget-container {
|
|
201
|
+
width: 100%;
|
|
202
|
+
max-width: 100%;
|
|
203
|
+
box-sizing: border-box;
|
|
204
|
+
position: relative;
|
|
205
|
+
margin: 0;
|
|
206
|
+
padding: 0;
|
|
207
|
+
overflow: hidden;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.nested-properties {
|
|
211
|
+
margin: 0.25rem 0 0.25rem 0.5rem;
|
|
212
|
+
padding-left: 0.5rem;
|
|
213
|
+
border-left: 1px solid #e5e7eb;
|
|
214
|
+
font-size: 0.8rem;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.nested-property-item {
|
|
218
|
+
margin-bottom: 0.5rem;
|
|
219
|
+
padding: 0.25rem 0.5rem;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.nested-property-item .property-name {
|
|
223
|
+
font-size: 0.85rem;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.nested-property-item .property-type {
|
|
227
|
+
font-size: 0.8rem;
|
|
228
|
+
padding: 0.1rem 0.3rem;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
.nested-property-item .property-desc {
|
|
232
|
+
font-size: 0.8rem;
|
|
233
|
+
margin-top: 0.25rem;
|
|
234
|
+
color: #64748b;
|
|
235
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/* Server item container */
|
|
2
|
+
.server-item-content {
|
|
3
|
+
cursor: pointer;
|
|
4
|
+
position: relative;
|
|
5
|
+
transition: all 0.2s ease;
|
|
6
|
+
border: 1px solid #e5e7eb;
|
|
7
|
+
border-radius: 0.5rem;
|
|
8
|
+
padding: 1rem;
|
|
9
|
+
padding-right: calc(120px + 3rem); /* Button width + spacing */
|
|
10
|
+
box-sizing: border-box;
|
|
11
|
+
background-color: #ffffff;
|
|
12
|
+
z-index: 1;
|
|
13
|
+
margin-bottom: 1rem;
|
|
14
|
+
width: 100%;
|
|
15
|
+
max-width: 100%;
|
|
16
|
+
overflow: visible;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.server-item-content:hover {
|
|
20
|
+
border-color: transparent;
|
|
21
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
|
22
|
+
transform: translateY(-1px);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/* Details widget */
|
|
26
|
+
.details-widget {
|
|
27
|
+
max-height: 0;
|
|
28
|
+
overflow: hidden;
|
|
29
|
+
transition: max-height 0.3s ease-out;
|
|
30
|
+
background-color: #f8fafc;
|
|
31
|
+
border-radius: 0 0 0.5rem 0.5rem;
|
|
32
|
+
margin: -1px 0 0;
|
|
33
|
+
border: 1px solid #e5e7eb;
|
|
34
|
+
border-top: none;
|
|
35
|
+
position: relative;
|
|
36
|
+
z-index: 0;
|
|
37
|
+
width: 100%;
|
|
38
|
+
max-width: 100%;
|
|
39
|
+
box-sizing: border-box;
|
|
40
|
+
left: 0;
|
|
41
|
+
right: 0;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.details-widget.expanded {
|
|
45
|
+
max-height: 2000px; /* Increased height to accommodate more content */
|
|
46
|
+
border-color: transparent;
|
|
47
|
+
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
|
|
48
|
+
transition: max-height 0.3s ease-in-out, box-shadow 0.2s ease;
|
|
49
|
+
width: 100%;
|
|
50
|
+
margin-left: 0;
|
|
51
|
+
margin-right: 0;
|
|
52
|
+
display: block;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.details-widget-content {
|
|
56
|
+
padding: 1rem;
|
|
57
|
+
width: 100%;
|
|
58
|
+
box-sizing: border-box;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.description-text {
|
|
62
|
+
color: #4b5563;
|
|
63
|
+
line-height: 1.5;
|
|
64
|
+
font-size: 0.875rem;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* Expand/collapse animation */
|
|
68
|
+
.server-item-content.expanded {
|
|
69
|
+
border-bottom: none;
|
|
70
|
+
border-bottom-left-radius: 0;
|
|
71
|
+
border-bottom-right-radius: 0;
|
|
72
|
+
border-color: transparent;
|
|
73
|
+
box-shadow: 0 -1px 8px rgba(0, 0, 0, 0.08);
|
|
74
|
+
margin-bottom: 0;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/* Server item layout */
|
|
78
|
+
.server-item-info {
|
|
79
|
+
width: 100%;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.server-item-header {
|
|
83
|
+
margin-bottom: 1rem;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.server-item-header h5 {
|
|
87
|
+
margin-bottom: 0.5rem;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/* Client status section */
|
|
91
|
+
.flex-wrap {
|
|
92
|
+
margin: -0.25rem; /* Negative margin to offset badge spacing */
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.flex-wrap > * {
|
|
96
|
+
margin: 0.25rem; /* Even spacing between badges */
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/* Install/Uninstall button section */
|
|
100
|
+
.action-buttons {
|
|
101
|
+
position: absolute;
|
|
102
|
+
right: 1rem;
|
|
103
|
+
top: calc(2rem + 0.5rem); /* Align with description text (header height + margin-bottom) */
|
|
104
|
+
margin: 0;
|
|
105
|
+
z-index: 2; /* Ensure buttons stay on top */
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.action-buttons button {
|
|
109
|
+
min-width: 100px;
|
|
110
|
+
padding: 0.5rem 1.5rem;
|
|
111
|
+
text-align: center;
|
|
112
|
+
font-weight: 600;
|
|
113
|
+
transition: all 0.15s ease;
|
|
114
|
+
white-space: nowrap;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/* Status badges */
|
|
118
|
+
.server-item-info .flex-wrap span {
|
|
119
|
+
display: inline-flex;
|
|
120
|
+
align-items: center;
|
|
121
|
+
padding: 0.375rem 0.75rem;
|
|
122
|
+
border-radius: 9999px;
|
|
123
|
+
font-size: 0.75rem;
|
|
124
|
+
line-height: 1;
|
|
125
|
+
white-space: nowrap;
|
|
126
|
+
}
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
<link rel="stylesheet" href="styles.css">
|
|
13
13
|
<link rel="stylesheet" href="css/modal.css">
|
|
14
14
|
<link rel="stylesheet" href="css/notifications.css">
|
|
15
|
+
<link rel="stylesheet" href="css/serverDetails.css">
|
|
16
|
+
<link rel="stylesheet" href="css/detailsWidget.css">
|
|
15
17
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
|
16
18
|
|
|
17
19
|
<!-- Alert container for notifications -->
|
|
@@ -160,19 +162,23 @@
|
|
|
160
162
|
setupSearch();
|
|
161
163
|
setupModalOutsideClick();
|
|
162
164
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
165
|
+
try {
|
|
166
|
+
// First fetch categories and wait for completion
|
|
167
|
+
await fetchServerCategories();
|
|
166
168
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
+
// Check URL parameters for category
|
|
170
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
171
|
+
const categoryParam = urlParams.get('category');
|
|
169
172
|
|
|
170
|
-
|
|
171
|
-
|
|
173
|
+
// If we have a category parameter or last selected category
|
|
174
|
+
const lastSelected = categoryParam || localStorage.getItem('lastSelectedCategory');
|
|
172
175
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
+
// Only show details after data is loaded
|
|
177
|
+
if (lastSelected) {
|
|
178
|
+
await showServerDetails(lastSelected);
|
|
179
|
+
}
|
|
180
|
+
} catch (error) {
|
|
181
|
+
console.error('Error during initialization:', error);
|
|
176
182
|
}
|
|
177
183
|
});
|
|
178
184
|
</script>
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
export class DetailsWidget {
|
|
2
|
+
constructor(container) {
|
|
3
|
+
this.container = container;
|
|
4
|
+
this.isExpanded = false;
|
|
5
|
+
this.expandedTool = null;
|
|
6
|
+
this.init();
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
init() {
|
|
10
|
+
// Create and append stylesheet
|
|
11
|
+
const link = document.createElement('link');
|
|
12
|
+
link.rel = 'stylesheet';
|
|
13
|
+
link.href = '/css/detailsWidget.css';
|
|
14
|
+
document.head.appendChild(link);
|
|
15
|
+
// Create wrapper to maintain proper width alignment
|
|
16
|
+
this.containerWrapper = document.createElement('div');
|
|
17
|
+
this.containerWrapper.className = 'details-widget-container';
|
|
18
|
+
this.containerWrapper.style.width = '100%';
|
|
19
|
+
this.containerWrapper.style.boxSizing = 'border-box';
|
|
20
|
+
this.containerWrapper.style.maxWidth = '100%';
|
|
21
|
+
this.containerWrapper.style.overflow = 'hidden';
|
|
22
|
+
|
|
23
|
+
// Create the widget element
|
|
24
|
+
this.widgetElement = document.createElement('div');
|
|
25
|
+
this.widgetElement.className = 'details-widget';
|
|
26
|
+
this.widgetElement.style.width = '100%';
|
|
27
|
+
this.widgetElement.style.boxSizing = 'border-box';
|
|
28
|
+
this.widgetElement.style.maxWidth = '100%';
|
|
29
|
+
|
|
30
|
+
// Create the content element
|
|
31
|
+
this.contentElement = document.createElement('div');
|
|
32
|
+
this.contentElement.className = 'details-widget-content';
|
|
33
|
+
this.contentElement.style.width = '100%';
|
|
34
|
+
this.contentElement.style.boxSizing = 'border-box';
|
|
35
|
+
|
|
36
|
+
// Build the DOM structure
|
|
37
|
+
this.widgetElement.appendChild(this.contentElement);
|
|
38
|
+
this.containerWrapper.appendChild(this.widgetElement);
|
|
39
|
+
|
|
40
|
+
// Insert after the server item while maintaining proper structure
|
|
41
|
+
this.container.after(this.containerWrapper);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
setContent(content) {
|
|
45
|
+
if (typeof content === 'string') {
|
|
46
|
+
this.contentElement.innerHTML = `
|
|
47
|
+
<div class="description-text">
|
|
48
|
+
${content || 'No description available.'}
|
|
49
|
+
</div>
|
|
50
|
+
`;
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Handle direct schema object or wrapped schema object
|
|
55
|
+
if (typeof content === 'object') {
|
|
56
|
+
const schemaData = content.schema || content; // Handle both {schema: data} and direct data
|
|
57
|
+
this.renderToolsList(schemaData);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
this.contentElement.innerHTML = '<p>Invalid content format</p>';
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Maintain compatibility with old toggle behavior
|
|
65
|
+
toggle() {
|
|
66
|
+
if (this.isExpanded) {
|
|
67
|
+
this.collapse();
|
|
68
|
+
} else {
|
|
69
|
+
this.expand();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
expand() {
|
|
74
|
+
this.isExpanded = true;
|
|
75
|
+
this.widgetElement.classList.add('expanded');
|
|
76
|
+
|
|
77
|
+
// Ensure proper dimensions based on container
|
|
78
|
+
const containerWidth = this.container.offsetWidth;
|
|
79
|
+
this.containerWrapper.style.width = `${containerWidth}px`;
|
|
80
|
+
this.containerWrapper.style.maxWidth = '100%';
|
|
81
|
+
this.containerWrapper.style.display = 'block';
|
|
82
|
+
|
|
83
|
+
// Add expanded state to container
|
|
84
|
+
if (this.container) {
|
|
85
|
+
this.container.classList.add('expanded');
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
collapse() {
|
|
90
|
+
this.isExpanded = false;
|
|
91
|
+
this.widgetElement.classList.remove('expanded');
|
|
92
|
+
if (this.container) {
|
|
93
|
+
this.container.classList.remove('expanded');
|
|
94
|
+
}
|
|
95
|
+
// Reset expanded tool state
|
|
96
|
+
this.expandedTool = null;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
renderToolsList(schemaContent) {
|
|
100
|
+
if (!schemaContent || typeof schemaContent !== 'object') {
|
|
101
|
+
this.contentElement.innerHTML = '<p>Invalid schema format</p>';
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
let html = `
|
|
106
|
+
<div class="tools-list">
|
|
107
|
+
`;
|
|
108
|
+
|
|
109
|
+
Object.entries(schemaContent).forEach(([toolName, toolInfo]) => {
|
|
110
|
+
if (!toolInfo) return;
|
|
111
|
+
|
|
112
|
+
html += `<div class="tool-card" data-tool="${this.escapeHtml(toolName)}">
|
|
113
|
+
<div class="tool-card-header">
|
|
114
|
+
<div class="tool-header">
|
|
115
|
+
<h3 class="text-md font-semibold text-blue-600">${toolInfo.name || toolName}</h3>
|
|
116
|
+
<div class="text-gray-600 text-sm">${toolInfo.description || 'No description available'}</div>
|
|
117
|
+
</div>
|
|
118
|
+
</div>
|
|
119
|
+
<div class="tool-details hidden" data-tool-details="${this.escapeHtml(toolName)}">
|
|
120
|
+
${this.renderInputSchema(toolInfo.inputSchema)}
|
|
121
|
+
</div>
|
|
122
|
+
</div>
|
|
123
|
+
`;
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
html += `
|
|
127
|
+
</div>
|
|
128
|
+
`;
|
|
129
|
+
|
|
130
|
+
this.contentElement.innerHTML = html;
|
|
131
|
+
|
|
132
|
+
// Add event listeners to tool cards
|
|
133
|
+
this.contentElement.querySelectorAll('.tool-card').forEach(card => {
|
|
134
|
+
const header = card.querySelector('.tool-card-header');
|
|
135
|
+
header.addEventListener('click', (e) => {
|
|
136
|
+
e.stopPropagation(); // Prevent click from bubbling up to server-item
|
|
137
|
+
const toolName = card.dataset.tool;
|
|
138
|
+
this.toggleToolDetails(toolName, card);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// Add click handler for the details area to prevent bubbling
|
|
142
|
+
const details = card.querySelector('.tool-details');
|
|
143
|
+
details.addEventListener('click', (e) => {
|
|
144
|
+
e.stopPropagation(); // Prevent click from bubbling up
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
toggleToolDetails(toolName, card) {
|
|
150
|
+
const detailsElement = card.querySelector(`[data-tool-details="${toolName}"]`);
|
|
151
|
+
const isExpanded = !detailsElement.classList.contains('hidden');
|
|
152
|
+
|
|
153
|
+
// Collapse all other expanded tools
|
|
154
|
+
if (this.expandedTool && this.expandedTool !== toolName) {
|
|
155
|
+
const prevCard = this.contentElement.querySelector(`[data-tool="${this.expandedTool}"]`);
|
|
156
|
+
if (prevCard) {
|
|
157
|
+
const prevDetails = prevCard.querySelector(`[data-tool-details="${this.expandedTool}"]`);
|
|
158
|
+
prevDetails?.classList.add('hidden');
|
|
159
|
+
prevCard.classList.remove('active');
|
|
160
|
+
setTimeout(() => {
|
|
161
|
+
prevDetails.classList.remove('visible');
|
|
162
|
+
}, 0);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Toggle current tool with animation
|
|
167
|
+
if (isExpanded) {
|
|
168
|
+
detailsElement.classList.remove('visible');
|
|
169
|
+
card.classList.remove('active');
|
|
170
|
+
setTimeout(() => {
|
|
171
|
+
detailsElement.classList.add('hidden');
|
|
172
|
+
}, 300); // Match transition duration from CSS
|
|
173
|
+
this.expandedTool = null;
|
|
174
|
+
} else {
|
|
175
|
+
detailsElement.classList.remove('hidden');
|
|
176
|
+
card.classList.add('active');
|
|
177
|
+
setTimeout(() => {
|
|
178
|
+
detailsElement.classList.add('visible');
|
|
179
|
+
}, 0);
|
|
180
|
+
this.expandedTool = toolName;
|
|
181
|
+
detailsElement.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
renderInputSchema(schema) {
|
|
186
|
+
if (!schema || typeof schema !== 'object') {
|
|
187
|
+
return '<p>No input schema available</p>';
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (!schema.properties || Object.keys(schema.properties).length === 0) {
|
|
191
|
+
return '<p>No input properties defined</p>';
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
let html = '<div class="properties-list">';
|
|
195
|
+
|
|
196
|
+
try {
|
|
197
|
+
// Render each property
|
|
198
|
+
Object.entries(schema.properties).forEach(([propName, propDetails]) => {
|
|
199
|
+
if (!propDetails) return;
|
|
200
|
+
|
|
201
|
+
const isRequired = schema.required?.includes(propName);
|
|
202
|
+
const type = this.getPropertyType(propDetails);
|
|
203
|
+
|
|
204
|
+
html += `<div class="property-item ${isRequired ? 'required' : ''}">
|
|
205
|
+
<div class="property-header">
|
|
206
|
+
<span class="property-name">${this.escapeHtml(propName)}${isRequired ? '<span class="required-star">*</span>' : ''}</span><span class="property-type">${this.escapeHtml(type)}</span>${propDetails.description ? `<span class="property-desc">${this.escapeHtml(propDetails.description)}</span>` : ''}
|
|
207
|
+
${propDetails.default !== undefined ? `<div class="property-default">Default: <code>${this.escapeHtml(JSON.stringify(propDetails.default))}</code></div>` : ''}
|
|
208
|
+
</div>
|
|
209
|
+
${this.renderNestedProperties(propDetails)}
|
|
210
|
+
</div>
|
|
211
|
+
`;
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
return html + '</div>';
|
|
215
|
+
} catch (error) {
|
|
216
|
+
console.error('Error rendering input schema:', error);
|
|
217
|
+
return '<p>Error rendering input schema</p>';
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
renderNestedProperties(propDetails) {
|
|
222
|
+
if (propDetails.properties) {
|
|
223
|
+
let html = '<div class="nested-properties">';
|
|
224
|
+
Object.entries(propDetails.properties).forEach(([name, details]) => {
|
|
225
|
+
const type = this.getPropertyType(details);
|
|
226
|
+
html += `
|
|
227
|
+
<div class="nested-property-item">
|
|
228
|
+
<span class="property-name">${this.escapeHtml(name)}</span><span class="property-type">${this.escapeHtml(type)}</span>
|
|
229
|
+
${details.description ? `<div class="property-desc">${this.escapeHtml(details.description)}</div>` : ''}
|
|
230
|
+
</div>
|
|
231
|
+
`;
|
|
232
|
+
});
|
|
233
|
+
return html + '</div>';
|
|
234
|
+
}
|
|
235
|
+
return '';
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
getPropertyType(propDetails) {
|
|
239
|
+
if (propDetails.anyOf) {
|
|
240
|
+
return `oneOf: [${propDetails.anyOf.map(type => type.type || 'any').join(', ')}]`;
|
|
241
|
+
}
|
|
242
|
+
if (propDetails.type === 'array') {
|
|
243
|
+
const itemType = propDetails.items?.type || 'any';
|
|
244
|
+
return `array<${itemType}>`;
|
|
245
|
+
}
|
|
246
|
+
return propDetails.type || 'any';
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
escapeHtml(unsafe) {
|
|
250
|
+
if (unsafe === undefined || unsafe === null) {
|
|
251
|
+
return '';
|
|
252
|
+
}
|
|
253
|
+
return String(unsafe)
|
|
254
|
+
.replace(/&/g, "&")
|
|
255
|
+
.replace(/</g, "<")
|
|
256
|
+
.replace(/>/g, ">")
|
|
257
|
+
.replace(/"/g, """)
|
|
258
|
+
.replace(/'/g, "'");
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
isVisible() {
|
|
262
|
+
return this.isExpanded;
|
|
263
|
+
}
|
|
264
|
+
}
|