Spaces:
Running
Running
Download webui/components/plugins/list/plugin-list.html from Leon4gr45/openoperator: direct link, hf CLI and curl.
- Browser
- Download file 20.8 kB
-
https://huggingface.co/spaces/Leon4gr45/openoperator/resolve/main/webui/components/plugins/list/plugin-list.html
- Command line
-
hf download hf://spaces/Leon4gr45/openoperator/webui/components/plugins/list/plugin-list.html
-
curl -L -o plugin-list.html https://huggingface.co/spaces/Leon4gr45/openoperator/resolve/main/webui/components/plugins/list/plugin-list.html
20.8 kB
| <html> | |
| <head> | |
| <title>Plugins</title> | |
| <script type="module"> | |
| import { store } from "/components/plugins/list/pluginListStore.js"; | |
| </script> | |
| </head> | |
| <body> | |
| <div x-data> | |
| <template x-if="$store.pluginListStore"> | |
| <div x-init="$store.pluginListStore.init && $store.pluginListStore.init()"> | |
| <ul class="nav nav-tabs" id="plugin-list-tabs" role="tablist"> | |
| <li class="nav-item" role="presentation"> | |
| <button class="nav-link" | |
| :class="{ active: $store.pluginListStore.activeTab === 'custom' }" | |
| id="plugins-custom-tab" | |
| type="button" | |
| role="tab" | |
| aria-controls="plugins-custom" | |
| :aria-selected="$store.pluginListStore.activeTab === 'custom'" | |
| @click="$store.pluginListStore.setTab('custom')"> | |
| Custom | |
| </button> | |
| </li> | |
| <li class="nav-item" role="presentation"> | |
| <button class="nav-link" | |
| :class="{ active: $store.pluginListStore.activeTab === 'builtin' }" | |
| id="plugins-builtin-tab" | |
| type="button" | |
| role="tab" | |
| aria-controls="plugins-builtin" | |
| :aria-selected="$store.pluginListStore.activeTab === 'builtin'" | |
| @click="$store.pluginListStore.setTab('builtin')"> | |
| Builtin | |
| </button> | |
| </li> | |
| <li class="nav-item" role="presentation"> | |
| <button class="nav-link" | |
| :class="{ active: $store.pluginListStore.activeTab === 'pluginHub' }" | |
| id="plugins-plugin-hub-tab" | |
| type="button" | |
| role="tab" | |
| aria-controls="plugins-plugin-hub" | |
| :aria-selected="$store.pluginListStore.activeTab === 'pluginHub'" | |
| @click="$store.pluginListStore.setTab('pluginHub')"> | |
| <x-icon class="pi-tab-icon" name="store"></x-icon> Browse | |
| </button> | |
| </li> | |
| </ul> | |
| <template x-if="$store.pluginListStore.activeTab !== 'pluginHub'"> | |
| <div> | |
| <div class="plugins-toolbar"> | |
| <div class="plugins-toolbar-search"> | |
| <input type="text" | |
| class="plugins-search-input" | |
| placeholder="Search plugins by name or description..." | |
| x-model="$store.pluginListStore.searchQuery"> | |
| </div> | |
| <div class="plugins-toolbar-actions"> | |
| <button type="button" | |
| class="button" | |
| title="Refresh" | |
| @click="$store.pluginListStore.refresh()" | |
| :disabled="$store.pluginListStore.loading"> | |
| <x-icon class="icon" name="refresh"></x-icon> Refresh | |
| </button> | |
| <x-extension id="plugins-list-header-buttons"></x-extension> | |
| </div> | |
| </div> | |
| <div x-show="$store.pluginListStore.loading" class="loading"> | |
| <span>Loading plugins...</span> | |
| </div> | |
| <div class="plugins-list"> | |
| <template x-for="plugin in (($store.pluginListStore.plugins || []).filter((plugin) => { | |
| const q = (($store.pluginListStore.searchQuery || '').trim().toLowerCase()); | |
| if (!q) return true; | |
| const name = (plugin.display_name || plugin.name || '').toLowerCase(); | |
| const description = (plugin.description || '').toLowerCase(); | |
| return name.includes(q) || description.includes(q); | |
| }))" :key="plugin.path || plugin.name"> | |
| <div class="plugin-card"> | |
| <div class="plugin-header"> | |
| <template x-if="plugin.thumbnail_url"> | |
| <img class="plugin-thumb" | |
| :src="plugin.thumbnail_url" | |
| :alt="plugin.display_name || plugin.name" | |
| loading="lazy"> | |
| </template> | |
| <div class="plugin-heading"> | |
| <div class="plugin-title" x-text="plugin.display_name || plugin.name || '(unnamed plugin)'"></div> | |
| <code class="plugin-path" x-text="plugin.path"></code> | |
| </div> | |
| <div class="plugin-actions" x-data="{ actionsOpen: false }"> | |
| <template x-if="plugin.has_main_screen"> | |
| <button type="button" | |
| class="button" | |
| title="Open" | |
| @click="$store.pluginListStore.openPlugin(plugin)"> | |
| <x-icon class="icon" name="dashboard"></x-icon> Open | |
| </button> | |
| </template> | |
| <template x-if="$store.pluginListStore.canOpenPluginConfig(plugin)"> | |
| <button type="button" | |
| class="button" | |
| title="Config" | |
| @click="$store.pluginListStore.openPluginConfig(plugin)"> | |
| <x-icon class="icon" name="settings"></x-icon> Config | |
| </button> | |
| </template> | |
| <template x-if="plugin.has_execute_script"> | |
| <button type="button" | |
| class="button" | |
| title="Execute" | |
| @click="$store.pluginListStore.openPluginExecute(plugin)"> | |
| <x-icon class="icon" name="terminal"></x-icon> Execute | |
| </button> | |
| </template> | |
| <button type="button" | |
| class="button icon-button" | |
| title="Info" | |
| aria-label="Info" | |
| @click="$store.pluginListStore.openPluginInfo(plugin)"> | |
| <x-icon class="icon" name="info"></x-icon> | |
| </button> | |
| <div class="dropdown plugin-actions-dropdown" | |
| @click.outside="actionsOpen = false" | |
| @keydown.escape.window="if (actionsOpen) actionsOpen = false"> | |
| <button type="button" | |
| class="btn-icon-action dropdown-trigger" | |
| title="More actions" | |
| aria-label="More actions" | |
| @click.stop="actionsOpen = !actionsOpen" | |
| :aria-expanded="actionsOpen.toString()"> | |
| <x-icon name="more_vert"></x-icon> | |
| </button> | |
| <div class="dropdown-menu" | |
| x-show="actionsOpen" | |
| x-transition | |
| style="display: none;"> | |
| <x-extension id="plugins-list-dropdown-start"></x-extension> | |
| <template x-if="plugin.has_readme"> | |
| <button type="button" | |
| class="dropdown-item" | |
| title="README" | |
| @click="$store.pluginListStore.openPluginDoc(plugin, 'readme'); actionsOpen = false"> | |
| <x-icon name="description"></x-icon> | |
| <span>README</span> | |
| </button> | |
| </template> | |
| <template x-if="plugin.has_license"> | |
| <button type="button" | |
| class="dropdown-item" | |
| title="License" | |
| @click="$store.pluginListStore.openPluginDoc(plugin, 'license'); actionsOpen = false"> | |
| <x-icon name="gavel"></x-icon> | |
| <span>License</span> | |
| </button> | |
| </template> | |
| <x-extension id="plugins-list-dropdown-end"></x-extension> | |
| <template x-if="plugin.is_custom"> | |
| <button type="button" | |
| class="dropdown-item plugin-dropdown-delete" | |
| title="Delete" | |
| @click="$confirmClick($event, () => { $store.pluginListStore.deletePlugin(plugin); actionsOpen = false; })"> | |
| <x-icon name="delete"></x-icon> | |
| <span>Delete</span> | |
| </button> | |
| </template> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="plugin-footer-row"> | |
| <div class="plugin-description" x-text="plugin.description || 'No description provided.'"></div> | |
| <div class="plugin-status-group"> | |
| <label class="toggle plugin-status-toggle" | |
| :class="{ 'disabled-appearance': plugin.always_enabled || $store.pluginListStore.loading }" | |
| :title="plugin.always_enabled ? 'Always enabled' : ($store.pluginListStore.isPluginEnabled(plugin) ? 'Disable plugin' : 'Enable plugin')"> | |
| <input type="checkbox" | |
| :checked="$store.pluginListStore.isPluginEnabled(plugin)" | |
| :disabled="plugin.always_enabled || $store.pluginListStore.loading" | |
| @change="$store.pluginListStore.updateToggle(plugin, $event.target.checked)" | |
| @click.stop> | |
| <span class="toggler"></span> | |
| </label> | |
| <span class="plugin-status-text" x-text="$store.pluginListStore.toggleStatusLabel(plugin)"></span> | |
| </div> | |
| </div> | |
| </div> | |
| </template> | |
| </div> | |
| </div> | |
| </template> | |
| <template x-if="$store.pluginListStore.activeTab === 'pluginHub'"> | |
| <x-component path="/plugins/_plugin_installer/webui/install-index.html"></x-component> | |
| </template> | |
| </div> | |
| </template> | |
| </div> | |
| <style> | |
| .nav { | |
| display: flex; | |
| padding-left: 0; | |
| margin: 0 0 1rem 0; | |
| list-style: none; | |
| border-bottom: 1px solid var(--color-border); | |
| gap: 0.25rem; | |
| } | |
| .nav-link { | |
| font-family: "Rubik", Arial, Helvetica, sans-serif; | |
| border: 1px solid transparent; | |
| border-top-left-radius: 4px; | |
| border-top-right-radius: 4px; | |
| padding: 0.4rem 0.7rem; | |
| background: transparent; | |
| color: var(--color-text-secondary); | |
| cursor: pointer; | |
| display: inline-flex; | |
| align-items: center; | |
| gap: 0.3rem; | |
| } | |
| .nav-link.active { | |
| color: var(--color-text-primary); | |
| border-color: var(--color-border); | |
| border-bottom-color: transparent; | |
| background: var(--color-background); | |
| } | |
| .pi-tab-icon { | |
| font-size: 1.1rem; | |
| } | |
| .plugins-toolbar { | |
| display: flex; | |
| align-items: center; | |
| gap: 0.75rem; | |
| flex-wrap: wrap; | |
| margin-top: 0.5rem; | |
| margin-bottom: 0.75rem; | |
| } | |
| .plugins-toolbar-search { | |
| flex: 1 1 22rem; | |
| min-width: 14rem; | |
| } | |
| .plugins-search-input { | |
| width: 100%; | |
| padding: 0.4rem 0.7rem; | |
| border: 1px solid var(--color-border); | |
| border-radius: 4px; | |
| background: var(--color-background); | |
| color: var(--color-text-primary); | |
| font-family: "Rubik", Arial, Helvetica, sans-serif; | |
| font-size: 0.95rem; | |
| } | |
| .plugins-search-input:focus { | |
| outline: none; | |
| border-color: var(--color-primary); | |
| } | |
| .plugins-toolbar-actions { | |
| margin-left: auto; | |
| display: flex; | |
| flex: 0 0 auto; | |
| gap: var(--spacing-sm); | |
| } | |
| .plugins-list { | |
| margin-top: 0.25rem; | |
| } | |
| .plugin-card { | |
| border: 1px solid var(--color-border); | |
| border-radius: 10px; | |
| padding: 0.75rem; | |
| margin-top: 0.75rem; | |
| background: var(--color-background); | |
| } | |
| .plugin-header { | |
| display: flex; | |
| align-items: flex-start; | |
| justify-content: space-between; | |
| gap: 1rem; | |
| flex-wrap: nowrap; | |
| min-width: 0; | |
| } | |
| .plugin-heading { | |
| display: flex; | |
| flex-direction: column; | |
| min-width: 0; | |
| flex: 1 1 auto; | |
| } | |
| .plugin-thumb { | |
| width: 44px; | |
| height: 44px; | |
| border-radius: 0.5rem; | |
| object-fit: contain; | |
| flex-shrink: 0; | |
| background: var(--color-panel); | |
| border: 1px solid var(--color-border); | |
| } | |
| .plugin-title { | |
| font-weight: 600; | |
| font-size: 1rem; | |
| min-width: 0; | |
| flex: 1 1 auto; | |
| } | |
| .plugin-actions { | |
| display: flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| padding-bottom: var(--spacing-sm); | |
| flex-wrap: nowrap; | |
| min-width: 0; | |
| flex: 0 0 auto; | |
| max-width: 100%; | |
| justify-content: flex-end; | |
| } | |
| .plugin-actions .button { | |
| padding: 0.3rem 0.6rem; | |
| font-size: 0.9rem; | |
| } | |
| .plugin-actions .button .icon { | |
| font-size: 1.1rem; | |
| } | |
| .plugin-actions-dropdown { | |
| flex: 0 0 auto; | |
| } | |
| .plugin-actions-dropdown:not(:has(.dropdown-menu .dropdown-item)) { | |
| display: none; | |
| } | |
| .plugin-actions-dropdown .dropdown-menu { | |
| margin-top: 0; | |
| top: calc(100% - 1px); | |
| } | |
| .plugin-actions-dropdown .plugin-dropdown-delete, | |
| .plugin-actions-dropdown .plugin-dropdown-delete .material-symbols-outlined { | |
| color: var(--color-accent); | |
| opacity: 1; | |
| } | |
| .plugin-actions-dropdown .plugin-dropdown-delete:hover { | |
| background-color: color-mix(in srgb, var(--color-accent) 10%, transparent); | |
| } | |
| .plugin-footer-row { | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| gap: 1rem; | |
| margin-top: 0.5rem; | |
| } | |
| .plugin-status-group { | |
| display: flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| flex: 0 0 auto; | |
| } | |
| .plugin-status-toggle { | |
| width: 48px; | |
| height: 28px; | |
| flex: 0 0 48px; | |
| } | |
| .plugin-status-toggle .toggler { | |
| border-radius: 999px; | |
| } | |
| .plugin-status-toggle .toggler:before { | |
| width: 20px; | |
| height: 20px; | |
| left: 4px; | |
| bottom: 4px; | |
| } | |
| .plugin-status-toggle input:checked + .toggler:before { | |
| transform: translateX(20px); | |
| } | |
| .plugin-status-toggle input:disabled + .toggler { | |
| cursor: default; | |
| } | |
| .plugin-status-toggle.disabled-appearance { | |
| opacity: 0.6; | |
| } | |
| .plugin-status-text { | |
| color: var(--color-text-primary); | |
| font-size: 0.9rem; | |
| font-weight: 600; | |
| min-width: 2rem; | |
| } | |
| .plugin-description { | |
| color: var(--color-text-secondary); | |
| font-size: var(--font-size-small); | |
| flex: 1 1 auto; | |
| min-width: 0; | |
| } | |
| .plugin-path { | |
| margin-top: 0.35rem; | |
| font-size: 0.85rem; | |
| color: var(--color-text-muted); | |
| min-width: 0; | |
| max-width: 100%; | |
| white-space: pre-wrap; | |
| word-break: break-word; | |
| overflow-wrap: anywhere; | |
| } | |
| .loading { | |
| width: 100%; | |
| text-align: center; | |
| margin-top: 0.75rem; | |
| margin-bottom: 0.75rem; | |
| color: var(--color-secondary); | |
| } | |
| @media (max-width: 768px) { | |
| .plugin-header { | |
| flex-direction: column; | |
| align-items: stretch; | |
| } | |
| .plugin-heading { | |
| width: 100%; | |
| flex: 0 0 auto; | |
| } | |
| .plugin-actions { | |
| width: 100%; | |
| justify-content: flex-start; | |
| padding-bottom: 0; | |
| flex-wrap: wrap; | |
| } | |
| .plugin-path { | |
| white-space: normal; | |
| word-break: break-word; | |
| } | |
| } | |
| </style> | |
| </body> | |
| </html> | |