Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • graphpolaris/frontend-v2
  • rijkheere/frontend-v-2-reordering-paoh
2 results
Show changes
Commits on Source (5)
Showing
with 239 additions and 624 deletions
node_modules
libs/storybook
\ No newline at end of file
node_modules/
libs/storybook
apps/web/dist
apps/web/dist/
apps/web/node_modules
apps/web/node_modules/
libs/shared/node_modules
libs/shared/node_modules/
\ No newline at end of file
GRAPHPOLARIS_VERSION=dev
BACKEND_URL=http://localhost
BACKEND_WSS_URL=ws://localhost:3001/
STAGING=dev
SKIP_LOGIN=true
BACKEND_USER=:3000
GRAPHPOLARIS_VERSION=dev
SENTRY_ENABLED=false
SENTRY_URL= GP_AUTH_URL=
\ No newline at end of file
GRAPHPOLARIS_VERSION=dev
BACKEND_URL=http://localhost
BACKEND_WSS_URL=ws://localhost:3001/
STAGING=dev
SKIP_LOGIN=true
BACKEND_USER=:3000
GRAPHPOLARIS_VERSION=dev
SENTRY_ENABLED=false
SENTRY_URL=
GP_AUTH_URL=
WIP_TABLEVIS=false
WIP_NODELINKVIS=false
WIP_RAWJSONVIS=false
WIP_PAOHVIS=true
WIP_MATRIXVIS=true
WIP_SEMANTICSUBSTRATESVIS=true
WIP_MAPVIS=true
WIP_INSIGHT_SHARING=true
WIP_VIEWER_PERMISSIONS=true
WIP_SHARABLE_EXPLORATION=true
\ No newline at end of file
......@@ -9,4 +9,16 @@ VITE_BACKEND_SCHEMA=:3002
SENTRY_ENABLED=false
SENTRY_URL=
GP_AUTH_URL=
\ No newline at end of file
GP_AUTH_URL=
WIP_TABLEVIS=false
WIP_NODELINKVIS=false
WIP_RAWJSONVIS=false
WIP_PAOHVIS=true
WIP_MATRIXVIS=true
WIP_SEMANTICSUBSTRATESVIS=true
WIP_MAPVIS=true
WIP_INSIGHT_SHARING=true
WIP_VIEWER_PERMISSIONS=true
WIP_SHARABLE_EXPLORATION=true
\ No newline at end of file
......@@ -8,4 +8,16 @@ BACKEND_USER=
SENTRY_ENABLED=false
SENTRY_URL=
GP_AUTH_URL=
\ No newline at end of file
GP_AUTH_URL=
WIP_TABLEVIS=false
WIP_NODELINKVIS=false
WIP_RAWJSONVIS=false
WIP_PAOHVIS=true
WIP_MATRIXVIS=true
WIP_SEMANTICSUBSTRATESVIS=true
WIP_MAPVIS=true
WIP_INSIGHT_SHARING=true
WIP_VIEWER_PERMISSIONS=true
WIP_SHARABLE_EXPLORATION=true
\ No newline at end of file
import React, { useEffect, useState } from 'react';
import {
useAppDispatch,
useAuthorizationCache,
useAuthCache,
useML,
useQuerybuilderGraph,
useQuerybuilderSettings,
......@@ -11,11 +11,10 @@ import { addError, setCurrentTheme } from '@graphpolaris/shared/lib/data-access/
import { resetGraphQueryResults, queryingBackend } from '@graphpolaris/shared/lib/data-access/store/graphQueryResultSlice';
import { Query2BackendQuery, QueryMultiGraph } from '@graphpolaris/shared/lib/querybuilder';
import { Navbar } from '../components/navbar/navbar';
import { Resizable } from '@graphpolaris/shared/lib/components/layout';
import { DashboardAlerts } from '@graphpolaris/shared/lib/data-access/authorization/dashboardAlerts';
import { FrozenOverlay, Resizable } from '@graphpolaris/shared/lib/components/layout';
import { DashboardAlerts } from '@graphpolaris/shared/lib/data-access/security/dashboardAlerts';
import { EventBus } from '@graphpolaris/shared/lib/data-access/api/eventBus';
import { Onboarding } from '../components/onboarding/onboarding';
import { wsQueryRequest } from '@graphpolaris/shared/lib/data-access/broker';
import { URLParams, setParam } from '@graphpolaris/shared/lib/data-access/api/url';
import { VisualizationPanel } from '@graphpolaris/shared/lib/vis';
import { QueryBuilder } from '@graphpolaris/shared/lib/querybuilder';
......@@ -24,6 +23,7 @@ import { InspectorPanel } from '@graphpolaris/shared/lib/inspector';
import { SearchBar } from '@graphpolaris/shared/lib/sidebar/search/SearchBar';
import { Schema } from '@graphpolaris/shared/lib/schema/panel';
import { InsightDialog } from '@graphpolaris/shared/lib/insight-sharing';
import { wsQueryRequest } from '@graphpolaris/shared/lib/data-access/broker';
import { ErrorBoundary } from '@graphpolaris/shared/lib/components/errorBoundary';
export type App = {
......@@ -31,7 +31,7 @@ export type App = {
};
export function App(props: App) {
const auth = useAuthorizationCache();
const auth = useAuthCache();
const query = useQuerybuilderGraph() as QueryMultiGraph;
const ml = useML();
const session = useSessionCache();
......@@ -76,7 +76,7 @@ export function App(props: App) {
<>
<Onboarding />
<DashboardAlerts />
<div className={'h-screen w-screen ' + (!auth.authorized ? 'blur-sm pointer-events-none ' : '')}>
<div className={'h-screen w-screen '}>
<div className="flex flex-col h-screen max-h-screen relative">
<aside className="absolute w-full h-12">
<Navbar />
......@@ -139,6 +139,12 @@ export function App(props: App) {
</main>
</div>
</div>
<FrozenOverlay>
{!auth.authentication?.authenticated && <span>Not Authenticated</span>}
{!auth.authorization.savestate.W && !session.currentSaveState && (
<span>Viewer account not authorized. Please load a shared exploration.</span>
)}
</FrozenOverlay>
</>
)}
</div>
......
import React, { useEffect, useState, useCallback } from 'react';
import {
useAppDispatch,
useSchemaGraph,
useSessionCache,
useAuthorizationCache,
useCheckPermissionPolicy,
} from '@graphpolaris/shared/lib/data-access';
import { deleteSaveState, selectSaveState } from '@graphpolaris/shared/lib/data-access/store/sessionSlice';
import { SettingsForm } from './forms/settings';
import { LoadingSpinner } from '@graphpolaris/shared/lib/components/LoadingSpinner';
import { addError } from '@graphpolaris/shared/lib/data-access/store/configSlice';
import { DropdownTrigger, DropdownContainer, DropdownItemContainer } from '@graphpolaris/shared/lib/components/dropdowns';
import { clearQB } from '@graphpolaris/shared/lib/data-access/store/querybuilderSlice';
import { clearSchema } from '@graphpolaris/shared/lib/data-access/store/schemaSlice';
import { DatabaseStatus, SaveStateI, nilUUID, wsDeleteState } from '@graphpolaris/shared/lib/data-access/broker';
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@graphpolaris/shared/lib/components/tooltip';
import { Icon } from '@graphpolaris/shared';
export default function DatabaseSelector({}) {
const dispatch = useAppDispatch();
const session = useSessionCache();
const schemaGraph = useSchemaGraph();
const authCache = useAuthorizationCache();
const [hovered, setHovered] = useState<string | null>(null);
const [connecting, setConnecting] = useState<boolean>(false);
const [dbSelectionMenuOpen, setDbSelectionMenuOpen] = useState<boolean>(false);
const [settingsMenuOpen, setSettingsMenuOpen] = useState<'add' | 'update' | undefined>(undefined);
const [selectedSaveState, setSelectedSaveState] = useState<SaveStateI | null>(null);
useEffect(() => {
if (
(!session.fetchingSaveStates &&
session.saveStates &&
Object.keys(session.saveStates).length === 0 &&
settingsMenuOpen === undefined) ||
session.currentSaveState === nilUUID
) {
setSettingsMenuOpen('add');
}
}, [session, settingsMenuOpen]);
useEffect(() => {
setConnecting(false);
}, [schemaGraph]);
useEffect(() => {
let timeoutId: ReturnType<typeof setTimeout>;
if (connecting) {
timeoutId = setTimeout(() => {
dispatch(addError("Couldn't establish connection"));
setConnecting(false);
dispatch(selectSaveState(undefined));
dispatch(clearQB());
dispatch(clearSchema());
}, 10000);
}
return () => {
if (timeoutId) clearTimeout(timeoutId);
};
}, [connecting]);
const { canRead, canWrite } = useCheckPermissionPolicy();
const [readAllowed, setReadAllowed] = useState(false);
const [writeAllowed, setWriteAllowed] = useState(false);
const resource = 'database';
const checkReadPermission = useCallback(async () => {
const result = await canRead(resource);
setReadAllowed(result);
}, [canRead]);
const checkWritePermission = useCallback(async () => {
const result = await canWrite(resource);
setWriteAllowed(result);
}, [canWrite]);
useEffect(() => {
checkReadPermission();
}, [checkReadPermission]);
useEffect(() => {
checkWritePermission();
}, [checkWritePermission]);
return (
<div className="menu-walkthrough">
<TooltipProvider delayDuration={1000}>
{settingsMenuOpen !== undefined && (
<SettingsForm
open={settingsMenuOpen}
saveState={settingsMenuOpen === 'update' ? selectedSaveState : null}
disableCancel={
(session.saveStates && Object.keys(session.saveStates).length === 0) ||
session.currentSaveState === '00000000-0000-0000-0000-000000000000'
}
onClose={() => {
setSettingsMenuOpen(undefined);
}}
/>
)}
<DropdownContainer
open={dbSelectionMenuOpen}
onOpenChange={(ret) => {
if (!ret) {
if (session.saveStates && Object.keys(session.saveStates).length === 0) setSettingsMenuOpen('add');
else setDbSelectionMenuOpen(!dbSelectionMenuOpen);
} else {
setDbSelectionMenuOpen(true);
}
}}
>
<DropdownTrigger
onClick={() => {
if (connecting || authCache.authorized === false || !!authCache.roomID || writeAllowed) {
console.debug('User blocked from editing query due to being a viewer');
setDbSelectionMenuOpen(!dbSelectionMenuOpen);
}
}}
className="w-[18rem]"
size="md"
disabled={connecting || authCache.authorized === false || !!authCache.roomID || !writeAllowed}
title={
<div className="flex items-center">
{connecting && session.currentSaveState && session.currentSaveState in session.saveStates ? (
<>
<LoadingSpinner />
<p className="ml-2 truncate">Connecting to {session.saveStates[session.currentSaveState].name}</p>
</>
) : session.currentSaveState && session.currentSaveState in session.saveStates && session.currentSaveState !== nilUUID ? (
<div className="flex">
<Icon component="icon-[ic--outline-storage]" size={20} className=" self-center" />
<span className="relative">
<span
className={`absolute bottom-0.5 right-3 h-2 w-2 border border-light rounded-full ${session.testedSaveState[session.currentSaveState] === DatabaseStatus.tested ? 'bg-success-500' : 'bg-danger-500'}`}
/>
</span>
<p className="ml-2 truncate">{session.saveStates[session.currentSaveState].name}</p>
</div>
) : session.saveStates === undefined ? (
<>
<LoadingSpinner />
<p className="ml-2">Retrieving databases</p>
</>
) : Object.keys(session.saveStates).length === 0 || session.currentSaveState === nilUUID ? (
<>
<p className="ml-2">Add your first Database</p>
</>
) : (
<>
<div className="h-2 w-2 rounded-full bg-secondary-500" />
<p className="ml-2">Select a database</p>
</>
)}
</div>
}
/>
{session.saveStates !== undefined && (
<DropdownItemContainer>
<li
className="flex items-center p-2 hover:bg-secondary-50 cursor-pointer"
onClick={(e) => {
e.preventDefault();
setDbSelectionMenuOpen(false);
setConnecting(false);
setSettingsMenuOpen('add');
}}
>
{session.saveStates && Object.keys(session.saveStates).length === 0 ? (
<>
<Icon component="icon-[ic--baseline-add]" size={24} />
<p className="ml-2">Add your first database</p>
</>
) : (
<>
<Icon component="icon-[ic--baseline-add]" size={24} />
<p className="ml-2">Add database</p>
</>
)}
</li>
{Object.values(session.saveStates)
.filter((save) => save.id !== nilUUID)
.map((save) => (
<li
key={save.id}
className="flex justify-between items-center px-4 py-2 hover:bg-primary-100 gap-2 cursor-pointer"
onClick={(e) => {
if (save.id !== session.currentSaveState) {
e.preventDefault();
setDbSelectionMenuOpen(false);
setConnecting(true);
dispatch(selectSaveState(save.id));
dispatch(clearQB());
dispatch(clearSchema());
} else {
setDbSelectionMenuOpen(false);
}
}}
onMouseEnter={() => setHovered(save.id)}
onMouseLeave={() => setHovered(null)}
>
<Tooltip placement={'left'}>
<TooltipTrigger>
<div
className={`h-[8px] w-[8px] rounded-full shrink-0 ${
session.testedSaveState[save.id] === DatabaseStatus.tested ? 'bg-success-500' : 'bg-danger-500'
}`}
/>
</TooltipTrigger>
<TooltipContent>
<p>
{session.testedSaveState[save.id] === DatabaseStatus.tested
? 'Database connection tested'
: 'Something went wrong when trying to connect'}
</p>
</TooltipContent>
</Tooltip>
<div className="w-full shrink min-w-0 flex flex-col">
<p className="truncate w-full shrink-0 min-w-0">{save.name}</p>
<p className="bg-light text-2xs text-secondary-500 truncate w-fit shrink-0 min-w-0 max-w-full h-full border border-secondary-200 rounded-sm p-0.5">
{save.db.protocol}
{save.db.url}
</p>
</div>
<div className={`flex items-center ml-2 ${hovered === save.id ? 'display' : 'invisible'}`}>
<div
className="text-secondary-700 hover:text-secondary-400 transition-colors duration-300"
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
setSettingsMenuOpen('update');
setSelectedSaveState(save);
}}
>
<Tooltip>
<TooltipTrigger>
<Icon component="icon-[ic--baseline-settings]" size={24} />
</TooltipTrigger>
<TooltipContent>
<p>Change the connection details</p>
</TooltipContent>
</Tooltip>
</div>
<div
className="text-secondary-700 hover:text-secondary-400 transition-colors duration-300"
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
setDbSelectionMenuOpen(false);
if (session.currentSaveState === save.id) {
dispatch(clearQB());
dispatch(clearSchema());
}
wsDeleteState(save.id);
dispatch(deleteSaveState(save.id));
}}
>
<Tooltip>
<TooltipTrigger>
<Icon component="icon-[ic--baseline-delete]" size={24} />
</TooltipTrigger>
<TooltipContent>
<p>Delete the database</p>
</TooltipContent>
</Tooltip>
</div>
</div>
</li>
))}
</DropdownItemContainer>
)}
</DropdownContainer>
</TooltipProvider>
</div>
);
}
import React, { useEffect, useRef, useState } from 'react';
import {
useAppDispatch,
SaveStateI,
wsUpdateState,
wsTestDatabaseConnection,
wsCreateState,
useAuthorizationCache,
nilUUID,
} from '@graphpolaris/shared/lib/data-access';
import { Dialog, DialogContent } from '@graphpolaris/shared/lib/components/layout';
import { Button } from '@graphpolaris/shared/lib/components/buttons';
import { useImmer } from 'use-immer';
import { addSaveState, testedSaveState } from '@graphpolaris/shared/lib/data-access/store/sessionSlice';
import { DatabaseForm, INITIAL_SAVE_STATE } from './databaseForm';
import { SampleDatabaseSelector } from './mockSaveStates';
import { Icon } from '@graphpolaris/shared';
type Connection = {
updating: boolean;
status: null | string;
verified: boolean | null;
};
export const SettingsForm = (props: { onClose(): void; open: 'add' | 'update'; saveState: SaveStateI | null; disableCancel?: boolean }) => {
const dispatch = useAppDispatch();
const ref = useRef<HTMLDialogElement>(null);
const auth = useAuthorizationCache();
const [formData, setFormData] = useImmer(
props.saveState && props.open === 'update' ? props.saveState : { ...INITIAL_SAVE_STATE, user_id: auth.userID || '' },
);
const [hasError, setHasError] = useState(false);
const [sampleDataPanel, setSampleDataPanel] = useState<boolean | null>(false);
const [connection, setConnection] = useState<Connection>({
updating: false,
status: null,
verified: null,
});
const formTitle = props.open === 'add' ? 'Add' : 'Update';
useEffect(() => {
if (props.saveState && props.open === 'update') {
setFormData(props.saveState);
setSampleDataPanel(null);
} else {
setSampleDataPanel(false);
}
}, [props.saveState]);
async function handleSubmit(saveStateData?: SaveStateI, forceAdd: boolean = false): Promise<void> {
if (!saveStateData) saveStateData = formData;
setConnection(() => ({
updating: true,
status: 'Testing database connection',
verified: null,
}));
wsTestDatabaseConnection(saveStateData.db, (data) => {
if (!saveStateData) {
console.error('formData is null');
return;
}
if (saveStateData.user_id !== auth.userID && auth.userID) {
console.error('user_id is not equal to auth.userID');
saveStateData.user_id = auth.userID;
}
if (data && data.status === 'success') {
setConnection((prevState) => ({
updating: false,
status: 'Database connection verified',
verified: true,
}));
if (props.open === 'add' || forceAdd) {
wsCreateState(saveStateData, (_data) => {
dispatch(addSaveState(_data));
dispatch(testedSaveState(_data.id));
closeDialog();
});
} else {
dispatch(testedSaveState(data.saveStateID));
wsUpdateState(saveStateData, (_data) => {
dispatch(addSaveState(_data));
closeDialog();
});
}
} else {
setConnection((prevState) => ({
updating: false,
status: 'Database connection test failed',
verified: false,
}));
}
});
}
function handlePortChanged(port: string): void {
if (!isNaN(Number(port)))
setFormData((draft) => {
draft.db.port = Number(port);
return draft;
});
}
function closeDialog(): void {
setConnection({
updating: false,
status: null,
verified: null,
});
setFormData({ ...INITIAL_SAVE_STATE, user_id: auth.userID || '' });
ref.current?.close();
props.onClose();
}
return (
<Dialog
open={!!props.open}
onOpenChange={(ret) => {
if (!ret) props.onClose;
}}
>
<DialogContent className="lg:min-w-[50rem]">
<div className="flex justify-between align-center m-2">
<h2 className="text-xl font-bold">{formTitle} Database Connection</h2>
<div>
{sampleDataPanel === true ? (
<Button variant="outline" label="Go back" onClick={() => setSampleDataPanel(false)} />
) : sampleDataPanel === false ? (
<>
<h1 className="font-light text-xs">No data?</h1>
<p className="font-light text-sm cursor-pointer underline" onClick={() => setSampleDataPanel(true)}>
Try sample data
</p>
</>
) : (
''
)}
</div>
</div>
<>
{sampleDataPanel === true ? (
<SampleDatabaseSelector
onClick={(data) => {
setHasError(false);
handleSubmit({ ...data, user_id: auth.userID || '' });
}}
/>
) : (
<DatabaseForm
data={formData}
onChange={(data: SaveStateI, error: boolean) => {
setFormData({ ...data, id: formData.id });
setHasError(error);
}}
/>
)}
{!(connection.status === null) && (
<div className={`flex flex-col justify-center items-center`}>
<div className="flex justify-center items-center">
{connection.verified === false && <Icon component="icon-[ic--baseline-error-outline]" className="text-secondary-400" />}
<p className="font-light text-sm text-secondary-400 ">{connection.status}</p>
</div>
{connection.verified === null && <progress className="progress w-56"></progress>}
</div>
)}
<div
className={`pt-4 flex flex-row gap-3 card-actions w-full justify-stretch items-center ${sampleDataPanel === true && 'hidden'}`}
>
<Button
variantType="primary"
className="flex-grow"
label={connection.updating ? (formTitle === 'Add' ? formTitle + 'ing...' : formTitle.slice(0, -1) + 'ing...') : formTitle}
onClick={(event) => {
event.preventDefault();
handleSubmit();
}}
disabled={connection.updating || hasError}
/>
{props.open === 'update' && (
<Button
variantType="secondary"
className="flex-grow"
label={'Clone'}
onClick={(event) => {
handleSubmit({ ...formData, name: formData.name + ' (copy)', id: nilUUID }, true);
}}
disabled={connection.updating || hasError}
/>
)}
<Button
variant="outline"
className="flex-grow"
label="Cancel"
disabled={props.disableCancel}
onClick={(event) => {
event.preventDefault();
closeDialog();
}}
/>
</div>
</>
</DialogContent>
</Dialog>
);
};
......@@ -2,13 +2,14 @@ import React from 'react';
type GpLogoProps = {
className?: string; // `className` is optional and is of type string
includeText?: boolean;
};
const GpLogo: React.FC<GpLogoProps> = ({ className = '' }) => {
const GpLogo: React.FC<GpLogoProps> = ({ className = '', includeText = true }) => {
return (
<>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 444 80"
viewBox={`0 0 ${includeText ? '444' : '80'} 80`}
fill="none"
preserveAspectRatio="xMidYMid meet"
className={`gp-logo ${className}`}
......@@ -38,12 +39,14 @@ const GpLogo: React.FC<GpLogoProps> = ({ className = '' }) => {
<path fill="#E29B27" d="m46.8153 55.6051 7.80257-7.80257 7.80257 7.80257-7.80257 7.80257z" />
<path fill="#EAAE2C" d="m39.0128 63.4077 7.80257-7.80257 7.80257 7.80257-7.80257 7.80257z" />
<path fill="#E9BE31" d="m31.2102 71.2102 7.80257-7.80257 7.80257 7.80257-7.80257 7.80257z" />
<path
fill="currentColor"
fillRule="evenodd"
d="M400.22 23.8855c.639.6389 1.42.9584 2.343.9584.887 0 1.632-.3195 2.236-.9584.639-.6389.958-1.4197.958-2.3426 0-.9228-.319-1.7037-.958-2.3426-.604-.6389-1.349-.9584-2.236-.9584-.923 0-1.704.3195-2.343.9584s-.958 1.4198-.958 2.3426c0 .9229.319 1.7037.958 2.3426Zm4.685 34.8731V29.5824h-4.845v29.1762h4.845Zm12.57-.6388c1.775.7453 3.78 1.118 6.016 1.118 2.095 0 3.94-.3549 5.538-1.0648 1.632-.7454 2.892-1.757 3.78-3.0348.887-1.2778 1.331-2.7153 1.331-4.3125-.036-1.7747-.533-3.2122-1.491-4.3126-.923-1.1003-2.041-1.9167-3.354-2.4491-1.314-.5679-3.017-1.1358-5.111-1.7037-1.669-.4614-2.982-.8696-3.94-1.2245-.923-.3905-1.704-.8874-2.343-1.4908-.603-.6389-.905-1.4375-.905-2.3959 0-1.2068.515-2.1829 1.544-2.9282 1.029-.7454 2.414-1.1181 4.153-1.1181 1.881 0 3.372.4614 4.472 1.3843 1.136.9228 1.757 2.1474 1.864 3.6736h4.844c-.141-2.8395-1.206-5.0757-3.194-6.7084-1.988-1.6327-4.596-2.4491-7.826-2.4491-2.095 0-3.958.3727-5.591 1.1181-1.633.7099-2.893 1.686-3.78 2.9283-.887 1.2423-1.331 2.6088-1.331 4.0995 0 1.8812.479 3.4075 1.438 4.5788.993 1.1358 2.165 2.0054 3.513 2.6088 1.385.5679 3.159 1.1358 5.325 1.7038 2.378.6034 4.135 1.2245 5.271 1.8634 1.135.6034 1.703 1.544 1.703 2.8218 0 1.2423-.532 2.2716-1.597 3.088-1.065.8164-2.52 1.2245-4.366 1.2245-1.987 0-3.602-.4614-4.845-1.3842-1.207-.9229-1.881-2.1119-2.023-3.5672h-5.005c.107 1.7747.675 3.3542 1.704 4.7385 1.029 1.3488 2.431 2.4136 4.206 3.1945Zm-32.431-23.799c.852-1.6683 2.058-2.9638 3.62-3.8867 1.597-.9228 3.532-1.3842 5.803-1.3842v5.0047h-1.277c-5.431 0-8.146 2.946-8.146 8.838v15.866h-4.845V29.5823h4.845v4.7385Zm-40.825 1.9168c-1.207 2.2361-1.81 4.8449-1.81 7.8264 0 2.9461.603 5.5726 1.81 7.8798 1.207 2.3071 2.857 4.0995 4.952 5.3773 2.094 1.2778 4.436 1.9167 7.027 1.9167 2.521 0 4.721-.5501 6.602-1.6505 1.917-1.1358 3.355-2.5555 4.313-4.2593v5.4307h4.898V29.5824h-4.898v5.3241c-.923-1.6682-2.325-3.0525-4.206-4.1528-1.881-1.1003-4.1-1.6505-6.655-1.6505-2.591 0-4.952.6212-7.081 1.8635-2.095 1.2423-3.745 2.9992-4.952 5.2709Zm21.563 2.1296c.887 1.6327 1.331 3.5494 1.331 5.7501 0 2.2006-.444 4.1351-1.331 5.8033-.887 1.6327-2.094 2.8928-3.62 3.7801-1.491.8519-3.142 1.2778-4.952 1.2778s-3.461-.4259-4.951-1.2778c-1.491-.8873-2.68-2.1474-3.568-3.7801-.887-1.6682-1.331-3.6204-1.331-5.8566 0-2.2006.444-4.1173 1.331-5.75.888-1.6328 2.077-2.8751 3.568-3.7269 1.49-.8519 3.141-1.2778 4.951-1.2778 1.81 0 3.461.4437 4.952 1.331 1.526.8519 2.733 2.0942 3.62 3.7269Zm-29.82-19.0073v39.3987h-4.845V19.3599h4.845Zm-33.63 38.0145c2.236 1.2423 4.721 1.8634 7.454 1.8634 2.768 0 5.288-.6211 7.56-1.8634 2.272-1.2423 4.064-2.9993 5.377-5.2709 1.349-2.3071 2.024-4.9692 2.024-7.9862 0-3.017-.657-5.6614-1.97-7.933-1.278-2.2716-3.035-4.0108-5.271-5.2176-2.236-1.2423-4.739-1.8635-7.507-1.8635-2.769 0-5.271.6212-7.507 1.8635-2.236 1.2068-4.011 2.9637-5.324 5.2709-1.278 2.2716-1.917 4.8982-1.917 7.8797 0 3.017.621 5.6791 1.863 7.9862 1.278 2.2716 3.017 4.0286 5.218 5.2709Zm12.352-3.6204c-1.526.8163-3.159 1.2245-4.898 1.2245-1.739 0-3.337-.3904-4.792-1.1713-1.455-.8164-2.627-2.0409-3.514-3.6736-.852-1.6328-1.278-3.6382-1.278-6.0163 0-2.3426.444-4.3303 1.331-5.9631.888-1.6327 2.059-2.8395 3.514-3.6204 1.491-.8163 3.124-1.2245 4.898-1.2245 1.74 0 3.355.4082 4.845 1.2245 1.491.7809 2.698 1.9877 3.621 3.6204.923 1.6328 1.384 3.6205 1.384 5.9631s-.479 4.3303-1.437 5.963c-.923 1.6327-2.148 2.8573-3.674 3.6737Zm-23.645-21.2435c0 3.088-1.064 5.6613-3.194 7.72-2.094 2.0232-5.307 3.0348-9.637 3.0348h-7.134v15.4932h-4.845V21.6493h11.979c4.189 0 7.365 1.0116 9.53 3.0347 2.201 2.0232 3.301 4.632 3.301 7.8265Zm-12.831 6.7617c2.698 0 4.685-.5857 5.963-1.757 1.278-1.1713 1.917-2.8395 1.917-5.0047 0-4.5787-2.627-6.8681-7.88-6.8681h-7.134v13.6298h7.134Zm-25.03-8.9445c-1.74-.9939-3.727-1.4908-5.963-1.4908-1.953 0-3.727.3727-5.324 1.1181-1.598.7099-2.876 1.7037-3.834 2.9815V19.3599h-7.454v39.3987h7.454V42.4667c0-2.3426.586-4.1351 1.757-5.3774 1.207-1.2778 2.84-1.9167 4.898-1.9167 2.023 0 3.621.6389 4.792 1.9167 1.171 1.2423 1.757 3.0348 1.757 5.3774v16.2919h7.454V41.4551c0-2.6621-.497-4.9337-1.491-6.8149-.958-1.9167-2.307-3.3542-4.046-4.3125Zm-51.204 3.1945c.958-1.3488 2.271-2.4669 3.939-3.3542 1.704-.9229 3.639-1.3843 5.804-1.3843 2.52 0 4.792.6212 6.815 1.8634 2.058 1.2423 3.673 3.0171 4.845 5.3242 1.206 2.2716 1.81 4.9159 1.81 7.933 0 3.017-.604 5.6968-1.81 8.0394-1.172 2.3071-2.787 4.0996-4.845 5.3774-2.023 1.2778-4.295 1.9167-6.815 1.9167-2.165 0-4.082-.4437-5.75-1.3311-1.633-.8873-2.964-2.0054-3.993-3.3542v18.2618h-7.454V29.2629h7.454v4.2593Zm15.599 10.3821c0-1.7748-.372-3.301-1.118-4.5788-.71-1.3133-1.668-2.3071-2.875-2.9815-1.171-.6744-2.449-1.0116-3.833-1.0116-1.349 0-2.627.3549-3.834 1.0648-1.171.6744-2.129 1.6682-2.875 2.9815-.709 1.3133-1.064 2.8573-1.064 4.632 0 1.7747.355 3.3187 1.064 4.632.746 1.3133 1.704 2.3249 2.875 3.0348 1.207.6744 2.485 1.0116 3.834 1.0116 1.384 0 2.662-.355 3.833-1.0648 1.207-.7099 2.165-1.7215 2.875-3.0348.746-1.3133 1.118-2.875 1.118-4.6852Zm-59.296-7.933c-1.172 2.3071-1.757 4.9514-1.757 7.933 0 3.017.585 5.6968 1.757 8.0394 1.206 2.3071 2.821 4.0996 4.845 5.3774 2.058 1.2778 4.33 1.9167 6.815 1.9167 2.2 0 4.135-.4437 5.803-1.3311 1.704-.9228 3.035-2.0764 3.993-3.4607v4.3126h7.507V29.2629h-7.507v4.206c-.994-1.3487-2.325-2.4668-3.993-3.3542-1.633-.8873-3.55-1.331-5.75-1.331-2.52 0-4.81.6212-6.868 1.8634-2.024 1.2423-3.639 3.0171-4.845 5.3242Zm20.391 3.4074c.71 1.2778 1.065 2.8218 1.065 4.632 0 1.8102-.355 3.372-1.065 4.6853-.71 1.2778-1.668 2.2716-2.875 2.9815-1.207.6744-2.502 1.0116-3.887 1.0116-1.348 0-2.626-.355-3.833-1.0648-1.171-.7099-2.13-1.7215-2.875-3.0348-.71-1.3488-1.065-2.9105-1.065-4.6852 0-1.7748.355-3.301 1.065-4.5788.745-1.3133 1.704-2.3071 2.875-2.9815 1.171-.6744 2.449-1.0116 3.833-1.0116 1.385 0 2.68.3549 3.887 1.0648 1.207.6744 2.165 1.6682 2.875 2.9815Zm-34.303-5.537c.958-1.5617 2.2-2.7863 3.727-3.6736 1.561-.8874 3.336-1.3311 5.324-1.3311v7.8265h-1.97c-2.343 0-4.117.5502-5.324 1.6505-1.172 1.1003-1.757 3.017-1.757 5.7501v14.6946h-7.454V29.263h7.454v4.5787Zm-25.96-4.6321c1.491.8164 2.663 2.0055 3.514 3.5672h8.572c-1.171-3.6914-3.301-6.5487-6.389-8.5719-3.088-2.0586-6.726-3.088-10.914-3.088-3.55 0-6.78.8164-9.69 2.4491-2.875 1.5973-5.1468 3.8512-6.815 6.7617-1.6328 2.875-2.4491 6.1405-2.4491 9.7964s.8163 6.9214 2.4491 9.7964c1.6682 2.8751 3.94 5.129 6.815 6.7617 2.91 1.5972 6.158 2.3958 9.743 2.3958 3.195 0 6.07-.6566 8.625-1.9699 2.591-1.3488 4.703-3.1235 6.336-5.3241 1.633-2.2007 2.697-4.5965 3.194-7.1876v-6.4955h-20.125v5.6969h12.778c-.568 2.6975-1.757 4.8094-3.567 6.3357-1.81 1.4908-4.135 2.2361-6.975 2.2361-2.307 0-4.33-.4969-6.069-1.4907-1.739-.9939-3.106-2.4136-4.1-4.2593-.958-1.8457-1.437-4.0109-1.437-6.4955 0-2.4136.479-4.5432 1.437-6.389.958-1.8456 2.29-3.2654 3.993-4.2593 1.704-.9938 3.656-1.4907 5.857-1.4907 1.987 0 3.727.4082 5.217 1.2245Z"
clipRule="evenodd"
/>
{includeText && (
<path
fill="currentColor"
fillRule="evenodd"
d="M400.22 23.8855c.639.6389 1.42.9584 2.343.9584.887 0 1.632-.3195 2.236-.9584.639-.6389.958-1.4197.958-2.3426 0-.9228-.319-1.7037-.958-2.3426-.604-.6389-1.349-.9584-2.236-.9584-.923 0-1.704.3195-2.343.9584s-.958 1.4198-.958 2.3426c0 .9229.319 1.7037.958 2.3426Zm4.685 34.8731V29.5824h-4.845v29.1762h4.845Zm12.57-.6388c1.775.7453 3.78 1.118 6.016 1.118 2.095 0 3.94-.3549 5.538-1.0648 1.632-.7454 2.892-1.757 3.78-3.0348.887-1.2778 1.331-2.7153 1.331-4.3125-.036-1.7747-.533-3.2122-1.491-4.3126-.923-1.1003-2.041-1.9167-3.354-2.4491-1.314-.5679-3.017-1.1358-5.111-1.7037-1.669-.4614-2.982-.8696-3.94-1.2245-.923-.3905-1.704-.8874-2.343-1.4908-.603-.6389-.905-1.4375-.905-2.3959 0-1.2068.515-2.1829 1.544-2.9282 1.029-.7454 2.414-1.1181 4.153-1.1181 1.881 0 3.372.4614 4.472 1.3843 1.136.9228 1.757 2.1474 1.864 3.6736h4.844c-.141-2.8395-1.206-5.0757-3.194-6.7084-1.988-1.6327-4.596-2.4491-7.826-2.4491-2.095 0-3.958.3727-5.591 1.1181-1.633.7099-2.893 1.686-3.78 2.9283-.887 1.2423-1.331 2.6088-1.331 4.0995 0 1.8812.479 3.4075 1.438 4.5788.993 1.1358 2.165 2.0054 3.513 2.6088 1.385.5679 3.159 1.1358 5.325 1.7038 2.378.6034 4.135 1.2245 5.271 1.8634 1.135.6034 1.703 1.544 1.703 2.8218 0 1.2423-.532 2.2716-1.597 3.088-1.065.8164-2.52 1.2245-4.366 1.2245-1.987 0-3.602-.4614-4.845-1.3842-1.207-.9229-1.881-2.1119-2.023-3.5672h-5.005c.107 1.7747.675 3.3542 1.704 4.7385 1.029 1.3488 2.431 2.4136 4.206 3.1945Zm-32.431-23.799c.852-1.6683 2.058-2.9638 3.62-3.8867 1.597-.9228 3.532-1.3842 5.803-1.3842v5.0047h-1.277c-5.431 0-8.146 2.946-8.146 8.838v15.866h-4.845V29.5823h4.845v4.7385Zm-40.825 1.9168c-1.207 2.2361-1.81 4.8449-1.81 7.8264 0 2.9461.603 5.5726 1.81 7.8798 1.207 2.3071 2.857 4.0995 4.952 5.3773 2.094 1.2778 4.436 1.9167 7.027 1.9167 2.521 0 4.721-.5501 6.602-1.6505 1.917-1.1358 3.355-2.5555 4.313-4.2593v5.4307h4.898V29.5824h-4.898v5.3241c-.923-1.6682-2.325-3.0525-4.206-4.1528-1.881-1.1003-4.1-1.6505-6.655-1.6505-2.591 0-4.952.6212-7.081 1.8635-2.095 1.2423-3.745 2.9992-4.952 5.2709Zm21.563 2.1296c.887 1.6327 1.331 3.5494 1.331 5.7501 0 2.2006-.444 4.1351-1.331 5.8033-.887 1.6327-2.094 2.8928-3.62 3.7801-1.491.8519-3.142 1.2778-4.952 1.2778s-3.461-.4259-4.951-1.2778c-1.491-.8873-2.68-2.1474-3.568-3.7801-.887-1.6682-1.331-3.6204-1.331-5.8566 0-2.2006.444-4.1173 1.331-5.75.888-1.6328 2.077-2.8751 3.568-3.7269 1.49-.8519 3.141-1.2778 4.951-1.2778 1.81 0 3.461.4437 4.952 1.331 1.526.8519 2.733 2.0942 3.62 3.7269Zm-29.82-19.0073v39.3987h-4.845V19.3599h4.845Zm-33.63 38.0145c2.236 1.2423 4.721 1.8634 7.454 1.8634 2.768 0 5.288-.6211 7.56-1.8634 2.272-1.2423 4.064-2.9993 5.377-5.2709 1.349-2.3071 2.024-4.9692 2.024-7.9862 0-3.017-.657-5.6614-1.97-7.933-1.278-2.2716-3.035-4.0108-5.271-5.2176-2.236-1.2423-4.739-1.8635-7.507-1.8635-2.769 0-5.271.6212-7.507 1.8635-2.236 1.2068-4.011 2.9637-5.324 5.2709-1.278 2.2716-1.917 4.8982-1.917 7.8797 0 3.017.621 5.6791 1.863 7.9862 1.278 2.2716 3.017 4.0286 5.218 5.2709Zm12.352-3.6204c-1.526.8163-3.159 1.2245-4.898 1.2245-1.739 0-3.337-.3904-4.792-1.1713-1.455-.8164-2.627-2.0409-3.514-3.6736-.852-1.6328-1.278-3.6382-1.278-6.0163 0-2.3426.444-4.3303 1.331-5.9631.888-1.6327 2.059-2.8395 3.514-3.6204 1.491-.8163 3.124-1.2245 4.898-1.2245 1.74 0 3.355.4082 4.845 1.2245 1.491.7809 2.698 1.9877 3.621 3.6204.923 1.6328 1.384 3.6205 1.384 5.9631s-.479 4.3303-1.437 5.963c-.923 1.6327-2.148 2.8573-3.674 3.6737Zm-23.645-21.2435c0 3.088-1.064 5.6613-3.194 7.72-2.094 2.0232-5.307 3.0348-9.637 3.0348h-7.134v15.4932h-4.845V21.6493h11.979c4.189 0 7.365 1.0116 9.53 3.0347 2.201 2.0232 3.301 4.632 3.301 7.8265Zm-12.831 6.7617c2.698 0 4.685-.5857 5.963-1.757 1.278-1.1713 1.917-2.8395 1.917-5.0047 0-4.5787-2.627-6.8681-7.88-6.8681h-7.134v13.6298h7.134Zm-25.03-8.9445c-1.74-.9939-3.727-1.4908-5.963-1.4908-1.953 0-3.727.3727-5.324 1.1181-1.598.7099-2.876 1.7037-3.834 2.9815V19.3599h-7.454v39.3987h7.454V42.4667c0-2.3426.586-4.1351 1.757-5.3774 1.207-1.2778 2.84-1.9167 4.898-1.9167 2.023 0 3.621.6389 4.792 1.9167 1.171 1.2423 1.757 3.0348 1.757 5.3774v16.2919h7.454V41.4551c0-2.6621-.497-4.9337-1.491-6.8149-.958-1.9167-2.307-3.3542-4.046-4.3125Zm-51.204 3.1945c.958-1.3488 2.271-2.4669 3.939-3.3542 1.704-.9229 3.639-1.3843 5.804-1.3843 2.52 0 4.792.6212 6.815 1.8634 2.058 1.2423 3.673 3.0171 4.845 5.3242 1.206 2.2716 1.81 4.9159 1.81 7.933 0 3.017-.604 5.6968-1.81 8.0394-1.172 2.3071-2.787 4.0996-4.845 5.3774-2.023 1.2778-4.295 1.9167-6.815 1.9167-2.165 0-4.082-.4437-5.75-1.3311-1.633-.8873-2.964-2.0054-3.993-3.3542v18.2618h-7.454V29.2629h7.454v4.2593Zm15.599 10.3821c0-1.7748-.372-3.301-1.118-4.5788-.71-1.3133-1.668-2.3071-2.875-2.9815-1.171-.6744-2.449-1.0116-3.833-1.0116-1.349 0-2.627.3549-3.834 1.0648-1.171.6744-2.129 1.6682-2.875 2.9815-.709 1.3133-1.064 2.8573-1.064 4.632 0 1.7747.355 3.3187 1.064 4.632.746 1.3133 1.704 2.3249 2.875 3.0348 1.207.6744 2.485 1.0116 3.834 1.0116 1.384 0 2.662-.355 3.833-1.0648 1.207-.7099 2.165-1.7215 2.875-3.0348.746-1.3133 1.118-2.875 1.118-4.6852Zm-59.296-7.933c-1.172 2.3071-1.757 4.9514-1.757 7.933 0 3.017.585 5.6968 1.757 8.0394 1.206 2.3071 2.821 4.0996 4.845 5.3774 2.058 1.2778 4.33 1.9167 6.815 1.9167 2.2 0 4.135-.4437 5.803-1.3311 1.704-.9228 3.035-2.0764 3.993-3.4607v4.3126h7.507V29.2629h-7.507v4.206c-.994-1.3487-2.325-2.4668-3.993-3.3542-1.633-.8873-3.55-1.331-5.75-1.331-2.52 0-4.81.6212-6.868 1.8634-2.024 1.2423-3.639 3.0171-4.845 5.3242Zm20.391 3.4074c.71 1.2778 1.065 2.8218 1.065 4.632 0 1.8102-.355 3.372-1.065 4.6853-.71 1.2778-1.668 2.2716-2.875 2.9815-1.207.6744-2.502 1.0116-3.887 1.0116-1.348 0-2.626-.355-3.833-1.0648-1.171-.7099-2.13-1.7215-2.875-3.0348-.71-1.3488-1.065-2.9105-1.065-4.6852 0-1.7748.355-3.301 1.065-4.5788.745-1.3133 1.704-2.3071 2.875-2.9815 1.171-.6744 2.449-1.0116 3.833-1.0116 1.385 0 2.68.3549 3.887 1.0648 1.207.6744 2.165 1.6682 2.875 2.9815Zm-34.303-5.537c.958-1.5617 2.2-2.7863 3.727-3.6736 1.561-.8874 3.336-1.3311 5.324-1.3311v7.8265h-1.97c-2.343 0-4.117.5502-5.324 1.6505-1.172 1.1003-1.757 3.017-1.757 5.7501v14.6946h-7.454V29.263h7.454v4.5787Zm-25.96-4.6321c1.491.8164 2.663 2.0055 3.514 3.5672h8.572c-1.171-3.6914-3.301-6.5487-6.389-8.5719-3.088-2.0586-6.726-3.088-10.914-3.088-3.55 0-6.78.8164-9.69 2.4491-2.875 1.5973-5.1468 3.8512-6.815 6.7617-1.6328 2.875-2.4491 6.1405-2.4491 9.7964s.8163 6.9214 2.4491 9.7964c1.6682 2.8751 3.94 5.129 6.815 6.7617 2.91 1.5972 6.158 2.3958 9.743 2.3958 3.195 0 6.07-.6566 8.625-1.9699 2.591-1.3488 4.703-3.1235 6.336-5.3241 1.633-2.2007 2.697-4.5965 3.194-7.1876v-6.4955h-20.125v5.6969h12.778c-.568 2.6975-1.757 4.8094-3.567 6.3357-1.81 1.4908-4.135 2.2361-6.975 2.2361-2.307 0-4.33-.4969-6.069-1.4907-1.739-.9939-3.106-2.4136-4.1-4.2593-.958-1.8457-1.437-4.0109-1.437-6.4955 0-2.4136.479-4.5432 1.437-6.389.958-1.8456 2.29-3.2654 3.993-4.2593 1.704-.9938 3.656-1.4907 5.857-1.4907 1.987 0 3.727.4082 5.217 1.2245Z"
clipRule="evenodd"
/>
)}
</svg>
</>
);
......
......@@ -9,24 +9,25 @@
* We do not test components/renderfunctions/styling files.
* See testing plan for more details.*/
import React, { useState, useRef, useEffect, useCallback } from 'react';
import { useAuthorizationCache, useAuth, useCheckPermissionPolicy } from '@graphpolaris/shared/lib/data-access';
import DatabaseSelector from './DatabaseManagement/dbConnectionSelector';
import { useAuthCache, useAuthentication } from '@graphpolaris/shared/lib/data-access';
import { DropdownItem } from '@graphpolaris/shared/lib/components/dropdowns';
import GpLogo from './gp-logo';
import { Popover, PopoverContent, PopoverTrigger } from '@graphpolaris/shared/lib/components/layout/Popover';
import { useDispatch } from 'react-redux';
import { Dialog, DialogContent, DialogTrigger } from '@graphpolaris/shared/lib/components/layout/Dialog';
import { UserManagementContent } from '@graphpolaris/shared/lib/components/panels/userManagementContent/UserManagementContent';
import { addInfo } from '@graphpolaris/shared/lib/data-access/store/configSlice';
import { showManagePermissions, showSharableExploration } from 'config';
import { Button, Dialog, DialogContent, DialogTrigger, useActiveSaveStateAuthorization, useSessionCache } from '@graphpolaris/shared';
import { ManagementTrigger, ManagementViews } from '@graphpolaris/shared/lib/management';
import { Members } from '@graphpolaris/shared/lib/management/Members';
export const Navbar = () => {
const dropdownRef = useRef<HTMLDivElement>(null);
const auth = useAuth();
const authCache = useAuthorizationCache();
const auth = useAuthentication();
const authCache = useAuthCache();
const authorization = useActiveSaveStateAuthorization();
const [menuOpen, setMenuOpen] = useState(false);
const dispatch = useDispatch();
const buildInfo = import.meta.env.GRAPHPOLARIS_VERSION;
const [managementOpen, setManagementOpen] = useState<boolean>(false);
const [current, setCurrent] = useState<ManagementViews>('overview');
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
......@@ -40,43 +41,12 @@ export const Navbar = () => {
};
}, [menuOpen]);
const { canRead, canWrite } = useCheckPermissionPolicy();
const [readAllowed, setReadAllowed] = useState(false);
const [writeAllowed, setWriteAllowed] = useState(false);
const resource = 'policy';
const checkReadPermission = useCallback(async () => {
const result = await canRead(resource);
setReadAllowed(result);
}, [canRead]);
const checkWritePermission = useCallback(async () => {
const result = await canWrite(resource);
setWriteAllowed(result);
}, [canWrite]);
useEffect(() => {
checkReadPermission();
}, [checkReadPermission]);
useEffect(() => {
checkWritePermission();
}, [checkWritePermission]);
const handleConfirmUsers = (users: { name: string; email: string; type: string }[]) => {
//TODO !FIXME: when the user clicks on confirm, users state is ready to be sent to backend
};
const handleClickShareLink = () => {
//TODO !FIXME: add copy link to clipoard functionality
dispatch(addInfo('Link copied to clipboard'));
};
return (
<nav className="w-full px-4 h-12 flex flex-row items-center gap-2 md:gap-3 lg:gap-4">
<a href="https://graphpolaris.com/" target="_blank" className="shrink-0 text-dark">
<GpLogo className="h-7" />
</a>
<DatabaseSelector />
<nav className="w-full px-2 h-12 flex flex-row items-center gap-2 md:gap-3 lg:gap-4">
<GpLogo className="h-7" includeText={false} />
<ManagementTrigger managementOpen={managementOpen} setManagementOpen={setManagementOpen} current={current} setCurrent={setCurrent} />
<Button label="Share" variantType="primary" size="sm" onClick={() => auth.newShareRoom()} />
<div className="ml-auto">
<div className="w-fit" ref={dropdownRef}>
<Popover>
......@@ -85,17 +55,17 @@ export const Navbar = () => {
className="relative inline-flex items-center justify-center w-8 h-8 overflow-hidden bg-secondary-500 rounded-full hover:bg-secondary-600 transition-colors duration-150 ease-in-out cursor-pointer"
onClick={() => setMenuOpen(!menuOpen)}
>
<span className="font-medium text-light">{authCache.username?.slice(0, 2).toUpperCase()}</span>
<span className="font-medium text-light">{authCache.authentication?.username?.slice(0, 2).toUpperCase()}</span>
</div>
</PopoverTrigger>
<PopoverContent className="w-56 z-30 bg-light rounded-sm border-[1px] outline-none">
<div className="p-2 text-sm border-b">
<h2 className="font-bold">user: {authCache.username}</h2>
<h3 className="text-xs break-words">session: {authCache.sessionID}</h3>
<h2 className="font-bold">user: {authCache.authentication?.username}</h2>
<h3 className="text-xs break-words">session: {authCache.authentication?.sessionID}</h3>
<h3 className="text-xs break-words">license: Creator</h3>
</div>
{authCache.authorized ? (
{authCache.authentication?.authenticated ? (
<>
{showSharableExploration() && (
<DropdownItem
......@@ -105,38 +75,36 @@ export const Navbar = () => {
}}
/>
)}
{authCache.authorization?.savestate?.W && authorization.database.W && (
<DropdownItem
value="Viewer Permissions"
onClick={() => {
setManagementOpen(true);
setCurrent('members');
}}
/>
)}
<DropdownItem value="Settings" onClick={() => {}} />
<DropdownItem value="Log out" onClick={() => {
location.replace(`${import.meta.env['GP_AUTH_URL']}/flows/-/default/invalidation/`)
}} />
<DropdownItem
value="Log out"
onClick={() => {
location.replace(`${import.meta.env['GP_AUTH_URL']}/flows/-/default/invalidation/`);
}}
/>
</>
) : (
<>
<DropdownItem value="Login" onClick={() => {}} />
</>
)}
{authCache?.roomID && (
{authCache.authentication?.roomID && (
<div className="p-2 border-b">
<h3 className="text-xs break-words">Share ID: {authCache.roomID}</h3>
<h3 className="text-xs break-words">Share ID: {authCache.authentication?.roomID}</h3>
</div>
)}
<div className="p-2 border-t">
<h3 className="text-xs">Version: {buildInfo}</h3>
</div>
{showManagePermissions() && writeAllowed && (
<>
<Dialog>
<DialogTrigger className="ml-2 text-sm hover:bg-secondary-200">Manage Viewers Permission</DialogTrigger>
<DialogContent>
<UserManagementContent
sessionId={authCache.sessionID ?? ''}
onConfirm={handleConfirmUsers}
onClickShareLink={handleClickShareLink}
/>
</DialogContent>
</Dialog>
</>
)}
</PopoverContent>
</Popover>
</div>
......
......@@ -3,7 +3,7 @@ import Joyride, { ACTIONS, EVENTS, STATUS, Step } from 'react-joyride';
import { useLocation } from 'react-router-dom';
import { Button } from '@graphpolaris/shared/lib/components/buttons';
import { useCases } from './use-cases';
import { useAuthorizationCache } from '@graphpolaris/shared/lib/data-access';
import { useAuthCache } from '@graphpolaris/shared/lib/data-access';
interface OnboardingState {
run?: boolean;
......@@ -12,7 +12,7 @@ interface OnboardingState {
export function Onboarding({}) {
const location = useLocation();
const auth = useAuthorizationCache();
const auth = useAuthCache();
const [showWalkthrough, setShowWalkthrough] = useState<boolean>(false);
const [onboarding, setOnboarding] = useState<OnboardingState>({
run: false,
......
version: '3.9'
services:
frontend:
image: harbor.graphpolaris.com/graphpolaris/frontend:latest
image: harbor.graphpolaris.com/graphpolaris/frontend-dev:latest
build:
context: ./
dockerfile: ./Dockerfile
container_name: frontend
ports:
- 4200:4200
environment:
......@@ -17,12 +16,25 @@ services:
# - BACKEND_USER=user-management-service
- STAGING=dev
- GRAPHPOLARIS_VERSION=dev
- GRAPHPOLARIS_VERSION=compose
- SKIP_LOGIN=false
- SENTRY_ENABLED=false
- SENTRY_URL=http://localhost
- GP_AUTH_URL=https://auth.staging.graphpolaris.com/
- WIP_TABLEVIS=false
- WIP_NODELINKVIS=false
- WIP_RAWJSONVIS=false
- WIP_PAOHVIS=true
- WIP_MATRIXVIS=true
- WIP_SEMANTICSUBSTRATESVIS=true
- WIP_MAPVIS=true
- WIP_INSIGHT_SHARING=true
- WIP_VIEWER_PERMISSIONS=true
- WIP_SHARABLE_EXPLORATION=true
restart: always
networks:
- graphpolaris_network
# networks:
# - graphpolaris_network
networks:
graphpolaris_network:
name: custom_network
external: true
# networks:
# graphpolaris_network:
# name: custom_network
# external: true
......@@ -3,7 +3,7 @@ import styles from './buttons.module.scss';
import { Icon } from '../icon';
import { Tooltip, TooltipContent, TooltipTrigger } from '../tooltip';
type ButtonProps = {
export type ButtonProps = {
as?: 'button' | 'a' | 'div';
variantType?: 'primary' | 'secondary' | 'danger';
variant?: 'solid' | 'outline' | 'ghost';
......@@ -33,6 +33,25 @@ type ButtonProps = {
onMouseLeaveCapture?: (e: any) => void;
onMouseOverCapture?: (e: any) => void;
onMouseOutCapture?: (e: any) => void;
// Drag and Drop
onDragStart?: (e: any) => void;
onDrag?: (e: any) => void;
onDragEnd?: (e: any) => void;
onDragEnter?: (e: any) => void;
onDragExit?: (e: any) => void;
onDragLeave?: (e: any) => void;
onDragOver?: (e: any) => void;
onDragStartCapture?: (e: any) => void;
onDragCapture?: (e: any) => void;
onDragEndCapture?: (e: any) => void;
onDragEnterCapture?: (e: any) => void;
onDragExitCapture?: (e: any) => void;
onDragLeaveCapture?: (e: any) => void;
onDragOverCapture?: (e: any) => void;
onDrop?: (e: any) => void;
onDropCapture?: (e: any) => void;
draggable?: boolean;
};
export const Button = React.forwardRef<HTMLButtonElement | HTMLAnchorElement | HTMLDivElement, ButtonProps>(
......@@ -139,6 +158,8 @@ export const Button = React.forwardRef<HTMLButtonElement | HTMLAnchorElement | H
[iconComponent, label, children],
);
const disabledClass = useMemo(() => (disabled ? 'cursor-not-allowed' : 'cursor-pointer'), [disabled]);
const ButtonComponent = as;
const isAnchor = as === 'a';
......@@ -148,8 +169,8 @@ export const Button = React.forwardRef<HTMLButtonElement | HTMLAnchorElement | H
{tooltip && <TooltipContent>{tooltip}</TooltipContent>}
<TooltipTrigger>
<ButtonComponent
className={`${styles.btn} ${typeClass} ${variantClass} ${sizeClass} ${blockClass} ${roundedClass} ${iconOnlyClass} ${className ? className : ''}`}
onClick={onClick}
className={`${styles.btn} ${typeClass} ${variantClass} ${sizeClass} ${blockClass} ${roundedClass} ${iconOnlyClass} ${disabledClass} ${className ? className : ''}`}
onClick={disabled ? undefined : onClick}
disabled={disabled}
aria-label={ariaLabel}
href={isAnchor ? href : undefined}
......
......@@ -19,6 +19,7 @@ type DropdownTriggerProps = {
popover?: boolean;
onClick?: () => void;
children?: ReactNode;
noDropdownArrow?: boolean;
};
export function DropdownTrigger({
......@@ -28,23 +29,30 @@ export function DropdownTrigger({
variant,
className,
onClick,
noDropdownArrow = false,
popover = true,
children = undefined,
}: DropdownTriggerProps) {
const paddingClass = size === 'xs' ? 'py-0' : size === 'sm' ? 'px-1 py-1' : size === 'md' ? 'px-2 py-1' : 'px-4 py-2';
const textSizeClass = size === 'xs' ? 'text-xs' : size === 'sm' ? 'text-sm' : size === 'md' ? 'text-base' : 'text-lg';
const disabledClass = disabled ? 'cursor-not-allowed' : 'cursor-pointer';
const variantClass =
variant === 'primary' || !variant
? 'border bg-light rounded'
: variant === 'ghost'
? 'bg-transparent shadow-none'
: 'border rounded bg-transparent';
const inner = children || (
const inner = children ? (
React.cloneElement(children as React.ReactElement, {
disabled: disabled,
})
) : (
<div
className={`inline-flex w-full truncate justify-between items-center gap-x-1.5 ${variantClass} ${textSizeClass} ${paddingClass} text-secondary-900 shadow-sm ${disabled ? ` cursor-not-allowed text-secondary-400 bg-secondary-100` : 'cursor-pointer'} pl-1 truncate`}
className={`inline-flex w-full truncate justify-between items-center gap-x-1.5 ${variantClass} ${textSizeClass} ${paddingClass} text-secondary-900 shadow-sm ${noDropdownArrow ? `pointer-events-none cursor-default` : ''} ${disabled ? ` cursor-not-allowed text-secondary-400 bg-secondary-100` : 'cursor-pointer'} pl-1 truncate`}
>
<span className={`text-${size}`}>{title}</span>
<Icon component="icon-[ic--baseline-arrow-drop-down]" size={16} />
{!noDropdownArrow && <Icon component="icon-[ic--baseline-arrow-drop-down]" size={16} />}
</div>
);
......
......@@ -2,8 +2,8 @@ import React, { ReactElement, ReactNode } from 'react';
import { SVGProps } from 'react';
// Define Sizes and IconProps types
export type Sizes = 8 | 10 | 12 | 14 | 16 | 20 | 24 | 28 | 32 | 36 | 40;
export const sizesArray: Sizes[] = [8, 10, 12, 14, 16, 20, 24, 28, 32, 36, 40];
export const sizesArray = [8, 10, 12, 14, 16, 20, 24, 28, 32, 36, 40, 48, 56] as const;
export type Sizes = (typeof sizesArray)[number];
export type IconProps = SVGProps<SVGSVGElement> & {
component?: ReactNode | ReactElement<any> | string;
......
import React, { useEffect, useState } from 'react';
import React, { MouseEventHandler, useEffect, useState } from 'react';
import styles from './inputs.module.scss';
import { DropdownTrigger, DropdownContainer, DropdownItem, DropdownItemContainer } from '../dropdowns';
import Info from '../info';
......@@ -34,7 +34,7 @@ type TextProps = {
className?: string;
validate?: (value: any) => boolean;
onChange?: (value: string) => void;
onClick?: (e: Event) => void;
onClick?: (e: any) => void;
};
type NumberProps = {
......
......@@ -11,7 +11,7 @@ import {
FloatingOverlay,
useId,
} from '@floating-ui/react';
import { Button } from '../buttons';
import { Button, ButtonProps } from '../buttons';
interface DialogOptions {
initialOpen?: boolean;
......@@ -200,9 +200,7 @@ export const DialogDescription = React.forwardRef<HTMLParagraphElement, React.HT
);
});
export const DialogClose = React.forwardRef<HTMLButtonElement, React.ButtonHTMLAttributes<HTMLButtonElement>>(
function DialogClose(props, ref) {
const { setOpen } = useDialogContext();
return <Button variant="solid" className="w-full" {...props} ref={ref} onClick={() => setOpen(false)} />;
},
);
export const DialogClose = React.forwardRef<HTMLButtonElement, ButtonProps>(function DialogClose(props, ref) {
const { setOpen } = useDialogContext();
return <Button variant="solid" className="w-full" {...props} ref={ref} onClick={() => setOpen(false)} />;
});
export const FrozenOverlay = (props: { children: React.ReactNode; enabled?: boolean }) => {
if (!props.enabled || !props.children || props.children === '') return null;
return (
<div className="absolute h-screen w-screen left-0 top-0 flex justify-center items-center blur-sm pointer-events-none z-50">
<div className="text-3xl font-bold">{props.children}</div>
</div>
);
};
export * from './Dialog';
export * from './Panel';
export * from './Resizable';
export * from './FrozenOverlay';
......@@ -64,9 +64,6 @@ export const TableUI = <T extends Record<string, any>>({ data, fieldConfigs, dro
return (
<div className="mt-2 w-full overflow-x-auto">
<div className="flex justify-end mb-4">
<Button variant="solid" size="md" label="Add Row" onClick={handleAddRow} />
</div>
<table className="min-w-full bg-white border border-gray-300 rounded-md">
<thead>
<tr className="bg-gray-100 border-b">
......
import React from 'react';
import { Button, ButtonProps } from '../buttons';
export const Tabs = (props: { children: React.ReactNode }) => {
type TabTypes = 'inline' | 'rounded' | 'simple';
type ContextType = {
tabType: TabTypes;
};
const TabContext = React.createContext<ContextType>({
tabType: 'inline',
});
export const Tabs = (props: { children: React.ReactNode; tabType?: TabTypes }) => {
const tabType = props.tabType || 'inline';
let className = '';
if (tabType === 'inline') {
className = 'flex items-stretch divide-x divide-secondary-200 border-x border-secondary-200 overflow-x-auto -my-px';
} else if (tabType === 'rounded') {
className = 'flex gap-x-1 border-b border-secondary-300 mb-5';
} else if (tabType === 'simple') {
className = 'flex gap-x-1';
}
return (
<div className="flex items-stretch divide-x divide-secondary-200 border-x border-secondary-200 overflow-x-auto -my-px">
{props.children}
</div>
<TabContext.Provider value={{ tabType: tabType }}>
<div className={className}>{props.children}</div>
</TabContext.Provider>
);
};
export const Tab = ({
activeTab,
text,
variant = 'ghost',
className = '',
...props
}: React.ButtonHTMLAttributes<HTMLDivElement> & {
}: ButtonProps & {
activeTab: boolean;
children: React.ReactNode;
children?: React.ReactNode;
text: string;
}) => {
const context = React.useContext(TabContext);
if (context.tabType === 'inline') {
className += ` pl-2 pr-1 gap-1 relative h-full text-secondary-500 border-secondary-200 before:content-['']
before:absolute before:left-0 before:bottom-0 before:h-[2px] before:w-full
${activeTab ? 'before:bg-primary-500' : 'before:bg-transparent hover:before:bg-secondary-300 hover:bg-secondary-200'}`;
} else if (context.tabType === 'rounded') {
className += ` -mb-px py-4 px-4 text-sm text-secondary-500 text-center border rounded-t-lg rounded-b-none
${activeTab ? 'active text-secondary-950 border-l-secondary-300 border-r-secondary-300 border-t-secondary-300 border-b-white' : ''}
before:bg-transparent hover:before:bg-secondary-300 hover:bg-secondary-200`;
} else if (context.tabType === 'simple') {
className += ` ${activeTab ? 'active bg-secondary-200 hover:bg-secondary-300' : 'hover:bg-secondary-100'}`;
}
return (
<div
className={`flex items-center pl-2 pr-1 gap-1 cursor-pointer relative border-secondary-200 before:content-[''] before:absolute before:left-0 before:bottom-0 before:h-[2px] before:w-full ${activeTab ? 'before:bg-primary-500' : 'before:bg-transparent hover:before:bg-secondary-300 hover:bg-secondary-200'}`}
{...props}
>
<p className={`text-xs text-secondary-500 font-semibold ${activeTab && 'text-secondary-950'}`}>{text}</p>
<Button className={className} label={text} variant={variant} size="xs" {...props}>
{/* <p className={`text-xs font-semibold ${activeTab && 'text-secondary-950'}`}>{text}</p> */}
{props.children}
</div>
</Button>
);
};