Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Makeeditable #612

Merged
merged 2 commits into from
Feb 28, 2024
Merged
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
298 changes: 223 additions & 75 deletions frontend/components/Viewing/MetadataInfo.js

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useState } from 'react';
import MetadataInfo from '../../MetadataInfo';
import RowWrapper from './RowWrapper';

export default function MetadataRenderer({ title, content }) {
export default function MetadataRenderer({ title, content, editable, uri }) {
if (!content) return null;
const [sectionIcon, setSectionIcon] = useState(null);
const contentConsolidated = content.map((row, index) => {
Expand All @@ -21,6 +21,8 @@ export default function MetadataRenderer({ title, content }) {
label={title}
title={contentConsolidated}
specific={true}
editable={editable}
uri={uri}
/>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ export default function SectionRenderer({ section, metadata }) {
isMounted = false; // <-- set the flag to false when the component unmounts
};
}, []);

if (data) {
if (section.link) {
data.forEach(registry => {
Expand Down
66 changes: 57 additions & 9 deletions frontend/components/Viewing/PageJSON/Rendering/TableBuilder.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
import { useEffect, useState } from 'react';
import styles from '../../../../styles/view.module.css';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faPlus } from '@fortawesome/free-solid-svg-icons';
import Link from 'next/link';
import RenderIcon from './RenderIcon';
import MetadataRenderer from './MetadataRenderer';
import parseQueryResult from '../Fetching/parseQueryResult';
import executeQueryFromTableJSON from '../Fetching/executeQueryFromTableJSON';
import RowWrapper from './RowWrapper';
import { useDispatch } from 'react-redux';
import { useSelector } from 'react-redux';
import { parseTableHeaders } from '../Parsing/parseTableHeaders';
import React, { createContext } from 'react';
import { isUriOwner } from '../../Shell';
import { getAfterThirdSlash } from '../../ViewHeader';
import getConfig from 'next/config';
const { publicRuntimeConfig } = getConfig();
import axios from 'axios';

/**
* This Component renders an individual table based on given JSON
Expand All @@ -19,20 +27,25 @@ import React, { createContext } from 'react';
*/
export default function TableBuilder({ uri, prefixes, table, metadata }) {
prefixes = prefixes.join('\n');

const objectUriParts = getAfterThirdSlash(uri);
const username = useSelector(state => state.user.username);
const objectUri = `${publicRuntimeConfig.backend}/${objectUriParts}`;
var isOwner = isUriOwner(objectUri, username);
return (
<div>
<TableRenderer
uri={uri}
prefixes={prefixes}
table={table}
metadata={metadata}
owner={isOwner}
/>
</div>
);
}

function TableRenderer({ uri, prefixes, table, metadata }) {
function TableRenderer({ uri, prefixes, table, metadata, owner }) {
const token = useSelector(state => state.user.token);
const [content, setContent] = useState(null);
const dispatch = useDispatch();
useEffect(() => {
Expand All @@ -43,12 +56,14 @@ function TableRenderer({ uri, prefixes, table, metadata }) {

const header = metadata ? null : createHeader(table.sections, content);

const isEditable = metadata && metadata.editable && owner;

if (!checkContentExist(content) && !metadata) {
return "No content to display for " + table.title;
}

if (metadata) {
return <MetadataRenderer title={table.title} content={content} />;
return <MetadataRenderer title={table.title} content={content} editable={isEditable} uri={uri}/>;
}

// if (content.length == 0) {
Expand All @@ -59,16 +74,35 @@ function TableRenderer({ uri, prefixes, table, metadata }) {
return <RowWrapper sections={row} key={index} metadata={false} />;
});

// const titleType = splitPredicate(metadata.rootPredicate);

// const handleAdd = () => {
// axios.post(`${objectUri}/add/${titleType}`, {
// object: editedDescription
// }, {
// headers: {
// "Accept": "text/plain; charset=UTF-8",
// "X-authorization": token
// }
// })
// .then(response => {

// })
// .catch(error => {
// console.error(`Error adding: ${titleType}`, error);
// });
// };

return (
<div>
{content.length > 0 && (
<table className={styles.table}>
<thead>
<tr>{header}</tr>
</thead>
<tbody>{rows}</tbody>
</table>
) }
<thead>
<tr>{header}</tr>
</thead>
<tbody>{rows}</tbody>
</table>
)}
</div>
);
}
Expand Down Expand Up @@ -102,6 +136,20 @@ function createHeader(columns, content) {
.filter(column => column !== undefined);
}

function EditableIcon({ onAddClick }) {
return (
<div style={{ textAlign: 'right', margin: '10px' }}>
<button onClick={onAddClick}>
<FontAwesomeIcon icon={faPlus} />
</button> {/* Style this as needed */}
</div>
);
}

function splitPredicate(predicate) {
return predicate.split(':')[1];
}

const tableFork = tableJSON => {
console.log(tableJSON);
tableJSON.sections.forEach(section => {
Expand Down
2 changes: 1 addition & 1 deletion frontend/components/Viewing/PageJSON/Types/Component.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
]
},
{
"title": "Role(s)",
"title": "Role",
"rootPredicate": "sbol:role",
"icon": "faUserTag",
"sections": [
Expand Down
2 changes: 1 addition & 1 deletion frontend/components/Viewing/PageJSON/Types/Component3.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
]
},
{
"title": "Roles",
"title": "Role",
"rootPredicate": "sbol:role",
"icon": "faUserTag",
"sections": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,19 @@
"PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>",
"PREFIX purl: <http://purl.obolibrary.org/obo/>"
],
"search": [
{
"twins": true,
"similar": true,
"uses": true
}
],
"metadata": [
{
"title": "Type",
"rootPredicate": "sbol:type",
"icon": "faPalette",
"editable": true,
"sections": [
{
"title": "Extra Work",
Expand All @@ -31,9 +39,10 @@
]
},
{
"title": "Role(s)",
"title": "Role",
"rootPredicate": "sbol:role",
"icon": "faUserTag",
"editable": true,
"sections": [
{
"title": "Extra Work",
Expand Down Expand Up @@ -207,7 +216,7 @@
"hide": true
},
{
"title": "Role(s)",
"title": "Role",
"group": true,
"predicates": [
"sbol:role"
Expand Down
2 changes: 1 addition & 1 deletion frontend/components/Viewing/PageJSON/Types/Feature3.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
],
"metadata": [
{
"title": "Roles",
"title": "Role",
"rootPredicate": "sbol:role",
"infoLink": "https://sbols.org/v3#role",
"icon": "faUserTag",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
],
"metadata": [
{
"title": "Roles",
"title": "Role",
"rootPredicate": "sbol:role",
"icon": "faUserTag",
"sections": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
],
"metadata": [
{
"title": "Roles",
"title": "Role",
"icon": "faUserTag",
"infoLink": "https://sbols.org/v2#role",
"rootPredicate": "sbol:role",
Expand Down
70 changes: 68 additions & 2 deletions frontend/components/Viewing/Shell.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import ViewHeader from './ViewHeader';
import GenericContent from './PageJSON/Rendering/GenericContent';
import MasterJSON from './PageJSON/MasterJSON';

import sequenceOntology from '../../namespace/sequence-ontology';
import systemsBiologyOntology from '../../namespace/systems-biology-ontology';
import edamOntology from '../../namespace/edam-ontology';

// import { BooleanContext, checkContentExist } from './PageJSON/Rendering/TableBuilder';
// import Section from './Sections/Section'
// import TableBuilder from './PageJSON/Rendering/TableBuilder';
Expand Down Expand Up @@ -95,8 +99,8 @@ export function isUriOwner(uri, currentUserUsername) {
// Split the URI and check if the segment after the domain is '/user'
const parts = uri.split('/');
if (parts.length > 3 && parts[3] === 'user') {
// Call helper function to check if the next segment matches the current user's username
return isUserOwner(parts[4], currentUserUsername);
// Call helper function to check if the next segment matches the current user's username
return isUserOwner(parts[4], currentUserUsername);
}
return false;
}
Expand All @@ -105,3 +109,65 @@ function isUserOwner(uriUsername, currentUserUsername) {
// Compare the username part of the URI with the current user's username
return uriUsername === currentUserUsername;
}

function formatTitle(title) {
let link;
const parts = title.split('/');
if (parts.length >= 2 && title.startsWith('http')) {
const lastPart = parts[parts.length - 1];
link = title;
if (/^1(\.0+)*$/.test(lastPart)) {
title = parts[parts.length - 2];
} else {
const delimiters = ['#', '%', '/'];
const lastPartSegments = lastPart.split(new RegExp(`[${delimiters.join('')}]`));

title = lastPartSegments.pop();
}
}
if (/SO:\s*(\d{7})/.test(title)) {
for (let key in sequenceOntology) {
if (title === key) {
title = sequenceOntology[key].name;
break;
}
}
}
if (/SBO:\s*(\d{7})/.test(title)) {
for (let key in systemsBiologyOntology) {
if (title === key) {
title = systemsBiologyOntology[key].name;
break;
}
}
}
if (/http:\/\/edamontology\.org\/format_\d{4}/.test(title)) {
for (let key in edamOntology) {
if (title === key) {
title = edamOntology[key];
}
}
}

return [title, link];
}

export function formatMultipleTitles(titles) {
// Split the titles string into an array of individual titles
const titleArray = titles.split(',');

// Process each title independently and also collect their links
const processedTitles = titleArray.map((singleTitle) => {
const [formattedTitle, link] = formatTitle(singleTitle.trim());
return { title: formattedTitle, link };
});

// Join the processed titles back into a single string, separated by commas
const formattedTitlesString = processedTitles.map(item => item.title).join(", ");
const linksArray = processedTitles.map(item => item.link);

// If you need to do something with linksArray, you can use it here

return [formattedTitlesString, linksArray];
}

24 changes: 16 additions & 8 deletions frontend/redux/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -899,7 +899,6 @@ export const getCanSubmitTo = () => async (dispatch, getState) => {
'X-authorization': token
};


let data;

try {
Expand All @@ -909,21 +908,30 @@ export const getCanSubmitTo = () => async (dispatch, getState) => {
console.error('Error:', error.message);
}
}

const submissions = await data.data;

let submissions;
if (data) {
submissions = data.data;
// Your logic for handling submissions goes here
} else {
// Logic in case data is undefined or null
console.error('No data received');
}
url = `${publicRuntimeConfig.backend}/shared`;


try {
data = await axios.get(url, { headers });
} catch (error) {
if (error.response) {
console.error('Error:', error.message);
}
}

const sharedSubmissions = await data.data;
let sharedSubmissions;
if (data) {
sharedSubmissions = data.data;
// Your logic for handling submissions goes here
} else {
// Logic in case data is undefined or null
console.error('No shared data received');
}

dispatch({
type: types.CANSUBMITTO,
Expand Down
Loading