Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@
"postcss-loader": "^7.1.0",
"prettier": "^2.8.6",
"raw-loader": "^4.0.2",
"rdf-ext": "^2.5.0",
"rdf-js": "^4.0.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
Expand All @@ -138,6 +139,7 @@
"recoil": "^0.7.7",
"rocketrml": "^2.1.2",
"sass-loader": "^13.2.1",
"shacl-engine": "^0.1.0",
"source-map-loader": "^4.0.1",
"source-map-support": "^0.5.21",
"style-loader": "^3.3.2",
Expand Down
36 changes: 5 additions & 31 deletions public/Person.ttl
Original file line number Diff line number Diff line change
Expand Up @@ -14,52 +14,26 @@ self:Philosopher

sh:property [
sh:path schema:givenName ;
sh:datatype rdf:langString ;
sh:languageIn ( "en" "nl" ) ;
sh:datatype xsd:string ;
sh:minCount 1 ;
sh:maxCount 1 ;
] ;

sh:property [
sh:path schema:familyName ;
sh:datatype xsd:string ;
sh:minCount 1 ;
sh:maxCount 1 ;
] ;

# sh:property [
# sh:path rdf:type ;
# sh:in ( dbo:Philosopher ) ;
# sh:minCount 1 ;
# sh:maxCount 1 ;
# ] ;

sh:property [
sh:path dbo:birthPlace ;
sh:nodeKind sh:IRI ;
sh:node self:Location ;
sh:datatype xsd:string1 ;
sh:maxCount 1 ;
] ;

sh:property [
sh:path dbo:birthDate ;
sh:datatype xsd:date;
sh:datatype xsd:string ;
sh:maxCount 1 ;
] .

# self:Location
# a sh:NodeShape ;

# sh:targetClass <http://dbpedia.org/ontology/Location> ;

# # sh:property [
# # sh:path rdf:type ;
# # sh:minCount 1 ;
# # sh:maxCount 1 ;
# # ] ;

