diff --git a/.npmrc b/.npmrc index ee4bf8f32..ad46c0d5b 100644 --- a/.npmrc +++ b/.npmrc @@ -1,4 +1,5 @@ # Hoist for Parcel public-hoist-pattern[]=@parcel/* public-hoist-pattern[]=postcss +public-hoist-pattern[]=process public-hoist-pattern[]=*eslint* diff --git a/package.json b/package.json index 63334c911..e2c97e8f7 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ }, "alias": { "html-parse-stringify": "html-parse-stringify/dist/html-parse-stringify.module.js", - "react-hook-form": "react-hook-form/dist/index.esm.mjs" + "react-hook-form": "react-hook-form/dist/index.esm.mjs", + "superstruct": "superstruct/lib/index.es.js" } } diff --git a/packages/console/package.json b/packages/console/package.json index 240047b1c..45cc76d2a 100644 --- a/packages/console/package.json +++ b/packages/console/package.json @@ -17,6 +17,7 @@ }, "dependencies": { "@logto/phrases": "^0.1.0", + "@logto/react": "^0.1.2", "@logto/schemas": "^0.1.0", "@monaco-editor/react": "^4.3.1", "@silverhand/essentials": "^1.1.6", @@ -55,6 +56,7 @@ "postcss": "^8.4.6", "postcss-modules": "^4.3.0", "prettier": "^2.3.2", + "process": "^0.11.10", "stylelint": "^13.13.1", "typescript": "^4.6.2" }, diff --git a/packages/console/src/App.module.scss b/packages/console/src/App.module.scss deleted file mode 100644 index 5b7c6a57f..000000000 --- a/packages/console/src/App.module.scss +++ /dev/null @@ -1,9 +0,0 @@ -@use '@/scss/underscore' as _; - -.content { - flex-grow: 1; - display: flex; - padding-right: _.unit(5); - margin-bottom: _.unit(6); - overflow: hidden; -} diff --git a/packages/console/src/App.tsx b/packages/console/src/App.tsx index e5fa00f8a..2a7e8c1a6 100644 --- a/packages/console/src/App.tsx +++ b/packages/console/src/App.tsx @@ -1,21 +1,21 @@ +import { LogtoProvider } from '@logto/react'; import React, { useEffect } from 'react'; import { BrowserRouter, Navigate, Route, Routes, useLocation, useNavigate } from 'react-router-dom'; import { SWRConfig } from 'swr'; import './scss/normalized.scss'; -import * as styles from './App.module.scss'; import AppContent from './components/AppContent'; -import Content from './components/Content'; -import Sidebar, { getPath, sections } from './components/Sidebar'; +import { getPath, sections } from './components/AppContent/components/Sidebar'; import Toast from './components/Toast'; -import Topbar from './components/Topbar'; import initI18n from './i18n/init'; import ApiResourceDetails from './pages/ApiResourceDetails'; import ApiResources from './pages/ApiResources'; import ApplicationDetails from './pages/ApplicationDetails'; import Applications from './pages/Applications'; +import Callback from './pages/Callback'; import ConnectorDetails from './pages/ConnectorDetails'; import Connectors from './pages/Connectors'; +import GetStarted from './pages/GetStarted'; import Users from './pages/Users'; import { fetcher } from './swr'; @@ -34,39 +34,37 @@ const Main = () => { }, [location.pathname, navigate]); return ( - - - - -
- - - - - } /> - - } /> - } /> - } /> - + + + + + } /> + }> + } /> + + } /> + + } /> + } /> + } /> - - } /> - } /> - - - } /> - } /> - } /> - - - } /> - - - -
-
-
+ + + } /> + } /> + + + } /> + } /> + } /> + + + } /> + + + + + ); }; diff --git a/packages/console/src/components/Sidebar/components/Item/index.module.scss b/packages/console/src/components/AppContent/components/Sidebar/components/Item/index.module.scss similarity index 100% rename from packages/console/src/components/Sidebar/components/Item/index.module.scss rename to packages/console/src/components/AppContent/components/Sidebar/components/Item/index.module.scss diff --git a/packages/console/src/components/Sidebar/components/Item/index.tsx b/packages/console/src/components/AppContent/components/Sidebar/components/Item/index.tsx similarity index 100% rename from packages/console/src/components/Sidebar/components/Item/index.tsx rename to packages/console/src/components/AppContent/components/Sidebar/components/Item/index.tsx diff --git a/packages/console/src/components/Sidebar/components/Section/index.module.scss b/packages/console/src/components/AppContent/components/Sidebar/components/Section/index.module.scss similarity index 100% rename from packages/console/src/components/Sidebar/components/Section/index.module.scss rename to packages/console/src/components/AppContent/components/Sidebar/components/Section/index.module.scss diff --git a/packages/console/src/components/Sidebar/components/Section/index.tsx b/packages/console/src/components/AppContent/components/Sidebar/components/Section/index.tsx similarity index 100% rename from packages/console/src/components/Sidebar/components/Section/index.tsx rename to packages/console/src/components/AppContent/components/Sidebar/components/Section/index.tsx diff --git a/packages/console/src/components/Sidebar/consts.ts b/packages/console/src/components/AppContent/components/Sidebar/consts.ts similarity index 100% rename from packages/console/src/components/Sidebar/consts.ts rename to packages/console/src/components/AppContent/components/Sidebar/consts.ts diff --git a/packages/console/src/components/Sidebar/icons/BarGraph.tsx b/packages/console/src/components/AppContent/components/Sidebar/icons/BarGraph.tsx similarity index 100% rename from packages/console/src/components/Sidebar/icons/BarGraph.tsx rename to packages/console/src/components/AppContent/components/Sidebar/icons/BarGraph.tsx diff --git a/packages/console/src/components/Sidebar/icons/Bolt.tsx b/packages/console/src/components/AppContent/components/Sidebar/icons/Bolt.tsx similarity index 100% rename from packages/console/src/components/Sidebar/icons/Bolt.tsx rename to packages/console/src/components/AppContent/components/Sidebar/icons/Bolt.tsx diff --git a/packages/console/src/components/Sidebar/icons/Box.tsx b/packages/console/src/components/AppContent/components/Sidebar/icons/Box.tsx similarity index 100% rename from packages/console/src/components/Sidebar/icons/Box.tsx rename to packages/console/src/components/AppContent/components/Sidebar/icons/Box.tsx diff --git a/packages/console/src/components/Sidebar/icons/Cloud.tsx b/packages/console/src/components/AppContent/components/Sidebar/icons/Cloud.tsx similarity index 100% rename from packages/console/src/components/Sidebar/icons/Cloud.tsx rename to packages/console/src/components/AppContent/components/Sidebar/icons/Cloud.tsx diff --git a/packages/console/src/components/Sidebar/icons/Connection.tsx b/packages/console/src/components/AppContent/components/Sidebar/icons/Connection.tsx similarity index 100% rename from packages/console/src/components/Sidebar/icons/Connection.tsx rename to packages/console/src/components/AppContent/components/Sidebar/icons/Connection.tsx diff --git a/packages/console/src/components/Sidebar/icons/Document.tsx b/packages/console/src/components/AppContent/components/Sidebar/icons/Document.tsx similarity index 100% rename from packages/console/src/components/Sidebar/icons/Document.tsx rename to packages/console/src/components/AppContent/components/Sidebar/icons/Document.tsx diff --git a/packages/console/src/components/Sidebar/icons/Gear.tsx b/packages/console/src/components/AppContent/components/Sidebar/icons/Gear.tsx similarity index 100% rename from packages/console/src/components/Sidebar/icons/Gear.tsx rename to packages/console/src/components/AppContent/components/Sidebar/icons/Gear.tsx diff --git a/packages/console/src/components/Sidebar/icons/Help.tsx b/packages/console/src/components/AppContent/components/Sidebar/icons/Help.tsx similarity index 100% rename from packages/console/src/components/Sidebar/icons/Help.tsx rename to packages/console/src/components/AppContent/components/Sidebar/icons/Help.tsx diff --git a/packages/console/src/components/Sidebar/icons/List.tsx b/packages/console/src/components/AppContent/components/Sidebar/icons/List.tsx similarity index 100% rename from packages/console/src/components/Sidebar/icons/List.tsx rename to packages/console/src/components/AppContent/components/Sidebar/icons/List.tsx diff --git a/packages/console/src/components/Sidebar/icons/UserProfile.tsx b/packages/console/src/components/AppContent/components/Sidebar/icons/UserProfile.tsx similarity index 100% rename from packages/console/src/components/Sidebar/icons/UserProfile.tsx rename to packages/console/src/components/AppContent/components/Sidebar/icons/UserProfile.tsx diff --git a/packages/console/src/components/Sidebar/icons/Web.tsx b/packages/console/src/components/AppContent/components/Sidebar/icons/Web.tsx similarity index 100% rename from packages/console/src/components/Sidebar/icons/Web.tsx rename to packages/console/src/components/AppContent/components/Sidebar/icons/Web.tsx diff --git a/packages/console/src/components/Sidebar/index.module.scss b/packages/console/src/components/AppContent/components/Sidebar/index.module.scss similarity index 100% rename from packages/console/src/components/Sidebar/index.module.scss rename to packages/console/src/components/AppContent/components/Sidebar/index.module.scss diff --git a/packages/console/src/components/Sidebar/index.tsx b/packages/console/src/components/AppContent/components/Sidebar/index.tsx similarity index 100% rename from packages/console/src/components/Sidebar/index.tsx rename to packages/console/src/components/AppContent/components/Sidebar/index.tsx diff --git a/packages/console/src/components/Sidebar/utils.ts b/packages/console/src/components/AppContent/components/Sidebar/utils.ts similarity index 100% rename from packages/console/src/components/Sidebar/utils.ts rename to packages/console/src/components/AppContent/components/Sidebar/utils.ts diff --git a/packages/console/src/components/Topbar/index.module.scss b/packages/console/src/components/AppContent/components/Topbar/index.module.scss similarity index 100% rename from packages/console/src/components/Topbar/index.module.scss rename to packages/console/src/components/AppContent/components/Topbar/index.module.scss diff --git a/packages/console/src/components/Topbar/index.tsx b/packages/console/src/components/AppContent/components/Topbar/index.tsx similarity index 100% rename from packages/console/src/components/Topbar/index.tsx rename to packages/console/src/components/AppContent/components/Topbar/index.tsx diff --git a/packages/console/src/components/AppContent/index.module.scss b/packages/console/src/components/AppContent/index.module.scss index e75884fe1..a4b179cc6 100644 --- a/packages/console/src/components/AppContent/index.module.scss +++ b/packages/console/src/components/AppContent/index.module.scss @@ -1,4 +1,5 @@ @use '@/scss/colors' as colors; +@use '@/scss/underscore' as _; .app { position: absolute; @@ -7,6 +8,18 @@ flex-direction: column; } +.content { + flex-grow: 1; + display: flex; + padding-right: _.unit(5); + margin-bottom: _.unit(6); + overflow: hidden; + + .main { + flex-grow: 1; + } +} + .light { @include colors.light-theme; } diff --git a/packages/console/src/components/AppContent/index.tsx b/packages/console/src/components/AppContent/index.tsx index 5fe800617..6e48f0e93 100644 --- a/packages/console/src/components/AppContent/index.tsx +++ b/packages/console/src/components/AppContent/index.tsx @@ -1,15 +1,21 @@ -import React, { ReactNode, useEffect } from 'react'; +import { useLogto } from '@logto/react'; +import React, { useEffect } from 'react'; +import { Outlet, useHref } from 'react-router-dom'; +import Sidebar from './components/Sidebar'; +import Topbar from './components/Topbar'; import * as styles from './index.module.scss'; type Theme = 'light'; type Props = { - children: ReactNode; theme: Theme; }; -const AppContent = ({ children, theme }: Props) => { +const AppContent = ({ theme }: Props) => { + const { isAuthenticated, signIn } = useLogto(); + const href = useHref('/callback'); + useEffect(() => { const classes = [styles.web, styles[theme]].filter((value): value is string => Boolean(value)); document.body.classList.add(...classes); @@ -19,7 +25,27 @@ const AppContent = ({ children, theme }: Props) => { }; }, [theme]); - return
{children}
; + useEffect(() => { + if (!isAuthenticated) { + void signIn(new URL(href, window.location.origin).toString()); + } + }, [href, isAuthenticated, signIn]); + + if (!isAuthenticated) { + return <>loading; + } + + return ( +
+ +
+ +
+ +
+
+
+ ); }; export default AppContent; diff --git a/packages/console/src/components/Content/index.module.scss b/packages/console/src/components/Content/index.module.scss deleted file mode 100644 index a13e02528..000000000 --- a/packages/console/src/components/Content/index.module.scss +++ /dev/null @@ -1,3 +0,0 @@ -.content { - flex-grow: 1; -} diff --git a/packages/console/src/components/Content/index.tsx b/packages/console/src/components/Content/index.tsx deleted file mode 100644 index e1f1742bd..000000000 --- a/packages/console/src/components/Content/index.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import React, { ReactNode } from 'react'; - -import * as styles from './index.module.scss'; - -type Props = { - children: ReactNode; -}; - -const Content = ({ children }: Props) => { - return
{children}
; -}; - -export default Content; diff --git a/packages/console/src/pages/Callback/index.tsx b/packages/console/src/pages/Callback/index.tsx new file mode 100644 index 000000000..f6aa8fdb0 --- /dev/null +++ b/packages/console/src/pages/Callback/index.tsx @@ -0,0 +1,19 @@ +import { useLogto } from '@logto/react'; +import React, { useEffect } from 'react'; +import { useNavigate } from 'react-router-dom'; + +const Callback = () => { + const { isAuthenticated, isLoading } = useLogto(); + const navigate = useNavigate(); + + // TO-DO: Error handling + useEffect(() => { + if (isAuthenticated && !isLoading) { + navigate('/', { replace: true }); + } + }, [isAuthenticated, isLoading, navigate]); + + return

Redirecting...

; +}; + +export default Callback; diff --git a/packages/console/src/pages/GetStarted/index.tsx b/packages/console/src/pages/GetStarted/index.tsx new file mode 100644 index 000000000..f667aeece --- /dev/null +++ b/packages/console/src/pages/GetStarted/index.tsx @@ -0,0 +1,7 @@ +import React from 'react'; + +const GetStarted = () => { + return
GetStarted
; +}; + +export default GetStarted; diff --git a/packages/core/src/oidc/init.ts b/packages/core/src/oidc/init.ts index 5f87b1dce..b97c0c819 100644 --- a/packages/core/src/oidc/init.ts +++ b/packages/core/src/oidc/init.ts @@ -91,7 +91,7 @@ export default async function initOidc(app: Koa): Promise { clientBasedCORS: (_, origin) => { console.log('origin', origin); - return origin.startsWith('http://localhost:3000'); + return origin.startsWith('http://localhost:3001'); }, findAccount: async (ctx, sub) => { await findUserById(sub); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e96a1024f..b6df382b6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -21,6 +21,7 @@ importers: packages/console: specifiers: '@logto/phrases': ^0.1.0 + '@logto/react': ^0.1.2 '@logto/schemas': ^0.1.0 '@monaco-editor/react': ^4.3.1 '@parcel/core': ^2.3.2 @@ -47,6 +48,7 @@ importers: postcss: ^8.4.6 postcss-modules: ^4.3.0 prettier: ^2.3.2 + process: ^0.11.10 react: ^17.0.2 react-dom: ^17.0.2 react-hook-form: ^7.27.1 @@ -61,6 +63,7 @@ importers: typescript: ^4.6.2 dependencies: '@logto/phrases': link:../phrases + '@logto/react': 0.1.2_react@17.0.2 '@logto/schemas': link:../schemas '@monaco-editor/react': 4.3.1_e62f1489d5efe674a41c3f8d6971effe '@silverhand/essentials': 1.1.6 @@ -98,6 +101,7 @@ importers: postcss: 8.4.6 postcss-modules: 4.3.0_postcss@8.4.6 prettier: 2.5.1 + process: 0.11.10 stylelint: 13.13.1 typescript: 4.6.2 @@ -2233,6 +2237,38 @@ packages: prop-types: 15.8.1 react: 17.0.2 react-dom: 17.0.2_react@17.0.2 + /@logto/browser/0.1.2: + resolution: {integrity: sha512-sTJjnx00BXYEChCbbO/LPs0x0wE1bDSHniFi+u93cynyEHgoT5yjMnH4N39NhrpmRdkXxOxaIkXmyAT1nSmYzQ==} + requiresBuild: true + dependencies: + '@logto/js': 0.1.2 + '@silverhand/essentials': 1.1.6 + jose: 4.6.0 + lodash.get: 4.4.2 + superstruct: 0.15.4 + dev: false + + /@logto/js/0.1.2: + resolution: {integrity: sha512-kz7l++gfpXa1OaUaB5WvnHNXQKEJDFnBzVYAofPADnPftHEF0zYRuQDCa8PJMd6/ECKfL1XPLMlJMNP/5U2fqQ==} + requiresBuild: true + dependencies: + '@silverhand/essentials': 1.1.6 + camelcase-keys: 7.0.2 + jose: 4.6.0 + js-base64: 3.7.2 + lodash.get: 4.4.2 + superstruct: 0.15.4 + dev: false + + /@logto/react/0.1.2_react@17.0.2: + resolution: {integrity: sha512-kxLOvxOv3IB8BjpbcoRFsBFX249wAfbOL0tfJlSWmOXrkPouai1bRItEFBHFKDI1zLJATVQRoJNQfaczJy/c0A==} + requiresBuild: true + peerDependencies: + react: '>=16.8.0' + dependencies: + '@logto/browser': 0.1.2 + '@silverhand/essentials': 1.1.6 + react: 17.0.2 dev: false /@nodelib/fs.scandir/2.1.5: @@ -4506,6 +4542,16 @@ packages: quick-lru: 4.0.1 dev: true + /camelcase-keys/7.0.2: + resolution: {integrity: sha512-Rjs1H+A9R+Ig+4E/9oyB66UC5Mj9Xq3N//vcLf2WzgdTi/3gUu3Z9KoqmlrEG4VuuLK8wJHofxzdQXz/knhiYg==} + engines: {node: '>=12'} + dependencies: + camelcase: 6.3.0 + map-obj: 4.3.0 + quick-lru: 5.1.1 + type-fest: 1.4.0 + dev: false + /camelcase/5.3.1: resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} engines: {node: '>=6'} @@ -4515,6 +4561,11 @@ packages: resolution: {integrity: sha512-tVI4q5jjFV5CavAU8DXfza/TJcZutVKo/5Foskmsqcm0MsL91moHvwiGNnqaa2o6PF/7yT5ikDRcVcl8Rj6LCA==} engines: {node: '>=10'} + /camelcase/6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + dev: false + /caniuse-api/3.0.0: resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==} dependencies: @@ -8568,6 +8619,14 @@ packages: resolution: {integrity: sha512-S7Xfsy8nN9Iw/AZxk+ZxEbd5ImIwJPM0TfAo8zI8FF+3lidQ2yiK4dqzsaPKSbZD0woNVSY0KCql6rlKc5V7ug==} dev: false + /jose/4.6.0: + resolution: {integrity: sha512-0hNAkhMBNi4soKSAX4zYOFV+aqJlEz/4j4fregvasJzEVtjDChvWqRjPvHwLqr5hx28Ayr6bsOs1Kuj87V0O8w==} + dev: false + + /js-base64/3.7.2: + resolution: {integrity: sha512-NnRs6dsyqUXejqk/yv2aiXlAvOs56sLkX6nUdeaNezI5LFFLlsZjOThmwnrcwh5ZZRwZlCMnVAY3CvhIhoVEKQ==} + dev: false + /js-tokens/4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -9073,7 +9132,6 @@ packages: /lodash.get/4.4.2: resolution: {integrity: sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=} - dev: true /lodash.ismatch/4.4.0: resolution: {integrity: sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc=} @@ -11565,6 +11623,11 @@ packages: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} dev: true + /process/0.11.10: + resolution: {integrity: sha1-czIwDoQBYb2j5podHZGn1LwW8YI=} + engines: {node: '>= 0.6.0'} + dev: true + /promise-deferred/2.0.3: resolution: {integrity: sha512-n10XaoznCzLfyPFOlEE8iurezHpxrYzyjgq/1eW9Wk1gJwur/N7BdBmjJYJpqMeMcXK4wEbzo2EvZQcqjYcKUQ==} engines: {node: '>= 0.4'} @@ -13156,6 +13219,10 @@ packages: - supports-color dev: true + /superstruct/0.15.4: + resolution: {integrity: sha512-eOoMeSbP9ZJChNOm/9RYjE+F36rYR966AAqeG3xhQB02j2sfAUXDp4EQ/7bAOqnlJnuFDB8yvOu50SocvKpUEw==} + dev: false + /supertest/6.2.2: resolution: {integrity: sha512-wCw9WhAtKJsBvh07RaS+/By91NNE0Wh0DN19/hWPlBOU8tAfOtbZoVSV4xXeoKoxgPx0rx2y+y+8660XtE7jzg==} engines: {node: '>=6.0.0'} @@ -13666,6 +13733,11 @@ packages: engines: {node: '>=8'} dev: true + /type-fest/1.4.0: + resolution: {integrity: sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==} + engines: {node: '>=10'} + dev: false + /type-fest/2.8.0: resolution: {integrity: sha512-O+V9pAshf9C6loGaH0idwsmugI2LxVNR7DtS40gVo2EXZVYFgz9OuNtOhgHLdHdapOEWNdvz9Ob/eeuaWwwlxA==} engines: {node: '>=12.20'}