Initial commit: Clean DSS implementation
Migrated from design-system-swarm with fresh git history.
Old project history preserved in /home/overbits/apps/design-system-swarm
Core components:
- MCP Server (Python FastAPI with mcp 1.23.1)
- Claude Plugin (agents, commands, skills, strategies, hooks, core)
- DSS Backend (dss-mvp1 - token translation, Figma sync)
- Admin UI (Node.js/React)
- Server (Node.js/Express)
- Storybook integration (dss-mvp1/.storybook)
Self-contained configuration:
- All paths relative or use DSS_BASE_PATH=/home/overbits/dss
- PYTHONPATH configured for dss-mvp1 and dss-claude-plugin
- .env file with all configuration
- Claude plugin uses ${CLAUDE_PLUGIN_ROOT} for portability
Migration completed: $(date)
🤖 Clean migration with full functionality preserved
This commit is contained in:
259
admin-ui/js/components/admin/ds-admin-settings.js
Normal file
259
admin-ui/js/components/admin/ds-admin-settings.js
Normal file
@@ -0,0 +1,259 @@
|
||||
/**
|
||||
* ds-admin-settings.js
|
||||
* Admin settings panel for DSS configuration
|
||||
* Allows configuration of hostname, port, and local/remote setup
|
||||
*/
|
||||
|
||||
import { useAdminStore } from '../../stores/admin-store.js';
|
||||
|
||||
export default class AdminSettings extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.adminStore = useAdminStore();
|
||||
this.state = this.adminStore.getState();
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
this.render();
|
||||
this.setupEventListeners();
|
||||
this.unsubscribe = this.adminStore.subscribe(() => {
|
||||
this.state = this.adminStore.getState();
|
||||
this.updateUI();
|
||||
});
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
if (this.unsubscribe) this.unsubscribe();
|
||||
}
|
||||
|
||||
render() {
|
||||
this.innerHTML = `
|
||||
<div style="padding: 24px; max-width: 600px;">
|
||||
<h2 style="margin-bottom: 24px; font-size: 20px;">DSS Settings</h2>
|
||||
|
||||
<!-- Hostname Setting -->
|
||||
<div style="margin-bottom: 24px;">
|
||||
<label style="display: block; margin-bottom: 8px; font-weight: 500;">
|
||||
Hostname
|
||||
</label>
|
||||
<input
|
||||
id="hostname-input"
|
||||
type="text"
|
||||
value="${this.state.hostname}"
|
||||
style="
|
||||
width: 100%;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid var(--vscode-input-border);
|
||||
background: var(--vscode-input-background);
|
||||
color: var(--vscode-foreground);
|
||||
border-radius: 4px;
|
||||
font-family: monospace;
|
||||
"
|
||||
placeholder="localhost or IP address"
|
||||
/>
|
||||
<div style="font-size: 11px; color: var(--vscode-text-dim); margin-top: 4px;">
|
||||
Default: localhost
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Port Setting -->
|
||||
<div style="margin-bottom: 24px;">
|
||||
<label style="display: block; margin-bottom: 8px; font-weight: 500;">
|
||||
Storybook Port
|
||||
</label>
|
||||
<input
|
||||
id="port-input"
|
||||
type="number"
|
||||
value="${this.state.port}"
|
||||
style="
|
||||
width: 100%;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid var(--vscode-input-border);
|
||||
background: var(--vscode-input-background);
|
||||
color: var(--vscode-foreground);
|
||||
border-radius: 4px;
|
||||
font-family: monospace;
|
||||
"
|
||||
placeholder="6006"
|
||||
min="1"
|
||||
max="65535"
|
||||
/>
|
||||
<div style="font-size: 11px; color: var(--vscode-text-dim); margin-top: 4px;">
|
||||
Default: 6006 (Storybook standard port)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- DSS Setup Type -->
|
||||
<div style="margin-bottom: 24px;">
|
||||
<label style="display: block; margin-bottom: 12px; font-weight: 500;">
|
||||
DSS Setup Type
|
||||
</label>
|
||||
<div style="display: flex; gap: 16px;">
|
||||
<label style="display: flex; align-items: center; cursor: pointer;">
|
||||
<input
|
||||
type="radio"
|
||||
name="setup-type"
|
||||
value="local"
|
||||
${this.state.isRemote ? '' : 'checked'}
|
||||
style="margin-right: 8px;"
|
||||
/>
|
||||
<span>Local</span>
|
||||
</label>
|
||||
<label style="display: flex; align-items: center; cursor: pointer;">
|
||||
<input
|
||||
type="radio"
|
||||
name="setup-type"
|
||||
value="remote"
|
||||
${this.state.isRemote ? 'checked' : ''}
|
||||
style="margin-right: 8px;"
|
||||
/>
|
||||
<span>Remote (Headless)</span>
|
||||
</label>
|
||||
</div>
|
||||
<div style="font-size: 11px; color: var(--vscode-text-dim); margin-top: 8px;">
|
||||
<strong>Local:</strong> Uses browser devtools and local services<br/>
|
||||
<strong>Remote:</strong> Uses headless tools and MCP providers
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Current Configuration Display -->
|
||||
<div style="
|
||||
background: var(--vscode-sidebar);
|
||||
border: 1px solid var(--vscode-border);
|
||||
border-radius: 4px;
|
||||
padding: 12px;
|
||||
margin-bottom: 24px;
|
||||
">
|
||||
<div style="font-size: 11px; color: var(--vscode-text-dim); margin-bottom: 8px;">CURRENT STORYBOOK URL:</div>
|
||||
<div style="
|
||||
font-family: monospace;
|
||||
font-size: 12px;
|
||||
word-break: break-all;
|
||||
color: var(--vscode-foreground);
|
||||
" id="storybook-url-display">
|
||||
${this.getStorybookUrlDisplay()}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
<div style="display: flex; gap: 8px;">
|
||||
<button
|
||||
id="save-btn"
|
||||
style="
|
||||
padding: 8px 16px;
|
||||
background: var(--vscode-button-background);
|
||||
color: var(--vscode-button-foreground);
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-weight: 500;
|
||||
"
|
||||
>
|
||||
Save Settings
|
||||
</button>
|
||||
<button
|
||||
id="reset-btn"
|
||||
style="
|
||||
padding: 8px 16px;
|
||||
background: var(--vscode-button-secondaryBackground);
|
||||
color: var(--vscode-button-secondaryForeground);
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-weight: 500;
|
||||
"
|
||||
>
|
||||
Reset to Defaults
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
setupEventListeners() {
|
||||
const hostnameInput = this.querySelector('#hostname-input');
|
||||
const portInput = this.querySelector('#port-input');
|
||||
const setupTypeRadios = this.querySelectorAll('input[name="setup-type"]');
|
||||
const saveBtn = this.querySelector('#save-btn');
|
||||
const resetBtn = this.querySelector('#reset-btn');
|
||||
|
||||
// Update on input (but don't save immediately)
|
||||
hostnameInput.addEventListener('change', () => {
|
||||
this.adminStore.setHostname(hostnameInput.value);
|
||||
});
|
||||
|
||||
portInput.addEventListener('change', () => {
|
||||
const port = parseInt(portInput.value);
|
||||
if (port > 0 && port <= 65535) {
|
||||
this.adminStore.setPort(port);
|
||||
}
|
||||
});
|
||||
|
||||
setupTypeRadios.forEach(radio => {
|
||||
radio.addEventListener('change', (e) => {
|
||||
this.adminStore.setRemote(e.target.value === 'remote');
|
||||
});
|
||||
});
|
||||
|
||||
saveBtn.addEventListener('click', () => {
|
||||
this.showNotification('Settings saved successfully!');
|
||||
console.log('[AdminSettings] Settings saved:', this.adminStore.getState());
|
||||
});
|
||||
|
||||
resetBtn.addEventListener('click', () => {
|
||||
if (confirm('Reset all settings to defaults?')) {
|
||||
this.adminStore.reset();
|
||||
this.render();
|
||||
this.setupEventListeners();
|
||||
this.showNotification('Settings reset to defaults');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
updateUI() {
|
||||
const hostnameInput = this.querySelector('#hostname-input');
|
||||
const portInput = this.querySelector('#port-input');
|
||||
const setupTypeRadios = this.querySelectorAll('input[name="setup-type"]');
|
||||
const urlDisplay = this.querySelector('#storybook-url-display');
|
||||
|
||||
if (hostnameInput) hostnameInput.value = this.state.hostname;
|
||||
if (portInput) portInput.value = this.state.port;
|
||||
|
||||
setupTypeRadios.forEach(radio => {
|
||||
radio.checked = (radio.value === 'remote') === this.state.isRemote;
|
||||
});
|
||||
|
||||
if (urlDisplay) {
|
||||
urlDisplay.textContent = this.getStorybookUrlDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
getStorybookUrlDisplay() {
|
||||
return this.adminStore.getStorybookUrl('default');
|
||||
}
|
||||
|
||||
showNotification(message) {
|
||||
const notification = document.createElement('div');
|
||||
notification.textContent = message;
|
||||
notification.style.cssText = `
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
background: var(--vscode-notifications-background);
|
||||
color: var(--vscode-foreground);
|
||||
padding: 12px 16px;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
|
||||
z-index: 1000;
|
||||
animation: slideIn 0.3s ease;
|
||||
`;
|
||||
document.body.appendChild(notification);
|
||||
|
||||
setTimeout(() => {
|
||||
notification.style.animation = 'slideOut 0.3s ease';
|
||||
setTimeout(() => notification.remove(), 300);
|
||||
}, 3000);
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('ds-admin-settings', AdminSettings);
|
||||
Reference in New Issue
Block a user