diff --git a/Makefile b/Makefile
index 58d1a0f..fcf1f31 100644
--- a/Makefile
+++ b/Makefile
@@ -33,12 +33,25 @@ clean-studio:
@printf "Clean studio...\n"
@cd studio && rm -rf node_modules && rm -rf dist && yarn cache clean && cd ..
-build-studio:
+build-biomedgps-studio:
@printf "Building studio based on openapi...\n"
@mkdir -p assets
+ @cp studio/logo/biomedgps.png studio/public/assets/logo-white.png
+ @cp studio/logo/biomedgps.png studio/src/assets/logo-white.png
+ @cp studio/logo/biomedgps.png studio/public/logo.png
# @cd studio && yarn && yarn openapi || true
@cd studio && yarn
- @cd studio && yarn build:embed && cd ..
+ @cd studio && yarn build:biomedgps-embed && cd ..
+
+build-rapex-studio:
+ @printf "Building studio based on openapi...\n"
+ @mkdir -p assets
+ @cp studio/logo/rapex.png studio/public/assets/logo-white.png
+ @cp studio/logo/rapex.png studio/src/assets/logo-white.png
+ @cp studio/logo/rapex.png studio/public/logo.png
+ # @cd studio && yarn && yarn openapi || true
+ @cd studio && yarn
+ @cd studio && yarn build:rapex-embed && cd ..
build-biomedgps:
@cargo build --release
@@ -46,13 +59,13 @@ build-biomedgps:
build-biomedgps-linux:
@cargo build --release --target=x86_64-unknown-linux-musl
-build-mac: build-studio build-biomedgps
+build-mac: build-biomedgps-studio build-biomedgps
@printf "\nDone!\n"
-build-linux: build-studio build-biomedgps
+build-linux: build-biomedgps-studio build-biomedgps
@printf "\nDone!\n"
-build-linux-on-mac: build-studio build-biomedgps-linux
+build-linux-on-mac: build-biomedgps-studio build-biomedgps-linux
@printf "\nDone!\n"
# You must run `make build-service` to build new api spec for studio when you change the api spec
@@ -66,8 +79,16 @@ changelog:
@python build/build_changelog.py --repo ../biominer-components --output-file ./studio/public/README/changelog.md --repo-name 'BioMedGPS UI'
@python build/build_changelog.py --repo . --output-file ./studio/public/README/changelog.md --repo-name BioMedGPS
-deploy: build-studio
+deploy: deploy-biomedgps
+
+deploy-biomedgps: build-biomedgps-studio
@docker run --rm -it -v "$(CURDIR)":/home/rust/src messense/rust-musl-cross:x86_64-musl cargo build --release
@rsync -avP target/x86_64-unknown-linux-musl/release/biomedgps target/x86_64-unknown-linux-musl/release/biomedgps-cli root@drugs.3steps.cn:/data/biomedgps/bin
@rsync -avP --delete assets/index.html root@drugs.3steps.cn:/var/www/html/biomedgps/index.html
- @rsync -avP --delete assets root@drugs.3steps.cn:/var/www/html/biomedgps/
\ No newline at end of file
+ @rsync -avP --delete assets root@drugs.3steps.cn:/var/www/html/biomedgps/
+
+deploy-rapex: build-rapex-studio
+ @docker run --rm -it -v "$(CURDIR)":/home/rust/src messense/rust-musl-cross:x86_64-musl cargo build --release
+ @rsync -avP target/x86_64-unknown-linux-musl/release/biomedgps target/x86_64-unknown-linux-musl/release/biomedgps-cli root@rapex.prophetdb.org:/data/rapex/bin
+ @rsync -avP --delete assets/index.html root@rapex.prophetdb.org:/var/www/html/rapex/index.html
+ @rsync -avP --delete assets root@rapex.prophetdb.org:/var/www/html/rapex/
\ No newline at end of file
diff --git a/studio/config/routes.ts b/studio/config/routes.ts
index a568d96..6c57563 100644
--- a/studio/config/routes.ts
+++ b/studio/config/routes.ts
@@ -1,4 +1,4 @@
-import { createElement } from "react";
+import { Children, createElement } from "react";
import * as icons from "@ant-design/icons";
import type { MenuDataItem } from '@ant-design/pro-components';
@@ -10,26 +10,40 @@ export const routes = [
component: './Home',
},
{
- path: '/knowledge-table',
- name: 'Knowledge Table',
- icon: 'table',
- hideInMenu: true,
- component: './KnowledgeTable',
- category: 'knowledge-graph'
- },
- {
- path: '/predict-model',
- name: 'Predict Drugs/Targets',
- icon: 'history',
- component: './ModelConfig',
- category: 'predict-model'
+ path: '/analyze-omics-data',
+ name: 'Analyze Omics Data',
+ icon: 'LineChartOutlined',
+ disabled: true,
+ component: './Home',
},
{
- path: '/knowledge-graph',
- name: 'Explain Your Results',
- icon: 'comment',
- component: './KnowledgeGraph',
- category: 'knowledge-graph'
+ path: '/predict-explain',
+ name: 'Predict & Explain',
+ icon: 'link',
+ routes: [
+ {
+ path: '/predict-explain/knowledge-table',
+ name: 'Knowledge Table',
+ icon: 'table',
+ hideInMenu: true,
+ component: './KnowledgeTable',
+ category: 'knowledge-graph'
+ },
+ {
+ path: '/predict-explain/predict-model',
+ name: 'Predict Drugs/Targets',
+ icon: 'history',
+ component: './ModelConfig',
+ category: 'predict-model'
+ },
+ {
+ path: '/predict-explain/knowledge-graph',
+ name: 'Explain Your Results',
+ icon: 'comment',
+ component: './KnowledgeGraph',
+ category: 'knowledge-graph'
+ },
+ ]
},
{
path: '/mecfs-longcovid',
diff --git a/studio/logo/biomedgps.png b/studio/logo/biomedgps.png
new file mode 100644
index 0000000..d3a9f9a
Binary files /dev/null and b/studio/logo/biomedgps.png differ
diff --git a/studio/logo/rapex.png b/studio/logo/rapex.png
new file mode 100644
index 0000000..78532c9
Binary files /dev/null and b/studio/logo/rapex.png differ
diff --git a/studio/package.json b/studio/package.json
index 949bcfd..3e64fec 100644
--- a/studio/package.json
+++ b/studio/package.json
@@ -7,14 +7,16 @@
"scripts": {
"dev": "max dev",
"build": "max build",
- "build:embed": "cross-env UMI_APP_IS_STATIC=true UMI_ENV=embed UMI_APP_AUTH0_CLIENT_ID=Y08FauV1dAEiocNIZt5LiOifzNgXr6Uo UMI_APP_AUTH0_DOMAIN=biomedgps.jp.auth0.com max build",
+ "build:biomedgps-embed": "cross-env UMI_APP_IS_STATIC=true UMI_ENV=embed UMI_APP_AUTH0_CLIENT_ID=Y08FauV1dAEiocNIZt5LiOifzNgXr6Uo UMI_APP_AUTH0_DOMAIN=biomedgps.jp.auth0.com max build",
+ "build:rapex-embed": "cross-env UMI_APP_IS_STATIC=true UMI_ENV=embed max build",
"build:analyze": "cross-env ANALYZE=true max build",
"format": "prettier --cache --write .",
"postinstall": "max setup",
"setup": "max setup",
"start": "npm run dev",
"start:local-dev": "cross-env UMI_APP_API_PREFIX=http://localhost:3000 max dev",
- "start:remote-dev": "cross-env UMI_APP_API_PREFIX=https://drugs.3steps.cn UMI_APP_AUTH0_CLIENT_ID=Y08FauV1dAEiocNIZt5LiOifzNgXr6Uo UMI_APP_AUTH0_DOMAIN=biomedgps.jp.auth0.com max dev",
+ "start:biomedgps-remote-dev": "cross-env UMI_APP_API_PREFIX=https://drugs.3steps.cn UMI_APP_AUTH0_CLIENT_ID=Y08FauV1dAEiocNIZt5LiOifzNgXr6Uo UMI_APP_AUTH0_DOMAIN=biomedgps.jp.auth0.com max dev",
+ "start:rapex-remote-dev": "cross-env UMI_APP_API_PREFIX=https://rapex.prophetdb.org max dev",
"openapi": "max openapi"
},
"dependencies": {
diff --git a/studio/public/README/about.md b/studio/public/README/about.md
index c8c2e45..3d34a4b 100644
--- a/studio/public/README/about.md
+++ b/studio/public/README/about.md
@@ -16,7 +16,7 @@ Construct and integrate knowledge graph, multi-omics data and d
## Features
-### Predict Drug/Target Module
+### Predict Drug/Target Module
- [x] Predict known drugs for your queried disease (Drug Repurposing).
- [x] Predict new indications for your queried drug.
@@ -26,7 +26,7 @@ Construct and integrate knowledge graph, multi-omics data and d
-### Explain Your Results Module
+### Explain Your Results Module
- [x] Knowledge graph studio for graph query, visualization and analysis.
- [x] Graph neural network for drug discovery, disease mechanism, biomarker screening and discovering response to toxicant exposure.
diff --git a/studio/public/assets/logo-white.png b/studio/public/assets/logo-white.png
index d3a9f9a..78532c9 100644
Binary files a/studio/public/assets/logo-white.png and b/studio/public/assets/logo-white.png differ
diff --git a/studio/public/logo.png b/studio/public/logo.png
index d3a9f9a..78532c9 100644
Binary files a/studio/public/logo.png and b/studio/public/logo.png differ
diff --git a/studio/src/app.tsx b/studio/src/app.tsx
index f167bbb..75889b9 100644
--- a/studio/src/app.tsx
+++ b/studio/src/app.tsx
@@ -4,7 +4,7 @@ import { RequestConfig, history, RuntimeConfig, request as UmiRequest } from 'um
import { PageLoading, SettingDrawer } from '@ant-design/pro-components';
import { Auth0Provider } from '@auth0/auth0-react';
import { CustomSettings, AppVersion } from '../config/defaultSettings';
-import { getJwtAccessToken, logout, logoutWithRedirect, getUsername } from '@/components/util';
+import { getJwtAccessToken, logout, logoutWithRedirect, getUsername, isAuthEnabled } from '@/components/util';
// import * as Sentry from "@sentry/react";
@@ -141,6 +141,10 @@ export async function getInitialState(): Promise<{
}
export function rootContainer(container: React.ReactNode): React.ReactNode {
+ if (!isAuthEnabled()) {
+ return container;
+ }
+
return (
{
// You can modify the css style of the menu item at the global.less file.
var spans = document.querySelectorAll('span.ant-pro-base-menu-horizontal-item-text');
+ console.log("Add new-tag to ME/CFS: ", spans);
spans.forEach(function (span) {
+ console.log("span.innerHTML: ", span.innerHTML);
if (span.innerHTML.startsWith("ME/CFS")) {
span.classList.add('new-tag');
}
diff --git a/studio/src/assets/logo-white.png b/studio/src/assets/logo-white.png
index d3a9f9a..78532c9 100644
Binary files a/studio/src/assets/logo-white.png and b/studio/src/assets/logo-white.png differ
diff --git a/studio/src/components/Header/index.tsx b/studio/src/components/Header/index.tsx
index cb7ee4d..afb25d4 100644
--- a/studio/src/components/Header/index.tsx
+++ b/studio/src/components/Header/index.tsx
@@ -1,7 +1,7 @@
import { QuestionCircleOutlined, InfoCircleOutlined, UserOutlined, FieldTimeOutlined, LogoutOutlined } from '@ant-design/icons';
import { Space, Menu, Button, message, Dropdown } from 'antd';
import React, { useEffect, useState } from 'react';
-import { getJwtAccessToken, logoutWithRedirect } from '@/components/util';
+import { getJwtAccessToken, logoutWithRedirect, isAuthEnabled } from '@/components/util';
import { useAuth0 } from "@auth0/auth0-react";
import type { MenuProps } from 'antd';
import { history } from 'umi';
@@ -160,14 +160,17 @@ const GlobalHeaderRight: React.FC = (props) => {
} style={{ height: '40px' }}>About
{
- !isAuthenticated ? (
+ isAuthEnabled() &&
+ !isAuthenticated ? (
) : (
-
+ isAuthEnabled() ?
+
}>{username}
-
+
+ : }>{username}
)
}
diff --git a/studio/src/components/util.ts b/studio/src/components/util.ts
index e568b89..9165548 100644
--- a/studio/src/components/util.ts
+++ b/studio/src/components/util.ts
@@ -89,7 +89,28 @@ export const logout = () => {
localStorage.removeItem('redirectUrl');
}
+export const isAuthEnabled = () => {
+ console.log("isAuthEnabled: ", process.env.UMI_APP_AUTH0_CLIENT_ID);
+ return process.env.UMI_APP_AUTH0_CLIENT_ID ? true : false
+}
+
+export const isAuthenticated = () => {
+ if (getUsername()) {
+ return true
+ }
+
+ if (!isAuthEnabled()) {
+ return true
+ }
+
+ return false
+}
+
export const logoutWithRedirect = () => {
+ if (!isAuthEnabled()) {
+ return
+ }
+
logout();
// Save the current hash as the redirect url
let currentUrl = window.location.hash.split("#").pop();
diff --git a/studio/src/components/webllm.ts b/studio/src/components/webllm.ts
index 1eb684f..8af17e4 100644
--- a/studio/src/components/webllm.ts
+++ b/studio/src/components/webllm.ts
@@ -1,27 +1,6 @@
import { ChatModule, InitProgressReport } from "@mlc-ai/web-llm";
import { message } from "antd";
-export const getJwtAccessToken = (): string | null => {
- let jwtToken = null;
- // Check if the cookie exists
- if (document.cookie && document.cookie.includes("jwt_access_token=")) {
- // Retrieve the cookie value
- // @ts-ignore
- jwtToken = document.cookie
- .split("; ")
- .find((row) => row.startsWith("jwt_access_token="))
- .split("=")[1];
- }
-
- if (jwtToken) {
- console.log("JWT access token found in the cookie.");
- return jwtToken;
- } else {
- console.log("JWT access token not found in the cookie.");
- return null;
- }
-}
-
export const initChat = async () => {
// const chat = new webllm.ChatWorkerClient(new Worker(
// new URL('./assets/web-llm.worker.js', import.meta.url),
diff --git a/studio/src/global.less b/studio/src/global.less
index 4560c98..8073a97 100644
--- a/studio/src/global.less
+++ b/studio/src/global.less
@@ -38,6 +38,16 @@ body,
.ant-pro-top-nav-header-logo img {
height: 45px;
}
+
+ // For mix layout
+ .ant-pro-global-header {
+ height: 100%;
+ }
+
+ .ant-pro-global-header-logo a>svg,
+ .ant-pro-global-header-logo a>img {
+ height: 45px;
+ }
}
.ant-pro-sider.ant-layout-sider.ant-pro-sider-fixed {
@@ -71,6 +81,7 @@ ol {
&-thead>tr,
&-tbody>tr {
+
>th,
>td {
white-space: pre;
@@ -85,7 +96,7 @@ ol {
// Compatible with IE11
@media screen and(-ms-high-contrast: active),
- (-ms-high-contrast: none) {
+(-ms-high-contrast: none) {
body .ant-design-pro>.ant-layout {
min-height: 100vh;
}
@@ -146,7 +157,8 @@ ol {
// For Markdown Table
.markdown-viewer {
tr:nth-child(odd) {
- background-color: #f2f2f2; /* 灰色 */
+ background-color: #f2f2f2;
+ /* 灰色 */
}
tr:nth-child(even) {
@@ -171,4 +183,4 @@ ol {
border-radius: 2px;
vertical-align: super;
line-height: 1;
-}
+}
\ No newline at end of file
diff --git a/studio/src/pages/Home/index.tsx b/studio/src/pages/Home/index.tsx
index c34d7a0..8efaf76 100644
--- a/studio/src/pages/Home/index.tsx
+++ b/studio/src/pages/Home/index.tsx
@@ -184,16 +184,16 @@ const HomePage: React.FC = () => {
console.log('Search:', value);
if (value && name) {
- history.push(`/knowledge-table?nodeId=${value}&nodeName=${name}`);
+ history.push(`/predict-explain/knowledge-table?nodeId=${value}&nodeName=${name}`);
return;
}
const filtered = filter(nodeOptions, (item) => item.value === value);
if (filtered.length === 0 || !filtered[0]?.metadata) {
- history.push(`/knowledge-table?nodeId=${value}`);
+ history.push(`/predict-explain/knowledge-table?nodeId=${value}`);
} else {
const metadata = filtered[0].metadata;
- history.push(`/knowledge-table?nodeId=${value}&nodeName=${metadata.name}`);
+ history.push(`/predict-explain/knowledge-table?nodeId=${value}&nodeName=${metadata.name}`);
}
};
@@ -236,7 +236,7 @@ const HomePage: React.FC = () => {
Enter a gene/protein, disease, drug or symptom name to find and explain related known knowledges in our platform.
- If you want to predict new knowledges, please go to the { history.push('/predict-model'); }}>Predict Drug/Target page.
+ If you want to predict new knowledges, please go to the { history.push('/predict-explain/predict-model'); }}>Predict Drug/Target page.
Please click the following examples to see the results.
diff --git a/studio/src/pages/KnowledgeGraph/index.tsx b/studio/src/pages/KnowledgeGraph/index.tsx
index 9808830..cbaca75 100644
--- a/studio/src/pages/KnowledgeGraph/index.tsx
+++ b/studio/src/pages/KnowledgeGraph/index.tsx
@@ -1,4 +1,4 @@
-import { getUsername, logoutWithRedirect } from '@/components/util';
+import { isAuthenticated, logoutWithRedirect } from '@/components/util';
import { Row, Col, Button, message as AntMessage, Empty } from 'antd';
import { KnowledgeGraph } from 'biominer-components';
import React, { useEffect, useState, memo, Suspense } from 'react';
@@ -22,13 +22,10 @@ const KnowledgeGraphWithChatBot: React.FC = () => {
const [chatBoxVisible, setChatBoxVisible] = useState(false)
const [span, setSpan] = useState(kgFullSpan)
const ChatBox = React.lazy(() => import('@/components/ChatBox'));
- const [username, setUsername] = useState(undefined);
useEffect(() => {
- const username = getUsername();
- setUsername(username);
-
- if (!username) {
+ console.log("isAuthenticated in KnowledgeGraph: ", isAuthenticated());
+ if (!isAuthenticated()) {
logoutWithRedirect();
}
}, [])
@@ -41,7 +38,7 @@ const KnowledgeGraphWithChatBot: React.FC = () => {
}
}, [chatBoxVisible])
- return username &&
+ return isAuthenticated() &&
{
chatBoxVisible ? (
diff --git a/studio/src/pages/KnowledgeTable/index.tsx b/studio/src/pages/KnowledgeTable/index.tsx
index 26686c0..f245891 100644
--- a/studio/src/pages/KnowledgeTable/index.tsx
+++ b/studio/src/pages/KnowledgeTable/index.tsx
@@ -12,7 +12,7 @@ import type { EdgeInfo } from '@/EdgeInfoPanel/index.t';
import NodeInfoPanel from '@/NodeInfoPanel';
import EdgeInfoPanel from '@/EdgeInfoPanel';
import { sortBy, filter, uniqBy, groupBy, map, sumBy, set } from 'lodash';
-import { guessColor, truncateString, getUsername, logoutWithRedirect } from '@/components/util';
+import { guessColor, truncateString, getUsername, logoutWithRedirect, isAuthEnabled, isAuthenticated } from '@/components/util';
import EntityCard from '@/components/EntityCard';
import './index.less';
@@ -134,14 +134,9 @@ const KnowledgeTable: React.FC = (props) => {
const [page, setPage] = useState(1);
const [pageSize, setPageSize] = useState(30);
const [refreshKey, setRefreshKey] = useState(0);
- const [username, setUsername] = useState(undefined);
useEffect(() => {
- const username = getUsername();
- console.log('Username: ', username);
- setUsername(username);
-
- if (!username) {
+ if (!isAuthenticated()) {
logoutWithRedirect();
} else {
@@ -211,7 +206,7 @@ const KnowledgeTable: React.FC = (props) => {
edges: selectedEdges,
};
pushGraphDataToLocalStorage(selectedGraphData);
- history.push('/knowledge-graph');
+ history.push('/predict-explain/knowledge-graph');
}
const getKnowledgesData = (
@@ -652,16 +647,16 @@ const KnowledgeTable: React.FC = (props) => {
const getTitle = (node: GraphNode) => {
return
- {node?.nlabel} Card - {node?.data.name}
-
+ {node?.nlabel} Card - {node?.data.name} [Click to show more details]
+ {/*
-
+ */}
;
}
- return username && (total == 0 ? (
+ return (isAuthenticated()) && (total == 0 ? (
= (props) => {
{currentNodes.length > 0 && currentNodes.map((node, index) => {
return node?.nlabel == 'Gene' ?
+ extra={getExtraButton(index.toString())}
+ >
: null;
})}
diff --git a/studio/src/pages/ModelConfig/index.tsx b/studio/src/pages/ModelConfig/index.tsx
index 9551684..6b5fcc9 100644
--- a/studio/src/pages/ModelConfig/index.tsx
+++ b/studio/src/pages/ModelConfig/index.tsx
@@ -15,7 +15,7 @@ import { fetchStatistics } from '@/services/swagger/KnowledgeGraph';
import { makeRelationTypes } from 'biominer-components/dist/utils';
import type { OptionType, RelationStat, ComposeQueryItem, QueryItem, GraphEdge, GraphNode } from 'biominer-components/dist/typings';
import EntityCard from '@/components/EntityCard';
-import { truncateString, getUsername, logoutWithRedirect } from '@/components/util';
+import { truncateString, getUsername, logoutWithRedirect, isAuthenticated } from '@/components/util';
import './index.less';
@@ -248,13 +248,10 @@ const ModelConfig: React.FC = (props) => {
const [nodeDataSources, setNodeDataSources] = useState([]);
const [relationTypeOptions, setRelationTypeOptions] = useState([]);
const [relationStat, setRelationStat] = useState([]);
- const [username, setUsername] = useState(undefined);
useEffect(() => {
- const username = getUsername();
- setUsername(username);
-
- if (!username) {
+ console.log("isAuthenticated in ModelConfig: ", isAuthenticated());
+ if (!isAuthenticated()) {
logoutWithRedirect();
} else {
fetchStatistics().then((data) => {
@@ -881,7 +878,7 @@ const ModelConfig: React.FC = (props) => {
}
return (
- username &&
+ isAuthenticated() &&