-
Notifications
You must be signed in to change notification settings - Fork 34
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added: FE Explorer and related visuals
- Loading branch information
1 parent
bd30918
commit b52b2e2
Showing
16 changed files
with
1,398 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { useEffect, useState } from 'react'; | ||
|
||
function getWindowDimensions() { | ||
const { innerWidth: width, innerHeight: height } = window; | ||
return { | ||
width, | ||
height, | ||
}; | ||
} | ||
|
||
export default function useWindowDimensions() { | ||
const [windowDimensions, setWindowDimensions] = useState(getWindowDimensions()); | ||
|
||
useEffect(() => { | ||
function handleResize() { | ||
setWindowDimensions(getWindowDimensions()); | ||
} | ||
|
||
window.addEventListener('resize', handleResize); | ||
return () => window.removeEventListener('resize', handleResize); | ||
}, []); | ||
|
||
return windowDimensions; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
#explorer-content { | ||
font-family: Vollkorn, Ubuntu, Optima, Segoe, Segoe UI, Candara, Calibri, Arial, sans-serif; | ||
margin: 40px; | ||
text-align: left; | ||
} | ||
|
||
#explorer-content>.group { | ||
border-top: 1px dotted lightgrey; | ||
border-left: 6px solid lightgrey; | ||
margin: 4px; | ||
margin-left: 46px; | ||
padding: 5px; | ||
vertical-align: top; | ||
background-color: rgba(200, 200, 200, 0.2); | ||
} | ||
|
||
#explorer-content>.doc-id { | ||
display: inline-block; | ||
border-radius: 6px; | ||
margin: 3px; | ||
padding: 3px; | ||
background-color: #f8f8f8; | ||
vertical-align: top; | ||
font-size: 90%; | ||
} | ||
|
||
#explorer-content>.tag { | ||
display: inline-block; | ||
border: 1px solid lightgrey; | ||
border-radius: 6px; | ||
margin: 3px; | ||
padding: 3px; | ||
background-color: #f8f8f8; | ||
vertical-align: top; | ||
font-size: 90%; | ||
max-width: 80px; | ||
white-space: nowrap; | ||
overflow: hidden; | ||
} | ||
|
||
#explorer-content>a { | ||
text-decoration: none; | ||
} | ||
|
||
#explorer-content>.icon { | ||
width: 140px; | ||
height: 140px; | ||
object-fit: cover; | ||
border-radius: 4px; | ||
margin-top: 26px; | ||
margin-bottom: 20px; | ||
filter: grayscale(100%); | ||
} | ||
|
||
#explorer-content>::placeholder { | ||
color: lightgrey; | ||
opacity: 1; | ||
} | ||
|
||
#explorer-content>:-ms-input-placeholder { | ||
color: lightgrey; | ||
} | ||
|
||
#explorer-content>::-ms-input-placeholder { | ||
color: lightgrey; | ||
} | ||
|
||
|
||
#explorer-content>div { | ||
vertical-align: top; | ||
} | ||
|
||
#explorer-content>content { | ||
margin-left: -20px; | ||
} | ||
|
||
#explorer-content>h1 { | ||
font-size: 50px; | ||
margin-bottom: 5px; | ||
margin-left: 16px; | ||
} | ||
|
||
#explorer-content>img { | ||
vertical-align: middle; | ||
height: 80px; | ||
} | ||
|
||
b { | ||
padding-top: 20px; | ||
padding-left: 12px; | ||
} | ||
p{ | ||
color: grey; margin-left: 26px; | ||
} | ||
#explorer-wrapper{ | ||
margin-left: 24px; margin-top: 20px; margin-bottom: 20px; color: grey; | ||
} | ||
|
||
#filter{ | ||
font-size: 16px; height: 32px; width: 320px; margin-bottom: 10px; | ||
} | ||
#search-summary{ | ||
display: inline-block; vertical-align: middle; | ||
} | ||
#graphs{font-size: 80%; color: grey;} | ||
|
||
.highlight{ | ||
background-color: yellow; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
import './explorer.scss'; | ||
|
||
import React, { useEffect, useState } from 'react'; | ||
import { Link } from 'react-router-dom'; | ||
import { Label, List } from 'semantic-ui-react'; | ||
|
||
import { LoadingAndErrorIndicator } from '../../components/LoadingAndErrorIndicator'; | ||
import { useDataStore } from '../../providers/DataProvider'; | ||
import { LinkedTreeDocument, TreeDocument } from '../../types'; | ||
|
||
export const Explorer = () => { | ||
const { dataLoading, dataTree } = useDataStore(); | ||
const [filter, setFilter] = useState(''); | ||
const [filteredTree, setFilteredTree] = useState<TreeDocument[]>(); | ||
|
||
const applyHighlight = (text, term) => { | ||
if (!term) return text; | ||
var index = text.toLowerCase().indexOf(term); | ||
if (index >= 0) { | ||
return ( | ||
<> | ||
{text.substring(0, index)} | ||
<span className="highlight">{text.substring(index, index + term.length)}</span> | ||
{text.substring(index + term.length)} | ||
</> | ||
); | ||
} | ||
return text; | ||
}; | ||
|
||
const filterFunc = (doc: TreeDocument, term: string) => | ||
doc.displayName && doc.displayName.toLowerCase().includes(term); | ||
const recursiveFilter = (doc: TreeDocument, term: string) => { | ||
if (doc.links) { | ||
const filteredLinks: LinkedTreeDocument[] = []; | ||
doc.links.forEach((x) => { | ||
const docu = recursiveFilter(x.document, term); | ||
if (docu) { | ||
filteredLinks.push({ ltype: x.ltype, document: docu }); | ||
} | ||
}); | ||
doc.links = filteredLinks; | ||
} | ||
if (filterFunc(doc, term) || doc.links?.length) { | ||
return doc; | ||
} | ||
return null; | ||
}; | ||
|
||
useEffect(() => { | ||
if (dataTree.length) { | ||
const treeCopy = structuredClone(dataTree); | ||
const filTree: TreeDocument[] = []; | ||
treeCopy | ||
.map((x) => recursiveFilter(x, filter)) | ||
.forEach((x) => { | ||
if (x) { | ||
filTree.push(x); | ||
} | ||
}); | ||
setFilteredTree(filTree); | ||
} | ||
}, [filter, dataTree, setFilteredTree]); | ||
|
||
function processNode(item) { | ||
if (!item) { | ||
return <></>; | ||
} | ||
const contains = item.links.filter((x) => x.ltype === 'Contains'); | ||
const linkedTo = item.links.filter((x) => x.ltype === 'Linked To'); | ||
return ( | ||
<List.Item key={Math.random()}> | ||
<List.Icon name="folder" /> | ||
<List.Content> | ||
<List.Header> | ||
<Link to={item.url}>{applyHighlight(item.displayName, filter)}</Link> | ||
</List.Header> | ||
{linkedTo.length > 0 && ( | ||
<List.Description> | ||
<Label.Group size="tiny" tag> | ||
{[...new Set(linkedTo.map((x: LinkedTreeDocument) => x.document.name))] | ||
.sort() | ||
.map((x: string) => ( | ||
<Link key={Math.random()} to={`/node/standard/${x}`}> | ||
<Label>{x}</Label> | ||
</Link> | ||
))} | ||
</Label.Group> | ||
</List.Description> | ||
)} | ||
{contains.length > 0 && ( | ||
<List.List>{contains.map((child) => processNode(child.document))}</List.List> | ||
)} | ||
</List.Content> | ||
</List.Item> | ||
); | ||
} | ||
function update(event) { | ||
setFilter(event.target.value.toLowerCase()); | ||
} | ||
|
||
return ( | ||
<> | ||
<div id="explorer-content"> | ||
<h1> | ||
<b>Explorer</b> | ||
</h1> | ||
<p> | ||
A visual explorer of Open Common Requirement Enumerations (CREs). Originally created by:{' '} | ||
<a target="_blank" href="https://zeljkoobrenovic.github.io/opencre-explorer/"> | ||
Zeljko Obrenovic | ||
</a> | ||
. | ||
</p> | ||
|
||
<div id="explorer-wrapper"> | ||
<div> | ||
<input id="filter" type="text" placeholder="search..." onKeyUp={update} /> | ||
<div id="search-summary"></div> | ||
</div> | ||
<div id="graphs"> | ||
graphs (3D): | ||
<a target="_blank" href="explorer/force_graph"> | ||
CRE dependencies | ||
</a>{' '} | ||
- | ||
{/* <a target="_blank" href="visuals/force-graph-3d-contains.html"> | ||
hierarchy only | ||
</a>{' '} | ||
- | ||
<a target="_blank" href="visuals/force-graph-3d-related.html"> | ||
related only | ||
</a>{' '} | ||
| | ||
<a target="_blank" href="visuals/force-graph-3d-linked.html"> | ||
links to external standards | ||
</a>{' '} | ||
| */} | ||
<a target="_blank" href="explorer/circles"> | ||
zoomable circles | ||
</a> | ||
</div> | ||
</div> | ||
<LoadingAndErrorIndicator loading={dataLoading} error={null} /> | ||
<List> | ||
{filteredTree?.map((item) => { | ||
return processNode(item); | ||
})} | ||
</List> | ||
</div> | ||
</> | ||
); | ||
}; |
32 changes: 32 additions & 0 deletions
32
application/frontend/src/pages/Explorer/visuals/circles/circles.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
|
||
.node { | ||
cursor: pointer; | ||
} | ||
|
||
.node:hover { | ||
stroke: #000; | ||
stroke-width: 1.5px; | ||
} | ||
|
||
.node--leaf { | ||
fill: white; | ||
} | ||
|
||
.label { | ||
font: 11px "Helvetica Neue", Helvetica, Arial, sans-serif; | ||
text-anchor: middle; | ||
text-shadow: 0 1px 0 #fff, 1px 0 0 #fff, -1px 0 0 #fff, 0 -1px 0 #fff; | ||
} | ||
|
||
.label, | ||
.node--root, | ||
.node--leaf { | ||
pointer-events: none; | ||
} | ||
|
||
.ui.button.screen-size-button { | ||
position: absolute; | ||
right: 0; | ||
margin: 0; | ||
background-color: transparent; | ||
} |
Oops, something went wrong.