-
-
Notifications
You must be signed in to change notification settings - Fork 1
Gsoc workflow dileep #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 55 commits
Commits
Show all changes
80 commits
Select commit
Hold shift + click to select a range
80d1ffa
initial file setup for the workflow graphical view
Dileepadari 29f35db
initial setup done with vue.js rendering
Dileepadari 3a86a6e
menu options added in the UI
Dileepadari 3bfb0ad
menu options added in the UI
Dileepadari 9f2a264
menu options added in the UI
Dileepadari f918892
menu options added in the UI
Dileepadari 3a57671
create the improved version of the UI
Dileepadari 638815f
panel created with some collisions
Dileepadari d7e9e98
layout changed and made it consistent
Dileepadari b199e86
custom css added and enhanced canvas
Dileepadari 1e3ff7c
added some functions and cleaned up code
Dileepadari 211d03f
added stages to the canvas
Dileepadari ef15204
adding the initial version of transitions
Dileepadari eaa0ec0
added the transitions and the placement logic and initial setup of fu…
Dileepadari 2ec20b8
added all the required functions and the getters and setter using aja…
Dileepadari 9a7ded3
made Api setup and all the required getters and initial setup for the…
Dileepadari 0106cd4
Added Undo and Redo Logic
Dileepadari 22af2dd
Cleared errors in Api calls
Dileepadari 77febbd
added modals for the add stage and transitions
Dileepadari 6729a5b
stages and transitions modals connected to existing logic
Dileepadari 693efae
positions fixed and undo, redo fixed
Dileepadari f802d55
delete stage completely executed
Dileepadari e1937d3
transition deletion and edit added and layout enhanced
Dileepadari 239deee
Added Accessibility needs and shortcuts (To be Enhanced)
Dileepadari 48504bf
some enhancements done
Dileepadari fff2f64
Save functionality and other validations done
Dileepadari 8187d7d
updated the auto saving for positions, translations updated and the a…
Dileepadari 69a901a
modal adjusted and some enhancements done
Dileepadari 03f3fdd
layout changed and made code modular
Dileepadari 06a36ad
improved the delete logic
Dileepadari 1c38d65
refactored code without delete functionality
Dileepadari 439e5d9
Merge remote-tracking branch 'origin/gsoc-workflow' into gsoc-workflo…
bembelimen 5153db2
the modal logic enhnaced using joomla.dialog
Dileepadari c20e368
validation added for the html respose of delete api
Dileepadari 542ad2c
validation added for the html respose of delete api
Dileepadari 2113502
shortcuts added and validated
Dileepadari bfb0410
undo and redo added for position ajax call
Dileepadari 6bcd4e1
landmarks for keyboard navigation improved
Dileepadari 53f199d
github linting styles adjusted
Dileepadari 70b642a
linting and css issues cleared
Dileepadari f098b47
some more refactoring
Dileepadari ae05b98
ceared lint issues again
Dileepadari 1958429
adjusted css alignments
Dileepadari 14fc988
all linting issues cleared
Dileepadari a799a07
css issues cleared and tab logic enhanced
Dileepadari 4e50ea1
fit view adjusted and some css edits done
Dileepadari bedd9e8
delete logic changed to json by overloading
Dileepadari 5c66af1
language strings and validation resolved
Dileepadari c2cede8
some linting validation
Dileepadari 56d2258
transition mode removed and positions bug fixed
Dileepadari fae346b
bugs cleared for positions and undo, fixed dot warnings
Dileepadari 9e5f2b3
minimap minimize logic added
Dileepadari b4dc905
permissions in backend implemented
Dileepadari d0c04ad
all permissions logic implemented and transition add by drag implemented
Dileepadari ab0128b
Merge remote-tracking branch 'Joomla/6.0-dev' into gsoc-workflow-dileep
bembelimen cd2eaed
changes done for review comments
Dileepadari 900d128
Merge branch 'gsoc-workflow-dileep' of https://github.com/joomla-proj…
Dileepadari 2288738
changes done for review comments:linting
Dileepadari 48e024a
minor fix in css
Dileepadari 5a533ca
js seperated to files
Dileepadari b63d859
small correction
Dileepadari 16e1dc1
transitions dropdown added without keyboard support
Dileepadari a446fc0
implemented all the changes regarding dropdowns
Dileepadari 2bb7f9c
deprecated functions removed
Dileepadari 80cc021
accessibility improved
Dileepadari 2897829
code quality increased in js
Dileepadari d8b3d26
Merge pull request #15 from joomla-projects/gsoc-workflow-experiment
Dileepadari bc7a18f
accessibility improved
Dileepadari 9bd6574
edge and stage layout changed
Dileepadari 245572d
accessibilityy fixer script added
Dileepadari 8402df4
css added
Dileepadari 0a56846
color contrast isues cleared
Dileepadari 0adc955
Merge remote-tracking branch 'Joomla/6.0-dev' into gsoc25/gsoc-workfl…
bembelimen 53d68c1
some changes for options dropdown and semantics
Dileepadari fc54e8e
changes for the keyboard navigation
Dileepadari 73b0ae4
sql changes
Dileepadari 9fe999a
css lint fixed
Dileepadari fcb3192
changed shortcuts
Dileepadari df147bb
removed unused dependency
Dileepadari f1af875
Added visual graph feature for non Admins in article at run transitio…
Dileepadari File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
1 change: 1 addition & 0 deletions
1
administrator/components/com_admin/sql/updates/mysql/6.0.0-2025-07-03.sql
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| ALTER TABLE `#__workflow_stages` ADD COLUMN `position` text DEFAULT NULL AFTER `default`; |
1 change: 1 addition & 0 deletions
1
administrator/components/com_admin/sql/updates/postgresql/6.0.0-2025-07-03.sql
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| ALTER TABLE "#__workflow_stages" ADD COLUMN "position" text DEFAULT NULL; |
45 changes: 45 additions & 0 deletions
45
administrator/components/com_workflow/resources/scripts/app/Event.es6.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| /** | ||
| * Simple Event Bus for cross-module communication | ||
| * Used to communicate between Joomla buttons and Vue app | ||
| */ | ||
| export default new class EventBus { | ||
| /** | ||
| * Internal registry of events | ||
| * @type {Object<string, Function[]>} | ||
| */ | ||
| constructor() { | ||
| this.events = {}; | ||
| } | ||
|
|
||
| /** | ||
| * Trigger a custom event with optional payload | ||
| * @param {string} event - Event name | ||
| * @param {*} [data=null] - Optional payload | ||
| */ | ||
| fire(event, data = null) { | ||
| (this.events[event] || []).forEach((fn) => fn(data)); | ||
| } | ||
|
|
||
| /** | ||
| * Register a callback for an event | ||
| * @param {string} event - Event name | ||
| * @param {Function} callback - Function to invoke on event | ||
| */ | ||
| listen(event, callback) { | ||
| if (!this.events[event]) { | ||
| this.events[event] = []; | ||
| } | ||
| this.events[event].push(callback); | ||
| } | ||
|
|
||
| /** | ||
| * Remove a listener from an event | ||
| * @param {string} event - Event name | ||
| * @param {Function} callback - Function to remove | ||
| */ | ||
| off(event, callback) { | ||
| if (this.events[event]) { | ||
| this.events[event] = this.events[event].filter((fn) => fn !== callback); | ||
| } | ||
| } | ||
| }(); |
206 changes: 206 additions & 0 deletions
206
administrator/components/com_workflow/resources/scripts/app/WorkflowGraphApi.es6.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,206 @@ | ||
| /** | ||
| * Handles API communication for the workflow graph. | ||
| */ | ||
| class WorkflowGraphApi { | ||
| /** | ||
| * Initializes the WorkflowGraphApi instance. | ||
| * | ||
| * @throws {TypeError} If required options are missing. | ||
| */ | ||
| constructor() { | ||
| const { | ||
| apiBaseUrl, | ||
| extension, | ||
| } = Joomla.getOptions('com_workflow', {}); | ||
|
|
||
| if (!apiBaseUrl) { | ||
| throw new TypeError(Joomla.Text._('COM_WORKFLOW_GRAPH_API_BASEURL_NOT_SET', 'Workflow API baseUrl is not defined')); | ||
| } | ||
|
|
||
| if (!extension) { | ||
| throw new TypeError(Joomla.Text._('COM_WORKFLOW_GRAPH_ERROR_EXTENSION_NOT_SET', 'Workflow extension is not set')); | ||
| } | ||
|
|
||
| this.baseUrl = apiBaseUrl; | ||
| this.extension = extension; | ||
| this.csrfToken = Joomla.getOptions('csrf.token', null); | ||
|
|
||
| if (!this.csrfToken) { | ||
| throw new TypeError(Joomla.Text._('COM_WORKFLOW_GRAPH_ERROR_CSRF_TOKEN_NOT_SET', 'CSRF token is not set')); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Makes a request using Joomla.request with better error handling. | ||
| * | ||
| * @param {string} url - The endpoint relative to baseUrl. | ||
| * @param {Object} [options={}] - Request config (method, data, headers). | ||
| * @returns {Promise<any>} The parsed response or error. | ||
| */ | ||
| async makeRequest(url, options = {}) { | ||
| const headers = options.headers || {}; | ||
| headers['X-Requested-With'] = 'XMLHttpRequest'; | ||
| options.headers = headers; | ||
| options[this.csrfToken] = 1; | ||
|
|
||
| return new Promise((resolve, reject) => { | ||
| Joomla.request({ | ||
| url: `${this.baseUrl}${url}&extension=${this.extension}`, | ||
| ...options, | ||
| onSuccess: (response) => { | ||
| const data = JSON.parse(response); | ||
| resolve(data); | ||
| }, | ||
| onError: (xhr) => { | ||
| let message = 'Network error'; | ||
| try { | ||
| const errorData = JSON.parse(xhr.responseText); | ||
| message = errorData.data || errorData.message || message; | ||
| } catch (e) { | ||
| message = xhr.statusText || message; | ||
| } | ||
| if (window.Joomla && window.Joomla.renderMessages) { | ||
| window.Joomla.renderMessages({ error: [message] }); | ||
| } | ||
| reject(new Error(message)); | ||
| }, | ||
| }); | ||
| }); | ||
| } | ||
|
|
||
| /** | ||
| * Fetches workflow data by ID. | ||
| * | ||
| * @param {number} id - Workflow ID. | ||
| * @returns {Promise<Object|null>} | ||
| */ | ||
| async getWorkflow(id) { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you work with some function comments to describe what the function does and what parameters are expected etc. (also for the other functions) |
||
| return this.makeRequest(`&task=graph.getWorkflow&workflow_id=${id}&format=json`); | ||
| } | ||
|
|
||
| /** | ||
| * Fetches stages for a given workflow. | ||
| * | ||
| * @param {number} workflowId - Workflow ID. | ||
| * @returns {Promise<Object[]|null>} | ||
| */ | ||
| async getStages(workflowId) { | ||
| return this.makeRequest(`&task=graph.getStages&workflow_id=${workflowId}&format=json`); | ||
| } | ||
|
|
||
| /** | ||
| * Fetches transitions for a given workflow. | ||
| * | ||
| * @param {number} workflowId - Workflow ID. | ||
| * @returns {Promise<Object[]|null>} | ||
| */ | ||
| async getTransitions(workflowId) { | ||
| return this.makeRequest(`&task=graph.getTransitions&workflow_id=${workflowId}&format=json`); | ||
| } | ||
|
|
||
| /** | ||
| * Deletes a stage from a workflow. | ||
| * | ||
| * @param {number} id - Stage ID. | ||
| * @param {number} workflowId - Workflow ID. | ||
| * @param {boolean} [stageDelete=0] - Optional flag to indicate if the stage should be deleted or just trashed. | ||
| * | ||
| * @returns {Promise<boolean>} | ||
| */ | ||
| async deleteStage(id, workflowId, stageDelete = false) { | ||
| try { | ||
| const formData = new FormData(); | ||
| formData.append('cid[]', id); | ||
| formData.append('workflow_id', workflowId); | ||
| formData.append('type', 'stage'); | ||
| formData.append(this.csrfToken, '1'); | ||
|
|
||
| const response = await this.makeRequest(`&task=${stageDelete ? 'graph.delete' : 'graph.trash'}&workflow_id=${workflowId}&format=json`, { | ||
| method: 'POST', | ||
| data: formData, | ||
| }); | ||
|
|
||
| if (response && response.success) { | ||
| if (window.Joomla && window.Joomla.renderMessages) { | ||
| window.Joomla.renderMessages({ | ||
| success: [response?.data?.message || response?.message], | ||
| }); | ||
| } | ||
| } | ||
| } catch (error) { | ||
| window.WorkflowGraph.Event.fire('Error', { error: error.message }); | ||
| throw error; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Deletes a transition from a workflow. | ||
| * | ||
| * @param {number} id - Transition ID. | ||
| * @param {number} workflowId - Workflow ID. | ||
| * @param {boolean} [transitionDelete=false] - Optional flag to indicate if the transition should be deleted or just trashed. | ||
| * | ||
| * @returns {Promise<boolean>} | ||
| */ | ||
| async deleteTransition(id, workflowId, transitionDelete = false) { | ||
| try { | ||
| const formData = new FormData(); | ||
| formData.append('cid[]', id); | ||
| formData.append('workflow_id', workflowId); | ||
| formData.append('type', 'transition'); | ||
| formData.append(this.csrfToken, '1'); | ||
|
|
||
| const response = await this.makeRequest(`&task=${transitionDelete ? 'graph.delete' : 'graph.trash'}&workflow_id=${workflowId}&format=json`, { | ||
| method: 'POST', | ||
| data: formData, | ||
| }); | ||
|
|
||
| if (response && response.success) { | ||
| if (window.Joomla && window.Joomla.renderMessages) { | ||
| window.Joomla.renderMessages({ | ||
| success: [response?.data?.message || response?.message], | ||
| }); | ||
| } | ||
| } | ||
| } catch (error) { | ||
| window.WorkflowGraph.Event.fire('Error', { error: error.message }); | ||
| throw error; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Updates the position of a stage. | ||
| * | ||
| * @param {number} workflowId - Workflow ID. | ||
| * @param {Object} positions - Position objects {x, y} of updated stages. | ||
| * @returns {Promise<Object|null>} | ||
| */ | ||
| async updateStagePosition(workflowId, positions) { | ||
| try { | ||
| const formData = new FormData(); | ||
| formData.append('workflow_id', workflowId); | ||
| formData.append(this.csrfToken, '1'); | ||
|
|
||
| if (positions === null || Object.keys(positions).length === 0) { | ||
| return true; | ||
| } | ||
|
|
||
| Object.entries(positions).forEach(([id, position]) => { | ||
| formData.append(`positions[${id}][x]`, position.x); | ||
| formData.append(`positions[${id}][y]`, position.y); | ||
| }); | ||
|
|
||
| const response = await this.makeRequest('&task=stages.updateStagesPosition&format=json', { | ||
| method: 'POST', | ||
| data: formData, | ||
| }); | ||
|
|
||
| return !!(response && response.success); | ||
| } catch (error) { | ||
| window.WorkflowGraph.Event.fire('Error', { error }); | ||
| throw error; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| export default new WorkflowGraphApi(); | ||
68 changes: 68 additions & 0 deletions
68
administrator/components/com_workflow/resources/scripts/components/App.vue
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| <template> | ||
| <div | ||
| id="workflow-app" | ||
| class="workflow-app-container d-flex flex-column flex-grow-1 min-vh-80" | ||
| role="application" | ||
| aria-label="appTitle" | ||
| > | ||
| <div | ||
| class="d-flex flex-column flex-shrink-0" | ||
| role="banner" | ||
| > | ||
| <WorkflowTitlebar | ||
| :save-status="saveStatus" | ||
| /> | ||
| </div> | ||
| <div class="d-flex flex-grow-1 overflow-hidden"> | ||
| <div | ||
| id="main-canvas" | ||
| class="flex-grow-1 position-relative" | ||
| role="main" | ||
| aria-labelledby="workflow-heading" | ||
| > | ||
| <WorkflowCanvas | ||
| ref="canvas" | ||
| :save-status="saveStatus" | ||
| :set-save-status="setSaveStatus" | ||
| @focus-request="handleCanvasFocus" | ||
| /> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </template> | ||
|
|
||
| <script setup> | ||
| import { ref, onMounted } from 'vue'; | ||
| import { useStore } from 'vuex'; | ||
| import WorkflowTitlebar from './Titlebar.vue'; | ||
| import WorkflowCanvas from './canvas/WorkflowCanvas.vue'; | ||
|
|
||
| const store = useStore(); | ||
| const saveStatus = ref('upToDate'); | ||
| function setSaveStatus(val) { | ||
| saveStatus.value = val; | ||
| } | ||
| const canvas = ref(null); | ||
|
|
||
| function handleCanvasFocus() { | ||
| canvas.value?.focus(); | ||
| } | ||
|
|
||
| onMounted(() => { | ||
| const { workflowId: idFromOpts = null } = Joomla.getOptions('com_workflow', {}); | ||
| const idFromURL = parseInt(new URL(window.location.href).searchParams.get('id'), 10); | ||
| const workflowIdFinal = idFromOpts || idFromURL; | ||
|
|
||
| if (workflowIdFinal !== null && !Number.isNaN(workflowIdFinal)) { | ||
| store.dispatch('loadWorkflow', workflowIdFinal); | ||
| } else { | ||
| throw new Error('COM_WORKFLOW_GRAPH_ERROR_INVALID_ID'); | ||
| } | ||
| }); | ||
| </script> | ||
|
|
||
| <script> | ||
| export default { | ||
| name: 'WorkflowGraphApp', | ||
| }; | ||
| </script> |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.