Compare commits
1 Commits
feature/de
...
actions_ed
| Author | SHA1 | Date | |
|---|---|---|---|
| 57702bd82d |
@@ -8,6 +8,10 @@ import {renderAnsi} from '../render/ansi.ts';
|
|||||||
import {POST, DELETE} from '../modules/fetch.ts';
|
import {POST, DELETE} from '../modules/fetch.ts';
|
||||||
import type {IntervalId} from '../types.ts';
|
import type {IntervalId} from '../types.ts';
|
||||||
import {toggleFullScreen} from '../utils.ts';
|
import {toggleFullScreen} from '../utils.ts';
|
||||||
|
import {createMonaco} from '../features/codeeditor.ts';
|
||||||
|
import type MonacoNamespace from 'monaco-editor';
|
||||||
|
|
||||||
|
type IStandaloneCodeEditor = MonacoNamespace.editor.IStandaloneCodeEditor;
|
||||||
|
|
||||||
// see "models/actions/status.go", if it needs to be used somewhere else, move it to a shared file like "types/actions.ts"
|
// see "models/actions/status.go", if it needs to be used somewhere else, move it to a shared file like "types/actions.ts"
|
||||||
type RunStatus = 'unknown' | 'waiting' | 'running' | 'success' | 'failure' | 'cancelled' | 'skipped' | 'blocked';
|
type RunStatus = 'unknown' | 'waiting' | 'running' | 'success' | 'failure' | 'cancelled' | 'skipped' | 'blocked';
|
||||||
@@ -123,6 +127,7 @@ export default defineComponent({
|
|||||||
isRunningWorkflow: false,
|
isRunningWorkflow: false,
|
||||||
hasDraftContent: false,
|
hasDraftContent: false,
|
||||||
draftTimestamp: null as Date | null,
|
draftTimestamp: null as Date | null,
|
||||||
|
monacoEditor: null as IStandaloneCodeEditor | null,
|
||||||
|
|
||||||
commitMessage: '',
|
commitMessage: '',
|
||||||
isCommittingWorkflow: false,
|
isCommittingWorkflow: false,
|
||||||
@@ -548,9 +553,85 @@ export default defineComponent({
|
|||||||
} finally {
|
} finally {
|
||||||
this.isLoadingWorkflow = false;
|
this.isLoadingWorkflow = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize Monaco editor if the editor is still open
|
||||||
|
if (this.showWorkflowEditor) {
|
||||||
|
// Use a small timeout to allow Vue to re-render the v-else block
|
||||||
|
setTimeout(() => {
|
||||||
|
this.initMonacoEditor();
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async initMonacoEditor() {
|
||||||
|
// 1. Dispose existing editor if any
|
||||||
|
if (this.monacoEditor) {
|
||||||
|
this.monacoEditor.dispose();
|
||||||
|
this.monacoEditor = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Poll for textarea element (max 20 attempts, 50ms interval)
|
||||||
|
let textarea: HTMLTextAreaElement | null = null;
|
||||||
|
for (let i = 0; i < 20; i++) {
|
||||||
|
textarea = document.querySelector('#workflow-content-textarea') as HTMLTextAreaElement;
|
||||||
|
if (textarea) break;
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 50));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!textarea) {
|
||||||
|
console.error('Failed to find workflow textarea for Monaco initialization');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 3. Create Monaco Editor
|
||||||
|
const {editor} = await createMonaco(textarea, this.workflowPath || 'workflow.yml', {
|
||||||
|
language: 'yaml',
|
||||||
|
wordWrap: 'on',
|
||||||
|
automaticLayout: true,
|
||||||
|
minimap: {enabled: false},
|
||||||
|
lineNumbers: 'on',
|
||||||
|
scrollBeyondLastLine: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.monacoEditor = editor;
|
||||||
|
|
||||||
|
// Hide the original textarea so only Monaco is visible
|
||||||
|
textarea.style.display = 'none';
|
||||||
|
|
||||||
|
// Force a layout update to ensure editor fills the container
|
||||||
|
// This fixes the "10 lines then blank" issue
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
editor.layout();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 4. Set up bidirectional sync and auto-save
|
||||||
|
let saveTimeout: ReturnType<typeof setTimeout> | null = null;
|
||||||
|
editor.onDidChangeModelContent(() => {
|
||||||
|
// Sync content back to Vue data
|
||||||
|
this.workflowContent = editor.getValue();
|
||||||
|
|
||||||
|
// Debounce saveDraft
|
||||||
|
if (saveTimeout) clearTimeout(saveTimeout);
|
||||||
|
saveTimeout = setTimeout(() => {
|
||||||
|
this.saveDraft();
|
||||||
|
}, 1000);
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to initialize Monaco editor:', e);
|
||||||
|
alert('Failed to load code editor: ' + e.message + '. Using simple text area instead.');
|
||||||
|
// Fallback: make sure textarea is visible if Monaco failed
|
||||||
|
textarea.style.display = 'block';
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
closeWorkflowEditor() {
|
closeWorkflowEditor() {
|
||||||
|
// Dispose Monaco editor
|
||||||
|
if (this.monacoEditor) {
|
||||||
|
this.monacoEditor.dispose();
|
||||||
|
this.monacoEditor = null;
|
||||||
|
}
|
||||||
this.showWorkflowEditor = false;
|
this.showWorkflowEditor = false;
|
||||||
this.workflowContent = '';
|
this.workflowContent = '';
|
||||||
this.workflowPath = '';
|
this.workflowPath = '';
|
||||||
@@ -817,12 +898,18 @@ export default defineComponent({
|
|||||||
{{ locale.changes_auto_saved }}
|
{{ locale.changes_auto_saved }}
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
<textarea
|
<div class="editor-wrapper" style="position: relative; height: 600px; border: 1px solid var(--color-secondary); border-radius: var(--border-radius); overflow: hidden;">
|
||||||
v-model="workflowContent"
|
<div v-if="!monacoEditor" style="position: absolute; top: 0; left: 0; right: 0; bottom: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; background: var(--color-body); z-index: 10; pointer-events: none;">
|
||||||
@input="saveDraft()"
|
<span class="ui active large text loader">Loading Editor...</span>
|
||||||
rows="15"
|
</div>
|
||||||
style="font-family: monospace; font-size: 12px;">
|
<textarea
|
||||||
</textarea>
|
id="workflow-content-textarea"
|
||||||
|
v-model="workflowContent"
|
||||||
|
@input="saveDraft()"
|
||||||
|
rows="15"
|
||||||
|
style="font-family: monospace; font-size: 12px; width: 100%; height: 100%; border: none; padding: 1em; box-sizing: border-box; resize: none;">
|
||||||
|
</textarea>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -860,6 +947,13 @@ export default defineComponent({
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
/* Monaco Editor Container */
|
||||||
|
:deep(.monaco-editor-container) {
|
||||||
|
height: 100% !important; /* Force full height of the wrapper */
|
||||||
|
width: 100% !important;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
.action-view-body {
|
.action-view-body {
|
||||||
padding-top: 12px;
|
padding-top: 12px;
|
||||||
padding-bottom: 12px;
|
padding-bottom: 12px;
|
||||||
|
|||||||
Reference in New Issue
Block a user