| 1 | <html> |
| 2 | <head> |
| 3 | <title>Plugin Execute</title> |
| 4 | <script type="module"> |
| 5 | import { store } from "/components/plugins/list/plugin-execute-store.js"; |
| 6 | </script> |
| 7 | </head> |
| 8 | <body> |
| 9 | <div x-data> |
| 10 | <template x-if="$store.pluginExecuteStore"> |
| 11 | <div x-destroy="$store.pluginExecuteStore.cleanup()" |
| 12 | x-create="$el.closest('.modal')?.querySelector('.modal-title') && ($el.closest('.modal').querySelector('.modal-title').textContent = 'Execute: ' + $store.pluginExecuteStore.pluginDisplayName)" |
| 13 | class="plugin-execute-root"> |
| 14 | |
| 15 | <div class="plugin-execute-idle" |
| 16 | x-show="!$store.pluginExecuteStore.running && $store.pluginExecuteStore.exitCode === null && !$store.pluginExecuteStore.output"> |
| 17 | <x-icon class="idle-icon" name="terminal"></x-icon> |
| 18 | <div class="idle-text"> |
| 19 | <span class="idle-headline">Press <strong>Run</strong> to execute <strong x-text="$store.pluginExecuteStore.pluginDisplayName"></strong></span> |
| 20 | <span class="idle-sub">This will run the plugin's <code>execute.py</code> script.</span> |
| 21 | <template x-if="$store.pluginExecuteStore.lastExecution"> |
| 22 | <span class="last-exec-info"> |
| 23 | Last run: |
| 24 | <span x-text="$store.pluginExecuteStore.formatTimestamp($store.pluginExecuteStore.lastExecution.executed_at)"></span> |
| 25 | — |
| 26 | <span :class="$store.pluginExecuteStore.lastExecution.exit_code === 0 ? 'exit-ok' : 'exit-err'" |
| 27 | x-text="$store.pluginExecuteStore.lastExecution.exit_code === 0 ? 'succeeded' : 'failed (exit ' + $store.pluginExecuteStore.lastExecution.exit_code + ')'"> |
| 28 | </span> |
| 29 | </span> |
| 30 | </template> |
| 31 | <template x-if="!$store.pluginExecuteStore.lastExecution"> |
| 32 | <span class="last-exec-info never-run">Never executed</span> |
| 33 | </template> |
| 34 | </div> |
| 35 | </div> |
| 36 | |
| 37 | <div class="plugin-execute-status" x-show="$store.pluginExecuteStore.running"> |
| 38 | <x-icon class="spin" name="progress_activity"></x-icon> |
| 39 | <span>Running execute.py...</span> |
| 40 | </div> |
| 41 | |
| 42 | <div class="plugin-execute-exit" x-show="!$store.pluginExecuteStore.running && $store.pluginExecuteStore.exitCode !== null"> |
| 43 | <x-icon |
| 44 | :class="$store.pluginExecuteStore.exitCode === 0 ? 'exit-ok' : 'exit-err'" |
| 45 | :name="$store.pluginExecuteStore.exitCode === 0 ? 'check_circle' : 'error'"></x-icon> |
| 46 | <span x-text="$store.pluginExecuteStore.exitCode === 0 ? 'Completed successfully (exit 0)' : 'Exited with code ' + $store.pluginExecuteStore.exitCode"></span> |
| 47 | </div> |
| 48 | |
| 49 | <pre class="plugin-execute-output" |
| 50 | x-show="$store.pluginExecuteStore.output || $store.pluginExecuteStore.running" |
| 51 | x-text="$store.pluginExecuteStore.output || ''"></pre> |
| 52 | </div> |
| 53 | </template> |
| 54 | </div> |
| 55 | |
| 56 | <div class="modal-footer" data-modal-footer> |
| 57 | <button class="btn btn-action footer-btn" |
| 58 | x-data |
| 59 | :disabled="$store.pluginExecuteStore?.running" |
| 60 | @click="$store.pluginExecuteStore?.run()"> |
| 61 | <x-icon class="icon" name="play_arrow"></x-icon> |
| 62 | <span x-text="$store.pluginExecuteStore?.exitCode !== null || $store.pluginExecuteStore?.output ? 'Rerun' : 'Run'">Run</span> |
| 63 | </button> |
| 64 | <button class="btn btn-cancel footer-btn" @click="window.closeModal?.()">Close</button> |
| 65 | </div> |
| 66 | |
| 67 | <style> |
| 68 | .plugin-execute-root { |
| 69 | display: flex; |
| 70 | flex-direction: column; |
| 71 | width: 100%; |
| 72 | } |
| 73 | |
| 74 | .plugin-execute-idle { |
| 75 | display: flex; |
| 76 | align-items: flex-start; |
| 77 | gap: 1rem; |
| 78 | padding: 2rem 1.5rem; |
| 79 | color: var(--color-text-secondary); |
| 80 | } |
| 81 | |
| 82 | .idle-icon { |
| 83 | font-size: 2.75rem; |
| 84 | opacity: 0.35; |
| 85 | flex-shrink: 0; |
| 86 | margin-top: 0.15rem; |
| 87 | } |
| 88 | |
| 89 | .idle-text { |
| 90 | display: flex; |
| 91 | flex-direction: column; |
| 92 | gap: 0.4rem; |
| 93 | } |
| 94 | |
| 95 | .idle-headline { |
| 96 | font-size: 1rem; |
| 97 | color: var(--color-text); |
| 98 | line-height: 1.4; |
| 99 | } |
| 100 | |
| 101 | .idle-sub { |
| 102 | font-size: 0.82rem; |
| 103 | opacity: 0.65; |
| 104 | } |
| 105 | |
| 106 | .last-exec-info { |
| 107 | font-size: 0.8rem; |
| 108 | opacity: 0.7; |
| 109 | margin-top: 0.25rem; |
| 110 | } |
| 111 | |
| 112 | .never-run { |
| 113 | font-style: italic; |
| 114 | } |
| 115 | |
| 116 | .plugin-execute-status { |
| 117 | display: flex; |
| 118 | align-items: center; |
| 119 | gap: 0.5rem; |
| 120 | padding: 0.75rem 1.5rem; |
| 121 | color: var(--color-text-secondary); |
| 122 | font-size: var(--font-size-small); |
| 123 | } |
| 124 | |
| 125 | .plugin-execute-exit { |
| 126 | display: flex; |
| 127 | align-items: center; |
| 128 | gap: 0.5rem; |
| 129 | padding: 0.5rem 1.5rem; |
| 130 | font-size: var(--font-size-small); |
| 131 | } |
| 132 | |
| 133 | .exit-ok { |
| 134 | color: var(--color-success, #27ae60); |
| 135 | } |
| 136 | |
| 137 | .exit-err { |
| 138 | color: var(--color-error, #e74c3c); |
| 139 | } |
| 140 | |
| 141 | .plugin-execute-output { |
| 142 | font-family: "Courier New", Courier, monospace; |
| 143 | font-size: 0.82rem; |
| 144 | background: var(--color-bg-secondary, #1e1e1e); |
| 145 | color: var(--color-text-primary); |
| 146 | padding: 1rem 1.5rem; |
| 147 | margin: 0; |
| 148 | overflow-y: auto; |
| 149 | max-height: 60vh; |
| 150 | white-space: pre-wrap; |
| 151 | word-break: break-word; |
| 152 | border-radius: 6px; |
| 153 | } |
| 154 | |
| 155 | @keyframes spin { |
| 156 | from { transform: rotate(0deg); } |
| 157 | to { transform: rotate(360deg); } |
| 158 | } |
| 159 | |
| 160 | .spin { |
| 161 | animation: spin 1s linear infinite; |
| 162 | } |
| 163 | |
| 164 | .footer-btn { |
| 165 | padding: 0.5rem 1.5rem; |
| 166 | font-size: 0.875rem; |
| 167 | font-weight: 500; |
| 168 | border-radius: 0.25rem; |
| 169 | } |
| 170 | </style> |
| 171 | </body> |
| 172 | </html> |