imcp 0.0.12 → 0.0.13
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/requirements/PipInstaller.js +10 -5
- package/dist/core/types.d.ts +4 -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/public/css/detailsWidget.css +157 -32
- package/dist/web/public/css/serverDetails.css +35 -19
- package/dist/web/public/index.html +2 -0
- package/dist/web/public/js/detailsWidget.js +43 -40
- package/dist/web/public/js/serverCategoryDetails.js +182 -120
- 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/requirements/PipInstaller.ts +10 -5
- package/src/core/types.ts +4 -0
- 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 +2 -0
- package/src/web/public/js/detailsWidget.js +264 -0
- package/src/web/public/js/serverCategoryDetails.js +182 -120
- package/src/web/server.ts +31 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
2
|
import { fileURLToPath } from 'url';
|
|
3
3
|
import { Logger } from '../utils/logger.js';
|
|
4
|
+
import { getServerSchemaProvider } from '../core/ServerSchemaProvider.js';
|
|
4
5
|
import { mcpManager } from '../core/MCPManager.js';
|
|
5
6
|
import { UPDATE_CHECK_INTERVAL_MS } from '../core/constants.js';
|
|
6
7
|
import { updateCheckTracker } from '../utils/UpdateCheckTracker.js';
|
|
@@ -96,6 +97,20 @@ export class ServerService {
|
|
|
96
97
|
}
|
|
97
98
|
}
|
|
98
99
|
}
|
|
100
|
+
/**
|
|
101
|
+
* Gets the schema for a specific server in a category
|
|
102
|
+
*/
|
|
103
|
+
async getServerSchema(categoryName, serverName) {
|
|
104
|
+
try {
|
|
105
|
+
const provider = await getServerSchemaProvider();
|
|
106
|
+
const serverMcpConfig = await mcpManager.getServerMcpConfig(categoryName, serverName);
|
|
107
|
+
return await provider.getSchema(categoryName, serverMcpConfig?.schemas || `${serverName}.json`);
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
Logger.error(`Failed to get schema for server ${serverName} in category ${categoryName}:`, error);
|
|
111
|
+
throw error;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
99
114
|
/**
|
|
100
115
|
* Installs a specific mcp tool for a server.
|
|
101
116
|
* TODO: This might require enhancing MCPManager to handle category-specific installs.
|
package/dist/utils/githubAuth.js
CHANGED
|
@@ -29,16 +29,6 @@ class GithubAuthError extends Error {
|
|
|
29
29
|
export async function checkGithubAuth() {
|
|
30
30
|
Logger.debug('Starting GitHub authentication check');
|
|
31
31
|
try {
|
|
32
|
-
// Check if git is installed
|
|
33
|
-
if (!await isToolInstalled('git')) {
|
|
34
|
-
Logger.log('Installing required Git...');
|
|
35
|
-
await installCLI('git');
|
|
36
|
-
// Verify git was installed correctly, with retry mechanism
|
|
37
|
-
if (!await isToolInstalled('git')) {
|
|
38
|
-
throw new Error('Failed to install Git. Please install it manually and try again.');
|
|
39
|
-
}
|
|
40
|
-
Logger.debug('Git installed successfully and verified');
|
|
41
|
-
}
|
|
42
32
|
// Check if gh CLI is installed
|
|
43
33
|
if (!await isToolInstalled('gh')) {
|
|
44
34
|
Logger.log('Installing required GitHub CLI...');
|
|
@@ -1,4 +1,19 @@
|
|
|
1
1
|
import { RegistryConfig, RequirementConfig } from '../core/types.js';
|
|
2
|
+
interface DownloadGithubReleaseResult {
|
|
3
|
+
version: string;
|
|
4
|
+
downloadPath: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Downloads a GitHub release asset
|
|
8
|
+
* @param repo GitHub repository in format owner/repo
|
|
9
|
+
* @param version Version to download, can be "latest"
|
|
10
|
+
* @param assetsName Assets name pattern (optional, but either assetsName or assetName must be provided)
|
|
11
|
+
* @param assetName Asset name pattern (optional, but either assetsName or assetName must be provided)
|
|
12
|
+
* @param isFolder Whether to treat the downloaded asset as a folder (default: false)
|
|
13
|
+
* @param targetDirectory Target directory for downloads (default: SETTINGS_DIR/downloads)
|
|
14
|
+
* @returns Object containing version and download path
|
|
15
|
+
*/
|
|
16
|
+
export declare function downloadGithubRelease(repo: string, version: string, assetsName?: string, assetName?: string, isFolder?: boolean, targetDirectory?: string): Promise<DownloadGithubReleaseResult>;
|
|
2
17
|
/**
|
|
3
18
|
* Helper to handle GitHub release downloads
|
|
4
19
|
* @param requirement The requirement configuration
|
|
@@ -9,3 +24,4 @@ export declare function handleGitHubRelease(requirement: RequirementConfig, regi
|
|
|
9
24
|
resolvedVersion: string;
|
|
10
25
|
resolvedPath: string;
|
|
11
26
|
}>;
|
|
27
|
+
export {};
|
|
@@ -3,78 +3,94 @@ import util from 'util';
|
|
|
3
3
|
import fs from 'fs/promises';
|
|
4
4
|
import path from 'path';
|
|
5
5
|
import { extractZipFile } from './clientUtils.js';
|
|
6
|
-
import { Logger } from './logger.js';
|
|
7
6
|
import { SETTINGS_DIR } from '../core/constants.js';
|
|
8
7
|
const execAsync = util.promisify(exec);
|
|
9
8
|
/**
|
|
10
|
-
*
|
|
11
|
-
* @param
|
|
12
|
-
* @param
|
|
13
|
-
* @
|
|
9
|
+
* Downloads a GitHub release asset
|
|
10
|
+
* @param repo GitHub repository in format owner/repo
|
|
11
|
+
* @param version Version to download, can be "latest"
|
|
12
|
+
* @param assetsName Assets name pattern (optional, but either assetsName or assetName must be provided)
|
|
13
|
+
* @param assetName Asset name pattern (optional, but either assetsName or assetName must be provided)
|
|
14
|
+
* @param isFolder Whether to treat the downloaded asset as a folder (default: false)
|
|
15
|
+
* @param targetDirectory Target directory for downloads (default: SETTINGS_DIR/downloads)
|
|
16
|
+
* @returns Object containing version and download path
|
|
14
17
|
*/
|
|
15
|
-
export async function
|
|
16
|
-
if (!
|
|
17
|
-
throw new Error('GitHub
|
|
18
|
+
export async function downloadGithubRelease(repo, version, assetsName, assetName, isFolder = false, targetDirectory) {
|
|
19
|
+
if (!repo) {
|
|
20
|
+
throw new Error('GitHub repository is required');
|
|
18
21
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const { repository, assetsName, assetName } = registry;
|
|
22
|
-
if (!repository) {
|
|
23
|
-
throw new Error('GitHub repository is required for GitHub release downloads');
|
|
22
|
+
if (!assetsName && !assetName) {
|
|
23
|
+
throw new Error('Either assetsName or assetName must be specified');
|
|
24
24
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const { stdout } = await execAsync(`gh release view --repo ${
|
|
25
|
+
const downloadsDir = targetDirectory || path.join(SETTINGS_DIR, 'downloads');
|
|
26
|
+
await fs.mkdir(downloadsDir, { recursive: true });
|
|
27
|
+
// Get latest version if needed
|
|
28
|
+
const { stdout } = await execAsync(`gh release view --repo ${repo} --json tagName --jq .tagName`);
|
|
29
29
|
const latestTag = stdout.trim();
|
|
30
30
|
let latestVersion = latestTag;
|
|
31
31
|
const tagWithVPrefix = latestVersion.startsWith('v');
|
|
32
32
|
if (tagWithVPrefix)
|
|
33
33
|
latestVersion = latestVersion.substring(1); // Remove 'v' prefix if present
|
|
34
|
-
|
|
34
|
+
const resolvedVersion = version.includes("latest") ? latestVersion : version;
|
|
35
|
+
// Resolve asset names
|
|
36
|
+
let resolvedAssetsName = '';
|
|
37
|
+
let resolvedAssetName = '';
|
|
35
38
|
if (assetsName) {
|
|
36
|
-
resolvedAssetsName = assetsName.replace('${latest}',
|
|
39
|
+
resolvedAssetsName = assetsName.replace('${latest}', resolvedVersion).replace('${version}', resolvedVersion);
|
|
37
40
|
}
|
|
38
41
|
if (assetName) {
|
|
39
|
-
resolvedAssetName = assetName.replace('${latest}',
|
|
42
|
+
resolvedAssetName = assetName.replace('${latest}', resolvedVersion).replace('${version}', resolvedVersion);
|
|
40
43
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
if (!pattern) {
|
|
46
|
-
throw new Error('Either assetsName or assetName must be specified for GitHub release downloads');
|
|
44
|
+
// Validate zip requirement for isFolder
|
|
45
|
+
const pattern = resolvedAssetsName || resolvedAssetName;
|
|
46
|
+
if (isFolder && (!resolvedAssetsName || !resolvedAssetsName.endsWith('.zip'))) {
|
|
47
|
+
throw new Error('When isFolder is true, assetsName must be provided and end with .zip');
|
|
47
48
|
}
|
|
48
49
|
// Download the release asset
|
|
49
50
|
const downloadPath = path.join(downloadsDir, path.basename(pattern));
|
|
50
51
|
if (!await fileExists(downloadPath)) {
|
|
51
|
-
await execAsync(`gh release download ${tagWithVPrefix ? `v${
|
|
52
|
+
await execAsync(`gh release download ${tagWithVPrefix ? `v${resolvedVersion}` : resolvedVersion} --repo ${repo} --pattern "${pattern}" -O "${downloadPath}"`);
|
|
52
53
|
}
|
|
53
|
-
// Handle zip
|
|
54
|
-
if (downloadPath.endsWith('.zip')) {
|
|
54
|
+
// Handle zip extraction if needed
|
|
55
|
+
if (isFolder && downloadPath.endsWith('.zip')) {
|
|
55
56
|
const extractDir = path.join(downloadsDir, path.basename(pattern, '.zip'));
|
|
56
57
|
await fs.mkdir(extractDir, { recursive: true });
|
|
57
|
-
// Extract the zip file
|
|
58
58
|
await extractZipFile(downloadPath, { dir: extractDir });
|
|
59
|
-
let assetPath = '';
|
|
60
59
|
// If resolvedAssetName is specified, look for it in the extracted directory
|
|
61
60
|
if (resolvedAssetName) {
|
|
62
|
-
assetPath = path.join(extractDir, resolvedAssetName);
|
|
61
|
+
const assetPath = path.join(extractDir, resolvedAssetName);
|
|
63
62
|
try {
|
|
64
63
|
await fs.access(assetPath);
|
|
65
|
-
return {
|
|
64
|
+
return { version: resolvedVersion, downloadPath: assetPath };
|
|
66
65
|
}
|
|
67
66
|
catch (error) {
|
|
68
67
|
throw new Error(`Asset ${resolvedAssetName} not found in extracted directory ${extractDir}`);
|
|
69
68
|
}
|
|
70
69
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
70
|
+
return { version: resolvedVersion, downloadPath: extractDir };
|
|
71
|
+
}
|
|
72
|
+
return { version: resolvedVersion, downloadPath };
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Helper to handle GitHub release downloads
|
|
76
|
+
* @param requirement The requirement configuration
|
|
77
|
+
* @param registry The GitHub release registry configuration
|
|
78
|
+
* @returns The path to the downloaded file
|
|
79
|
+
*/
|
|
80
|
+
export async function handleGitHubRelease(requirement, registry) {
|
|
81
|
+
if (!registry) {
|
|
82
|
+
throw new Error('GitHub release registry configuration is required');
|
|
83
|
+
}
|
|
84
|
+
const { repository, assetsName, assetName } = registry;
|
|
85
|
+
if (!repository) {
|
|
86
|
+
throw new Error('GitHub repository is required for GitHub release downloads');
|
|
76
87
|
}
|
|
77
|
-
|
|
88
|
+
const isZipAsset = assetsName?.endsWith('.zip') || false;
|
|
89
|
+
const result = await downloadGithubRelease(repository, requirement.version, assetsName, assetName, isZipAsset);
|
|
90
|
+
return {
|
|
91
|
+
resolvedVersion: result.version,
|
|
92
|
+
resolvedPath: result.downloadPath
|
|
93
|
+
};
|
|
78
94
|
}
|
|
79
95
|
async function fileExists(filePath) {
|
|
80
96
|
try {
|
|
@@ -1,30 +1,75 @@
|
|
|
1
1
|
.details-widget {
|
|
2
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;
|
|
3
10
|
}
|
|
4
11
|
|
|
5
|
-
.tools-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
padding: 0.
|
|
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;
|
|
10
37
|
}
|
|
11
38
|
|
|
12
39
|
.tool-card {
|
|
13
40
|
transition: all 0.3s ease-out;
|
|
14
41
|
border: 1px solid #e5e7eb;
|
|
15
|
-
|
|
16
|
-
|
|
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;
|
|
17
54
|
}
|
|
18
55
|
|
|
19
56
|
.tool-card.active {
|
|
20
|
-
box-shadow: 0 4px
|
|
21
|
-
border-
|
|
57
|
+
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.12);
|
|
58
|
+
border-color: transparent;
|
|
22
59
|
background-color: #f8fafc;
|
|
23
60
|
}
|
|
24
61
|
|
|
62
|
+
.tool-card:hover {
|
|
63
|
+
transform: translateY(-1px);
|
|
64
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
|
65
|
+
}
|
|
66
|
+
|
|
25
67
|
.tool-card-header {
|
|
26
68
|
position: relative;
|
|
27
69
|
padding-right: 2rem;
|
|
70
|
+
width: 100%;
|
|
71
|
+
box-sizing: border-box;
|
|
72
|
+
cursor: pointer;
|
|
28
73
|
}
|
|
29
74
|
|
|
30
75
|
.tool-card-header::after {
|
|
@@ -49,23 +94,33 @@
|
|
|
49
94
|
max-height: 0;
|
|
50
95
|
opacity: 0;
|
|
51
96
|
overflow: hidden;
|
|
52
|
-
transition: all 0.
|
|
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;
|
|
53
103
|
}
|
|
54
104
|
|
|
55
105
|
.tool-details.visible {
|
|
56
|
-
max-height:
|
|
106
|
+
max-height: 2000px;
|
|
57
107
|
opacity: 1;
|
|
58
|
-
padding
|
|
59
|
-
margin-top: 0.
|
|
108
|
+
padding: 0.1rem;
|
|
109
|
+
margin-top: 0.5rem;
|
|
60
110
|
border-top: 1px solid #e5e7eb;
|
|
111
|
+
width: 100%;
|
|
112
|
+
max-width: 100%;
|
|
113
|
+
box-sizing: border-box;
|
|
61
114
|
}
|
|
62
115
|
|
|
63
116
|
.property-item {
|
|
64
|
-
margin-bottom: 0.
|
|
65
|
-
padding
|
|
117
|
+
margin-bottom: 0.15rem;
|
|
118
|
+
padding: 0.5rem;
|
|
66
119
|
border-left: 2px solid #e5e7eb;
|
|
67
|
-
transition:
|
|
68
|
-
font-size: 0.
|
|
120
|
+
transition: all 0.2s ease;
|
|
121
|
+
font-size: 0.8rem;
|
|
122
|
+
background-color: white;
|
|
123
|
+
border-radius: 4px;
|
|
69
124
|
}
|
|
70
125
|
|
|
71
126
|
.property-item:hover {
|
|
@@ -73,38 +128,108 @@
|
|
|
73
128
|
}
|
|
74
129
|
|
|
75
130
|
.property-header {
|
|
76
|
-
margin-bottom: 0.
|
|
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;
|
|
77
139
|
}
|
|
78
140
|
|
|
79
141
|
.property-name {
|
|
80
142
|
font-weight: 600;
|
|
81
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;
|
|
82
150
|
}
|
|
83
151
|
|
|
84
152
|
.property-type {
|
|
85
153
|
color: #64748b;
|
|
86
|
-
font-size: 0.
|
|
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;
|
|
87
160
|
}
|
|
88
161
|
|
|
89
162
|
.property-desc {
|
|
90
|
-
color: #
|
|
91
|
-
font-size: 0.
|
|
92
|
-
|
|
93
|
-
|
|
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;
|
|
94
182
|
}
|
|
95
183
|
|
|
96
184
|
.required-fields {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
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;
|
|
102
208
|
}
|
|
103
209
|
|
|
104
210
|
.nested-properties {
|
|
105
|
-
margin
|
|
106
|
-
padding-left: 0.
|
|
211
|
+
margin: 0.25rem 0 0.25rem 0.5rem;
|
|
212
|
+
padding-left: 0.5rem;
|
|
107
213
|
border-left: 1px solid #e5e7eb;
|
|
108
|
-
|
|
109
|
-
|
|
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;
|
|
110
235
|
}
|
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
/* Server item container */
|
|
2
|
-
.server-item {
|
|
2
|
+
.server-item-content {
|
|
3
3
|
cursor: pointer;
|
|
4
4
|
position: relative;
|
|
5
5
|
transition: all 0.2s ease;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
.server-item-content {
|
|
9
|
-
position: relative;
|
|
10
6
|
border: 1px solid #e5e7eb;
|
|
11
7
|
border-radius: 0.5rem;
|
|
12
8
|
padding: 1rem;
|
|
13
9
|
padding-right: calc(120px + 3rem); /* Button width + spacing */
|
|
14
|
-
|
|
10
|
+
box-sizing: border-box;
|
|
15
11
|
background-color: #ffffff;
|
|
16
|
-
|
|
12
|
+
z-index: 1;
|
|
13
|
+
margin-bottom: 1rem;
|
|
14
|
+
width: 100%;
|
|
15
|
+
max-width: 100%;
|
|
16
|
+
overflow: visible;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
.server-item:hover
|
|
20
|
-
border-color:
|
|
21
|
-
box-shadow: 0 2px
|
|
19
|
+
.server-item-content:hover {
|
|
20
|
+
border-color: transparent;
|
|
21
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
|
22
22
|
transform: translateY(-1px);
|
|
23
23
|
}
|
|
24
24
|
|
|
@@ -29,20 +29,33 @@
|
|
|
29
29
|
transition: max-height 0.3s ease-out;
|
|
30
30
|
background-color: #f8fafc;
|
|
31
31
|
border-radius: 0 0 0.5rem 0.5rem;
|
|
32
|
-
margin
|
|
33
|
-
margin-bottom: 1rem;
|
|
32
|
+
margin: -1px 0 0;
|
|
34
33
|
border: 1px solid #e5e7eb;
|
|
35
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;
|
|
36
42
|
}
|
|
37
43
|
|
|
38
44
|
.details-widget.expanded {
|
|
39
|
-
max-height:
|
|
40
|
-
border-color:
|
|
41
|
-
|
|
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;
|
|
42
53
|
}
|
|
43
54
|
|
|
44
55
|
.details-widget-content {
|
|
45
56
|
padding: 1rem;
|
|
57
|
+
width: 100%;
|
|
58
|
+
box-sizing: border-box;
|
|
46
59
|
}
|
|
47
60
|
|
|
48
61
|
.description-text {
|
|
@@ -53,9 +66,12 @@
|
|
|
53
66
|
|
|
54
67
|
/* Expand/collapse animation */
|
|
55
68
|
.server-item-content.expanded {
|
|
69
|
+
border-bottom: none;
|
|
56
70
|
border-bottom-left-radius: 0;
|
|
57
71
|
border-bottom-right-radius: 0;
|
|
58
|
-
border-color:
|
|
72
|
+
border-color: transparent;
|
|
73
|
+
box-shadow: 0 -1px 8px rgba(0, 0, 0, 0.08);
|
|
74
|
+
margin-bottom: 0;
|
|
59
75
|
}
|
|
60
76
|
|
|
61
77
|
/* Server item layout */
|
|
@@ -84,13 +100,13 @@
|
|
|
84
100
|
.action-buttons {
|
|
85
101
|
position: absolute;
|
|
86
102
|
right: 1rem;
|
|
87
|
-
top:
|
|
88
|
-
transform: translateY(-50%);
|
|
103
|
+
top: calc(2rem + 0.5rem); /* Align with description text (header height + margin-bottom) */
|
|
89
104
|
margin: 0;
|
|
105
|
+
z-index: 2; /* Ensure buttons stay on top */
|
|
90
106
|
}
|
|
91
107
|
|
|
92
108
|
.action-buttons button {
|
|
93
|
-
min-width:
|
|
109
|
+
min-width: 100px;
|
|
94
110
|
padding: 0.5rem 1.5rem;
|
|
95
111
|
text-align: center;
|
|
96
112
|
font-weight: 600;
|
|
@@ -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 -->
|