init_updateMyProcesses_retrieve_ws_response-doing

This commit is contained in:
NicolasCantu 2025-02-10 09:18:29 +01:00
parent a4d0f5a843
commit d1cc2335e5
6 changed files with 410 additions and 195 deletions

203
process.diff Normal file
View File

@ -0,0 +1,203 @@
diff --git a/src/pages/process/process.ts b/src/pages/process/process.ts
index 27c1301..a4f8943 100755
--- a/src/pages/process/process.ts
+++ b/src/pages/process/process.ts
@@ -2,9 +2,15 @@ import { addSubscription } from '../../utils/subscription.utils';
import Services from '../../services/service';
import { getCorrectDOM } from '~/utils/html.utils';
import { Process } from 'pkg/sdk_client';
+import chatStyle from '../../../public/style/chat.css?inline';
+import { Database } from '../../services/database.service';
+
+let myProcesses = new Set();
+let allProcesses = new Set();
// Initialize function, create initial tokens with itens that are already selected by the user
export async function init() {
+
const container = getCorrectDOM('process-list-4nk-component') as HTMLElement;
const element = container.querySelector('select') as HTMLSelectElement;
// Create div that wroaps all the elements inside (select, elements selected, search div) to put select inside
@@ -43,6 +49,23 @@ export async function init() {
wrapper.appendChild(search_div);
addPlaceholder(wrapper);
+
+ await loadAllProcesses();
+
+ const database = await Database.getInstance();
+
+ try {
+ await database.updateMyProcesses({ myProcessesId: Array.from(myProcesses) });
+ const updateProcesses = await database.updateMyProcesses({ myProcessesId: Array.from(myProcesses) });
+ console.log("UPDATE PROCESSES d'INIT: ", updateProcesses);
+ } catch (error) {
+ console.error("Error updating my processes:", error);
+ }
+
+
+
+
+
}
function removePlaceholder(wrapper: HTMLElement) {
@@ -155,62 +178,39 @@ function clearAutocompleteList(select: HTMLSelectElement) {
if (autocomplete_list) autocomplete_list.innerHTML = '';
}
-// Populate the autocomplete list following a given query from the user
-function populateAutocompleteList(select: HTMLSelectElement, query: string, dropdown = false) {
+async function populateAutocompleteList(select: HTMLSelectElement, query: string, dropdown = false) {
const { autocomplete_options } = getOptions(select);
- let options_to_show;
+ let options_to_show = [];
- if (dropdown) {
- let messagingCounter = 1;
- const messagingOptions = select.querySelectorAll('option[value="messaging"]');
-
- options_to_show = autocomplete_options.map(option => {
- if (option === 'messaging') {
- // Récupérer l'élément option correspondant au compteur actuel
- const currentOption = messagingOptions[messagingCounter - 1];
- const processId = currentOption?.getAttribute('data-process-id');
- console.log(`Mapping messaging ${messagingCounter} with processId:`, processId);
-
- const optionText = `messaging ${messagingCounter}`;
- messagingCounter++;
-
- // Stocker le processId dans un attribut data sur le select
- select.setAttribute(`data-messaging-id-${messagingCounter - 1}`, processId || '');
-
- return optionText;
- }
- return option;
- });
- } else {
- options_to_show = autocomplete(query, autocomplete_options);
- }
+ console.log(myProcesses);
+
+ const mineArray = Array.from(myProcesses);
+ const allArray = Array.from(allProcesses).filter(id => !myProcesses.has(id));
const wrapper = select.parentNode;
const input_search = wrapper?.querySelector('.search-container');
const autocomplete_list = wrapper?.querySelector('.autocomplete-list');
if (autocomplete_list) autocomplete_list.innerHTML = '';
- const result_size = options_to_show.length;
- if (result_size == 1) {
+ const addProcessToList = (processId:string, isMine: boolean) => {
const li = document.createElement('li');
- li.innerText = options_to_show[0];
- li.setAttribute('data-value', options_to_show[0]);
+ li.innerText = processId;
+ li.setAttribute("data-value", processId);
+
+ if (isMine) {
+ li.classList.add("my-process");
+ li.style.cssText = `color: var(--accent-color)`;
+ }
+
if (li) addSubscription(li, 'click', selectOption);
autocomplete_list?.appendChild(li);
- if (query.length == options_to_show[0].length) {
- const event = new Event('click');
- li.dispatchEvent(event);
- }
- } else if (result_size > 1) {
- for (let i = 0; i < result_size; i++) {
- const li = document.createElement('li');
- li.innerText = options_to_show[i];
- li.setAttribute('data-value', options_to_show[i]);
- if (li) addSubscription(li, 'click', selectOption);
- autocomplete_list?.appendChild(li);
- }
- } else {
+ };
+
+ mineArray.forEach(processId => addProcessToList(processId, true));
+ allArray.forEach(processId => addProcessToList(processId, false));
+
+ if (myProcesses.size === 0 && allProcesses.size === 0) {
const li = document.createElement('li');
li.classList.add('not-cursor');
li.innerText = 'No options found';
@@ -392,6 +392,20 @@ addSubscription(document, 'click', () => {
}
});
+async function loadAllProcesses() {
+ try {
+ const [allProcessesNew, myProcessesNew] = await Promise.all([
+ getProcesses(),
+ getMyProcesses()
+ ]);
+
+ myProcesses = myProcesses.union(myProcessesNew);
+ allProcesses = allProcesses.union(allProcessesNew);
+ } catch (error) {
+ console.error("Error loading processes:", error);
+ }
+}
+
async function showSelectedProcess(elem: MouseEvent) {
const container = getCorrectDOM('process-list-4nk-component') as HTMLElement;
@@ -539,43 +553,36 @@ async function getDescription(processId: string, process: Process): Promise<stri
return null;
}
-async function getProcesses(): Promise<any[]> {
+async function getProcesses(): Promise<Set<string>> {
const service = await Services.getInstance();
const processes = await service.getProcesses();
+ const processIds = new Set<string>(Object.keys(processes));
- const res = Object.entries(processes).map(([key, value]) => ({
- key,
- value,
- }));
-
- return res;
+ return processIds;
}
-async function getMyProcesses() {
+async function getMyProcesses(): Promise<Set<string>> {
const service = await Services.getInstance();
try {
const processes = await service.getProcesses();
- const userProcessSet = new Set();
-
+ const userProcessSet = new Set<string>();
+
for (const [processId, process] of Object.entries(processes)) {
let roles;
try {
- roles = await this.getRoles(process);
+ roles = await service.getRoles(process);
if (!roles) {
roles = await process.states[0].encrypted_pcd.roles;
}
+ console.log("ROLES: ", roles);
+
+ const hasCurrentUser = service.rolesContainsUs(roles);
- const hasCurrentUser = Object.values(roles).some(role =>
- service.rolesContainsUs(role)
- );
-
if (hasCurrentUser) {
userProcessSet.add(processId);
}
-
} catch (e) {
continue;
- console.error(`Error processing process ${processId}:`, e);
}
}

View File

@ -383,7 +383,7 @@ class ChatElement extends HTMLElement {
const processRoles = this.processRoles;
const selectedMember = this.selectedMember;
for (const child of children) {
const roles = await this.getRoles(JSON.parse(child));
const roles = await service.getRoles(JSON.parse(child));
// Check that we and the other members are in the role
if (!service.isChildRole(processRoles, roles)) {
console.error('Child process roles are not a subset of parent')
@ -489,7 +489,7 @@ class ChatElement extends HTMLElement {
if (description !== "dm") {
continue;
}
const roles = await this.getRoles(process);
const roles = await service.getRoles(process);
if (!service.rolesContainsMember(roles, recipientAddresses)) {
console.error('Member is not part of the process');
continue;
@ -911,44 +911,6 @@ class ChatElement extends HTMLElement {
roleElement.appendChild(memberList);
}
async getRoles(process: Process): Promise<any | null> {
const service = await Services.getInstance();
// Get the `commited_in` value of the last state and remove it from the array
const currentCommitedIn = process.states.pop()?.commited_in;
if (currentCommitedIn === undefined) {
return null; // No states available
}
// Find the last state where `commited_in` is different
let lastDifferentState = process.states.findLast(
state => state.commited_in !== currentCommitedIn
);
if (!lastDifferentState) {
// It means that we only have one state that is not commited yet, that can happen with process we just created
// let's assume that the right description is in the last concurrent state and not handle the (arguably rare) case where we have multiple concurrent states on a creation
lastDifferentState = process.states.pop();
}
if (!lastDifferentState || !lastDifferentState.pcd_commitment) {
return null;
}
// Take the roles out of the state
const roles = lastDifferentState!.pcd_commitment['roles'];
if (roles) {
const userDiff = await service.getDiffByValue(roles);
if (userDiff) {
console.log("Successfully retrieved userDiff:", userDiff);
return userDiff.new_value;
}
}
return null;
}
private async switchTab(tabType: string, tabs: NodeListOf<Element>) {
// Mettre à jour les classes des onglets
tabs.forEach(tab => {
@ -1046,7 +1008,7 @@ class ChatElement extends HTMLElement {
const oneProcess = process.states[0].commited_in;
let roles;
try {
roles = await this.getRoles(process);
roles = await service.getRoles(process);
if (!roles) {
roles = await process.states[0].encrypted_pcd.roles;
}
@ -1421,7 +1383,7 @@ class ChatElement extends HTMLElement {
for (const [processId, process] of Object.entries(processes)) {
let roles;
try {
roles = await this.getRoles(process);
roles = await service.getRoles(process);
if (!roles) {
roles = await process.states[0].encrypted_pcd.roles;
}
@ -1483,7 +1445,7 @@ class ChatElement extends HTMLElement {
const service = await Services.getInstance();
const process = await service.getProcess(this.processId);
const roles = await this.getRoles(process);
const roles = await service.getRoles(process);
if (roles === null) {
console.error('no roles in process');
return;

View File

@ -2,9 +2,15 @@ import { addSubscription } from '../../utils/subscription.utils';
import Services from '../../services/service';
import { getCorrectDOM } from '~/utils/html.utils';
import { Process } from 'pkg/sdk_client';
import chatStyle from '../../../public/style/chat.css?inline';
import { Database } from '../../services/database.service';
let myProcesses = new Set();
let allProcesses = new Set();
// Initialize function, create initial tokens with itens that are already selected by the user
export async function init() {
const container = getCorrectDOM('process-list-4nk-component') as HTMLElement;
const element = container.querySelector('select') as HTMLSelectElement;
// Create div that wroaps all the elements inside (select, elements selected, search div) to put select inside
@ -43,6 +49,16 @@ export async function init() {
wrapper.appendChild(search_div);
addPlaceholder(wrapper);
await loadAllProcesses();
const database = await Database.getInstance();
try {
await database.updateMyProcesses({ myProcessesId: Array.from(myProcesses) });
} catch (error) {
console.error("Error updating my processes:", error);
}
}
function removePlaceholder(wrapper: HTMLElement) {
@ -155,62 +171,39 @@ function clearAutocompleteList(select: HTMLSelectElement) {
if (autocomplete_list) autocomplete_list.innerHTML = '';
}
// Populate the autocomplete list following a given query from the user
function populateAutocompleteList(select: HTMLSelectElement, query: string, dropdown = false) {
async function populateAutocompleteList(select: HTMLSelectElement, query: string, dropdown = false) {
const { autocomplete_options } = getOptions(select);
let options_to_show;
let options_to_show = [];
if (dropdown) {
let messagingCounter = 1;
const messagingOptions = select.querySelectorAll('option[value="messaging"]');
options_to_show = autocomplete_options.map(option => {
if (option === 'messaging') {
// Récupérer l'élément option correspondant au compteur actuel
const currentOption = messagingOptions[messagingCounter - 1];
const processId = currentOption?.getAttribute('data-process-id');
console.log(`Mapping messaging ${messagingCounter} with processId:`, processId);
const optionText = `messaging ${messagingCounter}`;
messagingCounter++;
// Stocker le processId dans un attribut data sur le select
select.setAttribute(`data-messaging-id-${messagingCounter - 1}`, processId || '');
return optionText;
}
return option;
});
} else {
options_to_show = autocomplete(query, autocomplete_options);
}
console.log(myProcesses);
const mineArray = Array.from(myProcesses);
const allArray = Array.from(allProcesses).filter(id => !myProcesses.has(id));
const wrapper = select.parentNode;
const input_search = wrapper?.querySelector('.search-container');
const autocomplete_list = wrapper?.querySelector('.autocomplete-list');
if (autocomplete_list) autocomplete_list.innerHTML = '';
const result_size = options_to_show.length;
if (result_size == 1) {
const addProcessToList = (processId:string, isMine: boolean) => {
const li = document.createElement('li');
li.innerText = options_to_show[0];
li.setAttribute('data-value', options_to_show[0]);
li.innerText = processId;
li.setAttribute("data-value", processId);
if (isMine) {
li.classList.add("my-process");
li.style.cssText = `color: var(--accent-color)`;
}
if (li) addSubscription(li, 'click', selectOption);
autocomplete_list?.appendChild(li);
if (query.length == options_to_show[0].length) {
const event = new Event('click');
li.dispatchEvent(event);
}
} else if (result_size > 1) {
for (let i = 0; i < result_size; i++) {
const li = document.createElement('li');
li.innerText = options_to_show[i];
li.setAttribute('data-value', options_to_show[i]);
if (li) addSubscription(li, 'click', selectOption);
autocomplete_list?.appendChild(li);
}
} else {
};
mineArray.forEach(processId => addProcessToList(processId, true));
allArray.forEach(processId => addProcessToList(processId, false));
if (myProcesses.size === 0 && allProcesses.size === 0) {
const li = document.createElement('li');
li.classList.add('not-cursor');
li.innerText = 'No options found';
@ -392,6 +385,20 @@ addSubscription(document, 'click', () => {
}
});
async function loadAllProcesses() {
try {
const [allProcessesNew, myProcessesNew] = await Promise.all([
getProcesses(),
getMyProcesses()
]);
myProcesses = myProcesses.union(myProcessesNew);
allProcesses = allProcesses.union(allProcessesNew);
} catch (error) {
console.error("Error loading processes:", error);
}
}
async function showSelectedProcess(elem: MouseEvent) {
const container = getCorrectDOM('process-list-4nk-component') as HTMLElement;
@ -539,43 +546,36 @@ async function getDescription(processId: string, process: Process): Promise<stri
return null;
}
async function getProcesses(): Promise<any[]> {
async function getProcesses(): Promise<Set<string>> {
const service = await Services.getInstance();
const processes = await service.getProcesses();
const processIds = new Set<string>(Object.keys(processes));
const res = Object.entries(processes).map(([key, value]) => ({
key,
value,
}));
return res;
return processIds;
}
async function getMyProcesses() {
async function getMyProcesses(): Promise<Set<string>> {
const service = await Services.getInstance();
try {
const processes = await service.getProcesses();
const userProcessSet = new Set();
const userProcessSet = new Set<string>();
for (const [processId, process] of Object.entries(processes)) {
let roles;
try {
roles = await this.getRoles(process);
roles = await service.getRoles(process);
if (!roles) {
roles = await process.states[0].encrypted_pcd.roles;
}
console.log("ROLES: ", roles);
const hasCurrentUser = service.rolesContainsUs(roles);
const hasCurrentUser = Object.values(roles).some(role =>
service.rolesContainsUs(role)
);
if (hasCurrentUser) {
userProcessSet.add(processId);
}
} catch (e) {
continue;
console.error(`Error processing process ${processId}:`, e);
}
}

View File

@ -1,3 +1,6 @@
let myProcessesId = new Set();
let toDownload = [];
self.addEventListener('install', (event) => {
event.waitUntil(self.skipWaiting()); // Activate worker immediately
});
@ -23,64 +26,33 @@ self.addEventListener('message', async (event) => {
data: itemsWithFlag,
});
};
const scanMissingData = async () => {
const myProcesses = getProcesses(myProcessesId);
event.ports[0].postMessage({
type: 'TO_DOWNLOAD',
data: toDownload,
});
}
fetchNotifications();
setInterval(fetchNotifications, 2 * 60 * 1000);
scanMissingData();
setInterval(scanMissingData, 2 * 1000);
}
if (data.type === 'SCAN_PROCESS') {
if (data.type === 'UPDATE_PROCESSES') {
try {
const { myProcessesId } = data.payload;
const db = await openDatabase();
// Créer un tableau pour stocker toutes les promesses de processus
const processPromises = myProcessesId.map(async (processId) => {
// Récupérer le processus
const process = await new Promise((resolve, reject) => {
const tx = db.transaction('processes', 'readonly');
const store = tx.objectStore('processes');
const request = store.get(processId);
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
if (!process || !process.states || process.states.length === 0) {
throw new Error(`Process ${processId} not found or invalid`);
}
// Récupérer les diffs pour chaque état
const diffPromises = process.states.map(async (state) => {
return new Promise((resolve, reject) => {
const tx = db.transaction('diffs', 'readonly');
const store = tx.objectStore('diffs');
for (const hash of state.pcd_commitment) {
const request = store.get(hash);
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
}
});
});
const diffs = await Promise.all(diffPromises);
process.diffs = diffs.filter(diff => diff != null);
return process;
});
const results = await Promise.all(processPromises);
const { processIds } = data.payload;
for (const processId of processIds) {
myProcessesId.add(processId);
}
console.log(myProcessesId);
event.ports[0].postMessage({
status: 'success',
message: 'All processes scanned',
data: results
});
} catch (error) {
event.ports[0].postMessage({ status: 'error', message: error.message });
}
setInterval(fetchNotifications, 2 * 1000);
}
if (data.type === 'ADD_OBJECT') {
@ -123,31 +95,55 @@ async function openDatabase() {
// Function to get all processes because it is asynchronous
async function getAllProcesses() {
const db = await openDatabase();
return new Promise((resolve, reject) => {
if (!db) {
reject(new Error('Database is not available'));
return;
}
const tx = db.transaction('processes', 'readonly');
const store = tx.objectStore('processes');
// const request = store.openCursor();
// const processes = [];
const request = store.getAll();
request.onsuccess = (event) => {
// const cursor = event.target.result;
// if (cursor) {
// processes.push({ key: cursor.key, ...cursor.value });
// cursor.continue();
// } else {
// resolve(processes);
// }
const allProcesses = store.getAll();
resolve(allProcesses);
request.onsuccess = () => {
resolve(request.result);
};
request.onerror = (event) => {
reject(event.target.error);
request.onerror = () => {
reject(request.error);
};
});
};
async function getAllItemsWithFlag() {
async function getProcesses(processIds) {
if (!processIds || processIds.length === 0) {
return [];
}
const db = await openDatabase();
if (!db) {
throw new Error('Database is not available');
}
const tx = db.transaction('processes', 'readonly');
const store = tx.objectStore('processes');
const requests = processIds.map((processId) => {
return new Promise((resolve) => {
const request = store.get(processId);
request.onsuccess = () => resolve(request.result);
request.onerror = () => {
console.error(`Error fetching process ${processId}:`, request.error);
resolve(undefined);
};
});
});
const results = await Promise.all(requests);
return results.filter(result => result !== undefined);
}
async function getAllDiffsNeedValidation() {
const db = await openDatabase();
const allProcesses = await getAllProcesses();

View File

@ -1,13 +1,11 @@
import Services from './service';
class Database {
export class Database {
private static instance: Database;
private db: IDBDatabase | null = null;
private dbName: string = '4nk';
private dbVersion: number = 1;
private serviceWorkerRegistration: ServiceWorkerRegistration | null = null;
private messageChannel: MessageChannel = new MessageChannel();
private messageChannelForGet: MessageChannel = new MessageChannel();
private storeDefinitions = {
AnkLabels: {
name: 'labels',
@ -163,10 +161,29 @@ class Database {
}
};
private handleUpdateProcessesResponse = async (event: MessageEvent) => {
const data = event.data;
console.log('Received response from service worker (UPDATE_PROCESSES):', data);
for (const process of data.data) {
console.log("PROCESS: ", process);
}
};
// TODO : get the message from the service worker to the client
// we get an object, then we have to loop to look for the diffs
// for each hash in INDEXEDB --> request for true or false
// if the diffs is found, we have to add the diff to the object
// we have to do that for each object
private handleGetObjectResponse = (event: MessageEvent) => {
console.log('Received response from service worker (GET_OBJECT):', event.data);
};
public addObject(payload: { storeName: string; object: any; key: any }): Promise<void> {
return new Promise((resolve, reject) => {
// Check if the service worker is active
@ -202,6 +219,45 @@ class Database {
}
});
}
public updateMyProcesses(payload: { myProcessesId: string[] }): Promise<void> {
return new Promise((resolve, reject) => {
// Check if the service worker is active
if (!this.serviceWorkerRegistration?.active) {
reject(new Error('Service worker is not active'));
return;
}
// Create a message channel for communication
const messageChannel = new MessageChannel();
// Handle the response from the service worker
messageChannel.port1.onmessage = (event) => {
if (event.data.status === 'success') {
resolve();
} else {
const error = event.data.message;
reject(new Error(error || 'Unknown error occurred while scanning our processes'));
}
};
try {
console.log('Sending UPDATE_PROCESSES msg with payload', payload);
this.serviceWorkerRegistration.active.postMessage(
{
type: 'UPDATE_PROCESSES',
payload,
},
[messageChannel.port2],
);
} catch (error) {
reject(new Error(`Failed to send message to service worker: ${error}`));
}
});
}
public async getObject(storeName: string, key: string): Promise<any | null> {
const db = await this.getDb();

View File

@ -524,20 +524,20 @@ export default class Services {
// get the process
try {
const process = await this.getProcess(diff.process_id);
const state = process.states.find(state => state.state_id === diff.state_id);
if (state) {
// Now we return the encrypted value for that field
const cipher = state.encrypted_pcd[diff.field];
if (cipher) {
return cipher;
} else {
console.error('Failed to get encrypted value');
}
}
} catch (e) {
console.error('Failed to get process:', e);
return null;
}
const state = process.states.find(state => state.state_id === diff.state_id);
if (state) {
// Now we return the encrypted value for that field
const cipher = state.encrypted_pcd[diff.field];
if (cipher) {
return cipher;
} else {
console.error('Failed to get encrypted value');
}
}
return null;
}
@ -1280,37 +1280,35 @@ export default class Services {
}
public async getRoles(process: Process): Promise<any | null> {
public async getRoles(process: Process): Promise<Record<string, RoleDefinition>> {
const currentCommitedIn = process.states.pop()?.commited_in;
if (currentCommitedIn === undefined) {
return null;
return {};
}
let lastDifferentState = process.states.findLast(
state => state.commited_in !== currentCommitedIn
state => state.commited_in !== currentCommitedIn
);
if (!lastDifferentState) {
lastDifferentState = process.states.pop();
lastDifferentState = process.states.pop();
}
if (!lastDifferentState || !lastDifferentState.pcd_commitment) {
return null;
return {};
}
const roles = lastDifferentState!.pcd_commitment['roles'];
if (roles) {
const userDiff = await this.getDiffByValue(roles);
if (userDiff) {
console.log("Successfully retrieved userDiff:", userDiff);
return userDiff.new_value;
}
const userDiff = await this.getDiffByValue(roles);
if (userDiff) {
console.log("Successfully retrieved userDiff:", userDiff);
return userDiff.new_value;
}
}
return null;
return {};
}
}