Skip to content

Commit

Permalink
fix import button (#51)
Browse files Browse the repository at this point in the history
  • Loading branch information
dormeiri authored Mar 21, 2023
1 parent f9c3c46 commit e506336
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 39 deletions.
53 changes: 29 additions & 24 deletions packages/ui/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,29 @@ import { Select } from './Select';
import { Toggle } from './Toggle';
import { VisNetwork } from './VisNetwork';
import { scanOutputStore } from './scanOutputStore';
import type { ScanResultExtended, SelectOption, FilterOption } from './types';
import type { SelectOption, FilterOption } from './types';
import { everyIncludes, produceNewRelationship } from './utils';

export function App() {
const [isImporting, setIsImporting] = useState<boolean>(true);

const [withDiff, setWithDiff] = useState(true);

const [scanOutput, setScanOutput] = useState<ScanResultExtended>();
const [tags, setTags] = useState<FilterOption<string>[]>([]);
const [resources, setResources] = useState<SelectOption<string>[]>([]);
const [selectedResourceId, setSelectedResourceId] = useState<string>();
const [isResourceEditOpen, setIsResourceEditOpen] = useState<boolean>(false);

const selectedTags = tags.filter((tag) => tag.selected);
const selectedTagValues = selectedTags.map((tag) => tag.value);
const selectedResource = selectedResourceId ? scanOutput?.resources.find((r) => r.id === selectedResourceId) : undefined;
const selectedResource = selectedResourceId ? scanOutputStore.scanOutput?.resources.find((r) => r.id === selectedResourceId) : undefined;

useEffect(() => {
scanOutputStore.importBundledScanOutput().then(syncWithStore);
(async () => {
await scanOutputStore.importBundledScanOutput();
setIsImporting(false);
syncWithStore();
})();
}, []);

useEffect(() => {
Expand All @@ -39,15 +44,20 @@ export function App() {
}
}, [tags]);

async function importScanOutput() {
await scanOutputStore.import(() => setIsImporting(true));
setIsImporting(false);
syncWithStore();
}

function syncWithStore() {
setScanOutput(JSON.parse(JSON.stringify(scanOutputStore.scanOutput)));
setTags(scanOutputStore.extractTagOptions());
setResources(scanOutputStore.extractResourceOptions());
}

function handleTagPillClick(clickedTag: SelectOption<string>): void {
const newTags = JSON.parse(JSON.stringify(tags));
newTags.find((tag) => tag.value === clickedTag.value).selected = false;
newTags.find((tag: SelectOption<string>) => tag.value === clickedTag.value).selected = false;
setTags(newTags);
}

Expand All @@ -64,8 +74,8 @@ export function App() {
}

function handleNewResource(resource: Resource): void {
const extendedResource = scanOutputStore.addResource(resource);
VisNetwork.addResource(extendedResource);
const extendedResource = scanOutputStore.addNode(resource);
VisNetwork.addNode(extendedResource);
syncWithStore();
closeResourceEditModal();
}
Expand All @@ -77,12 +87,15 @@ export function App() {
for (const relationship of resource.relationships ?? []) {
if ((relationship.diff ?? resource.diff) === '+') {
resource.relationships = resource.relationships?.filter((r) => r.resourceId !== relationship.resourceId);
VisNetwork.removeRelationship(resourceId, relationship.resourceId);
VisNetwork.removeEdge(resourceId, relationship.resourceId);
} else {
VisNetwork.updateRelationship(resource, relationship);
VisNetwork.syncEdgeStyle(resource, relationship);
}
}
} else VisNetwork.removeResource(resourceId);
} else {
VisNetwork.removeNode(resourceId);
setSelectedResourceId(undefined);
}
syncWithStore();
}

Expand All @@ -104,15 +117,15 @@ export function App() {
if (!relationship) throw new Error('Invalid relationship');
if ((relationship.diff ?? resource.diff) === '+') {
resource.relationships = resource.relationships?.filter((r) => r.resourceId !== relationshipResourceId);
VisNetwork.removeRelationship(resourceId, relationshipResourceId);
VisNetwork.removeEdge(resourceId, relationshipResourceId);
} else {
relationship.diff = '-';
VisNetwork.updateRelationship(resource, relationship);
VisNetwork.syncEdgeStyle(resource, relationship);
}
syncWithStore();
}

