Skip to content
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"@coasys/flux-poll-view": "0.11.0",
"@coasys/flux-post-view": "0.11.0",
"@coasys/flux-synergy-demo-view": "0.11.0",
"@coasys/flux-soa-tree-view": "0.11.0",
"@coasys/flux-table-view": "0.11.0",
"@coasys/flux-types": "0.11.0",
"@coasys/flux-ui": "0.11.0",
Expand Down
8 changes: 8 additions & 0 deletions app/src/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ export const viewOptions = [
pkg: '@coasys/flux-webrtc-view',
component: 'webrtc-view',
},
{
title: 'SoA Tree',
description: 'View State of Affairs nodes as a collapsible tree',
icon: 'diagram-3',
type: ChannelView.SoATree,
pkg: '@coasys/flux-soa-tree-view',
component: 'soa-tree-view',
},
{
title: 'Debug',
description: 'WebRTC debugger',
Expand Down
1 change: 1 addition & 0 deletions app/src/modules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ declare module '@coasys/flux-kanban-view';
declare module '@coasys/flux-table-view';
declare module '@coasys/flux-synergy-demo-view';
declare module '@coasys/flux-poll-view';
declare module '@coasys/flux-soa-tree-view';
4 changes: 4 additions & 0 deletions app/src/utils/fetchFluxApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const fetchFluxApp = async function (packageName: string) {
'@coasys/nillion-file-store',
'@coasys/flux-synergy-demo-view',
'@coasys/flux-poll-view',
'@coasys/flux-soa-tree-view',
];
const isOfficialApp = officialPackages.includes(packageName);

Expand Down Expand Up @@ -50,6 +51,9 @@ const fetchFluxApp = async function (packageName: string) {
if (packageName === '@coasys/flux-poll-view') {
module = await import('@coasys/flux-poll-view');
}
if (packageName === '@coasys/flux-soa-tree-view') {
module = await import('@coasys/flux-soa-tree-view');
}
} else {
module = await import(
/* @vite-ignore */
Expand Down
2 changes: 1 addition & 1 deletion packages/api/src/npmApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export async function getAllFluxApps(): Promise<FluxApp[]> {
}

export function getOfflineFluxApps(): FluxApp[] {
const packages = ['chat-view', 'post-view', 'graph-view', 'webrtc-view', 'table-view', 'kanban-board'];
const packages = ['chat-view', 'post-view', 'graph-view', 'webrtc-view', 'table-view', 'kanban-board', 'flux-soa-tree-view'];

const fluxApps = packages.map((name) => ({
created: '',
Expand Down
1 change: 1 addition & 0 deletions packages/types/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ export enum ChannelView {
Graph = 'flux://has_graph_view',
Voice = 'flux://has_voice_view',
Debug = 'flux://has_debug_view',
SoATree = 'flux://has_soa_tree_view',
}

export enum EntryType {
Expand Down
51 changes: 51 additions & 0 deletions views/soa-tree-view/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{
"name": "@coasys/flux-soa-tree-view",
"version": "0.11.0",
"description": "SoA Tree View for Flux",
"author": "Coasys <dev@coasys.org>",
"license": "ISC",
"type": "module",
"scripts": {
"start": "vite",
"dev": "vite",
"build": "vite build",
"test": "echo \"Tests to be implemented in follow-up PR\" && exit 0"
},
"main": "./dist/main.umd.cjs",
"module": "./dist/main.js",
"exports": {
".": {
"import": "./dist/main.js",
"require": "./dist/main.umd.cjs"
}
},
"files": [
"dist"
],
"keywords": [
"flux-plugin",
"ad4m-view"
],
"dependencies": {
"@coasys/ad4m": "0.11.1",
"@coasys/ad4m-react-hooks": "0.11.1",
"@coasys/flux-react-web": "0.11.0",
"@coasys/flux-api": "0.11.0",
"preact": "^10.13.1"
},
"devDependencies": {
"@babel/plugin-proposal-class-properties": "^7.18.6",
"@babel/plugin-proposal-decorators": "^7.21.0",
"@preact/preset-vite": "^2.5.0",
"vite": "^4.3.5",
"vite-plugin-css-injected-by-js": "^3.1.0"
},
"publishConfig": {
"access": "public"
},
"fluxapp": {
"name": "SoA Tree",
"description": "View State of Affairs nodes as a collapsible tree",
"icon": "diagram-3"
}
}
11 changes: 11 additions & 0 deletions views/soa-tree-view/src/App.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.appContainer {
margin: 0 auto;
width: 100%;
height: 100%;
}

.error {
padding: 2rem;
text-align: center;
color: var(--j-color-danger-500, #e53e3e);
}
26 changes: 26 additions & 0 deletions views/soa-tree-view/src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import styles from './App.module.css';
import { PerspectiveProxy } from '@coasys/ad4m';
import SoATreeView from './components/SoATreeView';
import '@coasys/flux-ui/dist/main.css'; // Runtime CSS import

type Props = {
perspective: PerspectiveProxy;
source: string;
};

export default function App({ perspective, source }: Props) {
if (!perspective?.uuid || !source) {
return (
Comment thread
coderabbitai[bot] marked this conversation as resolved.
<div className={styles.appContainer}>
<div className={styles.error}>
No perspective or source available
</div>
</div>
);
}
return (
<div className={styles.appContainer}>
<SoATreeView perspective={perspective} source={source} />
</div>
);
}
149 changes: 149 additions & 0 deletions views/soa-tree-view/src/components/SoANode.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
.nodeWrapper {
display: flex;
flex-direction: column;
}

.nodeHeader {
display: flex;
align-items: center;
gap: 6px;
padding: 4px 8px;
border-radius: 4px;
cursor: pointer;
user-select: none;
transition: background-color 0.15s;
}

.nodeHeader:hover {
background-color: var(--j-color-ui-100, #f1f5f9);
}

.nodeHeader.expanded {
background-color: var(--j-color-ui-50, #f8fafc);
}

.toggle {
font-size: 12px;
width: 14px;
flex-shrink: 0;
color: var(--j-color-ui-400, #94a3b8);
}

.icon {
font-size: 16px;
flex-shrink: 0;
}

.title {
font-size: 14px;
font-weight: 500;
color: var(--j-color-ui-800, #1e293b);
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}

.statusBadge {
font-size: 11px;
padding: 1px 6px;
border-radius: 10px;
color: #fff;
font-weight: 500;
flex-shrink: 0;
}

.priorityBadge {
font-size: 11px;
padding: 1px 6px;
border-radius: 10px;
background-color: var(--j-color-ui-200, #e2e8f0);
color: var(--j-color-ui-600, #475569);
font-weight: 500;
flex-shrink: 0;
}

.relCount {
font-size: 11px;
color: var(--j-color-ui-400, #94a3b8);
flex-shrink: 0;
}

.details {
display: flex;
flex-direction: column;
gap: 6px;
padding: 4px 0 8px;
}

.property {
display: flex;
align-items: center;
gap: 8px;
font-size: 13px;
}

.propLabel {
font-size: 12px;
color: var(--j-color-ui-400, #94a3b8);
font-weight: 500;
flex-shrink: 0;
min-width: 70px;
}

.confidenceBar {
width: 80px;
height: 6px;
background-color: var(--j-color-ui-200, #e2e8f0);
border-radius: 3px;
overflow: hidden;
flex-shrink: 0;
}

.confidenceFill {
height: 100%;
background-color: var(--j-color-primary-500, #3b82f6);
border-radius: 3px;
transition: width 0.2s;
}

.confidenceValue {
font-size: 12px;
color: var(--j-color-ui-500, #64748b);
}

.tagList {
display: flex;
flex-wrap: wrap;
gap: 4px;
}

.tag {
font-size: 11px;
padding: 1px 8px;
border-radius: 10px;
background-color: var(--j-color-ui-100, #f1f5f9);
color: var(--j-color-ui-600, #475569);
}

.relationships {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 4px;
}

.relBadge {
font-size: 11px;
padding: 2px 8px;
border-radius: 10px;
background-color: var(--j-color-ui-100, #f1f5f9);
color: var(--j-color-ui-600, #475569);
border: 1px solid var(--j-color-ui-200, #e2e8f0);
}

.children {
display: flex;
flex-direction: column;
gap: 2px;
}
Loading
Loading