diff --git a/src/sdk/MessageBus.ts b/src/sdk/MessageBus.ts index 5ae9ef9b..2712bead 100644 --- a/src/sdk/MessageBus.ts +++ b/src/sdk/MessageBus.ts @@ -369,179 +369,112 @@ export default class MessageBus { } // Returns all processes details, including processes we only have public data for - public getAllProcessesDecoded(filterPublicValues: (publicValues: { [key: string]: any }) => boolean): Promise { - return new Promise((resolve: (processesDecoded: any[]) => void, reject: (error: string) => void) => { - this.getAllProcesses().then(async (processes: any) => { - const processesDecoded: any[] = []; - - for (const processId of Object.keys(processes)) { - const process = processes[processId]; - if (!process.states) { - continue; - } - - const publicDataDecoded: { [key: string]: any } = {}; - - for (let stateId = 0; stateId < process.states.length - 1; stateId++) { - const state = process.states[stateId]; - if (!state) { - continue; - } - - const publicDataEncoded = state.public_data; - if (!publicDataEncoded) { - continue; - } - - for (const key of Object.keys(publicDataEncoded)) { - publicDataDecoded[key] = await this.getPublicData(publicDataEncoded[key]); - } - } - - if (!filterPublicValues(publicDataDecoded)) { - continue; - } - - let processDecoded: any; - - for (let stateId = 0; stateId < process.states.length - 1; stateId++) { - const lastState = process.states[stateId]; - if (!lastState) { - continue; - } - - const lastStateId = lastState.state_id; - if (!lastStateId) { - continue; - } - - try { - let processData = await this.getData(processId, lastStateId); - if (!processData) { - continue; - } - - const isEmpty = Object.keys(processData).length === 0; - if (isEmpty) { - continue; - } - - for (const key of Object.keys(publicDataDecoded)) { - processData[key] = publicDataDecoded[key]; - } - processData = MapUtils.toJson(processData); - - if (!processDecoded) { - processDecoded = { - processId, - lastStateId, - processData, - }; - } else { - for (const key of Object.keys(processData)) { - processDecoded.processData[key] = processData[key]; - } - processDecoded.lastStateId = lastStateId; - } - } catch (error) { - console.error(error); - } - } - - processesDecoded.push(processDecoded); - } - - resolve(processesDecoded); - }).catch(reject); - }); + public getAllProcessesDecoded(filterData: (processId: string, data: { [key: string]: any }) => boolean): Promise<{ [processId: string]: { [key: string]: any } }> { + return this.getAllProcesses().then((processes: { [processId: string]: any }) => this.getProcessesDecodedInternal( + processes, + filterData, + )); } // Returns details about processes that we are involved in - public getProcessesDecoded(filterPublicValues: (publicValues: { [key: string]: any }) => boolean): Promise { - return new Promise((resolve: (processesDecoded: any[]) => void, reject: (error: string) => void) => { - this.getProcesses().then(async (processes: any) => { - const processesDecoded: any[] = []; + public getProcessesDecoded(filterData: (processId: string, data: { [key: string]: any }) => boolean): Promise<{ [processId: string]: { [key: string]: any } }> { + return this.getProcesses().then((processes: { [processId: string]: any }) => this.getProcessesDecodedInternal( + processes, + filterData, + )); + } - for (const processId of Object.keys(processes)) { - const process = processes[processId]; - if (!process.states) { - continue; - } + // Returns the data of any process we have the id for + public getProcessData(processId: string): Promise<{ [key: string]: any }> { + return this.getAllProcesses().then((processes: { [processId: string]: any }) => this.getProcessesDecodedInternal( + { [processId]: processes[processId] }, + () => true, // We don't filter + )); + } - const publicDataDecoded: { [key: string]: any } = {}; + /** + * Internal method that handles the common logic for both getProcessesDecoded and getAllProcessesDecoded + * @param processes - Processes to decode + * @param filterData - Filter function for all data (public + private) + * @returns Promise with decoded processes map + */ + private async getProcessesDecodedInternal( + processes: { [processId: string]: { states: any[] } }, + filterData: (processId: string, data: { [key: string]: any }) => boolean + ): Promise<{ [processId: string]: { [key: string]: any } }> { + const processesDecoded: { [processId: string]: { [key: string]: any } } = {}; - for (let stateId = 0; stateId < process.states.length - 1; stateId++) { - const state = process.states[stateId]; - if (!state) { - continue; - } + for (const processId of Object.keys(processes)) { + const process = processes[processId]; + if (!process || !process.states) { + continue; + } - const publicDataEncoded = state.public_data; - if (!publicDataEncoded) { - continue; - } + // We get the last commited state + const lastCommitedStateIndex = process.states.findLastIndex((state: any) => state.commited_in !== process.states[process.states.length - 1].commited_in); + const lastCommitedState = process.states[lastCommitedStateIndex]; + if (!lastCommitedState) { + continue; + } - for (const key of Object.keys(publicDataEncoded)) { - publicDataDecoded[key] = await this.getPublicData(publicDataEncoded[key]); - } - } + const publicDataDecoded: { [key: string]: any } = {}; + // We simply take the public data from the last commited state - if (!filterPublicValues(publicDataDecoded)) { - continue; - } + const publicDataEncoded = lastCommitedState.public_data; + if (!publicDataEncoded) { + continue; + } - let processDecoded: any; + try { + for (const key of Object.keys(publicDataEncoded)) { + publicDataDecoded[key] = await this.getPublicData(publicDataEncoded[key]); + } + } catch (error) { + console.error(error); + } - for (let stateId = 0; stateId < process.states.length - 1; stateId++) { - const lastState = process.states[stateId]; - if (!lastState) { - continue; - } + const processData = publicDataDecoded; - const lastStateId = lastState.state_id; - if (!lastStateId) { - continue; - } - - try { - let processData = await this.getData(processId, lastStateId); - if (!processData) { - continue; - } - - const isEmpty = Object.keys(processData).length === 0; - if (isEmpty) { - continue; - } - - for (const key of Object.keys(publicDataDecoded)) { - processData[key] = publicDataDecoded[key]; - } - processData = MapUtils.toJson(processData); - - if (!processDecoded) { - processDecoded = { - processId, - lastStateId, - processData, - }; - } else { - for (const key of Object.keys(processData)) { - processDecoded.processData[key] = processData[key]; - } - processDecoded.lastStateId = lastStateId; - } - } catch (error) { - console.error(error); - } - } - - processesDecoded.push(processDecoded); + // Process all states backward to build the final decoded object + for (let stateIndex = lastCommitedStateIndex; stateIndex >= 0; stateIndex--) { + const state = process.states[stateIndex]; + if (!state) { + continue; } - resolve(processesDecoded); - }).catch(reject); - }); + const stateId = state.state_id; + if (!stateId) { + continue; + } + + try { + const stateData = await this.getData(processId, stateId); + if (!stateData || Object.keys(stateData).length === 0) { + continue; + } + + for (const key of Object.keys(stateData)) { + // If we already have the key, it means the same data was update in a later state, so don't overwrite it + if (processData[key]) { + continue; + } else { + processData[key] = stateData[key]; + } + } + } catch (error) { + console.error(error); + } + } + + // filter data if needed + if (filterData && !filterData(processId, processData)) { + continue; + } + + processesDecoded[processId] = processData; + } + + return processesDecoded; } public createProcess(processData: any, privateFields: string[], roles: {}): Promise {