From f9447c9c1446436000923de84120888e7649838b Mon Sep 17 00:00:00 2001 From: Suhail Kakar Date: Tue, 26 Mar 2024 01:38:52 +0530 Subject: [PATCH 01/69] api: add create, get and get all endpoints --- .../www/hooks/use-api/endpoints/project.ts | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 packages/www/hooks/use-api/endpoints/project.ts diff --git a/packages/www/hooks/use-api/endpoints/project.ts b/packages/www/hooks/use-api/endpoints/project.ts new file mode 100644 index 0000000000..f71e80f2bc --- /dev/null +++ b/packages/www/hooks/use-api/endpoints/project.ts @@ -0,0 +1,57 @@ +import qs from "qs"; +import { ApiState } from "../types"; +import { SetStateAction } from "react"; + +// temporary: +// TODO: Import the Project type from @livpeer.studio/api +type Project = { + id: string; + name: string; + createdAt: number; +}; + +let context: any; +let setState: (value: SetStateAction) => void; + +export const setSharedScope = ( + _context: any, + _setState: (value: SetStateAction) => void +) => { + context = _context; + setState = _setState; +}; + +export const createProject = async (params): Promise => { + const [res, project] = await context.fetch(`/project`, { + method: "POST", + body: JSON.stringify(params), + headers: { + "content-type": "application/json", + }, + }); + + if (res.status !== 201) { + throw new Error(project.errors.join(", ")); + } + return project; +}; + +export const getProject = async (projectId): Promise => { + const [res, project] = await context.fetch(`/project/${projectId}`); + if (res.status !== 200) { + throw project && typeof project === "object" + ? { ...project, status: res.status } + : new Error(project); + } + return project; +}; + +export const getProjects = async (): Promise => { + const [res, projects] = await context.fetch(`/project`); + if (res.status !== 200) { + throw projects && typeof projects === "object" + ? { ...projects, status: res.status } + : new Error(projects); + } + return projects; +}; From 954802482d37754092e4aae87729e3beccbb66cd Mon Sep 17 00:00:00 2001 From: Suhail Kakar Date: Tue, 26 Mar 2024 02:37:46 +0530 Subject: [PATCH 02/69] feat: add create project option --- .../Project/createProjectDialog.tsx | 104 ++++++++++++++++++ packages/www/components/Sidebar/index.tsx | 12 +- packages/www/hooks/use-api/index.tsx | 3 + 3 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 packages/www/components/Project/createProjectDialog.tsx diff --git a/packages/www/components/Project/createProjectDialog.tsx b/packages/www/components/Project/createProjectDialog.tsx new file mode 100644 index 0000000000..4e7f21c03d --- /dev/null +++ b/packages/www/components/Project/createProjectDialog.tsx @@ -0,0 +1,104 @@ +import { + Box, + Button, + Flex, + AlertDialog, + AlertDialogTitle, + AlertDialogContent, + AlertDialogCancel, + TextField, + Heading, + Label, +} from "@livepeer/design-system"; +import { useCallback, useState } from "react"; +import Spinner from "components/Spinner"; +import { createProject } from "hooks/use-api/endpoints/project"; + +const CreateProjectDialog = ({ + isOpen, + onOpenChange, + onCreate, +}: { + isOpen: boolean; + onOpenChange: (isOpen: boolean) => void; + onCreate: (projectName: string) => Promise; +}) => { + const [creating, setCreating] = useState(false); + const [projectName, setProjectName] = useState(""); + + return ( + + + + Create Project + + + { + e.preventDefault(); + if (creating) { + return; + } + setCreating(true); + try { + await onCreate(projectName); + } catch (error) { + console.error(error); + } finally { + setCreating(false); + } + }}> + + + setProjectName(e.target.value)} + placeholder="e.g. My first project" + /> + + + + + + + + + + + + ); +}; + +export default CreateProjectDialog; diff --git a/packages/www/components/Sidebar/index.tsx b/packages/www/components/Sidebar/index.tsx index fd7fff1ae6..f372ad966a 100644 --- a/packages/www/components/Sidebar/index.tsx +++ b/packages/www/components/Sidebar/index.tsx @@ -30,6 +30,7 @@ import { useApi } from "../../hooks"; import Router from "next/router"; import { RocketIcon, ChatBubbleIcon, LoopIcon } from "@radix-ui/react-icons"; import Contact from "../Contact"; +import CreateProjectDialog from "components/Project/createProjectDialog"; export const NavLink = styled(A, { fontSize: 14, @@ -71,7 +72,15 @@ export type SidebarId = | "billing/plans"; const Sidebar = ({ id }: { id: SidebarId }) => { - const { user, logout } = useApi(); + const { user, logout, createProject } = useApi(); + + const onCreateClick = async (projectName: string) => { + const project = await createProject({ + name: projectName, + }); + + console.log(project); + }; return ( { justifyContent: "flex-end", bottom: 0, }}> + { @@ -97,6 +98,7 @@ const makeContext = ( ...userEndpointsFunctions, ...versionEndpointsFunctions, ...webhookEndpointsFunctions, + ...projectEndpointsFunctions, }; accessControlEndpointsFunctions.setSharedScope(context, setState); @@ -114,6 +116,7 @@ const makeContext = ( userEndpointsFunctions.setSharedScope(context, setState); versionEndpointsFunctions.setSharedScope(context, setState); webhookEndpointsFunctions.setSharedScope(context, setState); + projectEndpointsFunctions.setSharedScope(context, setState); delete context.setSharedScope; From 5c9e90d8c8cd7f8a20d22605d3af9d6a57a5a09f Mon Sep 17 00:00:00 2001 From: Suhail Kakar Date: Fri, 29 Mar 2024 16:19:03 +0530 Subject: [PATCH 03/69] feat: add project toggle --- .../Project/createProjectDialog.tsx | 2 +- packages/www/components/Sidebar/NavIcons.tsx | 24 ++++ packages/www/components/Sidebar/index.tsx | 122 +++++++++++++++++- packages/www/hooks/use-project.tsx | 17 +++ 4 files changed, 158 insertions(+), 7 deletions(-) create mode 100644 packages/www/hooks/use-project.tsx diff --git a/packages/www/components/Project/createProjectDialog.tsx b/packages/www/components/Project/createProjectDialog.tsx index 4e7f21c03d..fee5bc33c4 100644 --- a/packages/www/components/Project/createProjectDialog.tsx +++ b/packages/www/components/Project/createProjectDialog.tsx @@ -27,7 +27,7 @@ const CreateProjectDialog = ({ const [projectName, setProjectName] = useState(""); return ( - + Create Project diff --git a/packages/www/components/Sidebar/NavIcons.tsx b/packages/www/components/Sidebar/NavIcons.tsx index 280a855a30..03c584a92d 100644 --- a/packages/www/components/Sidebar/NavIcons.tsx +++ b/packages/www/components/Sidebar/NavIcons.tsx @@ -108,3 +108,27 @@ export const AssetsIcon = ({ active = false }) => ( ); + +export const TopBottomChevron = ({ active = false }) => ( + + + + + + +); diff --git a/packages/www/components/Sidebar/index.tsx b/packages/www/components/Sidebar/index.tsx index f372ad966a..0b69aac1c5 100644 --- a/packages/www/components/Sidebar/index.tsx +++ b/packages/www/components/Sidebar/index.tsx @@ -11,11 +11,8 @@ import { DropdownMenuGroup, DropdownMenuTrigger, DropdownMenuItem, - AlertDialog, - AlertDialogTrigger, - AlertDialogContent, } from "@livepeer/design-system"; -import { ChevronDownIcon } from "@radix-ui/react-icons"; +import { ChevronDownIcon, PlusIcon } from "@radix-ui/react-icons"; import ThemeSwitch from "../ThemeSwitch"; import Link from "next/link"; import { @@ -25,12 +22,17 @@ import { BillingIcon, UsageIcon, AssetsIcon, + TopBottomChevron, } from "./NavIcons"; import { useApi } from "../../hooks"; import Router from "next/router"; import { RocketIcon, ChatBubbleIcon, LoopIcon } from "@radix-ui/react-icons"; import Contact from "../Contact"; import CreateProjectDialog from "components/Project/createProjectDialog"; +import { useQueries, useQuery } from "react-query"; +import { useState } from "react"; +import { FiCheck } from "react-icons/fi"; +import useProject from "hooks/use-project"; export const NavLink = styled(A, { fontSize: 14, @@ -72,7 +74,9 @@ export type SidebarId = | "billing/plans"; const Sidebar = ({ id }: { id: SidebarId }) => { - const { user, logout, createProject } = useApi(); + const { user, logout, createProject, getProjects } = useApi(); + const { setCurrentProject, currentProject } = useProject(); + const [showCreateProjectAlert, setShowCreateProjectAlert] = useState(false); const onCreateClick = async (projectName: string) => { const project = await createProject({ @@ -82,6 +86,10 @@ const Sidebar = ({ id }: { id: SidebarId }) => { console.log(project); }; + const { data } = useQuery("projects", getProjects); + + const activeProject = data?.find((project) => project.id === currentProject); + return ( { justifyContent: "flex-end", bottom: 0, }}> - + setShowCreateProjectAlert(isOpen)} + isOpen={showCreateProjectAlert} + /> + { + + + + + {activeProject?.name} + + + + + + Projects + + + {data?.map((project) => ( + setCurrentProject(project)} + key={project.id} + css={{ + p: "$2", + "&:hover": { + backgroundColor: "$neutral4", + borderRadius: "$3", + }, + }} + align={"center"} + justify={"between"}> + {project.name || "Untitled"} + {currentProject === project.id && } + + ))} + + + + setShowCreateProjectAlert(true)} + align={"center"} + css={{ + color: "$neutral12", + gap: "$2", + cursor: "pointer", + }}> + + New project + + + + + + { + localStorage.setItem("currentProject", project.id); + window.location.reload(); + }; + + const getCurrentProject = () => { + if (typeof window !== "undefined") { + return localStorage.getItem("currentProject"); + } + }; + + return { + setCurrentProject, + currentProject: getCurrentProject(), + }; +} From f5dea08b69205f297d9ecc0644a8e9df2c22dc12 Mon Sep 17 00:00:00 2001 From: Suhail Kakar Date: Fri, 29 Mar 2024 16:19:20 +0530 Subject: [PATCH 04/69] ui: add active project to breadcrumb --- packages/www/components/Breadcrumbs/index.tsx | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/packages/www/components/Breadcrumbs/index.tsx b/packages/www/components/Breadcrumbs/index.tsx index d7c290a9e7..9cea7cd102 100644 --- a/packages/www/components/Breadcrumbs/index.tsx +++ b/packages/www/components/Breadcrumbs/index.tsx @@ -1,5 +1,8 @@ import { styled, Box } from "@livepeer/design-system"; +import { useApi } from "hooks"; +import useProject from "hooks/use-project"; import { Children, isValidElement } from "react"; +import { useQuery } from "react-query"; const BreadcrumbsOl = styled("ol", { display: "flex", @@ -38,6 +41,10 @@ function insertSeparators(items) { } const Breadcrumbs = ({ children }) => { + const { currentProject } = useProject(); + const { getProjects } = useApi(); + const { data } = useQuery("projects", getProjects); + const allItems = Children.toArray(children) .filter((child) => { return isValidElement(child); @@ -54,6 +61,22 @@ const Breadcrumbs = ({ children }) => { {child} )); + + if (currentProject) { + const project = data?.find((project) => project.id === currentProject); + allItems.unshift( + + {project?.name} + + ); + } return ( {insertSeparators(allItems)} From 7c514f3747c8e1a9040db20f8f49d56c2cb25a52 Mon Sep 17 00:00:00 2001 From: Suhail Kakar Date: Fri, 29 Mar 2024 18:32:19 +0530 Subject: [PATCH 05/69] add projectsId to assets API --- packages/www/hooks/use-api/endpoints/asset.ts | 19 ++++++++++++------- packages/www/hooks/use-project.tsx | 11 ++++------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/packages/www/hooks/use-api/endpoints/asset.ts b/packages/www/hooks/use-api/endpoints/asset.ts index 32dea844d3..52de91fdb2 100644 --- a/packages/www/hooks/use-api/endpoints/asset.ts +++ b/packages/www/hooks/use-api/endpoints/asset.ts @@ -5,6 +5,7 @@ import { HttpError } from "../../../lib/utils"; import { Upload } from "tus-js-client"; import qs from "qs"; import { getCursor } from "../helpers"; +import { projectId } from "hooks/use-project"; let context: any; let setState: (value: SetStateAction) => void; @@ -41,13 +42,16 @@ export const uploadAssets = async ( const requestAssetUpload = async ( params ): Promise<{ tusEndpoint: string }> => { - const [res, assetUpload] = await context.fetch(`/asset/request-upload`, { - method: "POST", - body: JSON.stringify(params), - headers: { - "content-type": "application/json", - }, - }); + const [res, assetUpload] = await context.fetch( + `/asset/request-upload?projectId=${projectId}`, + { + method: "POST", + body: JSON.stringify(params), + headers: { + "content-type": "application/json", + }, + } + ); if (!res.ok) { throw new Error(assetUpload.errors.join(", ")); @@ -157,6 +161,7 @@ export const getAssets = async ( cursor: opts?.cursor, count: opts?.count, details: 1, + projectId: projectId, })}` ); if (res.status !== 200) { diff --git a/packages/www/hooks/use-project.tsx b/packages/www/hooks/use-project.tsx index e9a02ac451..5b7a94eb95 100644 --- a/packages/www/hooks/use-project.tsx +++ b/packages/www/hooks/use-project.tsx @@ -1,17 +1,14 @@ +export const projectId = + typeof window !== "undefined" && localStorage.getItem("currentProject"); + export default function useProject() { const setCurrentProject = (project) => { localStorage.setItem("currentProject", project.id); window.location.reload(); }; - const getCurrentProject = () => { - if (typeof window !== "undefined") { - return localStorage.getItem("currentProject"); - } - }; - return { setCurrentProject, - currentProject: getCurrentProject(), + currentProject: projectId, }; } From 7e5bdeb5ba603a97a877b6d6292143569cea3ea2 Mon Sep 17 00:00:00 2001 From: Suhail Kakar Date: Fri, 29 Mar 2024 22:11:48 +0530 Subject: [PATCH 06/69] Update index.tsx --- packages/www/components/Sidebar/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/www/components/Sidebar/index.tsx b/packages/www/components/Sidebar/index.tsx index 0b69aac1c5..d4b115d990 100644 --- a/packages/www/components/Sidebar/index.tsx +++ b/packages/www/components/Sidebar/index.tsx @@ -187,7 +187,7 @@ const Sidebar = ({ id }: { id: SidebarId }) => { css={{ color: "$neutral11", }}> - {activeProject?.name} + {activeProject?.name || "Untitled"} From 3050c862091905dcb8f0d423f4cd511e72461ba8 Mon Sep 17 00:00:00 2001 From: Suhail Kakar Date: Tue, 2 Apr 2024 13:07:04 +0530 Subject: [PATCH 07/69] add projectId to api tokens --- .../www/hooks/use-api/endpoints/apiToken.ts | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/packages/www/hooks/use-api/endpoints/apiToken.ts b/packages/www/hooks/use-api/endpoints/apiToken.ts index aeaf58ba5c..7f58920c94 100644 --- a/packages/www/hooks/use-api/endpoints/apiToken.ts +++ b/packages/www/hooks/use-api/endpoints/apiToken.ts @@ -4,6 +4,7 @@ import { SetStateAction } from "react"; import { ApiToken, Error as ApiError } from "@livepeer.studio/api"; import { getCursor } from "../helpers"; import { trackPageView } from "../tracking"; +import { projectId } from "hooks/use-project"; let context: any; let setState: (value: SetStateAction) => void; @@ -35,6 +36,7 @@ export const getApiTokens = async ( limit: opts?.limit, cursor: opts?.cursor, count: opts?.count, + projectId: projectId, })}` ); const nextCursor = getCursor(res.headers.get("link")); @@ -44,13 +46,16 @@ export const getApiTokens = async ( export const createApiToken = async (params): Promise => { trackPageView(params.email, "/create-api-token"); - const [res, token] = await context.fetch(`/api-token`, { - method: "POST", - body: JSON.stringify(params), - headers: { - "content-type": "application/json", - }, - }); + const [res, token] = await context.fetch( + `/api-token?projectId=${projectId}`, + { + method: "POST", + body: JSON.stringify(params), + headers: { + "content-type": "application/json", + }, + } + ); if (res.status !== 201) { throw new Error(JSON.stringify(res.errors)); } From 897a352e10801648eafe117cdff87db7731720e4 Mon Sep 17 00:00:00 2001 From: Suhail Kakar Date: Tue, 2 Apr 2024 13:14:58 +0530 Subject: [PATCH 08/69] add projectId to stream and wehooks --- .../www/hooks/use-api/endpoints/apiToken.ts | 2 +- packages/www/hooks/use-api/endpoints/asset.ts | 2 +- .../www/hooks/use-api/endpoints/stream.ts | 4 +++- .../www/hooks/use-api/endpoints/webhook.ts | 19 ++++++++++++------- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/packages/www/hooks/use-api/endpoints/apiToken.ts b/packages/www/hooks/use-api/endpoints/apiToken.ts index 7f58920c94..106a7401c1 100644 --- a/packages/www/hooks/use-api/endpoints/apiToken.ts +++ b/packages/www/hooks/use-api/endpoints/apiToken.ts @@ -36,7 +36,7 @@ export const getApiTokens = async ( limit: opts?.limit, cursor: opts?.cursor, count: opts?.count, - projectId: projectId, + projectId, })}` ); const nextCursor = getCursor(res.headers.get("link")); diff --git a/packages/www/hooks/use-api/endpoints/asset.ts b/packages/www/hooks/use-api/endpoints/asset.ts index 52de91fdb2..4aff5b7dc5 100644 --- a/packages/www/hooks/use-api/endpoints/asset.ts +++ b/packages/www/hooks/use-api/endpoints/asset.ts @@ -161,7 +161,7 @@ export const getAssets = async ( cursor: opts?.cursor, count: opts?.count, details: 1, - projectId: projectId, + projectId, })}` ); if (res.status !== 200) { diff --git a/packages/www/hooks/use-api/endpoints/stream.ts b/packages/www/hooks/use-api/endpoints/stream.ts index aefc99b954..3a3e7fb4ff 100644 --- a/packages/www/hooks/use-api/endpoints/stream.ts +++ b/packages/www/hooks/use-api/endpoints/stream.ts @@ -8,6 +8,7 @@ import { HttpError } from "../../../lib/utils"; import { ApiState, StreamInfo } from "../types"; import { getCursor } from "../helpers"; import { SetStateAction } from "react"; +import { projectId } from "hooks/use-project"; let context: any; let setState: (value: SetStateAction) => void; @@ -59,6 +60,7 @@ export const getStreams = async ( cursor: opts?.cursor, count: opts?.count, streamsonly: 1, + projectId, })}` ); if (res.status !== 200) { @@ -123,7 +125,7 @@ export const generateJwt = async (playbackId: string): Promise => { }; export const createStream = async (params): Promise => { - const [res, stream] = await context.fetch(`/stream`, { + const [res, stream] = await context.fetch(`/stream?projectId=${projectId}`, { method: "POST", body: JSON.stringify(params), headers: { diff --git a/packages/www/hooks/use-api/endpoints/webhook.ts b/packages/www/hooks/use-api/endpoints/webhook.ts index 9349c616ae..a7919c66e3 100644 --- a/packages/www/hooks/use-api/endpoints/webhook.ts +++ b/packages/www/hooks/use-api/endpoints/webhook.ts @@ -3,6 +3,7 @@ import { ApiState, WebhookLogs } from "../types"; import { SetStateAction } from "react"; import { Webhook } from "@livepeer.studio/api"; import { getCursor } from "../helpers"; +import { projectId } from "hooks/use-project"; let context: any; let setState: (value: SetStateAction) => void; @@ -34,6 +35,7 @@ export const getWebhooks = async ( cursor, filters: f, count, + projectId, })}` ); const nextCursor = getCursor(res.headers.get("link")); @@ -52,13 +54,16 @@ export const getWebhook = async (webhookId): Promise => { }; export const createWebhook = async (params): Promise => { - const [res, webhook] = await context.fetch(`/webhook`, { - method: "POST", - body: JSON.stringify(params), - headers: { - "content-type": "application/json", - }, - }); + const [res, webhook] = await context.fetch( + `/webhook?projectId=${projectId}`, + { + method: "POST", + body: JSON.stringify(params), + headers: { + "content-type": "application/json", + }, + } + ); if (res.status !== 201) { throw new Error(webhook.errors.join(", ")); From eba1defa142511f9ee118afcd4e3554bedd140e0 Mon Sep 17 00:00:00 2001 From: Suhail Kakar Date: Fri, 5 Apr 2024 19:50:01 +0530 Subject: [PATCH 09/69] refactor: sidebar --- packages/www/components/Sidebar/NavIcons.tsx | 14 + packages/www/components/Sidebar/index.tsx | 357 ++++++++++++------- 2 files changed, 242 insertions(+), 129 deletions(-) diff --git a/packages/www/components/Sidebar/NavIcons.tsx b/packages/www/components/Sidebar/NavIcons.tsx index 03c584a92d..b35ec72b7d 100644 --- a/packages/www/components/Sidebar/NavIcons.tsx +++ b/packages/www/components/Sidebar/NavIcons.tsx @@ -132,3 +132,17 @@ export const TopBottomChevron = ({ active = false }) => ( ); + +export const SettingsIcon = ({ active = false }) => ( + + + +); diff --git a/packages/www/components/Sidebar/index.tsx b/packages/www/components/Sidebar/index.tsx index d4b115d990..0545ad6bec 100644 --- a/packages/www/components/Sidebar/index.tsx +++ b/packages/www/components/Sidebar/index.tsx @@ -11,6 +11,7 @@ import { DropdownMenuGroup, DropdownMenuTrigger, DropdownMenuItem, + Button, } from "@livepeer/design-system"; import { ChevronDownIcon, PlusIcon } from "@radix-ui/react-icons"; import ThemeSwitch from "../ThemeSwitch"; @@ -23,15 +24,16 @@ import { UsageIcon, AssetsIcon, TopBottomChevron, + SettingsIcon, } from "./NavIcons"; import { useApi } from "../../hooks"; -import Router from "next/router"; +import Router, { useRouter } from "next/router"; import { RocketIcon, ChatBubbleIcon, LoopIcon } from "@radix-ui/react-icons"; import Contact from "../Contact"; import CreateProjectDialog from "components/Project/createProjectDialog"; import { useQueries, useQuery } from "react-query"; import { useState } from "react"; -import { FiCheck } from "react-icons/fi"; +import { FiCheck, FiChevronLeft } from "react-icons/fi"; import useProject from "hooks/use-project"; export const NavLink = styled(A, { @@ -63,32 +65,114 @@ export type SidebarId = | "home" | "streams" | "streams/sessions" - // /dashboard/stream-health - unhandled in the sidebar | "streams/health" | "assets" | "developers" | "developers/signing-keys" | "developers/webhooks" - | "usage" - | "billing" - | "billing/plans"; + | "settings/general" + | "settings/projects" + | "settings/usage" + | "settings/billing" + | "settings/billing/plans"; -const Sidebar = ({ id }: { id: SidebarId }) => { - const { user, logout, createProject, getProjects } = useApi(); - const { setCurrentProject, currentProject } = useProject(); - const [showCreateProjectAlert, setShowCreateProjectAlert] = useState(false); - - const onCreateClick = async (projectName: string) => { - const project = await createProject({ - name: projectName, - }); +export const generalSidebarItems = [ + { + title: "Home", + path: "/dashboard", + icon: , + id: "home", + }, + { + title: "Streams", + path: "/dashboard/streams", + icon: , + id: "streams", + children: [ + { + title: "Sessions", + path: "/dashboard/sessions", + id: "streams/sessions", + }, + ], + }, + { + title: "Assets", + path: "/dashboard/assets", + icon: , + id: "assets", + }, + { + title: "Developers", + path: "/dashboard/developers/api-keys", + icon: , + id: "developers", + children: [ + { + title: "API Keys", + path: "/dashboard/developers/api-keys", + id: "developers", + }, + { + title: "Signing Keys", + path: "/dashboard/developers/signing-keys", + id: "developers/signing-keys", + }, + { + title: "Webhooks", + path: "/dashboard/developers/webhooks", + id: "developers/webhooks", + }, + ], + }, + { + title: "Settings", + path: "/dashboard/settings/general", + icon: , + id: "settings", + }, +]; - console.log(project); - }; +const settingsSidebarItems = [ + { + title: "Settings", + path: "/dashboard/workspace/general", + icon: , + id: "settings/general", + children: [ + { + title: "General", + path: "/dashboard/settings/general", + id: "settings/general", + }, + { + title: "Projects", + path: "/dashboard/settings/projects", + id: "settings/projects", + }, + { + title: "Usage", + path: "/dashboard/settings/usage", + id: "settings/usage", + }, + { + title: "Billing", + path: "/dashboard/settings/billing", + id: "settings/billing", + }, + { + title: "Plans", + path: "/dashboard/settings/billing/plans", + id: "settings/billing/plans", + }, + ], + }, +]; - const { data } = useQuery("projects", getProjects); +const Sidebar = ({ id }: { id: SidebarId }) => { + const { user, logout } = useApi(); - const activeProject = data?.find((project) => project.id === currentProject); + const { pathname } = useRouter(); return ( { justifyContent: "flex-end", bottom: 0, }}> + {pathname.includes("settings") ? ( + + ) : ( + + )} + + ); +}; + +const GeneralSidebar = ({ id, user }: { id: SidebarId; user: User }) => { + const { createProject, getProjects } = useApi(); + + const [showCreateProjectAlert, setShowCreateProjectAlert] = useState(false); + const { setCurrentProject, currentProject } = useProject(); + + const goBack = () => { + Router.push("/dashboard"); + }; + + const onCreateClick = async (projectName: string) => { + const project = await createProject({ + name: projectName, + }); + }; + + const { data } = useQuery("projects", getProjects); + + const activeProject = data?.find((project) => project.id === currentProject); + + return ( + <> setShowCreateProjectAlert(isOpen)} @@ -270,115 +385,31 @@ const Sidebar = ({ id }: { id: SidebarId }) => { textDecoration: "none", }, }}> - - - - Home - - - - - - - Streams - - - - {id?.split("/")[0] === "streams" && ( - :first-child": { - mt: "$1", - }, - }}> - - Sessions - - - )} - - - - - Assets - - - - - - - Developers - - - - {id?.split("/")[0] === "developers" && ( - - - API Keys - - - - Signing Keys - - - - - Webhooks - - - - )} - - - - - - - Usage - - - - - - - - - Billing - - - - {id?.split("/")[0] === "billing" && ( - :first-child": { - mt: "$1", - }, - }}> - - Plans - - - )} - + {generalSidebarItems.map((item) => ( + + + + {item.icon} + {item.title} + + + {item.children && id === item.id && ( + + {item.children.map((child) => ( + + {child.title} + + ))} + + )} + + ))} { - + + ); +}; + +const SettingsSidebar = ({ id, user }: { id: SidebarId; user: User }) => { + const goBack = () => { + Router.push("/dashboard"); + }; + + return ( + <> + + + + + + {settingsSidebarItems.map((item) => ( + + + {item.icon} + {item.title} + + {item.children && ( + + {item.children.map((child) => ( + + {child.title} + + ))} + + )} + + ))} + + + ); }; From 3858478fe0fb131e9e980b75d21d143864e00105 Mon Sep 17 00:00:00 2001 From: Suhail Kakar Date: Fri, 5 Apr 2024 19:50:11 +0530 Subject: [PATCH 10/69] ui: complete settings page --- .../www/components/Project/ProjectTile.tsx | 107 ++++++++ packages/www/content/index.tsx | 9 + packages/www/lib/url-sanitizer.tsx | 4 + .../{ => settings}/billing/index.tsx | 0 .../{ => settings}/billing/plans.tsx | 0 .../www/pages/dashboard/settings/general.tsx | 244 ++++++++++++++++++ .../www/pages/dashboard/settings/projects.tsx | 73 ++++++ .../dashboard/{ => settings}/usage/index.tsx | 0 8 files changed, 437 insertions(+) create mode 100644 packages/www/components/Project/ProjectTile.tsx create mode 100644 packages/www/lib/url-sanitizer.tsx rename packages/www/pages/dashboard/{ => settings}/billing/index.tsx (100%) rename packages/www/pages/dashboard/{ => settings}/billing/plans.tsx (100%) create mode 100644 packages/www/pages/dashboard/settings/general.tsx create mode 100644 packages/www/pages/dashboard/settings/projects.tsx rename packages/www/pages/dashboard/{ => settings}/usage/index.tsx (100%) diff --git a/packages/www/components/Project/ProjectTile.tsx b/packages/www/components/Project/ProjectTile.tsx new file mode 100644 index 0000000000..0ab901bbb9 --- /dev/null +++ b/packages/www/components/Project/ProjectTile.tsx @@ -0,0 +1,107 @@ +import { + Box, + Flex, + Text, + DropdownMenu, + DropdownMenuContent, + DropdownMenuTrigger, + Button, +} from "@livepeer/design-system"; +import { GoDotFill } from "react-icons/go"; +import Image from "next/image"; +import React from "react"; +import { sanitizeUrl } from "lib/url-sanitizer"; +import { DotsHorizontalIcon } from "@radix-ui/react-icons"; +import { HiDotsHorizontal } from "react-icons/hi"; +import Link from "next/link"; +import { generalSidebarItems } from "components/Sidebar"; + +export default function ProjectTile({ + name, + url, + + ...props +}) { + return ( + + + + + {name || "Untitled project"} + + + + + + + + + {generalSidebarItems.map((item) => ( + + {item.title} + + ))} + + + + + + + {sanitizeUrl(url)} + + + + + ); +} diff --git a/packages/www/content/index.tsx b/packages/www/content/index.tsx index eb8e380d2e..a7cb4c3c4c 100644 --- a/packages/www/content/index.tsx +++ b/packages/www/content/index.tsx @@ -206,3 +206,12 @@ export const DashboardPlans = { url: makeCompleteUrl(), }, }; + +export const DashboardSettingsGeneral = { + metaData: { + title: makeCompleteTitle("Settings"), + description: + "Start for free, then pay as you grow. Enjoy flexible pricing for projects of all sizes.", + url: makeCompleteUrl(), + }, +}; diff --git a/packages/www/lib/url-sanitizer.tsx b/packages/www/lib/url-sanitizer.tsx new file mode 100644 index 0000000000..9d68676049 --- /dev/null +++ b/packages/www/lib/url-sanitizer.tsx @@ -0,0 +1,4 @@ +export function sanitizeUrl(url: string) { + const urlObject = new URL(url); + return urlObject.hostname + urlObject.pathname; +} diff --git a/packages/www/pages/dashboard/billing/index.tsx b/packages/www/pages/dashboard/settings/billing/index.tsx similarity index 100% rename from packages/www/pages/dashboard/billing/index.tsx rename to packages/www/pages/dashboard/settings/billing/index.tsx diff --git a/packages/www/pages/dashboard/billing/plans.tsx b/packages/www/pages/dashboard/settings/billing/plans.tsx similarity index 100% rename from packages/www/pages/dashboard/billing/plans.tsx rename to packages/www/pages/dashboard/settings/billing/plans.tsx diff --git a/packages/www/pages/dashboard/settings/general.tsx b/packages/www/pages/dashboard/settings/general.tsx new file mode 100644 index 0000000000..4271039d5c --- /dev/null +++ b/packages/www/pages/dashboard/settings/general.tsx @@ -0,0 +1,244 @@ +import Layout from "layouts/dashboard"; +import { useApi, useLoggedIn } from "hooks"; +import { + Box, + Heading, + Flex, + Text, + TextField, + Button, +} from "@livepeer/design-system"; +import { DashboardSettingsGeneral as Content } from "content"; +import React, { useRef, useState } from "react"; +import Image from "next/image"; +import { useQuery } from "react-query"; +import { projectId } from "hooks/use-project"; + +const Settings = () => { + useLoggedIn(); + const { user } = useApi(); + const [projectLogo, setProjectLogo] = useState(null); + + const { getProject } = useApi(); + + const { data } = useQuery(["project", projectId], () => + getProject(projectId) + ); + + const [projectName, setProjectName] = useState(data?.name); + + const logoRef = useRef(null); + + const handleSubmit = () => { + console.log("Project Name: ", projectName); + console.log("Project Logo: ", projectLogo); + }; + + if (!user) { + return ; + } + return ( + + + + + + Settings + + + Manage your project settings + + + + + + + Logo + + logoRef.current?.click()} + src={ + projectLogo + ? URL.createObjectURL(projectLogo) + : workspaces[0].projects[0].logo + } + alt="Project logo" + style={{ + borderRadius: "12px", + cursor: "pointer", + }} + width={90} + height={90} + /> + { + const file = e.target.files?.[0]; + if (file) { + setProjectLogo(file); + } + }} + /> + + Pick a logo for your project. Recommended size is 256x256px. + + + + + Project Name + + setProjectName(e.target.value)} + value={projectName} + id="projectName" + css={{ + width: "20%", + }} + placeholder="Project Name" + /> + + + + + + + Delete Project + + + If you want to permanently delete this project and all of its + data, including but not limited to streams, sessions, and assets, + you can do so below. + + + + + + + ); +}; + +// Placeholder constants, it will be removed and replaced with real data from the API +export const workspaces = [ + { + name: "Paramount", + logo: "https://pbs.twimg.com/profile_images/1712502841494138880/GofqA30R_400x400.jpg", + url: "https://livepeer.studio/paramount", + projects: [ + { + name: "Paramount Plus", + logo: "https://pbs.twimg.com/profile_images/1712502841494138880/GofqA30R_400x400.jpg", + url: "https://livepeer.studio/paramount/paramount-plus", + activeStreams: 10, + isDefault: true, + inProgressUploads: 5, + }, + { + name: "Paramount Dev", + logo: "https://i.pinimg.com/564x/bf/9a/7a/bf9a7a4ead767c8d66c613b76e2d3596.jpg", + url: "https://livepeer.studio/paramount/paramount-dev", + activeStreams: 21, + inProgressUploads: 48, + }, + ], + members: [ + { + name: "John Doe", + email: "john@livepeer.org", + role: "Admin", + }, + ], + }, +]; + +export default Settings; diff --git a/packages/www/pages/dashboard/settings/projects.tsx b/packages/www/pages/dashboard/settings/projects.tsx new file mode 100644 index 0000000000..93b6b422c6 --- /dev/null +++ b/packages/www/pages/dashboard/settings/projects.tsx @@ -0,0 +1,73 @@ +import Layout from "layouts/dashboard"; +import { useApi, useLoggedIn } from "hooks"; +import { DashboardStreams as Content } from "content"; +import { + Box, + Heading, + Flex, + Text, + TextField, + Button, +} from "@livepeer/design-system"; +import { workspaces } from "./general"; +import Image from "next/image"; +import ProjectTile from "components/Project/ProjectTile"; +import { useQuery } from "react-query"; + +const WorkspaceProjects = () => { + useLoggedIn(); + const { user } = useApi(); + + const { getProjects } = useApi(); + const { data } = useQuery("projects", getProjects); + + if (!user) { + return ; + } + + return ( + + + + + + Projects + + + Manage your workspace projects + + + + + {data.map((project) => ( + + ))} + + + + ); +}; + +export default WorkspaceProjects; diff --git a/packages/www/pages/dashboard/usage/index.tsx b/packages/www/pages/dashboard/settings/usage/index.tsx similarity index 100% rename from packages/www/pages/dashboard/usage/index.tsx rename to packages/www/pages/dashboard/settings/usage/index.tsx From 5230c01c5aa0b1c88211739b3c025d1a371c7e3e Mon Sep 17 00:00:00 2001 From: Suhail Kakar Date: Mon, 8 Apr 2024 10:43:05 +0530 Subject: [PATCH 11/69] ui: fix nav active state --- packages/www/components/Sidebar/index.tsx | 4 ++-- packages/www/pages/dashboard/settings/billing/index.tsx | 2 +- packages/www/pages/dashboard/settings/billing/plans.tsx | 4 ++-- packages/www/pages/dashboard/settings/general.tsx | 2 +- packages/www/pages/dashboard/settings/projects.tsx | 2 +- packages/www/pages/dashboard/settings/usage/index.tsx | 5 ++++- 6 files changed, 11 insertions(+), 8 deletions(-) diff --git a/packages/www/components/Sidebar/index.tsx b/packages/www/components/Sidebar/index.tsx index 0545ad6bec..9d68af4361 100644 --- a/packages/www/components/Sidebar/index.tsx +++ b/packages/www/components/Sidebar/index.tsx @@ -74,7 +74,7 @@ export type SidebarId = | "settings/projects" | "settings/usage" | "settings/billing" - | "settings/billing/plans"; + | "settings/plans"; export const generalSidebarItems = [ { @@ -163,7 +163,7 @@ const settingsSidebarItems = [ { title: "Plans", path: "/dashboard/settings/billing/plans", - id: "settings/billing/plans", + id: "settings/plans", }, ], }, diff --git a/packages/www/pages/dashboard/settings/billing/index.tsx b/packages/www/pages/dashboard/settings/billing/index.tsx index 58a5eac207..cbfcf16029 100644 --- a/packages/www/pages/dashboard/settings/billing/index.tsx +++ b/packages/www/pages/dashboard/settings/billing/index.tsx @@ -184,7 +184,7 @@ const Billing = () => { } return ( diff --git a/packages/www/pages/dashboard/settings/billing/plans.tsx b/packages/www/pages/dashboard/settings/billing/plans.tsx index d870e10889..b489be43c3 100644 --- a/packages/www/pages/dashboard/settings/billing/plans.tsx +++ b/packages/www/pages/dashboard/settings/billing/plans.tsx @@ -1,4 +1,4 @@ -import Layout from "../../../layouts/dashboard"; +import Layout from "../../../../layouts/dashboard"; import { Box, Flex, Heading } from "@livepeer/design-system"; import { useApi, useLoggedIn } from "hooks"; import Plans from "components/Plans"; @@ -13,7 +13,7 @@ const PlansPage = () => { } return ( { } return ( { return ( { return ; } return ( - + Date: Mon, 8 Apr 2024 10:55:01 +0530 Subject: [PATCH 12/69] ui: add project selection logic --- .../www/components/Project/ProjectTile.tsx | 37 ++++++++++++------- .../www/components/UsageSummary/index.tsx | 2 +- packages/www/hooks/use-project.tsx | 6 ++- .../dashboard/settings/billing/index.tsx | 2 +- .../www/pages/dashboard/settings/projects.tsx | 6 ++- 5 files changed, 34 insertions(+), 19 deletions(-) diff --git a/packages/www/components/Project/ProjectTile.tsx b/packages/www/components/Project/ProjectTile.tsx index 0ab901bbb9..6d0fd4ebd4 100644 --- a/packages/www/components/Project/ProjectTile.tsx +++ b/packages/www/components/Project/ProjectTile.tsx @@ -14,14 +14,22 @@ import { sanitizeUrl } from "lib/url-sanitizer"; import { DotsHorizontalIcon } from "@radix-ui/react-icons"; import { HiDotsHorizontal } from "react-icons/hi"; import Link from "next/link"; -import { generalSidebarItems } from "components/Sidebar"; +import { NavLink, generalSidebarItems } from "components/Sidebar"; +import useProject from "hooks/use-project"; +import { useRouter } from "next/router"; -export default function ProjectTile({ - name, - url, +export default function ProjectTile({ name, url, id, ...props }) { + const { setCurrentProject } = useProject(); + + const navigate = (id, path) => { + setCurrentProject( + { + id, + }, + false + ); + }; - ...props -}) { return ( {generalSidebarItems.map((item) => ( - - {item.title} - + { + navigate(id, item.path); + }}> + + {item.title} + + ))} diff --git a/packages/www/components/UsageSummary/index.tsx b/packages/www/components/UsageSummary/index.tsx index 12b3d5715a..882d70b199 100644 --- a/packages/www/components/UsageSummary/index.tsx +++ b/packages/www/components/UsageSummary/index.tsx @@ -144,7 +144,7 @@ const UsageSummary = () => { setOverUsageBill(oBill); let [res, uInvoice] = await getUpcomingInvoice(user.stripeCustomerId); setUpcomingInvoice(uInvoice?.invoices); - setUpcomingInvoiceTotal((uInvoice?.invoices.total / 100) | 0); + setUpcomingInvoiceTotal((uInvoice?.invoices?.total / 100) | 0); } }; diff --git a/packages/www/hooks/use-project.tsx b/packages/www/hooks/use-project.tsx index 5b7a94eb95..496aee4739 100644 --- a/packages/www/hooks/use-project.tsx +++ b/packages/www/hooks/use-project.tsx @@ -2,9 +2,11 @@ export const projectId = typeof window !== "undefined" && localStorage.getItem("currentProject"); export default function useProject() { - const setCurrentProject = (project) => { + const setCurrentProject = (project, shouldReload = true) => { localStorage.setItem("currentProject", project.id); - window.location.reload(); + if (shouldReload) { + window.location.reload(); + } }; return { diff --git a/packages/www/pages/dashboard/settings/billing/index.tsx b/packages/www/pages/dashboard/settings/billing/index.tsx index cbfcf16029..25723433ca 100644 --- a/packages/www/pages/dashboard/settings/billing/index.tsx +++ b/packages/www/pages/dashboard/settings/billing/index.tsx @@ -107,7 +107,7 @@ const Billing = () => { setOverUsageBill(oBill); let [res, uInvoice] = await getUpcomingInvoice(user.stripeCustomerId); setUpcomingInvoice(uInvoice?.invoices); - setUpcomingInvoiceTotal((uInvoice?.invoices.total / 100) | 0); + setUpcomingInvoiceTotal((uInvoice?.invoices?.total / 100) | 0); } }; diff --git a/packages/www/pages/dashboard/settings/projects.tsx b/packages/www/pages/dashboard/settings/projects.tsx index 1187f69fbf..bc9b33f2a9 100644 --- a/packages/www/pages/dashboard/settings/projects.tsx +++ b/packages/www/pages/dashboard/settings/projects.tsx @@ -53,15 +53,17 @@ const WorkspaceProjects = () => { Projects - Manage your workspace projects + Manage your projects {data.map((project) => ( ))} From 5bdecd131d996e0defb68332a1dd089c111925f5 Mon Sep 17 00:00:00 2001 From: Suhail Kakar Date: Mon, 8 Apr 2024 16:55:13 +0530 Subject: [PATCH 13/69] minimial changes.. --- packages/www/components/Sidebar/index.tsx | 3 ++- packages/www/hooks/use-api/endpoints/project.ts | 11 +++++++++++ packages/www/pages/dashboard/settings/general.tsx | 9 ++++++++- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/packages/www/components/Sidebar/index.tsx b/packages/www/components/Sidebar/index.tsx index 9d68af4361..35ff9d6a73 100644 --- a/packages/www/components/Sidebar/index.tsx +++ b/packages/www/components/Sidebar/index.tsx @@ -35,6 +35,7 @@ import { useQueries, useQuery } from "react-query"; import { useState } from "react"; import { FiCheck, FiChevronLeft } from "react-icons/fi"; import useProject from "hooks/use-project"; +import { User } from "@livepeer.studio/api"; export const NavLink = styled(A, { fontSize: 14, @@ -197,7 +198,7 @@ const Sidebar = ({ id }: { id: SidebarId }) => { }; const GeneralSidebar = ({ id, user }: { id: SidebarId; user: User }) => { - const { createProject, getProjects } = useApi(); + const { createProject, getProjects, logout } = useApi(); const [showCreateProjectAlert, setShowCreateProjectAlert] = useState(false); const { setCurrentProject, currentProject } = useProject(); diff --git a/packages/www/hooks/use-api/endpoints/project.ts b/packages/www/hooks/use-api/endpoints/project.ts index f71e80f2bc..15a0524e13 100644 --- a/packages/www/hooks/use-api/endpoints/project.ts +++ b/packages/www/hooks/use-api/endpoints/project.ts @@ -55,3 +55,14 @@ export const getProjects = async (): Promise => { } return projects; }; + +export const deleteProject = async (projectId) => { + const [res, project] = await context.fetch(`/project/${projectId}`, { + method: "DELETE", + }); + if (res.status !== 204) { + throw project && typeof project === "object" + ? { ...project, status: res.status } + : new Error(project); + } +}; diff --git a/packages/www/pages/dashboard/settings/general.tsx b/packages/www/pages/dashboard/settings/general.tsx index ab7ea143ec..4cfda2ef86 100644 --- a/packages/www/pages/dashboard/settings/general.tsx +++ b/packages/www/pages/dashboard/settings/general.tsx @@ -25,7 +25,7 @@ const Settings = () => { getProject(projectId) ); - const [projectName, setProjectName] = useState(data?.name); + const [projectName, setProjectName] = useState(); const logoRef = useRef(null); @@ -34,6 +34,12 @@ const Settings = () => { console.log("Project Logo: ", projectLogo); }; + const deleteProject = () => { + if (confirm("Are you sure you want to delete this project?")) { + console.log("Project deleted"); + } + }; + if (!user) { return ; } @@ -191,6 +197,7 @@ const Settings = () => { you can do so below. - } - css={{ mb: "$3" }} - /> - )} - {showPromo && ( - - - - } - css={{ mb: "$7" }} - /> - )} - - - - - - - - - - - ); -}; - -const DashboardPage = () => { - useLoggedIn(); - const { user } = useApi(); - - if (!user) { - return ; - } - - return ( - - - - ); -}; - -export default DashboardPage; + return
; +} diff --git a/packages/www/pages/dashboard/assets/[id]/index.tsx b/packages/www/pages/dashboard/projects/[projectId]/assets/[id]/index.tsx similarity index 100% rename from packages/www/pages/dashboard/assets/[id]/index.tsx rename to packages/www/pages/dashboard/projects/[projectId]/assets/[id]/index.tsx diff --git a/packages/www/pages/dashboard/assets/index.tsx b/packages/www/pages/dashboard/projects/[projectId]/assets/index.tsx similarity index 93% rename from packages/www/pages/dashboard/assets/index.tsx rename to packages/www/pages/dashboard/projects/[projectId]/assets/index.tsx index b8dfd6474d..379c77e495 100644 --- a/packages/www/pages/dashboard/assets/index.tsx +++ b/packages/www/pages/dashboard/projects/[projectId]/assets/index.tsx @@ -1,4 +1,4 @@ -import Layout from "../../../layouts/dashboard"; +import Layout from "../../../../../layouts/dashboard"; import { Box } from "@livepeer/design-system"; import { useApi, useLoggedIn } from "hooks"; import AssetsTable from "components/AssetsTable"; diff --git a/packages/www/pages/dashboard/developers/api-keys.tsx b/packages/www/pages/dashboard/projects/[projectId]/developers/api-keys.tsx similarity index 93% rename from packages/www/pages/dashboard/developers/api-keys.tsx rename to packages/www/pages/dashboard/projects/[projectId]/developers/api-keys.tsx index 51783deb81..753bba3b96 100644 --- a/packages/www/pages/dashboard/developers/api-keys.tsx +++ b/packages/www/pages/dashboard/projects/[projectId]/developers/api-keys.tsx @@ -1,4 +1,4 @@ -import Layout from "../../../layouts/dashboard"; +import Layout from "../../../../../layouts/dashboard"; import { Box } from "@livepeer/design-system"; import { useApi, useLoggedIn } from "hooks"; import ApiKeysTable from "components/ApiKeys"; diff --git a/packages/www/pages/dashboard/developers/signing-keys.tsx b/packages/www/pages/dashboard/projects/[projectId]/developers/signing-keys.tsx similarity index 93% rename from packages/www/pages/dashboard/developers/signing-keys.tsx rename to packages/www/pages/dashboard/projects/[projectId]/developers/signing-keys.tsx index 03b4ee3334..74369adcc6 100644 --- a/packages/www/pages/dashboard/developers/signing-keys.tsx +++ b/packages/www/pages/dashboard/projects/[projectId]/developers/signing-keys.tsx @@ -1,4 +1,4 @@ -import Layout from "../../../layouts/dashboard"; +import Layout from "../../../../../layouts/dashboard"; import { Box } from "@livepeer/design-system"; import { useApi, useLoggedIn } from "hooks"; import { DashboardSigningKeys as Content } from "content"; diff --git a/packages/www/pages/dashboard/developers/webhooks/[id].tsx b/packages/www/pages/dashboard/projects/[projectId]/developers/webhooks/[id].tsx similarity index 100% rename from packages/www/pages/dashboard/developers/webhooks/[id].tsx rename to packages/www/pages/dashboard/projects/[projectId]/developers/webhooks/[id].tsx diff --git a/packages/www/pages/dashboard/developers/webhooks/index.tsx b/packages/www/pages/dashboard/projects/[projectId]/developers/webhooks/index.tsx similarity index 100% rename from packages/www/pages/dashboard/developers/webhooks/index.tsx rename to packages/www/pages/dashboard/projects/[projectId]/developers/webhooks/index.tsx diff --git a/packages/www/pages/dashboard/projects/[projectId]/index.tsx b/packages/www/pages/dashboard/projects/[projectId]/index.tsx new file mode 100644 index 0000000000..3eab61a099 --- /dev/null +++ b/packages/www/pages/dashboard/projects/[projectId]/index.tsx @@ -0,0 +1,132 @@ +import { useEffect, useState } from "react"; +import Link from "next/link"; +import Layout from "../../../../layouts/dashboard"; +import { Box, Button, useSnackbar } from "@livepeer/design-system"; +import GettingStarted from "components/GettingStarted"; +import UsageSummary from "components/UsageSummary"; +import StreamsTable from "components/StreamsTable"; +import Spinner from "components/Spinner"; +import Banner from "components/Banner"; + +import { useLoggedIn, useApi } from "hooks"; +import { Dashboard as Content } from "content"; +import Ripe, { categories, pages } from "lib/ripe"; + +Ripe.trackPage({ + category: categories.DASHBOARD, + name: pages.DASHBOARD_HOME, +}); + +const Dashboard = () => { + const { user, verifyEmail, getUserProduct } = useApi(); + const { emailValid } = user; + + const [loading, setLoading] = useState(false); + const product = getUserProduct(user); + const showPromo = user.disabled; + const [openSnackbar] = useSnackbar(); + + const resendVerificationEmail = async () => { + setLoading(true); + const res = await verifyEmail(user.email); + setLoading(false); + + if (res.errors) { + openSnackbar(`Errors: ${res.errors.join(", ")}`); + } else { + openSnackbar( + `We've sent you a link to verify your email. Please check your inbox at ${user.email}` + ); + } + }; + + useEffect(() => { + Ripe.identifyUser(user.id, { + firstName: user.firstName, + lastName: user.lastName, + email: user.email, + }); + }, []); + + return ( + + {!emailValid && ( + resendVerificationEmail()}> + {loading && ( + + )} + Resend the verification email + + } + css={{ mb: "$3" }} + /> + )} + {showPromo && ( + + + + } + css={{ mb: "$7" }} + /> + )} + + + + + + + + + + + ); +}; + +const DashboardPage = () => { + useLoggedIn(); + const { user } = useApi(); + + if (!user) { + return ; + } + + return ( + + + + ); +}; + +export default DashboardPage; diff --git a/packages/www/pages/dashboard/sessions/index.tsx b/packages/www/pages/dashboard/projects/[projectId]/sessions/index.tsx similarity index 100% rename from packages/www/pages/dashboard/sessions/index.tsx rename to packages/www/pages/dashboard/projects/[projectId]/sessions/index.tsx diff --git a/packages/www/pages/dashboard/settings.tsx b/packages/www/pages/dashboard/projects/[projectId]/settings.tsx similarity index 100% rename from packages/www/pages/dashboard/settings.tsx rename to packages/www/pages/dashboard/projects/[projectId]/settings.tsx diff --git a/packages/www/pages/dashboard/stream-health.tsx b/packages/www/pages/dashboard/projects/[projectId]/stream-health.tsx similarity index 99% rename from packages/www/pages/dashboard/stream-health.tsx rename to packages/www/pages/dashboard/projects/[projectId]/stream-health.tsx index 40df2d9cdc..9b981e3e28 100644 --- a/packages/www/pages/dashboard/stream-health.tsx +++ b/packages/www/pages/dashboard/projects/[projectId]/stream-health.tsx @@ -7,7 +7,7 @@ import { TextField, Label, } from "@livepeer/design-system"; -import Layout from "../../layouts/dashboard"; +import Layout from "../../../../layouts/dashboard"; import { useApi } from "hooks"; import { useEffect, useState } from "react"; import { StreamInfo } from "hooks/use-api/types"; diff --git a/packages/www/pages/dashboard/streams/[id]/index.tsx b/packages/www/pages/dashboard/projects/[projectId]/streams/[id]/index.tsx similarity index 100% rename from packages/www/pages/dashboard/streams/[id]/index.tsx rename to packages/www/pages/dashboard/projects/[projectId]/streams/[id]/index.tsx diff --git a/packages/www/pages/dashboard/streams/index.tsx b/packages/www/pages/dashboard/projects/[projectId]/streams/index.tsx similarity index 100% rename from packages/www/pages/dashboard/streams/index.tsx rename to packages/www/pages/dashboard/projects/[projectId]/streams/index.tsx From 0a6aa15431dcc49c8cccc0e79b2d52aa9e4c54cc Mon Sep 17 00:00:00 2001 From: Suhail Kakar Date: Tue, 16 Apr 2024 02:53:37 +0530 Subject: [PATCH 19/69] ui: update project settings --- packages/www/components/Breadcrumbs/index.tsx | 8 +- packages/www/components/Sidebar/index.tsx | 4 +- .../projects/[projectId]/settings.tsx | 91 ++++++++----------- 3 files changed, 46 insertions(+), 57 deletions(-) diff --git a/packages/www/components/Breadcrumbs/index.tsx b/packages/www/components/Breadcrumbs/index.tsx index 853db96a20..8b54b71195 100644 --- a/packages/www/components/Breadcrumbs/index.tsx +++ b/packages/www/components/Breadcrumbs/index.tsx @@ -42,12 +42,12 @@ function insertSeparators(items) { } const Breadcrumbs = ({ children }) => { - const { currentProject } = useProject(); + const { activeProjectId } = useProject(); const { getProjects } = useApi(); const { data } = useQuery("projects", getProjects); const pathname = usePathname(); - const isSettingsPage = false; + const isSettingsPage = pathname?.includes("account"); const allItems = Children.toArray(children) .filter((child) => { @@ -80,8 +80,8 @@ const Breadcrumbs = ({ children }) => { ); } else { - if (currentProject) { - const project = data?.find((project) => project.id === currentProject); + if (activeProjectId) { + const project = data?.find((project) => project.id === activeProjectId); allItems.unshift( { }; const SettingsSidebar = ({ id, user }: { id: SidebarId; user: User }) => { + const { appendProjectId } = useProject(); const goBack = () => { - Router.push(""); + Router.push(appendProjectId("/")); }; return ( diff --git a/packages/www/pages/dashboard/projects/[projectId]/settings.tsx b/packages/www/pages/dashboard/projects/[projectId]/settings.tsx index 4899604787..674f2f4a9b 100644 --- a/packages/www/pages/dashboard/projects/[projectId]/settings.tsx +++ b/packages/www/pages/dashboard/projects/[projectId]/settings.tsx @@ -12,7 +12,11 @@ import { DashboardSettingsGeneral as Content } from "content"; import React, { useRef, useState } from "react"; import Image from "next/image"; import { useQuery } from "react-query"; -import { projectId } from "hooks/use-project"; +import useProject from "hooks/use-project"; +import { ImageIcon, RocketIcon } from "@radix-ui/react-icons"; +import { GoRocket } from "react-icons/go"; +import { FaImage, FaImages } from "react-icons/fa"; +import { FiImage } from "react-icons/fi"; const Settings = () => { useLoggedIn(); @@ -21,13 +25,19 @@ const Settings = () => { const [projectName, setProjectName] = useState(); const logoRef = useRef(null); - const { data } = useQuery(["project", projectId], getProject); + const { activeProjectId } = useProject(); + + const { data } = useQuery(["project", activeProjectId], () => + getProject(activeProjectId) + ); const handleSubmit = () => { console.log("Project Name: ", projectName); console.log("Project Logo: ", projectLogo); }; + console.log(data); + const deleteProject = () => { if (confirm("Are you sure you want to delete this project?")) { console.log("Project deleted"); @@ -39,7 +49,7 @@ const Settings = () => { } return ( { }}> Logo - logoRef.current?.click()} - src={ - projectLogo - ? URL.createObjectURL(projectLogo) - : workspaces[0].projects[0].logo - } - alt="Project logo" - style={{ - borderRadius: "12px", - }} - width={90} - height={90} - /> + {!projectLogo ? ( + logoRef.current?.click()} + justify={"center"} + align="center" + css={{ + width: "90px", + height: "90px", + background: "$neutral3", + borderRadius: "$3", + }} + /> + ) : ( + logoRef.current?.click()} + src={URL.createObjectURL(projectLogo)} + alt="Project logo" + style={{ + borderRadius: "12px", + }} + width={90} + height={90} + /> + )} { p: "$4", fontSize: "$2", mt: "$3", - backgroundColor: "black", - color: "white", + backgroundColor: "$hiContrast", + color: "$loContrast", }}> Update @@ -207,37 +227,4 @@ const Settings = () => { ); }; -// Placeholder constants, it will be removed and replaced with real data from the API -export const workspaces = [ - { - name: "Paramount", - logo: "https://pbs.twimg.com/profile_images/1712502841494138880/GofqA30R_400x400.jpg", - url: "https://livepeer.studio/paramount", - projects: [ - { - name: "Paramount Plus", - logo: "https://pbs.twimg.com/profile_images/1712502841494138880/GofqA30R_400x400.jpg", - url: "https://livepeer.studio/paramount/paramount-plus", - activeStreams: 10, - isDefault: true, - inProgressUploads: 5, - }, - { - name: "Paramount Dev", - logo: "https://i.pinimg.com/564x/bf/9a/7a/bf9a7a4ead767c8d66c613b76e2d3596.jpg", - url: "https://livepeer.studio/paramount/paramount-dev", - activeStreams: 21, - inProgressUploads: 48, - }, - ], - members: [ - { - name: "John Doe", - email: "john@livepeer.org", - role: "Admin", - }, - ], - }, -]; - export default Settings; From c1ad0d19aba8557a6ce91812977b80ad8b7199ee Mon Sep 17 00:00:00 2001 From: Suhail Kakar Date: Tue, 16 Apr 2024 03:01:03 +0530 Subject: [PATCH 20/69] ui: add new project button --- .../www/components/Project/ProjectTile.tsx | 2 +- .../www/pages/dashboard/account/projects.tsx | 47 ++++++++++++++----- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/packages/www/components/Project/ProjectTile.tsx b/packages/www/components/Project/ProjectTile.tsx index 7c61acdfc4..f9eb9e49d5 100644 --- a/packages/www/components/Project/ProjectTile.tsx +++ b/packages/www/components/Project/ProjectTile.tsx @@ -114,7 +114,7 @@ export default function ProjectTile({ name, url, id, ...props }) { + Date: Tue, 16 Apr 2024 03:58:19 +0530 Subject: [PATCH 21/69] updating all links to new folder structure --- .../www/components/AssetsTable/helpers.tsx | 14 +++++++------ packages/www/components/AssetsTable/index.tsx | 11 +++++++++- .../www/components/GettingStarted/index.tsx | 11 +++++++--- packages/www/components/Sidebar/index.tsx | 8 +++---- .../Site/PricingCalculator/Calculator.tsx | 2 +- .../StreamDetails/SessionsTable/ClipsCell.tsx | 6 +++++- .../StreamSessionsTable/helpers.tsx | 5 +++-- .../components/StreamSessionsTable/index.tsx | 5 ++++- .../www/components/StreamsTable/helpers.tsx | 12 ++++++----- .../www/components/StreamsTable/index.tsx | 8 +++++-- .../www/components/UsageSummary/index.tsx | 2 +- .../WebhookDialogs/DeleteDialog.tsx | 5 ++++- .../www/components/WebhooksTable/helpers.tsx | 13 ++++++------ .../www/components/WebhooksTable/index.tsx | 6 ++++-- packages/www/hooks/use-project.tsx | 3 +++ .../pages/dashboard/account/billing/index.tsx | 7 +++++-- .../[projectId]/assets/[id]/index.tsx | 4 +++- .../[projectId]/developers/api-keys.tsx | 7 ++++++- .../[projectId]/developers/signing-keys.tsx | 7 ++++++- .../[projectId]/developers/webhooks/[id].tsx | 8 ++++++- .../[projectId]/developers/webhooks/index.tsx | 7 ++++++- .../dashboard/projects/[projectId]/index.tsx | 9 ++++++-- .../projects/[projectId]/settings.tsx | 21 +++++++++++-------- .../[projectId]/streams/[id]/index.tsx | 4 +++- packages/www/pages/register.tsx | 2 +- packages/www/pages/verify-new-email.tsx | 4 +++- packages/www/pages/verify.tsx | 4 +++- 27 files changed, 137 insertions(+), 58 deletions(-) diff --git a/packages/www/components/AssetsTable/helpers.tsx b/packages/www/components/AssetsTable/helpers.tsx index 98c1a9ada0..3ebf3bdb68 100644 --- a/packages/www/components/AssetsTable/helpers.tsx +++ b/packages/www/components/AssetsTable/helpers.tsx @@ -14,6 +14,7 @@ import { RowsPageFromStateResult, SortTypeArgs } from "../Table/types"; import { State } from "../Table"; import TableEmptyState from "../Table/components/TableEmptyState"; import { useApi } from "hooks"; +import useProject from "hooks/use-project"; type ApiClient = ReturnType; @@ -100,7 +101,8 @@ export const rowsPageFromState = async ( userId: string, getAssets: ApiClient["getAssets"], getTasks: ApiClient["getTasks"], - onDeleteAsset: Function + onDeleteAsset: Function, + appendProjectId: Function ): Promise> => { const assetsPromise = getAssets(userId, { filters: formatFiltersForApiRequest(state.filters), @@ -137,7 +139,7 @@ export const rowsPageFromState = async ( id: asset.id, name: { id: asset.id, - href: `/dashboard/assets/${asset.id}`, + href: appendProjectId(`/assets/${asset.id}`), name: asset.name, isStatusFailed, errorMessage, @@ -149,18 +151,18 @@ export const rowsPageFromState = async ( ), fallback: , - href: `/dashboard/assets/${asset.id}`, + href: appendProjectId(`/assets/${asset.id}`), }, sessionId: { children: {sessionId}, fallback: , - href: `/dashboard/sessions?sessionId=${sessionId}`, + href: appendProjectId(`/sessions?sessionId=${sessionId}`), }, createdAt: { id: asset.id, date: new Date(asset.createdAt), fallback: , - href: `/dashboard/assets/${asset.id}`, + href: appendProjectId(`/assets/${asset.id}`), asset: asset as Asset, // CreatedAt cell expect SDK asset instead of API }, updatedAt: { @@ -169,7 +171,7 @@ export const rowsPageFromState = async ( ? new Date(asset.status.updatedAt) : null, fallback: , - href: `/dashboard/assets/${asset.id}`, + href: appendProjectId(`/assets/${asset.id}`), }, action: { id: asset.id, diff --git a/packages/www/components/AssetsTable/index.tsx b/packages/www/components/AssetsTable/index.tsx index 3fd8be401e..cd87645320 100644 --- a/packages/www/components/AssetsTable/index.tsx +++ b/packages/www/components/AssetsTable/index.tsx @@ -17,6 +17,7 @@ import { rowsPageFromState, } from "./helpers"; import { makeCreateAction } from "../Table/helpers"; +import useProject from "hooks/use-project"; const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); @@ -36,6 +37,7 @@ const AssetsTable = ({ const { getAssets, uploadAssets, deleteAsset, getTasks, getFileUploads } = useApi(); const [openSnackbar] = useSnackbar(); + const { appendProjectId } = useProject(); const createDialogState = useToggleState(); const { state, stateSetter } = useTableState({ pageSize, @@ -71,7 +73,14 @@ const AssetsTable = ({ const fetcher: Fetcher = useCallback( async (state) => - rowsPageFromState(state, userId, getAssets, getTasks, onDeleteAsset), + rowsPageFromState( + state, + userId, + getAssets, + getTasks, + onDeleteAsset, + appendProjectId + ), [userId] ); diff --git a/packages/www/components/GettingStarted/index.tsx b/packages/www/components/GettingStarted/index.tsx index b80bf337bd..096b310ffb 100644 --- a/packages/www/components/GettingStarted/index.tsx +++ b/packages/www/components/GettingStarted/index.tsx @@ -12,8 +12,10 @@ import { } from "@livepeer/design-system"; import Link from "next/link"; import { ArrowRightIcon, ArrowTopRightIcon } from "@radix-ui/react-icons"; +import useProject from "hooks/use-project"; const GettingStarted = ({ firstName = "" }) => { + const { appendProjectId } = useProject(); return ( <> @@ -37,7 +39,7 @@ const GettingStarted = ({ firstName = "" }) => { - + diff --git a/packages/www/components/StreamDetails/SessionsTable/ClipsCell.tsx b/packages/www/components/StreamDetails/SessionsTable/ClipsCell.tsx index a97e47ebac..2a9fec2fef 100644 --- a/packages/www/components/StreamDetails/SessionsTable/ClipsCell.tsx +++ b/packages/www/components/StreamDetails/SessionsTable/ClipsCell.tsx @@ -1,6 +1,7 @@ import { CellComponentProps, TableData } from "components/Table/types"; import { Box, Link, Badge } from "@livepeer/design-system"; import { ArrowRightIcon, ArrowTopRightIcon } from "@radix-ui/react-icons"; +import useProject from "hooks/use-project"; function makeMP4Url(url: string, profileName: string): string { if (url.endsWith(".mp4")) { @@ -26,13 +27,16 @@ const ClipsCell = ({ cell, }: CellComponentProps) => { const id = cell.value.id; + const { appendProjectId } = useProject(); return ( {cell.value.clipsCounts > 0 ? ( + href={appendProjectId( + "/assets?sourceSessionId=" + cell.value.sessionId + )}> {cell.value.clipsCounts} diff --git a/packages/www/components/StreamSessionsTable/helpers.tsx b/packages/www/components/StreamSessionsTable/helpers.tsx index 06065c6a1b..c50738925c 100644 --- a/packages/www/components/StreamSessionsTable/helpers.tsx +++ b/packages/www/components/StreamSessionsTable/helpers.tsx @@ -74,7 +74,8 @@ export const rowsPageFromState = async ( state: State, userId: string, getStreamSessionsByUserId: Function, - openSnackbar: Function + openSnackbar: Function, + appendProjectId: Function ): Promise> => { const [streams, nextCursor, count] = await getStreamSessionsByUserId( userId, @@ -102,7 +103,7 @@ export const rowsPageFromState = async ( Created by stream {stream.parentStream.name} ) : null, - href: `/dashboard/streams/${stream.parentId}`, + href: appendProjectId(`/streams/${stream.parentId}`), }, recordingUrl: { id: stream.id, diff --git a/packages/www/components/StreamSessionsTable/index.tsx b/packages/www/components/StreamSessionsTable/index.tsx index 47ba860f8f..995290a8f4 100644 --- a/packages/www/components/StreamSessionsTable/index.tsx +++ b/packages/www/components/StreamSessionsTable/index.tsx @@ -14,6 +14,7 @@ import { rowsPageFromState, StreamSessionsTableData, } from "./helpers"; +import useProject from "hooks/use-project"; const StreamSessionsTable = ({ title = "Sessions" }: { title?: string }) => { const { user, getStreamSessionsByUserId } = useApi(); @@ -23,6 +24,7 @@ const StreamSessionsTable = ({ title = "Sessions" }: { title?: string }) => { }); const [openSnackbar] = useSnackbar(); const columns = useMemo(makeColumns, []); + const { appendProjectId } = useProject(); const fetcher: Fetcher = useCallback( async (state) => @@ -30,7 +32,8 @@ const StreamSessionsTable = ({ title = "Sessions" }: { title?: string }) => { state, user.id, getStreamSessionsByUserId, - openSnackbar + openSnackbar, + appendProjectId ), [getStreamSessionsByUserId, user.id] ); diff --git a/packages/www/components/StreamsTable/helpers.tsx b/packages/www/components/StreamsTable/helpers.tsx index 8ecab2799f..5a095f8dbb 100644 --- a/packages/www/components/StreamsTable/helpers.tsx +++ b/packages/www/components/StreamsTable/helpers.tsx @@ -7,6 +7,7 @@ import TableEmptyState from "../Table/components/TableEmptyState"; import { FilterItem, formatFiltersForApiRequest } from "../Table/filters"; import { stringSort, dateSort } from "../Table/sorts"; import { RowsPageFromStateResult, SortTypeArgs } from "../Table/types"; +import useProject from "hooks/use-project"; export type StreamsTableData = { id: string; @@ -63,7 +64,8 @@ export const makeColumns = () => [ export const rowsPageFromState = async ( state: State, userId: string, - getStreams: Function + getStreams: Function, + appendProjectId: Function ): Promise> => { let active: boolean; const filteredFilters = state.filters.filter((f) => { @@ -93,22 +95,22 @@ export const rowsPageFromState = async ( Created by token {stream.createdByTokenName} ) : null, - href: `/dashboard/streams/${stream.id}`, + href: appendProjectId(`/streams/${stream.id}`), }, details: { stream }, createdAt: { date: new Date(stream.createdAt), fallback: , - href: `/dashboard/streams/${stream.id}`, + href: appendProjectId(`/streams/${stream.id}`), }, lastSeen: { date: stream.lastSeen ? new Date(stream.lastSeen) : null, fallback: , - href: `/dashboard/streams/${stream.id}`, + href: appendProjectId(`/streams/${stream.id}`), }, status: { children: stream.isActive ? "Active" : "Idle", - href: `/dashboard/streams/${stream.id}`, + href: appendProjectId(`/streams/${stream.id}`), }, })); return { rows, nextCursor, count }; diff --git a/packages/www/components/StreamsTable/index.tsx b/packages/www/components/StreamsTable/index.tsx index 0052732a46..7b16a41e30 100644 --- a/packages/www/components/StreamsTable/index.tsx +++ b/packages/www/components/StreamsTable/index.tsx @@ -21,6 +21,7 @@ import { import { makeSelectAction, makeCreateAction } from "../Table/helpers"; import TableHeader from "../Table/components/TableHeader"; import TableStateDeleteDialog from "../Table/components/TableStateDeleteDialog"; +import useProject from "hooks/use-project"; const StreamsTable = ({ title = "Streams", @@ -45,8 +46,11 @@ const StreamsTable = ({ initialOrder: sortByToString(DefaultSortBy), }); const columns = useMemo(makeColumns, []); + const { appendProjectId } = useProject(); + const fetcher: Fetcher = useCallback( - async (state) => rowsPageFromState(state, userId, getStreams), + async (state) => + rowsPageFromState(state, userId, getStreams, appendProjectId), [userId] ); @@ -59,7 +63,7 @@ const StreamsTable = ({ await state.invalidate(); const query = router.query.admin === "true" ? { admin: true } : {}; await router.push({ - pathname: `/dashboard/streams/${newStream.id}`, + pathname: appendProjectId(`/streams/${newStream.id}`), query, }); }, diff --git a/packages/www/components/UsageSummary/index.tsx b/packages/www/components/UsageSummary/index.tsx index 882d70b199..a96b060e46 100644 --- a/packages/www/components/UsageSummary/index.tsx +++ b/packages/www/components/UsageSummary/index.tsx @@ -296,7 +296,7 @@ const UsageSummary = () => { justify="between" align="center" css={{ fontSize: "$3", color: "$hiContrast" }}> - + View billing diff --git a/packages/www/components/WebhookDialogs/DeleteDialog.tsx b/packages/www/components/WebhookDialogs/DeleteDialog.tsx index 33276305a9..c04618c4c3 100644 --- a/packages/www/components/WebhookDialogs/DeleteDialog.tsx +++ b/packages/www/components/WebhookDialogs/DeleteDialog.tsx @@ -11,6 +11,7 @@ import { } from "@livepeer/design-system"; import router from "next/router"; import Spinner from "../Spinner"; +import useProject from "hooks/use-project"; const DeleteDialog = ({ deleteDialogOpen, @@ -27,13 +28,15 @@ const DeleteDialog = ({ deleteWebhook(): Promise; invalidateQuery(): Promise; }) => { + const { appendProjectId } = useProject(); + const onDeleteClick = async () => { setDeleting(true); await deleteWebhook(); await invalidateQuery(); setDeleting(false); setDeleteDialogOpen(false); - router.push("/dashboard/developers/webhooks"); + router.push(appendProjectId("/developers/webhooks")); }; return ( diff --git a/packages/www/components/WebhooksTable/helpers.tsx b/packages/www/components/WebhooksTable/helpers.tsx index 049e145106..bf8805bf6c 100644 --- a/packages/www/components/WebhooksTable/helpers.tsx +++ b/packages/www/components/WebhooksTable/helpers.tsx @@ -46,7 +46,8 @@ export const makeColumns = () => [ export const rowsPageFromState = async ( state, - getWebhooks: Function + getWebhooks: Function, + appendProjectId: Function ): Promise> => { const [webhooks, nextCursor, _res, count] = await getWebhooks( false, @@ -66,7 +67,7 @@ export const rowsPageFromState = async ( id: webhook.id, name: { children: webhook.name, - href: `/dashboard/developers/webhooks/${webhook.id}`, + href: appendProjectId(`/developers/webhooks/${webhook.id}`), css: { overflow: "hidden", "text-overflow": "ellipsis", @@ -88,7 +89,7 @@ export const rowsPageFromState = async ( {webhook.url} ), - href: `/dashboard/developers/webhooks/${webhook.id}`, + href: appendProjectId(`/developers/webhooks/${webhook.id}`), css: {}, }, events: { @@ -106,20 +107,20 @@ export const rowsPageFromState = async ( ), - href: `/dashboard/developers/webhooks/${webhook.id}`, + href: appendProjectId(`/developers/webhooks/${webhook.id}`), css: {}, }, lastFailure: { date: new Date(webhook?.status?.lastFailure?.timestamp), fallback:

-

, - href: `/dashboard/developers/webhooks/${webhook.id}`, + href: appendProjectId(`/developers/webhooks/${webhook.id}`), css: {}, }, lastTriggeredAt: { date: new Date(webhook?.status?.lastTriggeredAt), fallback:

-

, - href: `/dashboard/developers/webhooks/${webhook.id}`, + href: appendProjectId(`/developers/webhooks/${webhook.id}`), css: {}, }, }; diff --git a/packages/www/components/WebhooksTable/index.tsx b/packages/www/components/WebhooksTable/index.tsx index eb5f6ac1f3..35180fb0c0 100644 --- a/packages/www/components/WebhooksTable/index.tsx +++ b/packages/www/components/WebhooksTable/index.tsx @@ -20,6 +20,7 @@ import { } from "./helpers"; import { makeCreateAction, makeSelectAction } from "../Table/helpers"; import TableStateDeleteDialog from "../Table/components/TableStateDeleteDialog"; +import useProject from "hooks/use-project"; const WebhooksTable = ({ title = "Endpoints" }: { title?: string }) => { const router = useRouter(); @@ -33,9 +34,10 @@ const WebhooksTable = ({ title = "Endpoints" }: { title?: string }) => { }); const columns = useMemo(makeColumns, []); + const { appendProjectId } = useProject(); const fetcher: Fetcher = useCallback( - async (state) => rowsPageFromState(state, getWebhooks), + async (state) => rowsPageFromState(state, getWebhooks, appendProjectId), [getWebhooks, user.id] ); @@ -49,7 +51,7 @@ const WebhooksTable = ({ title = "Endpoints" }: { title?: string }) => { await state.invalidate(); const query = router.query.admin === "true" ? { admin: true } : {}; await router.push({ - pathname: `/dashboard/developers/webhooks/${newWebhook.id}`, + pathname: appendProjectId(`/developers/webhooks/${newWebhook.id}`), query, }); }; diff --git a/packages/www/hooks/use-project.tsx b/packages/www/hooks/use-project.tsx index bfb439b576..c72cd3198e 100644 --- a/packages/www/hooks/use-project.tsx +++ b/packages/www/hooks/use-project.tsx @@ -3,6 +3,9 @@ import useApi from "./use-api"; import { usePathname } from "next/navigation"; import { useRouter } from "next/router"; +export const projectId = + typeof window !== "undefined" && localStorage.getItem("currentProject"); + const useProject = () => { const { query: { projectId }, diff --git a/packages/www/pages/dashboard/account/billing/index.tsx b/packages/www/pages/dashboard/account/billing/index.tsx index e8e263fd1c..5f6e7064ee 100644 --- a/packages/www/pages/dashboard/account/billing/index.tsx +++ b/packages/www/pages/dashboard/account/billing/index.tsx @@ -274,7 +274,10 @@ const Billing = () => { plan. - + @@ -348,7 +351,7 @@ const Billing = () => {
- + diff --git a/packages/www/pages/dashboard/projects/[projectId]/assets/[id]/index.tsx b/packages/www/pages/dashboard/projects/[projectId]/assets/[id]/index.tsx index aee13bfc2f..32d679d8cd 100644 --- a/packages/www/pages/dashboard/projects/[projectId]/assets/[id]/index.tsx +++ b/packages/www/pages/dashboard/projects/[projectId]/assets/[id]/index.tsx @@ -7,6 +7,7 @@ import AssetOverviewTab from "components/AssetDetails/AssetOverviewTab"; import AssetEventLogTab from "components/AssetDetails/AssetEventLogTab"; import { Asset } from "@livepeer.studio/api"; import Ripe, { categories, pages } from "lib/ripe"; +import useProject from "hooks/use-project"; Ripe.trackPage({ category: categories.DASHBOARD, @@ -23,6 +24,7 @@ const AssetDetails = () => { ); const [editAssetDialogOpen, setEditAssetDialogOpen] = useState(false); const [embedVideoDialogOpen, setEmbedVideoDialogOpen] = useState(false); + const { appendProjectId } = useProject(); const { query } = router; const id = query.id as string; @@ -57,7 +59,7 @@ const AssetDetails = () => { setEmbedVideoDialogOpen={setEmbedVideoDialogOpen} refetchAsset={() => refetchAsset()} breadcrumbs={[ - { title: "Assets", href: "/dashboard/assets" }, + { title: "Assets", href: appendProjectId("/assets") }, { title: asset?.name }, ]}> {currentTab === "Overview" ? ( diff --git a/packages/www/pages/dashboard/projects/[projectId]/developers/api-keys.tsx b/packages/www/pages/dashboard/projects/[projectId]/developers/api-keys.tsx index 753bba3b96..b9ac53b3d1 100644 --- a/packages/www/pages/dashboard/projects/[projectId]/developers/api-keys.tsx +++ b/packages/www/pages/dashboard/projects/[projectId]/developers/api-keys.tsx @@ -4,6 +4,7 @@ import { useApi, useLoggedIn } from "hooks"; import ApiKeysTable from "components/ApiKeys"; import { DashboardAPIKeys as Content } from "content"; import Ripe, { categories, pages } from "lib/ripe"; +import useProject from "hooks/use-project"; Ripe.trackPage({ category: categories.DASHBOARD, @@ -13,6 +14,7 @@ Ripe.trackPage({ const ApiKeys = () => { useLoggedIn(); const { user } = useApi(); + const { appendProjectId } = useProject(); if (!user) { return ; @@ -21,7 +23,10 @@ const ApiKeys = () => { diff --git a/packages/www/pages/dashboard/projects/[projectId]/developers/signing-keys.tsx b/packages/www/pages/dashboard/projects/[projectId]/developers/signing-keys.tsx index 74369adcc6..e1d3395207 100644 --- a/packages/www/pages/dashboard/projects/[projectId]/developers/signing-keys.tsx +++ b/packages/www/pages/dashboard/projects/[projectId]/developers/signing-keys.tsx @@ -3,10 +3,12 @@ import { Box } from "@livepeer/design-system"; import { useApi, useLoggedIn } from "hooks"; import { DashboardSigningKeys as Content } from "content"; import SigningKeysTable from "components/SigningKeysTable"; +import useProject from "hooks/use-project"; const SigningKeys = () => { useLoggedIn(); const { user } = useApi(); + const { appendProjectId } = useProject(); if (!user) { return ; @@ -15,7 +17,10 @@ const SigningKeys = () => { diff --git a/packages/www/pages/dashboard/projects/[projectId]/developers/webhooks/[id].tsx b/packages/www/pages/dashboard/projects/[projectId]/developers/webhooks/[id].tsx index e461a028e5..7e66743e0e 100644 --- a/packages/www/pages/dashboard/projects/[projectId]/developers/webhooks/[id].tsx +++ b/packages/www/pages/dashboard/projects/[projectId]/developers/webhooks/[id].tsx @@ -5,6 +5,7 @@ import { useRouter } from "next/router"; import { useQuery, useQueryClient } from "react-query"; import WebhookDetails from "components/WebhookDetails"; import { DashboardWebhooks as Content } from "content"; +import useProject from "hooks/use-project"; const WebhookDetail = () => { useLoggedIn(); @@ -12,6 +13,8 @@ const WebhookDetail = () => { const [logFilters, setLogFilters] = useState(); const { getWebhook, getWebhookLogs } = useApi(); + const { appendProjectId } = useProject(); + const router = useRouter(); const { id } = router.query; @@ -46,7 +49,10 @@ const WebhookDetail = () => { id="developers/webhooks" breadcrumbs={[ { title: "Developers" }, - { title: "Webhooks", href: "/dashboard/developers/webhooks" }, + { + title: "Webhooks", + href: appendProjectId("/developers/webhooks"), + }, { title: webhookData?.name }, ]} {...Content.metaData}> diff --git a/packages/www/pages/dashboard/projects/[projectId]/developers/webhooks/index.tsx b/packages/www/pages/dashboard/projects/[projectId]/developers/webhooks/index.tsx index 951abc5b57..486d06a4da 100644 --- a/packages/www/pages/dashboard/projects/[projectId]/developers/webhooks/index.tsx +++ b/packages/www/pages/dashboard/projects/[projectId]/developers/webhooks/index.tsx @@ -2,10 +2,12 @@ import Layout from "layouts/dashboard"; import { useApi, useLoggedIn } from "hooks"; import WebhooksTable from "components/WebhooksTable"; import { DashboardWebhooks as Content } from "content"; +import useProject from "hooks/use-project"; const Webhooks = () => { useLoggedIn(); const { user } = useApi(); + const { appendProjectId } = useProject(); if (!user) { return ; @@ -15,7 +17,10 @@ const Webhooks = () => { diff --git a/packages/www/pages/dashboard/projects/[projectId]/index.tsx b/packages/www/pages/dashboard/projects/[projectId]/index.tsx index 3eab61a099..8a10d0fe3d 100644 --- a/packages/www/pages/dashboard/projects/[projectId]/index.tsx +++ b/packages/www/pages/dashboard/projects/[projectId]/index.tsx @@ -11,6 +11,7 @@ import Banner from "components/Banner"; import { useLoggedIn, useApi } from "hooks"; import { Dashboard as Content } from "content"; import Ripe, { categories, pages } from "lib/ripe"; +import useProject from "hooks/use-project"; Ripe.trackPage({ category: categories.DASHBOARD, @@ -20,6 +21,7 @@ Ripe.trackPage({ const Dashboard = () => { const { user, verifyEmail, getUserProduct } = useApi(); const { emailValid } = user; + const { appendProjectId } = useProject(); const [loading, setLoading] = useState(false); const product = getUserProduct(user); @@ -82,7 +84,10 @@ const Dashboard = () => { title="Upgrade" description="Your free tier usage limit has been reached or we were unable to process your payment. Upgrade to our Growth or Scale plans or update your payment method to continue using Livepeer Studio." button={ - + - } - css={{ mb: "$3" }} - /> - )} - {showPromo && ( - - - - } - css={{ mb: "$7" }} - /> - )} - - - - - - - - - - - ); -}; - -const DashboardPage = () => { - useLoggedIn(); - const { user } = useApi(); - - if (!user) { - return ; - } - - return ( - - - - ); -}; - -export default DashboardPage; + }, []); + return
; +} diff --git a/packages/www/pages/assets/[id]/index.tsx b/packages/www/pages/projects/[projectId]/assets/[id]/index.tsx similarity index 100% rename from packages/www/pages/assets/[id]/index.tsx rename to packages/www/pages/projects/[projectId]/assets/[id]/index.tsx diff --git a/packages/www/pages/assets/index.tsx b/packages/www/pages/projects/[projectId]/assets/index.tsx similarity index 100% rename from packages/www/pages/assets/index.tsx rename to packages/www/pages/projects/[projectId]/assets/index.tsx diff --git a/packages/www/pages/dashboard/projects/[projectId]/developers/api-keys.tsx b/packages/www/pages/projects/[projectId]/developers/api-keys.tsx similarity index 100% rename from packages/www/pages/dashboard/projects/[projectId]/developers/api-keys.tsx rename to packages/www/pages/projects/[projectId]/developers/api-keys.tsx diff --git a/packages/www/pages/dashboard/projects/[projectId]/developers/signing-keys.tsx b/packages/www/pages/projects/[projectId]/developers/signing-keys.tsx similarity index 100% rename from packages/www/pages/dashboard/projects/[projectId]/developers/signing-keys.tsx rename to packages/www/pages/projects/[projectId]/developers/signing-keys.tsx diff --git a/packages/www/pages/dashboard/projects/[projectId]/developers/webhooks/[id].tsx b/packages/www/pages/projects/[projectId]/developers/webhooks/[id].tsx similarity index 100% rename from packages/www/pages/dashboard/projects/[projectId]/developers/webhooks/[id].tsx rename to packages/www/pages/projects/[projectId]/developers/webhooks/[id].tsx diff --git a/packages/www/pages/dashboard/projects/[projectId]/developers/webhooks/index.tsx b/packages/www/pages/projects/[projectId]/developers/webhooks/index.tsx similarity index 100% rename from packages/www/pages/dashboard/projects/[projectId]/developers/webhooks/index.tsx rename to packages/www/pages/projects/[projectId]/developers/webhooks/index.tsx diff --git a/packages/www/pages/dashboard/projects/[projectId]/index.tsx b/packages/www/pages/projects/[projectId]/index.tsx similarity index 83% rename from packages/www/pages/dashboard/projects/[projectId]/index.tsx rename to packages/www/pages/projects/[projectId]/index.tsx index 8a10d0fe3d..431ffa8350 100644 --- a/packages/www/pages/dashboard/projects/[projectId]/index.tsx +++ b/packages/www/pages/projects/[projectId]/index.tsx @@ -1,6 +1,6 @@ import { useEffect, useState } from "react"; import Link from "next/link"; -import Layout from "../../../../layouts/dashboard"; +import Layout from "../../../layouts/dashboard"; import { Box, Button, useSnackbar } from "@livepeer/design-system"; import GettingStarted from "components/GettingStarted"; import UsageSummary from "components/UsageSummary"; @@ -10,18 +10,10 @@ import Banner from "components/Banner"; import { useLoggedIn, useApi } from "hooks"; import { Dashboard as Content } from "content"; -import Ripe, { categories, pages } from "lib/ripe"; -import useProject from "hooks/use-project"; - -Ripe.trackPage({ - category: categories.DASHBOARD, - name: pages.DASHBOARD_HOME, -}); const Dashboard = () => { const { user, verifyEmail, getUserProduct } = useApi(); const { emailValid } = user; - const { appendProjectId } = useProject(); const [loading, setLoading] = useState(false); const product = getUserProduct(user); @@ -42,14 +34,6 @@ const Dashboard = () => { } }; - useEffect(() => { - Ripe.identifyUser(user.id, { - firstName: user.firstName, - lastName: user.lastName, - email: user.email, - }); - }, []); - return ( {!emailValid && ( @@ -84,10 +68,7 @@ const Dashboard = () => { title="Upgrade" description="Your free tier usage limit has been reached or we were unable to process your payment. Upgrade to our Growth or Scale plans or update your payment method to continue using Livepeer Studio." button={ - + diff --git a/packages/www/components/Sidebar/index.tsx b/packages/www/components/Sidebar/index.tsx index b9b3885f53..bbb1aba227 100644 --- a/packages/www/components/Sidebar/index.tsx +++ b/packages/www/components/Sidebar/index.tsx @@ -73,11 +73,11 @@ export type SidebarId = | "developers/signing-keys" | "developers/webhooks" | "settings" - | "account/general" - | "account/projects" - | "account/usage" - | "account/billing" - | "account/plans"; + | "settings/general" + | "settings/projects" + | "settings/usage" + | "settings/billing" + | "settings/plans"; export const generalSidebarItems = [ { @@ -141,27 +141,27 @@ const settingsSidebarItems = [ title: "Workspace", path: "#", icon: , - id: "account/workspace", + id: "settings/workspace", children: [ { title: "Projects", - path: "/account/projects", - id: "account/projects", + path: "/settings/projects", + id: "settings/projects", }, { title: "Plans", - path: "/account/billing/plans", - id: "account/plans", + path: "/settings/billing/plans", + id: "settings/plans", }, { title: "Usage", - path: "/account/usage", - id: "account/usage", + path: "/settings/usage", + id: "settings/usage", }, { title: "Billing", - path: "/account/billing", - id: "account/billing", + path: "/settings/billing", + id: "settings/billing", }, ], }, @@ -200,7 +200,7 @@ const Sidebar = ({ id }: { id: SidebarId }) => { justifyContent: "flex-end", bottom: 0, }}> - {pathname.includes("account") ? ( + {pathname.includes("settings") ? ( ) : ( @@ -276,24 +276,92 @@ const GeneralSidebar = ({ id, user }: { id: SidebarId; user: User }) => { border: "1px solid $colors$neutral6", width: "12rem", ml: "$4", - mt: "$1", }}> - + + { + e.preventDefault(); + Router.push("/settings/projects"); + }}> + Projects + + { + e.preventDefault(); + Router.push("/settings/billing/plans"); + }}> + Plans + + { + e.preventDefault(); + Router.push("/settings/billing"); + }}> + Billing + { e.preventDefault(); - Router.push("/account/projects"); + Router.push("/settings/usage"); }}> - Account setting + Usage { e.preventDefault(); logout(); }}> - Logout + Logout @@ -306,8 +374,9 @@ const GeneralSidebar = ({ id, user }: { id: SidebarId; user: User }) => { align={"center"} as={DropdownMenuTrigger} css={{ - p: "$2", - gap: "$3", + py: "$1", + px: "$2", + gap: "$2", mb: "$2", mt: "-$1", ml: "$4", @@ -330,41 +399,49 @@ const GeneralSidebar = ({ id, user }: { id: SidebarId; user: User }) => { - Projects + + Projects + {data?.map((project) => ( - setCurrentProject(project)} - key={project.id} + - {project.name || "Untitled project"} - {activeProjectId === project.id && } - + }}> + { + setCurrentProject(project); + }} + css={{ width: "100%" }} + key={project.id} + align={"center"} + justify={"between"}> + {project.name || "Untitled project"} + {activeProjectId === project.id && } + + ))} { - setShowCreateProjectAlert(true)} - align={"center"} + - Create new project - + setShowCreateProjectAlert(true)} + align={"center"}> + Create new project + + Router.push("/account/projects")} + onClick={() => Router.push("/settings/projects")} align={"center"} css={{ color: "$neutral12", cursor: "default", + borderRadius: "$3", + px: "$2", + py: "$1", + "&:hover": { + backgroundColor: "$neutral4", + }, }}> - View all projects + View all projects diff --git a/packages/www/components/UsageSummary/index.tsx b/packages/www/components/UsageSummary/index.tsx index 85b2d7b06e..1e1c7cdaff 100644 --- a/packages/www/components/UsageSummary/index.tsx +++ b/packages/www/components/UsageSummary/index.tsx @@ -304,7 +304,7 @@ const UsageSummary = () => { justify="between" align="center" css={{ fontSize: "$3", color: "$hiContrast" }}> - + { const currentProject = localStorage.getItem("currentProject"); - console.log(currentProject); if (currentProject) { console.log("Redirecting to project: ", currentProject); push(`/projects/${currentProject}`); } - push(`/account/projects/`); + push(`/settings/projects/`); }, []); return
; } diff --git a/packages/www/pages/register.tsx b/packages/www/pages/register.tsx index b6e218ec4b..0bf54e5731 100644 --- a/packages/www/pages/register.tsx +++ b/packages/www/pages/register.tsx @@ -38,7 +38,7 @@ const RegisterPage = () => { if (email && emailValidToken) { verify(email, emailValidToken).then(() => { if (selectedPlan === "1") { - router.replace("/account/billing/plans?promptUpgrade=true"); + router.replace("/settings/billing/plans?promptUpgrade=true"); } else { router.replace("/"); } diff --git a/packages/www/pages/account/billing/index.tsx b/packages/www/pages/settings/billing/index.tsx similarity index 98% rename from packages/www/pages/account/billing/index.tsx rename to packages/www/pages/settings/billing/index.tsx index b3304baf40..c14acf1a06 100644 --- a/packages/www/pages/account/billing/index.tsx +++ b/packages/www/pages/settings/billing/index.tsx @@ -190,7 +190,7 @@ const Billing = () => { } return ( @@ -280,7 +280,7 @@ const Billing = () => { plan. - + @@ -354,7 +354,7 @@ const Billing = () => { - + { } return ( diff --git a/packages/www/pages/account/projects.tsx b/packages/www/pages/settings/projects.tsx similarity index 93% rename from packages/www/pages/account/projects.tsx rename to packages/www/pages/settings/projects.tsx index 93dbdf97af..974a01c6f8 100644 --- a/packages/www/pages/account/projects.tsx +++ b/packages/www/pages/settings/projects.tsx @@ -26,7 +26,7 @@ const WorkspaceProjects = () => { return ( { }}> {data?.map((project, i) => ( ))} diff --git a/packages/www/pages/account/usage/index.tsx b/packages/www/pages/settings/usage/index.tsx similarity index 99% rename from packages/www/pages/account/usage/index.tsx rename to packages/www/pages/settings/usage/index.tsx index ea3dab7c87..6069951180 100644 --- a/packages/www/pages/account/usage/index.tsx +++ b/packages/www/pages/settings/usage/index.tsx @@ -161,7 +161,7 @@ const Usage = () => { } return ( diff --git a/packages/www/pages/verify-new-email.tsx b/packages/www/pages/verify-new-email.tsx index b165452ce4..181f819033 100644 --- a/packages/www/pages/verify-new-email.tsx +++ b/packages/www/pages/verify-new-email.tsx @@ -27,7 +27,7 @@ const VerifyPage = () => { verifyNewEmail(email, emailValidToken) .then(() => { if (selectedPlan === "1") { - router.replace("/account/billing/plans?promptUpgrade=true"); + router.replace("/settings/billing/plans?promptUpgrade=true"); } else { router.replace("/"); } diff --git a/packages/www/pages/verify.tsx b/packages/www/pages/verify.tsx index 76730508ab..969b5e85b8 100644 --- a/packages/www/pages/verify.tsx +++ b/packages/www/pages/verify.tsx @@ -27,7 +27,7 @@ const VerifyPage = () => { verify(email, emailValidToken) .then(() => { if (selectedPlan === "1") { - router.replace("/account/billing/plans?promptUpgrade=true"); + router.replace("/settings/billing/plans?promptUpgrade=true"); } else { router.replace("/"); } From febfcce6360ac70433eeb635e6815e8641981e61 Mon Sep 17 00:00:00 2001 From: Suhail Kakar Date: Wed, 29 May 2024 00:04:29 +0530 Subject: [PATCH 28/69] fix: update redirect logic --- .../www/components/Project/ProjectTile.tsx | 2 +- packages/www/components/Sidebar/index.tsx | 2 +- packages/www/hooks/use-api/tokenStorage.ts | 3 +++ packages/www/hooks/use-project.tsx | 4 +++- packages/www/pages/index.tsx | 20 +++++++++++++------ 5 files changed, 22 insertions(+), 9 deletions(-) diff --git a/packages/www/components/Project/ProjectTile.tsx b/packages/www/components/Project/ProjectTile.tsx index 942bcebb55..efd1fe13c4 100644 --- a/packages/www/components/Project/ProjectTile.tsx +++ b/packages/www/components/Project/ProjectTile.tsx @@ -42,7 +42,7 @@ export default function ProjectTile({ name, id, ...props }) { "&:hover": { cursor: "pointer", transition: ".2s", - borderColor: "$hiContrast", + borderColor: "$neutral9", }, }}> diff --git a/packages/www/components/Sidebar/index.tsx b/packages/www/components/Sidebar/index.tsx index bbb1aba227..c10c98883e 100644 --- a/packages/www/components/Sidebar/index.tsx +++ b/packages/www/components/Sidebar/index.tsx @@ -200,7 +200,7 @@ const Sidebar = ({ id }: { id: SidebarId }) => { justifyContent: "flex-end", bottom: 0, }}> - {pathname.includes("settings") ? ( + {pathname.includes("settings/") ? ( ) : ( diff --git a/packages/www/hooks/use-api/tokenStorage.ts b/packages/www/hooks/use-api/tokenStorage.ts index 4c5169128e..e858f1f794 100644 --- a/packages/www/hooks/use-api/tokenStorage.ts +++ b/packages/www/hooks/use-api/tokenStorage.ts @@ -1,3 +1,5 @@ +import { PROJECT_ID_KEY } from "hooks/use-project"; + export const TOKEN_KEY = "PERSISTENT_TOKEN"; export const REFRESH_TOKEN_KEY = "REFRESH_TOKEN"; @@ -33,6 +35,7 @@ export const clearTokens = () => { try { localStorage.removeItem(TOKEN_KEY); localStorage.removeItem(REFRESH_TOKEN_KEY); + localStorage.remove(PROJECT_ID_KEY); } catch (err) { console.error(`Error clearing persistent token: ${err.message}.`); } diff --git a/packages/www/hooks/use-project.tsx b/packages/www/hooks/use-project.tsx index 065d4ea59a..2758c9ed94 100644 --- a/packages/www/hooks/use-project.tsx +++ b/packages/www/hooks/use-project.tsx @@ -6,6 +6,8 @@ import { useRouter } from "next/router"; export const projectId = typeof window !== "undefined" && localStorage.getItem("currentProject"); +export const PROJECT_ID_KEY = "selectedProject"; + const useProject = () => { const { query: { projectId }, @@ -17,7 +19,7 @@ const useProject = () => { }; const setCurrentProject = (project, path?: string) => { - localStorage.setItem("currentProject", project.id); + localStorage.setItem(PROJECT_ID_KEY, project.id); push(`/projects/${project.id}${path ?? ""}`); }; diff --git a/packages/www/pages/index.tsx b/packages/www/pages/index.tsx index 65d69ea825..472ec617a6 100644 --- a/packages/www/pages/index.tsx +++ b/packages/www/pages/index.tsx @@ -1,19 +1,27 @@ /** * This page is solely for the purpose of redirecting user to their default project + * + * If user has a default project, redirect to that project, else redirect to the first project (default project) */ +import { useApi } from "hooks"; +import useProject from "hooks/use-project"; import { useRouter } from "next/router"; import React, { useEffect } from "react"; +import { useQuery } from "react-query"; +import { projectId as selectedProject } from "hooks/use-project"; export default function Dashboard() { const { push } = useRouter(); + const { getProjects } = useApi(); + const { data: projects } = useQuery("projects", getProjects); + useEffect(() => { - const currentProject = localStorage.getItem("currentProject"); - if (currentProject) { - console.log("Redirecting to project: ", currentProject); - push(`/projects/${currentProject}`); + if (selectedProject) { + push(`/projects/${selectedProject}`); + } else if (projects?.length > 0) { + push(`/projects/${projects[0].id}`); } - push(`/settings/projects/`); - }, []); + }, [projects]); return
; } From 8a64527d261f1e13b5d300426648fbf260e2c6fa Mon Sep 17 00:00:00 2001 From: Suhail Kakar Date: Wed, 29 May 2024 00:21:29 +0530 Subject: [PATCH 29/69] update typo import --- packages/www/components/Sidebar/index.tsx | 4 ---- packages/www/hooks/use-api/endpoints/project.ts | 9 +-------- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/packages/www/components/Sidebar/index.tsx b/packages/www/components/Sidebar/index.tsx index c10c98883e..70a7355688 100644 --- a/packages/www/components/Sidebar/index.tsx +++ b/packages/www/components/Sidebar/index.tsx @@ -215,10 +215,6 @@ const GeneralSidebar = ({ id, user }: { id: SidebarId; user: User }) => { const [showCreateProjectAlert, setShowCreateProjectAlert] = useState(false); const { setCurrentProject, activeProjectId, appendProjectId } = useProject(); - const goBack = () => { - Router.push(""); - }; - const onCreateClick = async (projectName: string) => { const project = await createProject({ name: projectName, diff --git a/packages/www/hooks/use-api/endpoints/project.ts b/packages/www/hooks/use-api/endpoints/project.ts index 15a0524e13..01b3ca64f9 100644 --- a/packages/www/hooks/use-api/endpoints/project.ts +++ b/packages/www/hooks/use-api/endpoints/project.ts @@ -1,14 +1,7 @@ import qs from "qs"; import { ApiState } from "../types"; import { SetStateAction } from "react"; - -// temporary: -// TODO: Import the Project type from @livpeer.studio/api -type Project = { - id: string; - name: string; - createdAt: number; -}; +import { Project } from "@livepeer.studio/api"; let context: any; let setState: (value: SetStateAction) => void; From d7fdf83f937a9abc8bfdc4f062a8fce758312590 Mon Sep 17 00:00:00 2001 From: Suhail Kakar Date: Wed, 29 May 2024 16:52:25 +0530 Subject: [PATCH 30/69] clean up imports --- packages/www/components/Breadcrumbs/index.tsx | 2 +- packages/www/components/Sidebar/index.tsx | 1 + packages/www/content/index.tsx | 9 ++++++++ packages/www/pages/index.tsx | 1 - .../pages/projects/[projectId]/settings.tsx | 4 ---- packages/www/pages/settings/projects.tsx | 23 +++++++++++++++---- 6 files changed, 30 insertions(+), 10 deletions(-) diff --git a/packages/www/components/Breadcrumbs/index.tsx b/packages/www/components/Breadcrumbs/index.tsx index 9dd7d58737..f47c0237c3 100644 --- a/packages/www/components/Breadcrumbs/index.tsx +++ b/packages/www/components/Breadcrumbs/index.tsx @@ -47,7 +47,7 @@ const Breadcrumbs = ({ children }) => { const { data } = useQuery("projects", getProjects); const pathname = usePathname(); - const isSettingsPage = pathname?.includes("settings"); + const isSettingsPage = pathname?.includes("settings/"); const allItems = Children.toArray(children) .filter((child) => { diff --git a/packages/www/components/Sidebar/index.tsx b/packages/www/components/Sidebar/index.tsx index 70a7355688..148ab41a8a 100644 --- a/packages/www/components/Sidebar/index.tsx +++ b/packages/www/components/Sidebar/index.tsx @@ -412,6 +412,7 @@ const GeneralSidebar = ({ id, user }: { id: SidebarId; user: User }) => { }}> {data?.map((project) => ( { useLoggedIn(); diff --git a/packages/www/pages/settings/projects.tsx b/packages/www/pages/settings/projects.tsx index 974a01c6f8..fece976a33 100644 --- a/packages/www/pages/settings/projects.tsx +++ b/packages/www/pages/settings/projects.tsx @@ -1,6 +1,6 @@ import Layout from "layouts/dashboard"; import { useApi, useLoggedIn } from "hooks"; -import { DashboardStreams as Content } from "content"; +import { DashboardProjects as Content } from "content"; import { Box, Heading, @@ -12,12 +12,21 @@ import { import ProjectTile from "components/Project/ProjectTile"; import { useQuery } from "react-query"; import { PlusIcon } from "@radix-ui/react-icons"; +import useProject from "hooks/use-project"; +import { useState } from "react"; +import CreateProjectDialog from "components/Project/createProjectDialog"; const WorkspaceProjects = () => { useLoggedIn(); - const { user } = useApi(); + const { user, getProjects, createProject } = useApi(); + const [showCreateProjectAlert, setShowCreateProjectAlert] = useState(false); + + const onCreateClick = async (projectName: string) => { + const project = await createProject({ + name: projectName, + }); + }; - const { getProjects } = useApi(); const { data } = useQuery("projects", getProjects); if (!user) { @@ -81,13 +90,19 @@ const WorkspaceProjects = () => { }}> {data?.map((project, i) => ( ))} + + setShowCreateProjectAlert(isOpen)} + isOpen={showCreateProjectAlert} + /> ); }; From 8f753ec6a682e9a3e63744df988b6f3494446180 Mon Sep 17 00:00:00 2001 From: Suhail Kakar Date: Wed, 29 May 2024 18:44:07 +0530 Subject: [PATCH 31/69] fix redirect link logic --- packages/www/components/Sidebar/index.tsx | 17 +++++++---------- packages/www/hooks/use-project.tsx | 21 ++++++++++----------- packages/www/pages/index.tsx | 2 +- packages/www/pages/settings/projects.tsx | 1 + 4 files changed, 19 insertions(+), 22 deletions(-) diff --git a/packages/www/components/Sidebar/index.tsx b/packages/www/components/Sidebar/index.tsx index 148ab41a8a..59725362e1 100644 --- a/packages/www/components/Sidebar/index.tsx +++ b/packages/www/components/Sidebar/index.tsx @@ -28,9 +28,8 @@ import { useApi } from "../../hooks"; import Router, { useRouter } from "next/router"; import { RocketIcon, ChatBubbleIcon, LoopIcon } from "@radix-ui/react-icons"; import Contact from "../Contact"; -import { useJune, events } from "hooks/use-june"; -import { useCallback, useEffect, useState } from "react"; -import { isExport } from "lib/utils"; +import { useJune } from "hooks/use-june"; +import { useEffect, useState } from "react"; import { useQuery } from "react-query"; import CreateProjectDialog from "components/Project/createProjectDialog"; import { User } from "@livepeer.studio/api"; @@ -551,13 +550,11 @@ const GeneralSidebar = ({ id, user }: { id: SidebarId; user: User }) => { Status diff --git a/packages/www/hooks/use-project.tsx b/packages/www/hooks/use-project.tsx index 2758c9ed94..2238b392b2 100644 --- a/packages/www/hooks/use-project.tsx +++ b/packages/www/hooks/use-project.tsx @@ -1,21 +1,22 @@ -import { useQuery, useQueryClient } from "react-query"; -import useApi from "./use-api"; -import { usePathname } from "next/navigation"; import { useRouter } from "next/router"; -export const projectId = - typeof window !== "undefined" && localStorage.getItem("currentProject"); - export const PROJECT_ID_KEY = "selectedProject"; +export const projectId = + typeof window !== "undefined" && localStorage.getItem(PROJECT_ID_KEY); + const useProject = () => { const { - query: { projectId }, + query: { projectId: routerProjectId }, push, } = useRouter(); + const activeProjectId = + routerProjectId || + (typeof window !== "undefined" && localStorage.getItem(PROJECT_ID_KEY)); + const appendProjectId = (path) => { - return `/projects/${projectId}${path}`; + return `/projects/${activeProjectId}${path}`; }; const setCurrentProject = (project, path?: string) => { @@ -25,9 +26,7 @@ const useProject = () => { return { appendProjectId, - activeProjectId: - projectId ?? - (typeof window !== "undefined" && localStorage.getItem("currentProject")), + activeProjectId, setCurrentProject, }; }; diff --git a/packages/www/pages/index.tsx b/packages/www/pages/index.tsx index 34610e63ff..26cdb0eb53 100644 --- a/packages/www/pages/index.tsx +++ b/packages/www/pages/index.tsx @@ -19,7 +19,7 @@ export default function Dashboard() { if (selectedProject) { push(`/projects/${selectedProject}`); } else if (projects?.length > 0) { - push(`/projects/${projects[0].id}`); + push(`/projects/${projects.reverse()?.[0].id}`); } }, [projects]); return
; diff --git a/packages/www/pages/settings/projects.tsx b/packages/www/pages/settings/projects.tsx index fece976a33..9168352603 100644 --- a/packages/www/pages/settings/projects.tsx +++ b/packages/www/pages/settings/projects.tsx @@ -72,6 +72,7 @@ const WorkspaceProjects = () => {