Skip to content

Commit

Permalink
Resolve DOO-61, DOO-72 "Comments, Board UI, Sheets, and Tenancy API" (#…
Browse files Browse the repository at this point in the history
…63)

* Images work in live collab.

* Images serialization and deserialization.

* Cleanup and tenant api.

* Fix tests/linting.

* Remove adjust skip.

* Skeleton top bar layout.

* Top bar ui.

* Comments sheet.

* Tenancy and stores.

* Hooked stores, all but streaming indicator.

* Base UI template complete.

* Comments

* Add dashboard logo

* Fix board scroll data format.
  • Loading branch information
Yyassin authored Jan 13, 2024
1 parent b6b0aec commit 0d9bc7d
Show file tree
Hide file tree
Showing 42 changed files with 1,692 additions and 346 deletions.
2 changes: 2 additions & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
"@radix-ui/react-dropdown-menu": "^2.0.6",
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-select": "^2.0.0",
"@radix-ui/react-separator": "^1.0.3",
"@radix-ui/react-slider": "^1.1.2",
"@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-toolbar": "^1.0.4",
Expand Down
47 changes: 47 additions & 0 deletions client/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

36 changes: 33 additions & 3 deletions client/src/App.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,33 @@
* { margin: 0; padding: 0;}
root { height: 100%;}
body, html { height:100%; background-color: transparent !important; }
* {
margin: 0;
padding: 0;
}
root {
height: 100% !important;
}
body,
html {
height: 100%;
background-color: transparent !important;
}

/* Custom scrollbar */
::-webkit-scrollbar {
width: var(--scrollbar-w);
}
::-webkit-scrollbar-track {
background-color: transparent;
}
::-webkit-scrollbar-thumb {
background-color: var(--scrollbar-colour);
border-radius: 30px;
border: 5px solid transparent;
background-clip: content-box;
outline-offset: -20px;
}
::-webkit-scrollbar-thumb:hover {
background-color: var(--scrollbar-hover);
}
::-webkit-scrollbar-corner {
background: rgba(0, 0, 0, 0);
}
15 changes: 5 additions & 10 deletions client/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,23 @@ function App() {
const { isTransparent } = useAppStore(['isTransparent']);
const { isWindowActive } = useElectronIPCStore(['isWindowActive']);

// Set root height to 100% when transparent
// Set root height to 100%
useEffect(() => {
const root = document.getElementById('root');
const radixThemes = document.getElementsByClassName(
'radix-themes',
)[0] as HTMLElement;
if (IS_ELECTRON_INSTANCE && isTransparent) {
root && (root.style.height = '100%');
radixThemes && (radixThemes.style.height = '100%');
} else {
root && (root.style.height = '');
radixThemes && (radixThemes.style.height = '100%');
}
}, [isTransparent]);
root && (root.style.height = '100%');
radixThemes && (radixThemes.style.height = '100%');
}, []);