# sh:property [
# sh:path rdfs:label ;
# sh:datatype rdf:langString ;
# sh:languageIn ( "de" "fr" ) ;
# sh:minCount 1 ;
# sh:maxCount 1 ;
# ] .
15 changes: 13 additions & 2 deletions src/containers/Configure/InteractiveTableHeaders.tsx
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to solve this using CSS's :hover selector? The only issue I can forsee is that you need to be quite specific with the selector?

Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const TableHeaders: React.FC<Props> = ({ shaclShapeMeta }) => {
const [transformationConfig, setTransformationConfig] = useRecoilState(transformationConfigState);
const [selectedHeader, setSelectedHeader] = React.useState<ColumnConfiguration | undefined>();
const prefixes = useRecoilValue(prefixState);
const [activeDragOverColumn, setActiveDragOverColumn] = React.useState('')

let columns = transformationConfig.columnConfiguration

Expand All @@ -46,12 +47,21 @@ const TableHeaders: React.FC<Props> = ({ shaclShapeMeta }) => {

const dragOver = (columnConfig: ColumnConfiguration) => !columnConfig.shaclColumn ? (event: any) => {
event.preventDefault();
setActiveDragOverColumn(columnConfig.columnName)
event.dataTransfer.dropEffect = "move";
} : undefined


const dragOut = (columnConfig: ColumnConfiguration) => !columnConfig.shaclColumn ? (event: any) => {
setActiveDragOverColumn('')
} : undefined



const dropArea = (columnConfig: ColumnConfiguration) => !columnConfig.shaclColumn ? (event: any) => {
event.preventDefault();
const propertyIri = event.dataTransfer.getData("application/ld-wizard");
setActiveDragOverColumn('')

setTransformationConfig((state) => {
const columnConfiguration = [...state.columnConfiguration];
Expand Down Expand Up @@ -90,12 +100,13 @@ const TableHeaders: React.FC<Props> = ({ shaclShapeMeta }) => {

return (
<TableCell
onDragStart={dragStart(columnConfig)}
onDragStart={dragStart(columnConfig)}
draggable={columnConfig.shaclColumn}
onDrop={dropArea(columnConfig)}
onDragOver={dragOver(columnConfig)}
onDragLeave={dragOut(columnConfig)}
key={`${columnConfig.columnName}${idx}`}
className={getClassName(styles.tableHeader, { [styles.disabled]: isKeyColumn, [styles.shaclColumn]: columnConfig.shaclColumn })}
className={getClassName(styles.tableHeader, { [styles.disabled]: isKeyColumn, [styles.shaclColumn]: columnConfig.shaclColumn, [styles.draggingOver]: columnConfig.columnName === activeDragOverColumn })}
// Implement the disable here, I still want to be able to use tooltip
onClick={columnConfig.disabled ? undefined : () => setSelectedHeader(columnConfig)}
// Replace Default tableCell with ButtonBase to create ripple effects on click
Expand Down
5 changes: 5 additions & 0 deletions src/containers/Configure/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,18 @@ th.tableHeader {
cursor: default;
background-color: #ccc;
}

&.shaclColumn {
cursor: move; /* fallback if grab cursor is unsupported */
cursor: grab;
cursor: -moz-grab;
cursor: -webkit-grab;
background-color: #ffdec4;
}

&.draggingOver {
background-color: #ffdec4;
}
}
.hint {
pointer-events: none;
Expand Down
24 changes: 21 additions & 3 deletions src/containers/Publish/DownloadResults.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@ import { getFileBaseName } from "../../utils/helpers.ts";
interface Props {
transformationResult: string;
refinedCsv: Matrix | undefined;
shaclConforms: boolean | null,
shaclReport?: string
}
const DownloadResults: React.FC<Props> = ({ transformationResult, refinedCsv }) => {
const DownloadResults: React.FC<Props> = ({ transformationResult, refinedCsv, shaclConforms, shaclReport }) => {
const downloadRef = React.useRef<HTMLAnchorElement>(null);
const source = useRecoilValue(sourceState);

const transformationConfig = useRecoilValue(transformationConfigState);


const downloadFile = (content: File | string | undefined, defaultName: string, mediaType: string) => {
if (!downloadRef.current || !content) return;
if (typeof content === "string") {
Expand Down Expand Up @@ -87,8 +88,12 @@ const DownloadResults: React.FC<Props> = ({ transformationResult, refinedCsv })
<CardHeader title="Download RDF" avatar={<FontAwesomeIcon icon="file" />} />
<CardContent className={styles.downloadContent}>
Download the transformed Linked Data (RDF) to your local machine.

{shaclConforms === false ? <span><br /><br /><FontAwesomeIcon icon={["fas", "xmark"]} /> The data does not conform to the selected SHACL shape</span> : null}
{shaclConforms === true ? <span><br /><br /><FontAwesomeIcon icon={["fas", "check"]} /> The data does conform to the selected SHACL shape</span> : null}
Comment on lines +91 to +93
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be nice to use the mui Alert component for this. This might also offer a "better" place to allow the user to download the SHACL report (either as an action or as a button in the alert)

</CardContent>
<CardActions>
{shaclConforms !== false ?
<Button
onClick={() => downloadFile(transformationResult, rdfFileName, "application/n-triples")}
component="span"
Expand All @@ -97,7 +102,20 @@ const DownloadResults: React.FC<Props> = ({ transformationResult, refinedCsv })
style={{textTransform: 'none'}}
>
Download RDF
</Button>
</Button> :
<SplitButton
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think UX wise, splitting into two makes a bit more sense, as they download separate results. a SHACL report and the transformed output. The split button approach makes more sense if we're talking about the same product. (Unless I missed something and the SHACL report does include the transformed result)

actions={["rdf", "shacl"]}
getOptionsLabel={(option) => option === 'rdf' ? `RDF` : 'SHACL report'}
getButtonlabel={(selectedOption) => selectedOption === 'rdf' ? `Download RDF` : 'Download SHACL report'}
onActionSelected={(result) => {
if (result === 'rdf') {
downloadFile(transformationResult, rdfFileName, "application/n-triples")
}
else {
downloadFile(shaclReport, 'shacl-validation-report.nt', "application/n-triples")
}
}}
/>}
</CardActions>
</Card>
<Card variant="outlined" className={styles.downloadSegment}>
Expand Down
28 changes: 27 additions & 1 deletion src/containers/Publish/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ import { currentTokenState } from "../../state/clientJs.ts";
import DownloadResults from "./DownloadResults.tsx";
import { wizardAppConfig, PublishElement } from "../../config/index.ts";
import { Matrix } from "../../Definitions.ts";
import { Validator } from 'shacl-engine'
import rdf from 'rdf-ext'
import { Parser, Store, Writer } from 'n3'

interface Props { }
export const Step = 3;
const Publish: React.FC<Props> = ({ }) => {
Expand All @@ -21,6 +25,9 @@ const Publish: React.FC<Props> = ({ }) => {
const [transformationResult, setTransformationResult] = React.useState<string>();
const [transformationError, setTransformationError] = React.useState<string>();
const [progress, setProgress] = React.useState(0);
const [conforms, setConforms] = React.useState(null);
const [shaclReportTurtle, setShaclReportTurtle] = React.useState('');


function LinearProgressWithLabel(props: LinearProgressProps & { value: number }) {
return (
Expand Down Expand Up @@ -252,6 +259,25 @@ function LinearProgressWithLabel(props: LinearProgressProps & { value: number })
source: tempRefinedCsv || parsedCsv,
type: "rml",
});

if (transformationConfig.shaclShape) {
const shaclShapes = await wizardAppConfig.getShaclShapes()

const selectedShaclShape = shaclShapes.find(shaclShape => shaclShape.iri === transformationConfig.shaclShape)
const parser = new Parser()
const quads = await parser.parse(transformationResult)
const store = new Store(quads)
const validator = new Validator(selectedShaclShape.store, { factory: rdf })
const report = await validator.validate({ dataset: store })

setConforms(report.conforms)

if (!report.conforms) {
const writer = new Writer()
for (const quad of report.dataset) writer.addQuad(quad)
writer.end((error, result) => setShaclReportTurtle(result))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a comment that this function is synchronous. In most functions, giving a callback indicates asynchronous functionality

}
}
setTransformationResult(transformationResult);
}
};
Expand Down Expand Up @@ -296,7 +322,7 @@ function LinearProgressWithLabel(props: LinearProgressProps & { value: number })
}
const publishOptions: { [P in PublishElement]: React.ReactElement } = {
download: (
<DownloadResults refinedCsv={refinedCsv} transformationResult={transformationResult} key="Download-to-browser" />
<DownloadResults shaclReport={shaclReportTurtle} shaclConforms={conforms} refinedCsv={refinedCsv} transformationResult={transformationResult} key="Download-to-browser" />
),
triplyDB: (
<ErrorBoundary
Expand Down
2 changes: 1 addition & 1 deletion src/theme/global.scss
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,4 @@
body {
margin: 0;
}
}
}
Loading