diff --git a/.gitignore b/.gitignore index ab1d496..6439228 100644 --- a/.gitignore +++ b/.gitignore @@ -80,4 +80,11 @@ workflow_rename_log.json # Node.js artifacts (if using npm) node_modules/ -package-lock.json \ No newline at end of file +package-lock.json + +#db +*.db-shm +*.db-wal + +# versions +.python-version \ No newline at end of file diff --git a/static/index.html b/static/index.html index b2d1cbc..967b8f3 100644 --- a/static/index.html +++ b/static/index.html @@ -1,1016 +1,1063 @@ + - - - ⚡ N8N Workflow Documentation - + + + ⚡ N8N Workflow Documentation + + + -
- -
-
-

⚡ N8N Workflow Documentation

-

Lightning-fast workflow browser with instant search

-
-
- 0 - Total -
-
- 0 - Active -
-
- 0 - Total Nodes -
-
- 0 - Integrations -
-
-
-
+
+ +
+
+

⚡ N8N Workflow Documentation

+

Lightning-fast workflow browser with instant search

+
+
+ 0 + Total +
+
+ 0 + Active +
+
+ 0 + Total Nodes +
+
+ 0 + Integrations +
+
+
+
- -
-
-
- -
- -
-
- - -
- -
- - -
- -
- -
- - -
- -
- Loading... -
-
+ +
+
+
+
- -
-
- -
-
-

Loading workflows...

-

Please wait while we fetch your workflow data

-
+
+
+ + +
- - +
+ + +
- - +
+ +
- - - - - -
-
- - - + +
+ Loading... +
+
- + // Set download link + this.elements.downloadBtn.href = `/api/workflows/${workflow.filename}/download`; + this.elements.downloadBtn.download = workflow.filename; + + // Reset view states + this.elements.jsonSection.classList.add('hidden'); + this.elements.diagramSection.classList.add('hidden'); + + this.elements.workflowModal.classList.remove('hidden'); + } + + closeModal() { + this.elements.workflowModal.classList.add('hidden'); + this.currentWorkflow = null; + this.currentJsonData = null; + this.currentDiagramData = null; + + // Reset button states + this.elements.viewJsonBtn.textContent = '📄 View JSON'; + this.elements.viewDiagramBtn.textContent = '📊 View Diagram'; + + // Reset copy button states + this.resetCopyButton('copyJsonBtn'); + this.resetCopyButton('copyDiagramBtn'); + } + + async toggleJsonView() { + if (!this.currentWorkflow) return; + + const isVisible = !this.elements.jsonSection.classList.contains('hidden'); + + if (isVisible) { + this.elements.jsonSection.classList.add('hidden'); + this.elements.viewJsonBtn.textContent = '📄 View JSON'; + } else { + try { + this.elements.jsonViewer.textContent = 'Loading...'; + this.elements.jsonSection.classList.remove('hidden'); + this.elements.viewJsonBtn.textContent = '📄 Hide JSON'; + + const data = await this.apiCall(`/workflows/${this.currentWorkflow.filename}`); + const jsonString = JSON.stringify(data.raw_json, null, 2); + this.currentJsonData = jsonString; + this.elements.jsonViewer.textContent = jsonString; + } catch (error) { + this.elements.jsonViewer.textContent = 'Error loading JSON: ' + error.message; + this.currentJsonData = null; + } + } + } + + async toggleDiagramView() { + if (!this.currentWorkflow) return; + + const isVisible = !this.elements.diagramSection.classList.contains('hidden'); + + if (isVisible) { + this.elements.diagramSection.classList.add('hidden'); + this.elements.viewDiagramBtn.textContent = '📊 View Diagram'; + } else { + try { + this.elements.diagramViewer.textContent = 'Loading diagram...'; + this.elements.diagramSection.classList.remove('hidden'); + this.elements.viewDiagramBtn.textContent = '📊 Hide Diagram'; + + const data = await this.apiCall(`/workflows/${this.currentWorkflow.filename}/diagram`); + this.currentDiagramData = data.diagram; + + // Create a Mermaid diagram that will be rendered + this.elements.diagramViewer.innerHTML = ` +
${data.diagram}
+ `; + + // Re-initialize Mermaid for the new diagram + if (typeof mermaid !== 'undefined') { + mermaid.init(undefined, this.elements.diagramViewer.querySelector('.mermaid')); + } + } catch (error) { + this.elements.diagramViewer.textContent = 'Error loading diagram: ' + error.message; + this.currentDiagramData = null; + } + } + } + + updateLoadMoreButton() { + const hasMore = this.state.currentPage < this.state.totalPages; + + if (hasMore && this.state.workflows.length > 0) { + this.elements.loadMoreContainer.classList.remove('hidden'); + } else { + this.elements.loadMoreContainer.classList.add('hidden'); + } + } + + showState(state) { + // Hide all states + this.elements.loadingState.classList.add('hidden'); + this.elements.errorState.classList.add('hidden'); + this.elements.noResultsState.classList.add('hidden'); + this.elements.workflowGrid.classList.add('hidden'); + + // Show the requested state + switch (state) { + case 'loading': + this.elements.loadingState.classList.remove('hidden'); + break; + case 'error': + this.elements.errorState.classList.remove('hidden'); + break; + case 'no-results': + this.elements.noResultsState.classList.remove('hidden'); + break; + case 'content': + this.elements.workflowGrid.classList.remove('hidden'); + break; + } + } + + showError(message) { + this.elements.errorMessage.textContent = message; + this.showState('error'); + } + + escapeHtml(text) { + const div = document.createElement('div'); + div.textContent = text; + return div.innerHTML; + } + + async copyToClipboard(text, buttonId) { + if (!text) { + console.warn('No content to copy'); + return; + } + + try { + await navigator.clipboard.writeText(text); + this.showCopySuccess(buttonId); + } catch (error) { + // Fallback for older browsers + this.fallbackCopyToClipboard(text, buttonId); + } + } + + fallbackCopyToClipboard(text, buttonId) { + const textArea = document.createElement('textarea'); + textArea.value = text; + textArea.style.position = 'fixed'; + textArea.style.left = '-999999px'; + textArea.style.top = '-999999px'; + document.body.appendChild(textArea); + textArea.focus(); + textArea.select(); + + try { + document.execCommand('copy'); + this.showCopySuccess(buttonId); + } catch (error) { + console.error('Failed to copy text: ', error); + } finally { + document.body.removeChild(textArea); + } + } + + showCopySuccess(buttonId) { + const button = document.getElementById(buttonId); + if (!button) return; + + const originalText = button.innerHTML; + button.innerHTML = '✅ Copied!'; + button.classList.add('copied'); + + setTimeout(() => { + button.innerHTML = originalText; + button.classList.remove('copied'); + }, 2000); + } + + resetCopyButton(buttonId) { + const button = document.getElementById(buttonId); + if (!button) return; + + button.innerHTML = '📋 Copy'; + button.classList.remove('copied'); + } + } + + // Initialize the app + document.addEventListener('DOMContentLoaded', () => { + window.workflowApp = new WorkflowApp(); + }); + + \ No newline at end of file