Compare commits

..

4 Commits

Author SHA1 Message Date
Sosthene
94b6e58cd0 Display private data for each process 2025-06-15 10:37:08 +02:00
Sosthene
32d76e2328 Update getData 2025-06-15 10:35:24 +02:00
Sosthene
32b5f697c5 Rm dead code 2025-06-15 10:34:55 +02:00
Sosthene
ac68c1d4b1 make iframeUrl export 2025-06-15 10:34:20 +02:00
4 changed files with 94 additions and 67 deletions

View File

@ -14,7 +14,7 @@ import FolderModal from './components/FolderModal';
import { ProfilePrivateFields, setDefaultProfileRoles, type ProfileCreated, type ProfileData } from './sdk/models/ProfileData' import { ProfilePrivateFields, setDefaultProfileRoles, type ProfileCreated, type ProfileData } from './sdk/models/ProfileData'
import { FolderPrivateFields, setDefaultFolderRoles, type FolderCreated, type FolderData } from './sdk/models/FolderData' import { FolderPrivateFields, setDefaultFolderRoles, type FolderCreated, type FolderData } from './sdk/models/FolderData'
const iframeUrl = 'https://dev3.4nkweb.com' export const iframeUrl = 'https://dev3.4nkweb.com'
function App() { function App() {
const [receivedMessages, setReceivedMessages] = useState<{ timestamp: string; data: any }[]>([]) const [receivedMessages, setReceivedMessages] = useState<{ timestamp: string; data: any }[]>([])

View File

@ -172,3 +172,9 @@
margin-bottom: 0.25rem; margin-bottom: 0.25rem;
font-size: 0.8rem; font-size: 0.8rem;
} }
.process-actions {
margin-top: 20px;
padding: 10px;
text-align: center;
}

View File

@ -1,14 +1,14 @@
import { useState, memo } from 'react'; import { useState, memo } from 'react';
import './ProcessesViewer.css'; import './ProcessesViewer.css';
import { isFileBlob, type FileBlob } from '../sdk/models/Data';
import MessageBus from '../sdk/MessageBus';
import { iframeUrl } from '../App';
interface BlockState { interface BlockState {
commited_in: string; commited_in: string;
state_id: string; state_id: string;
pcd_commitment: Record<string, string>; pcd_commitment: Record<string, string>;
public_data: { public_data: Record<string, any>;
memberPublicName?: string | number[];
pairedAddresses?: string[] | number[];
};
// Autres propriétés disponibles si nécessaires // Autres propriétés disponibles si nécessaires
} }
@ -28,6 +28,7 @@ interface ProcessesViewerProps {
function ProcessesViewer({ processes, myProcesses }: ProcessesViewerProps) { function ProcessesViewer({ processes, myProcesses }: ProcessesViewerProps) {
const [expandedBlocks, setExpandedBlocks] = useState<string[]>([]); const [expandedBlocks, setExpandedBlocks] = useState<string[]>([]);
const [isFiltered, setIsFiltered] = useState<boolean>(false); const [isFiltered, setIsFiltered] = useState<boolean>(false);
const [privateData, setPrivateData] = useState<Record<string, Record<string, any>>>({});
const handleFilterClick = () => { const handleFilterClick = () => {
setIsFiltered(prev => !prev); setIsFiltered(prev => !prev);
@ -51,24 +52,49 @@ function ProcessesViewer({ processes, myProcesses }: ProcessesViewerProps) {
); );
}; };
const formatAddress = (address: string | number[] | undefined): string => { const fetchPrivateData = async (processId: string, stateId: string) => {
if (!address) return "Adresse non disponible"; if (!expandedBlocks.includes(processId) || !myProcesses.includes(processId)) {
return;
if (Array.isArray(address)) { }
// Si c'est un tableau de nombres, on le convertit en chaîne de caractères
try { try {
// Convertir les codes ASCII en caractères const messageBus = MessageBus.getInstance(iframeUrl);
const chars = address.map(code => String.fromCharCode(Number(code))); await messageBus.isReady();
return chars.join('');
} catch (e) {
return "Adresse encodée (format non supporté)";
}
} else if (typeof address === 'string') {
// Si c'est déjà une chaîne, on la retourne telle quelle
return address;
}
return "Format d'adresse inconnu"; const data = await messageBus.getData(processId, stateId);
console.log(data);
setPrivateData(prev => ({
...prev,
[stateId]: data
}));
console.log(privateData);
} catch (error) {
console.error('Error fetching private data:', error);
}
};
const handleDownload = (name: string | undefined, fileBlob: FileBlob) => {
const blob = new Blob([fileBlob.data], { type: fileBlob.type });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = name || 'download';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
};
const formatValue = (key: string, value: string | number[] | FileBlob) => {
if (isFileBlob(value)) {
return (
<div>
<span>{key}</span>
<button onClick={() => handleDownload(key, value)}>Download</button>
</div>
);
}
return JSON.stringify(value || ''); // TODO handle most common cases
}; };
const formatName = (name: string | number[] | undefined): string => { const formatName = (name: string | number[] | undefined): string => {
@ -154,31 +180,48 @@ function ProcessesViewer({ processes, myProcesses }: ProcessesViewerProps) {
</ul> </ul>
</div> </div>
<div className="state-private-data">
<h5>Données privées</h5>
<div className="private-data-item">
{!myProcesses.includes(processId) ? (
<div className="no-data-message">
Vous n'avez pas accès aux données privées de ce processus
</div>
) : !privateData[state.state_id] ? (
(() => {
fetchPrivateData(processId, state.state_id);
return <div>Chargement...</div>;
})()
) : Object.keys(privateData[state.state_id]).length > 0 ? (
Object.entries(privateData[state.state_id]).map(([key, value]) => (
<div key={key}>
<strong>{key}:</strong> {formatValue(key, value)}
</div>
))
) : (
<div className="no-data-message">
Aucune donnée privée disponible
</div>
)}
</div>
</div>
<div className="state-public-data"> <div className="state-public-data">
<h5>Données publiques</h5> <h5>Données publiques</h5>
<div className="public-data-item"> <div className="public-data-item">
<strong>Nom:</strong> {formatName(state.public_data.memberPublicName)} {Object.keys(state.public_data).length > 0 ? (
Object.entries(state.public_data).map(([key, value]) => (
<div key={key}>
<strong>{key}:</strong> {formatValue(key, value)}
</div> </div>
{state.public_data.pairedAddresses && (
<div className="public-data-item">
<strong>Adresses associées:</strong>
<ul className="address-list">
{Array.isArray(state.public_data.pairedAddresses) ?
(typeof state.public_data.pairedAddresses[0] === 'string' ? (
(state.public_data.pairedAddresses as string[]).map((addr, i) => (
<li key={i}>{addr}</li>
)) ))
) : ( ) : (
<li>{formatAddress(state.public_data.pairedAddresses as number[])}</li> <div className="no-data-message">
)) : ( Aucune donnée publique disponible
<li>{String(state.public_data.pairedAddresses || '')}</li>
)
}
</ul>
</div> </div>
)} )}
</div> </div>
</div> </div>
</div>
); );
})} })}
</div> </div>