return (
<div
style={{
backgroundColor: 'transparent',
height: '100%',
// Add border when transparent
...(isTransparent && {
height: '100%',
boxShadow: `0px 0px 0px 2px rgba(129, 140, 248, ${
isWindowActive ? 0.8 : 0.5
}) inset`,
Expand Down
3 changes: 2 additions & 1 deletion client/src/api/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { sfu } from './sfu';
import { stableDiffusion } from './stableDiffusion';
import { tenancy } from './tenancy';

export { sfu, stableDiffusion };
export { sfu, tenancy, stableDiffusion };
9 changes: 7 additions & 2 deletions client/src/api/sfu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,17 @@ import axios from 'axios';
* @param roomID String, the ID of the room to poll.
* @param initConsumer Function, callback to initialize the consumer when a stream is available.
*/
const pollOngoingStream = async (roomID: string, initConsumer: () => void) => {
const pollOngoingStream = async (
roomID: string,
initConsumer: (id: string) => void,
) => {
try {
const { data } = await axios.put(REST.sfu.poll, {
roomId: roomID,
});
data.roomHasProducer && initConsumer();
// Initialize the consumer, and pass the producer ID to set the active producer id for
// styling purposes.
data.producerId && initConsumer(data.producerId);
} catch (e) {
console.error('Failed to poll for ongoing stream');
}
Expand Down
27 changes: 27 additions & 0 deletions client/src/api/tenancy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { REST } from '@/constants';
import axios from 'axios';

/**
* Defines REST methods for the live socket
* tenancy API.
* @author Yousef Yassin
*/

/**
* Returns a list of active tenants, referenced
* by their ids, in the specified room.
* @param roomID The ID of the room to query.
* @returns The list of active tenants.
*/
const getActiveTenants = async (roomID: string) => {
try {
const { data } = await axios.put(REST.tenants.get, {
roomId: roomID,
});
return data.tenantIds;
} catch (e) {
console.error('Failed to query tenants');
}
};

export const tenancy = { get: getActiveTenants };
117 changes: 117 additions & 0 deletions client/src/components/lib/BoardHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import React from 'react';
import { Button, buttonVariants } from '../ui/button';
import { ArrowLeftIcon, ChatBubbleIcon } from '@radix-ui/react-icons';
import { useAppStore } from '@/stores/AppStore';
import { Users2Icon } from 'lucide-react';
import { cn } from '@/lib/utils';
import UserList from './UserList/UserList';
import { useCanvasBoardStore } from '@/stores/CanavasBoardStore';
import { unixToFormattedDate } from '@/lib/misc';

/**
* Defines a header for the board containing the title, last modified date, and buttons for sharing and viewing comments. A list of active
* users in the room is also displayed.
* @author Yousef Yassin
*/

/**
* The board header component.
* @param Control parameters for the share dialog.
* @returns The component
*/
const BoardHeader = ({
isShareDialogOpen,
setIsShareDialogOpen,
}: {
isShareDialogOpen: boolean;
setIsShareDialogOpen: (value: boolean) => void;
}) => {
const { boardMeta } = useCanvasBoardStore(['boardMeta']);
const {
setMode,
isUsingStableDiffusion,
isViewingComments,
setIsViewingComments,
setIsUsingStableDiffusion,
} = useAppStore([
'setMode',
'isUsingStableDiffusion',
'isViewingComments',
'setIsViewingComments',
'setIsUsingStableDiffusion',
]);

return (
<div
className="flex flex-row justify-between items-center p-[0.5rem]"
style={{
backgroundColor: 'white',
flexGrow: 1,
zIndex: 10,
}}
>
<div className="flex flex-row">
<div className="flex flex-row">
<div
className="flex items-center pr-[1.5rem] pl-[0.5rem]"
style={{
height: '100%',
}}
>
{/* Back to dashboard button */}
<Button
variant="secondary"
className="border-solid border-2 border-indigo-300 hover:border-indigo-400 stroke-indigo-300 hover:stroke-indigo-400 px-3 py-2"
onClick={() => setMode('dashboard')}
>
<span className="sr-only">Back to dashboard</span>
<ArrowLeftIcon className="h-4 w-4" />
</Button>
</div>
{/* Board info */}
<div className="flex flex-col">
<h2 className="text-xl font-semibold tracking-tight">
{boardMeta.title}
</h2>
<p className="text-sm text-muted-foreground">
Last Edited: {unixToFormattedDate(boardMeta.lastModified)}
</p>
</div>
</div>
</div>
{/* Right side justified, we push this to the left when the sidebar is opened */}
<div
className={`flex flex-row gap-12 items-center transition-spacing duration-300 ease-in-out ${
isUsingStableDiffusion || isViewingComments ? 'mr-[25rem]' : ''
}`}
>
{/* Avatars of active tenants */}
<UserList />
{/* Comment section button */}
<Button
variant="secondary"
className="border-solid border-2 border-indigo-300 hover:border-indigo-400 stroke-indigo-300 hover:stroke-indigo-400 px-3 py-2 "
onClick={() => {
setIsViewingComments(!isViewingComments);
!isViewingComments && setIsUsingStableDiffusion(false);
}}
>
<ChatBubbleIcon className="h-4 w-4" />
</Button>
{/* Share Dialog */}
<Button
className={cn(
buttonVariants({ variant: 'ghost', size: 'sm' }),
'h-full bg-muted text-gray-200 bg-indigo-300 hover:bg-indigo-400 hover:text-white justify-start items-center border-2 border-indigo-300 hover:border-indigo-400',
)}
onClick={() => setIsShareDialogOpen(!isShareDialogOpen)}
>
<Users2Icon className="h-4 w-4 mr-2" />
<span className="ml-auto">Share</span>
</Button>
</div>
</div>
);
};

export default BoardHeader;
35 changes: 27 additions & 8 deletions client/src/components/lib/BoardScroll.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import React from 'react';
import { CalendarIcon } from '@radix-ui/react-icons';
import { useAppStore } from '@/stores/AppStore';
import { useCanvasBoardStore } from '@/stores/CanavasBoardStore';
import { unixToFormattedDate } from '@/lib/misc';

/**
* Define a react component that all the user's boards in a folder
Expand All @@ -9,14 +11,23 @@ import { useAppStore } from '@/stores/AppStore';

export const BoardScroll = () => {
const { setMode } = useAppStore(['setMode']);
const { setBoardMeta } = useCanvasBoardStore(['setBoardMeta']);

//To be changed to fetch proper boards based on folder
const boards = [
{ board: 'unit1', date: '23.09.2023' },
{ board: 'unit2', date: '22.09.2023' },
{ board: 'unit3', date: '21.09.2023' },
{ board: 'unit4', date: '20.09.2023' },
{ board: 'unit5', date: '19.09.2023' },
{ board: 'Sieve Principle Visuals', date: 1671880200, roomID: '1' },
{ board: 'Online Bipartite Matching', date: 1671881200, roomID: '2' },
{
board: 'Generative Adversarial Networks',
date: 1671882200,
roomID: '3',
},
{ board: 'Two-player General Sum Games', date: 1671885200, roomID: '4' },
{
board: 'Counterfactual Regret Minimization',
date: 1671887200,
roomID: '5',
},
];
return (
<div className="relative flex mx-2 items-center h-[250px]">
Expand All @@ -25,12 +36,20 @@ export const BoardScroll = () => {
<div
key={board.board}
className="relative w-[500px] h-[200px] rounded-md inline-block mx-3 mt-4 bg-[#ebebeb] cursor-pointer hover:scale-105 ease-in-out duration-300"
onClick={() => setMode('canvas')}
onClick={() => {
setMode('canvas');
// TODO: Should perform and cache concurrent fetches for the board and its comments here
setBoardMeta({
roomID: board.roomID,
title: board.board,
lastModified: board.date,
});
}}
>
{board.board}
<div className="flex flex-row gap-2 absolute inset-x-0 bottom-0">
<div className="flex flex-row gap-2 absolute inset-x-0 bottom-0 items-center">
<CalendarIcon className="ml-2" />
<div>{board.date} </div>
<div>{unixToFormattedDate(board.date)}</div>
</div>
</div>
))}
Expand Down
Loading

0 comments on commit 0d9bc7d

Please sign in to comment.