From f3000498736b22c079c19e5037885a6e693c08a5 Mon Sep 17 00:00:00 2001 From: Jamie Pine Date: Mon, 17 Oct 2022 21:01:40 -0700 Subject: [PATCH] improvements to key manager ui --- .../components/explorer/ExplorerTopBar.tsx | 8 +- packages/interface/src/components/key/Key.tsx | 103 +++++++++ .../interface/src/components/key/KeyList.tsx | 59 +++++ .../src/components/key/KeyManager.tsx | 211 ++---------------- .../src/components/key/KeyMounter.tsx | 87 ++++++++ .../src/components/layout/Sidebar.tsx | 10 +- packages/ui/package.json | 8 +- packages/ui/src/Tabs.tsx | 16 ++ packages/ui/src/Typography.tsx | 3 + packages/ui/src/index.ts | 2 + pnpm-lock.yaml | Bin 817251 -> 814875 bytes 11 files changed, 303 insertions(+), 204 deletions(-) create mode 100644 packages/interface/src/components/key/Key.tsx create mode 100644 packages/interface/src/components/key/KeyList.tsx create mode 100644 packages/interface/src/components/key/KeyMounter.tsx create mode 100644 packages/ui/src/Tabs.tsx create mode 100644 packages/ui/src/Typography.tsx diff --git a/packages/interface/src/components/explorer/ExplorerTopBar.tsx b/packages/interface/src/components/explorer/ExplorerTopBar.tsx index c9edbd401..e67f95f79 100644 --- a/packages/interface/src/components/explorer/ExplorerTopBar.tsx +++ b/packages/interface/src/components/explorer/ExplorerTopBar.tsx @@ -1,4 +1,4 @@ -import { ChevronLeftIcon, ChevronRightIcon, PhotoIcon } from '@heroicons/react/24/outline'; +import { ChevronLeftIcon, ChevronRightIcon, TagIcon } from '@heroicons/react/24/outline'; import { OperatingSystem, getExplorerStore, @@ -264,12 +264,12 @@ export const TopBar: React.FC = (props) => { // } > -
+
- - + + diff --git a/packages/interface/src/components/key/Key.tsx b/packages/interface/src/components/key/Key.tsx new file mode 100644 index 000000000..87b55670f --- /dev/null +++ b/packages/interface/src/components/key/Key.tsx @@ -0,0 +1,103 @@ +import { InformationCircleIcon } from '@heroicons/react/24/outline'; +import { + EllipsisVerticalIcon, + EyeIcon, + EyeSlashIcon, + KeyIcon, + LockClosedIcon, + LockOpenIcon, + PlusIcon, + TrashIcon, + XMarkIcon +} from '@heroicons/react/24/solid'; +import { Button, Input, Select, SelectOption } from '@sd/ui'; +import clsx from 'clsx'; +import { Eject, EjectSimple, Plus } from 'phosphor-react'; +import { useState } from 'react'; + +import { Toggle } from '../primitive'; +import { DefaultProps } from '../primitive/types'; +import { Tooltip } from '../tooltip/Tooltip'; + +export type KeyManagerProps = DefaultProps; + +// TODO: Replace this with Prisma type when integrating with backend +export interface Key { + id: string; + name: string; + mounted?: boolean; + locked?: boolean; + stats?: { + objectCount?: number; + containerCount?: number; + }; + // Nodes this key is mounted on + nodes?: string[]; // will be node object +} + +export const Key: React.FC<{ data: Key; index: number }> = ({ data, index }) => { + const odd = (index || 0) % 2 === 0; + + return ( +
+
+ +
+
+
{data.name}
+ {data.mounted && ( +
+ {data.nodes?.length || 0 > 0 ? `${data.nodes?.length || 0} nodes` : 'This node'} +
+ )} +
+ {/*
#{data.id}
*/} + {data.stats ? ( +
+ {data.stats.objectCount && ( +
+ {data.stats.objectCount} Objects +
+ )} + {data.stats.containerCount && ( +
+ {data.stats.containerCount} Containers +
+ )} +
+ ) : ( + !data.mounted && ( +
Key not mounted
+ ) + )} +
+
+
+ {data.mounted && ( + + + + )} + +
+
+ ); +}; diff --git a/packages/interface/src/components/key/KeyList.tsx b/packages/interface/src/components/key/KeyList.tsx new file mode 100644 index 000000000..ffebd9397 --- /dev/null +++ b/packages/interface/src/components/key/KeyList.tsx @@ -0,0 +1,59 @@ +import { Button, CategoryHeading, Input, Select, SelectOption } from '@sd/ui'; +import clsx from 'clsx'; +import { Eject, EjectSimple, Plus } from 'phosphor-react'; +import { useState } from 'react'; + +import { Toggle } from '../primitive'; +import { DefaultProps } from '../primitive/types'; +import { Tooltip } from '../tooltip/Tooltip'; +import { Key } from './Key'; + +export type KeyListProps = DefaultProps; + +export function KeyList(props: KeyListProps) { + return ( +
+
+
+ {/* Mounted keys */} +
+ + + + + + +
+
+
+
+ +
+ +
+
+ ); +} diff --git a/packages/interface/src/components/key/KeyManager.tsx b/packages/interface/src/components/key/KeyManager.tsx index c4cd6212a..f6854d1d2 100644 --- a/packages/interface/src/components/key/KeyManager.tsx +++ b/packages/interface/src/components/key/KeyManager.tsx @@ -1,15 +1,4 @@ -import { InformationCircleIcon } from '@heroicons/react/24/outline'; -import { - EyeIcon, - EyeSlashIcon, - KeyIcon, - LockClosedIcon, - LockOpenIcon, - PlusIcon, - TrashIcon, - XMarkIcon -} from '@heroicons/react/24/solid'; -import { Button, Input } from '@sd/ui'; +import { Button, Input, Select, SelectOption, Tabs } from '@sd/ui'; import clsx from 'clsx'; import { Eject, EjectSimple, Plus } from 'phosphor-react'; import { useState } from 'react'; @@ -17,189 +6,31 @@ import { useState } from 'react'; import { Toggle } from '../primitive'; import { DefaultProps } from '../primitive/types'; import { Tooltip } from '../tooltip/Tooltip'; +import { Key } from './Key'; +import { KeyList } from './KeyList'; +import { KeyMounter } from './KeyMounter'; export type KeyManagerProps = DefaultProps; -interface FakeKey { - id: string; - name: string; - mounted?: boolean; - locked?: boolean; - stats?: { - objectCount?: number; - containerCount?: number; - }; - // Nodes this key is mounted on - nodes?: string[]; // will be node object -} - -const Heading: React.FC<{ children: React.ReactNode }> = ({ children }) => ( -
{children}
-); - -const Key: React.FC<{ data: FakeKey; index: number }> = ({ data, index }) => { - const odd = (index || 0) % 2 === 0; - - return ( -
-
- -
-
-
{data.name}
- {data.mounted && ( -
- {data.nodes?.length || 0 > 0 ? `${data.nodes?.length || 0} nodes` : 'This node'} -
- )} -
- {/*
#{data.id}
*/} - {data.stats && ( -
- {data.stats.objectCount && ( -
- {data.stats.objectCount} Objects -
- )} - {data.stats.containerCount && ( -
- {data.stats.containerCount} Containers -
- )} -
- )} -
-
-
- {data.mounted ? ( - <> - - - - - {data.locked ? ( - - - - ) : ( - - - - )} - - ) : ( - - - - )} -
-
- ); -}; - export function KeyManager(props: KeyManagerProps) { - const [showKey, setShowKey] = useState(false); - const [toggle, setToggle] = useState(false); - - const CurrentEyeIcon = showKey ? EyeSlashIcon : EyeIcon; - return ( -
-
- Mount key -
-
- - -
- - - -
-
- - Sync with Library - - - -
-

- Files encrypted with this key will be revealed and decrypted on the fly. -

-
-
-
-
- Mounted keys -
- - - - - - -
-
-
-
- -
- -
+
+ + + + Mount + + + Keys + + + + + + + + +
); } diff --git a/packages/interface/src/components/key/KeyMounter.tsx b/packages/interface/src/components/key/KeyMounter.tsx new file mode 100644 index 000000000..7902973ec --- /dev/null +++ b/packages/interface/src/components/key/KeyMounter.tsx @@ -0,0 +1,87 @@ +import { InformationCircleIcon } from '@heroicons/react/24/outline'; +import { + EllipsisVerticalIcon, + EyeIcon, + EyeSlashIcon, + KeyIcon, + LockClosedIcon, + LockOpenIcon, + PlusIcon, + TrashIcon, + XMarkIcon +} from '@heroicons/react/24/solid'; +import { Button, CategoryHeading, Input, Select, SelectOption } from '@sd/ui'; +import clsx from 'clsx'; +import { Eject, EjectSimple, Plus } from 'phosphor-react'; +import { useState } from 'react'; + +import { Toggle } from '../primitive'; +import { DefaultProps } from '../primitive/types'; +import { Tooltip } from '../tooltip/Tooltip'; +import { Key } from './Key'; + +export function KeyMounter() { + const [showKey, setShowKey] = useState(false); + const [toggle, setToggle] = useState(false); + + const [key, setKey] = useState(''); + const [encryptionAlgo, setEncryptionAlgo] = useState('XChaCha20Poly1305'); + const [hashingAlgo, setHashingAlgo] = useState('Argon2id'); + + const CurrentEyeIcon = showKey ? EyeSlashIcon : EyeIcon; + + return ( +
+ Mount key +
+
+ setKey(e.target.value)} + autoFocus + type={showKey ? 'text' : 'password'} + className="flex-grow !py-0.5" + /> + +
+
+ +
+ + Sync with Library + + + +
+ +
+
+ Encryption + +
+
+ Hashing + +
+
+

+ Files encrypted with this key will be revealed and decrypted on the fly. +

+ +
+ ); +} diff --git a/packages/interface/src/components/layout/Sidebar.tsx b/packages/interface/src/components/layout/Sidebar.tsx index 8102055ab..07e738bc0 100644 --- a/packages/interface/src/components/layout/Sidebar.tsx +++ b/packages/interface/src/components/layout/Sidebar.tsx @@ -2,7 +2,7 @@ import { CogIcon, LockClosedIcon, PhotoIcon } from '@heroicons/react/24/outline' import { PlusIcon } from '@heroicons/react/24/solid'; import { useCurrentLibrary, useLibraryMutation, useLibraryQuery, usePlatform } from '@sd/client'; import { LocationCreateArgs } from '@sd/client'; -import { Button, Dropdown, OverlayPanel } from '@sd/ui'; +import { Button, CategoryHeading, Dropdown, OverlayPanel } from '@sd/ui'; import clsx from 'clsx'; import { CheckCircle, CirclesFour, Planet, WaveTriangle } from 'phosphor-react'; import { NavLink, NavLinkProps, useNavigate } from 'react-router-dom'; @@ -37,10 +37,6 @@ const Icon = ({ component: Icon, ...props }: any) => ( ); -const Heading: React.FC<{ children: React.ReactNode }> = ({ children }) => ( -
{children}
-); - // cute little helper to decrease code clutter const macOnly = (platform: string | undefined, classnames: string) => platform === 'macOS' ? classnames : ''; @@ -71,7 +67,7 @@ function LibraryScopedSection() { return ( <>
- Locations + Locations {locations?.map((location) => { return (
@@ -135,7 +131,7 @@ function LibraryScopedSection() {
{tags?.length ? (
- Tags + Tags
{tags?.slice(0, 6).map((tag, index) => ( diff --git a/packages/ui/package.json b/packages/ui/package.json index 17794be2c..98639e5c4 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -20,21 +20,23 @@ "@headlessui/react": "^1.7.3", "@heroicons/react": "^2.0.12", "@radix-ui/react-context-menu": "^1.0.0", - "@radix-ui/react-select": "^1.0.0", "@radix-ui/react-dialog": "^1.0.0", "@radix-ui/react-dropdown-menu": "^1.0.0", + "@radix-ui/react-select": "^1.0.0", + "@radix-ui/react-tabs": "^1.0.0", + "@sd/assets": "workspace:*", "@tailwindcss/forms": "^0.5.3", "class-variance-authority": "^0.2.3", - "@sd/assets": "workspace:*", "clsx": "^1.2.1", "phosphor-react": "^1.4.1", "postcss": "^8.4.17", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-router-dom": "6.4.2", "react-loading-icons": "^1.1.0", + "react-router-dom": "6.4.2", "react-spring": "^9.5.5", "storybook": "^6.5.12", + "tailwind-styled-components": "2.1.7", "tailwindcss": "^3.1.8", "tailwindcss-radix": "^2.6.0" }, diff --git a/packages/ui/src/Tabs.tsx b/packages/ui/src/Tabs.tsx new file mode 100644 index 000000000..5633f760c --- /dev/null +++ b/packages/ui/src/Tabs.tsx @@ -0,0 +1,16 @@ +import * as TabsPrimitive from '@radix-ui/react-tabs'; +import tw from 'tailwind-styled-components'; + +export const Root = tw(TabsPrimitive.Root)` + flex flex-col +`; + +export const Content = tw(TabsPrimitive.TabsContent)``; + +export const List = tw(TabsPrimitive.TabsList)` + flex flex-row p-2 items-center space-x-1 border-b border-gray-500/30 +`; + +export const Trigger = tw(TabsPrimitive.TabsTrigger)` + text-white px-1.5 py-0.5 rounded text-sm font-medium radix-state-active:bg-primary +`; diff --git a/packages/ui/src/Typography.tsx b/packages/ui/src/Typography.tsx new file mode 100644 index 000000000..4cd14d77e --- /dev/null +++ b/packages/ui/src/Typography.tsx @@ -0,0 +1,3 @@ +import tw from 'tailwind-styled-components'; + +export const CategoryHeading = tw.h3`mt-1 mb-1 text-xs font-semibold text-gray-300`; diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts index f88a5c1f4..b3410b985 100644 --- a/packages/ui/src/index.ts +++ b/packages/ui/src/index.ts @@ -6,3 +6,5 @@ export * as ContextMenu from './ContextMenu'; export * from './OverlayPanel'; export * from './Input'; export * from './Select'; +export * as Tabs from './Tabs'; +export * from './Typography'; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3eaefc63dd26e98de1675c1cac06c2b289d262d5..1fe1c2addac99600831accf38c3a662095bf3e3c 100644 GIT binary patch delta 1446 zcmZ`(eQZ-z6wkYFuYK>eYs<>MK$gNj*fQ7Gj?#5QCL8194NBKB)~+C1yLPO!Ti3N| zS45aGai~GW3p)r1exaZnLZ)1WFoz`am6+iNQ4B(Y(MU|#AH*2N;A=O+V)Vaz&OPUz z-|wE^IkzW_2Yxi3crXvneTcNMEygJ!{VbI+Qk}m@g~#gU_$5IJ6VK90JTX&&$E`C* zzA$#o!DE#g{6S?VR#g>@G}uCEIc1S(BIxs$wTHTTLfyXZXrxM4t~cuOZig0c6*MDX zt-U~D%{n#Sztk}D+PYg*?*FA!z>F$14PD>gFQ4s@n6>lLQA3*mh+>@6DnnOqhSN5QK z9M4lHEj2V8LJuY(4gAJr;PFI3Dj%eL5r3AQO@ud4@g$@a4)XGw$dvYo1i5JdplrdQYqgN0ay+Zf1Qui5{pDR}r_cwGgN}79*aw=&1mQE+1T%$Sq zp^M!9o*v*QOP#qv7sKit#6qh|sfJxY&>C|6Cpzqe*UJ?wXCD2wxarnl*T=L~{_D?<;QUug#_Ni0|?kBUL^*mb+cTcmOaO@JR z0`(ZHhx_N)#pL!Gc6~bd_aZfEljJk}s3;kWaeFe!{+(P01+sgL8n*A_3W@j%r>4kX zuX5ZBl6QoA#xp6cMLsUA!AhABmKzKaSV zbuY}|ho;L!Lhv{=U#8cSU0S}CD(LmO+oMa27QI1l;CY=+NIA;7-BEwcCm8hRO1%kA z-cgj3woE>c!Y2!6J(Rh`d8af&2X~UVaTua3|Pok$n@Y{OC4#)Dqa!Vw>EWX)kUuF-~#Ol|?!PrD)gH2Gd|FMIF z=n|r0cehQjS8lNy#AYEDUe~u) zY+qf|)oG1;JbqVK!rA1lY2IQntuaN6E23gzg{>}ZF*LwcCn^TRc8UY^3zseJr|mRf z4&!oqzBcOi2jl*3@8l;`>5O_ajOQ>}DXgTnRPl8hXd0QBWORYTkw_^9Z!%`2#?Csd OD3~0W7lswrFaHA(xcs63 delta 2058 zcma)6drVVT9L_nnx4n;2Kq!wQql)zf>x0&|I5sVy0TfFqkAfSBtvsb`Z7ISMgENZA z+z8kBo4ToN#${8`iSFo(%9bs4x-46qZZ5`{Y+06&F%y?8*_OGBO!1F-@&0x0IluSs z`@RFWO+Vf>oxDF+6YTVESl{gJwzY+G!q#9U)Yf43`vZ->b{KjeC&KbmIDXWa`J4*0 zcj+YI`@~Ezq$ugp{icp|fvHlCE_e3IVC*_Y3ju>lc-}K>G_m3g5)6fzqghoK(A1OB zLr?kFn0P^1!EAGSh|_~sBe+n5=D@xhG?(12K_B>@svg0ZX@NTzkWx62IiF-)Lggs+ ziG6@WgOkYM82TkTgAoLdVg};&;RN#0P8{Wh@~`dWojrIR61=B0aN-k&2Gw4?aqnd@ zVE0~}OKWmEH--G0JA$^3oVNCEpVimW(r#p8_AlAI$s8c&cu}~NoJ{nG@xqx}d{n)RY#YKxnN%8avkPG07(PI@9>rBN znNES=@u3fc|1{1b+T-{e$#x#*(UIa2{MFNR5KoFv;v#B>;-@PTGSX9s>NLj5QZ5bW z<;!~4Ud3eXRjP-XL}DT&U!r5lZ`Y`WcyUJSZuX5!&3(I_~t4o$tI)eGZl6+^A*=AhRZLM{M%ew<%tG}|7`HI*KJPOdXl?c3bG%39u8RG1ZMYc)sg8~k>MGr!i<^*v=V{vV3;5dQwxpf5t)3B^LBRdauWD&makX23H@R2Nwr13+e%Eo;)dG&u*Mf-iYOzA5;98_ZT&7 zi82fkA)>>OafMQWs3k01wNhMfSprAO5_nr28P@UFWUx-fr9j+U3RYHU*BgZ~LmJt$ zn6E^Moc6)@pDsMx8d|EgfMc9a0DU$;3!K^fY?uRVDMYjR`q-9@oh^Q!C?E#2-lVsK nYZq&QyNmdNCnTuuk{Aelc%4cVj2;g9@?`TKN)r*KY5dB+5ZmOj