View File

@ -264,8 +264,8 @@ export default class MessageBus {
}); });
} }
public getData(processId: string, stateId: string): Promise<any> { public getData(processId: string, stateId: string): Promise<Record<string, any>> {
return new Promise<any>((resolve: (data: any) => void, reject: (error: string) => void) => { return new Promise<Record<string, any>>((resolve: (data: Record<string, any>) => void, reject: (error: string) => void) => {
this.checkToken().then(() => { this.checkToken().then(() => {
const userStore = UserStore.getInstance(); const userStore = UserStore.getInstance();
const accessToken = userStore.getAccessToken()!; const accessToken = userStore.getAccessToken()!;
@ -273,7 +273,7 @@ export default class MessageBus {
const correlationId = uuidv4(); const correlationId = uuidv4();
this.initMessageListener(correlationId); this.initMessageListener(correlationId);
const unsubscribe = EventBus.getInstance().on('DATA_RETRIEVED', (responseId: string, data: any) => { const unsubscribe = EventBus.getInstance().on('DATA_RETRIEVED', (responseId: string, data: Record<string, any>) => {
if (responseId !== correlationId) { if (responseId !== correlationId) {
return; return;
} }
@ -295,7 +295,7 @@ export default class MessageBus {
type: 'RETRIEVE_DATA', type: 'RETRIEVE_DATA',
processId, processId,
stateId, stateId,
token: accessToken accessToken
}); });
}).catch(console.error); }).catch(console.error);
}); });
@ -596,28 +596,6 @@ export default class MessageBus {
EventBus.getInstance().emit('GET_MY_PROCESSES', correlationId, message.myProcesses); EventBus.getInstance().emit('GET_MY_PROCESSES', correlationId, message.myProcesses);
break; break;
case 'PROFILE_CREATED': // CREATE_PROFILE
if (this.errors[correlationId]) {
const error = this.errors[correlationId];
delete this.errors[correlationId];
EventBus.getInstance().emit('ERROR_PROFILE_CREATED', correlationId, error);
return;
}
EventBus.getInstance().emit('MESSAGE_RECEIVED', message);
EventBus.getInstance().emit('PROFILE_CREATED', correlationId, message.profileCreated);
break;
case 'FOLDER_CREATED': // CREATE_FOLDER
if (this.errors[correlationId]) {
const error = this.errors[correlationId];
delete this.errors[correlationId];
EventBus.getInstance().emit('ERROR_FOLDER_CREATED', correlationId, error);
return;
}
EventBus.getInstance().emit('MESSAGE_RECEIVED', message);
EventBus.getInstance().emit('FOLDER_CREATED', message.folderCreated);
break;
case 'DATA_RETRIEVED': // RETRIEVE_DATA case 'DATA_RETRIEVED': // RETRIEVE_DATA
if (this.errors[correlationId]) { if (this.errors[correlationId]) {
const error = this.errors[correlationId]; const error = this.errors[correlationId];