return scanOutput == null ? (
return isImporting ? (
<div>Loading...</div>
) : (
<div className="flex h-screen">
Expand All @@ -125,7 +138,7 @@ export function App() {
</div>
<div className="flex gap-1 flex-wrap">
<Button label="Download" onClick={() => scanOutputStore.download()} icon={FolderArrowDownIcon} />
<Button label="Import" onClick={() => scanOutputStore.import().then(syncWithStore)} icon={ArrowDownTrayIcon} />
<Button label="Import" onClick={importScanOutput} icon={ArrowDownTrayIcon} />
<Button label="Add Resource" onClick={() => setIsResourceEditOpen(true)} icon={PlusIcon} />
<Toggle label="Show diff" checked={withDiff} onChange={setWithDiff} />
</div>
Expand All @@ -147,15 +160,7 @@ export function App() {
)}
</div>
<div>
{scanOutput && (
<VisNetwork
scanOutput={scanOutput}
selectedTags={selectedTagValues}
resourceSelected={setSelectedResourceId}
selectedResourceId={selectedResourceId}
withDiff={withDiff}
/>
)}
<VisNetwork selectedTags={selectedTagValues} resourceSelected={setSelectedResourceId} selectedResourceId={selectedResourceId} withDiff={withDiff} />
</div>
<NewResourceModal isOpen={isResourceEditOpen} close={closeResourceEditModal} save={handleNewResource} />
</div>
Expand Down
21 changes: 8 additions & 13 deletions packages/ui/src/VisNetwork.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { DataSet, DataView } from 'vis-data';
import { Network } from 'vis-network';

import { getTypeImagePath } from './constants';
import { scanOutputStore } from './scanOutputStore';
import type { Diff, RelationshipExtended, ResourceExtended } from './types';
import { everyIncludes } from './utils';

Expand Down Expand Up @@ -55,9 +56,6 @@ interface Group {
}

export interface VisNetworkProps {
scanOutput: {
resources: ResourceExtended[];
};
selectedTags: string[];
selectedResourceId: string | undefined;
resourceSelected: (nodeId: string | undefined) => void;
Expand All @@ -72,7 +70,7 @@ export class VisNetwork extends React.Component<VisNetworkProps> {
private static nodes: DataView<any>;
private static network?: Network;

public static addResource(resource: ResourceExtended) {
public static addNode(resource: ResourceExtended) {
const node = produceNode(resource);
if (node.group && !VisNetwork.groups[node.group]) {
node.shape = 'image';
Expand All @@ -88,7 +86,7 @@ export class VisNetwork extends React.Component<VisNetworkProps> {
VisNetwork.nodes.getDataSet().update(produceNode(resource));
}

public static removeResource(resourceId: string) {
public static removeNode(resourceId: string) {
VisNetwork.nodes.getDataSet().remove(resourceId);
}

Expand All @@ -101,14 +99,14 @@ export class VisNetwork extends React.Component<VisNetworkProps> {
VisNetwork.edges.getDataSet().add(edge);
}

public static updateRelationship(resource: ResourceExtended, relationship: RelationshipExtended) {
public static syncEdgeStyle(resource: ResourceExtended, relationship: RelationshipExtended) {
if (resource.diff ?? relationship.diff) {
const existingEdge = VisNetwork.edges.get(produceEdgeId(resource.id, relationship.resourceId));
VisNetwork.edges.getDataSet().update({ ...existingEdge, color: produceEdgeColor(resource.diff, relationship.diff) });
}
}

public static removeRelationship(resourceId: string, relationshipResourceId: string) {
public static removeEdge(resourceId: string, relationshipResourceId: string) {
VisNetwork.edges.getDataSet().remove(produceEdgeId(resourceId, relationshipResourceId));
}

Expand Down Expand Up @@ -159,14 +157,14 @@ export class VisNetwork extends React.Component<VisNetworkProps> {
}

private extractNodes(): DataView<any> {
return new DataView(new DataSet(this.props.scanOutput.resources.map(produceNode)), {
return new DataView(new DataSet(scanOutputStore.scanOutput.resources.map(produceNode)), {
filter: (node) => (this.props.withDiff || node.diff == null) && everyIncludes(this.props.selectedTags, node.tags),
});
}

private extractEdges(): DataView<any> {
const edges: Record<string, any> = {};
for (const resource of this.props.scanOutput.resources) {
for (const resource of scanOutputStore.scanOutput.resources) {
for (const relationship of resource.relationships ?? []) {
const id = produceEdgeId(resource.id, relationship.resourceId);
edges[id] ??= produceEdge(resource, relationship);
Expand Down Expand Up @@ -198,10 +196,7 @@ export class VisNetwork extends React.Component<VisNetworkProps> {
for (const edge of VisNetwork.network.getConnectedEdges(this.props.selectedResourceId)) {
VisNetwork.network.updateEdge(edge, { width: edgeWidth.selected });
}
VisNetwork.network.focus(this.props.selectedResourceId, {
animation: true,
scale: 1,
});
VisNetwork.network.focus(this.props.selectedResourceId, { animation: true, scale: 1 });
}
}

Expand Down
13 changes: 11 additions & 2 deletions packages/ui/src/scanOutputStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ import type { Resource } from '@noodle-graph/types';
import { ResourceAlreadyExistError } from './errors';
import type { ResourceExtended, ScanResultExtended, SelectOption, FilterOption } from './types';

type ImportState = 'importing' | 'imported' | undefined;

class ScanOutputStore {
private _importState: ImportState;

// If there is any performance issue, we can store the resources as object instead of array.
private firstScanOutput: ScanResultExtended = { resources: [] };
private _scanOutput: ScanResultExtended = { resources: [] };
Expand All @@ -12,6 +16,10 @@ class ScanOutputStore {
return this._scanOutput;
}

public get importState(): ImportState {
return this._importState;
}

public download(): void {
const blob = new Blob([JSON.stringify(this._scanOutput)], { type: 'application/json' });
const url = window.URL.createObjectURL(blob);
Expand All @@ -22,7 +30,7 @@ class ScanOutputStore {
window.URL.revokeObjectURL(url);
}

public import(): Promise<void> {
public import(onImportStarted: () => void): Promise<void> {
return new Promise((resolve) => {
const input = document.createElement('input');
input.type = 'file';
Expand All @@ -32,6 +40,7 @@ class ScanOutputStore {
if (!file) {
return;
}
onImportStarted();
const reader = new FileReader();
reader.onload = (e) => {
if (e.target?.result == null) return;
Expand Down Expand Up @@ -83,7 +92,7 @@ class ScanOutputStore {
}
}

public addResource(resource: Resource): ResourceExtended {
public addNode(resource: Resource): ResourceExtended {
if (this._scanOutput.resources.some((r) => r.id === resource.id)) throw new ResourceAlreadyExistError();

const newResource: ResourceExtended = { ...resource, source: 'ui', diff: '+' };
Expand Down

0 comments on commit e506336

Please sign in to comment.