Skip to content

[dashboard] Implement Teams UI (selector, creation wizard, members page, project page) #4401

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitpod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ tasks:
vscode:
extensions:
- bajdzis.vscode-database
- bradlc.vscode-tailwindcss
- EditorConfig.EditorConfig
- golang.go
- hangxingliu.vscode-nginx-conf-hint
Expand Down
78 changes: 27 additions & 51 deletions components/dashboard/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,15 @@
*/

import React, { Suspense, useContext, useEffect, useState } from 'react';
import Menu from './components/Menu';
import Menu from './Menu';
import { BrowserRouter } from "react-router-dom";
import { Redirect, Route, Switch } from "react-router";

import { Login } from './Login';
import { UserContext } from './user-context';
import { TeamsContext } from './teams/teams-context';
import { getGitpodService } from './service/service';
import { shouldSeeWhatsNew, WhatsNew } from './WhatsNew';
import settingsMenu from './settings/settings-menu';
import { User } from '@gitpod/gitpod-protocol';
import { adminMenu } from './admin/admin-menu';
import gitpodIcon from './icons/gitpod.svg';
import { ErrorCodes } from '@gitpod/gitpod-protocol/lib/messaging/error';

Expand All @@ -30,6 +28,9 @@ const Integrations = React.lazy(() => import(/* webpackPrefetch: true */ './sett
const Preferences = React.lazy(() => import(/* webpackPrefetch: true */ './settings/Preferences'));
const StartWorkspace = React.lazy(() => import(/* webpackPrefetch: true */ './start/StartWorkspace'));
const CreateWorkspace = React.lazy(() => import(/* webpackPrefetch: true */ './start/CreateWorkspace'));
const NewTeam = React.lazy(() => import(/* webpackPrefetch: true */ './teams/NewTeam'));
const Members = React.lazy(() => import(/* webpackPrefetch: true */ './teams/Members'));
const Projects = React.lazy(() => import(/* webpackPrefetch: true */ './projects/Projects'));
const InstallGitHubApp = React.lazy(() => import(/* webpackPrefetch: true */ './prebuilds/InstallGitHubApp'));
const FromReferrer = React.lazy(() => import(/* webpackPrefetch: true */ './FromReferrer'));
const UserSearch = React.lazy(() => import(/* webpackPrefetch: true */ './admin/UserSearch'));
Expand All @@ -42,23 +43,28 @@ function Loading() {
}

function isGitpodIo() {
return window.location.hostname === 'gitpod.io' || window.location.hostname === 'gitpod-staging.com' || window.location.hostname.endsWith('gitpod-dev.com')
return window.location.hostname === 'gitpod.io' || window.location.hostname === 'gitpod-staging.com' || window.location.hostname.endsWith('gitpod-dev.com') || window.location.hostname.endsWith('gitpod-io-dev.com')
}

function App() {
const { user, setUser } = useContext(UserContext);
const { teams, setTeams } = useContext(TeamsContext);

const [loading, setLoading] = useState<boolean>(true);
const [isWhatsNewShown, setWhatsNewShown] = useState(false);
const [isSetupRequired, setSetupRequired] = useState(false);
const [ loading, setLoading ] = useState<boolean>(true);
const [ isWhatsNewShown, setWhatsNewShown ] = useState(false);
const [ isSetupRequired, setSetupRequired ] = useState(false);

useEffect(() => {
(async () => {
try {
const usr = await getGitpodService().server.getLoggedInUser()
setUser(usr);
const [ user, teams ] = await Promise.all([
getGitpodService().server.getLoggedInUser(),
getGitpodService().server.getTeams(),
]);
setUser(user);
setTeams(teams);
} catch (error) {
console.log(error);
console.error(error);
if (error && "code" in error) {
if (error.code === ErrorCodes.SETUP_REQUIRED) {
setSetupRequired(true);
Expand Down Expand Up @@ -139,7 +145,7 @@ function App() {

let toRender: React.ReactElement = <Route>
<div className="container">
{renderMenu(user)}
<Menu />
<Switch>
<Route path="/setup" exact component={Setup} />
<Route path="/workspaces" exact component={Workspaces} />
Expand All @@ -148,6 +154,7 @@ function App() {
<Route path="/notifications" exact component={Notifications} />
<Route path="/plans" exact component={Plans} />
<Route path="/teams" exact component={Teams} />
<Route path="/new-team" exact component={NewTeam} />
<Route path="/variables" exact component={EnvironmentVariables} />
<Route path="/preferences" exact component={Preferences} />
<Route path="/install-github-app" exact component={InstallGitHubApp} />
Expand Down Expand Up @@ -177,6 +184,13 @@ function App() {
<p className="mt-4 text-lg text-gitpod-red">{decodeURIComponent(getURLHash())}</p>
</div>
</Route>
{(teams || []).map(team => <Route path={`/${team.slug}`}>
<Route exact path={`/${team.slug}`}>
<Redirect to={`/${team.slug}/projects`} />
</Route>
<Route exact path={`/${team.slug}/members`} component={Members} />
<Route exact path={`/${team.slug}/projects`} component={Projects} />
</Route>)}
<Route path="*" render={
(match) => {

Expand All @@ -187,8 +201,7 @@ function App() {
<h1 className="text-gray-500 text-3xl">404</h1>
<p className="mt-4 text-lg">Page not found.</p>
</div>;
}
}>
}}>
</Route>
</Switch>
</div>
Expand Down Expand Up @@ -218,41 +231,4 @@ function getURLHash() {
return window.location.hash.replace(/^[#/]+/, '');
}

const renderMenu = (user?: User) => {
const left = [
{
title: 'Workspaces',
link: '/workspaces',
alternatives: ['/']
},
{
title: 'Settings',
link: '/settings',
alternatives: settingsMenu.flatMap(e => e.link)
}
];

if (user && user?.rolesOrPermissions?.includes('admin')) {
left.push({
title: 'Admin',
link: '/admin',
alternatives: adminMenu.flatMap(e => e.link)
});
}

return <Menu
left={left}
right={[
{
title: 'Docs',
link: 'https://www.gitpod.io/docs/',
},
{
title: 'Community',
link: 'https://community.gitpod.io/',
}
]}
/>;
}

export default App;
2 changes: 1 addition & 1 deletion components/dashboard/src/FromReferrer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export default function FromReferrer() {
<h3 className="text-center pb-3 text-gray-500 dark:text-gray-400">No Referrer Found</h3>
<div className="text-center pb-6 text-gray-500">
<p>It looks like you are trying to open a workspace, but the referrer URL is empty. This happens when the git hoster doesn't send the referrer header.
<br/> Please prefix the repository URL with <pre>https://gitpod.io/#</pre> in order to start a workspace. <a className="text-gray-400 underline underline-thickness-thin underline-offset-small hover:text-gray-600" href="https://www.gitpod.io/docs/getting-started/">Learn more</a></p>
<br/> Please prefix the repository URL with <pre>https://gitpod.io/#</pre> in order to start a workspace. <a className="text-gray-400 learn-more hover:text-gray-600" href="https://www.gitpod.io/docs/getting-started/">Learn more</a></p>
</div>
<span>
<Link to="/"><button className="secondary">Go to Dashboard</button></Link>
Expand Down
14 changes: 10 additions & 4 deletions components/dashboard/src/Login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import { AuthProviderInfo } from "@gitpod/gitpod-protocol";
import { useContext, useEffect, useState } from "react";
import { UserContext } from "./user-context";
import { TeamsContext } from "./teams/teams-context";
import { getGitpodService } from "./service/service";
import { iconForAuthProvider, openAuthorizeWindow, simplifyProviderName, getSafeURLRedirect } from "./provider-utils";
import gitpod from './images/gitpod.svg';
Expand Down Expand Up @@ -39,10 +40,11 @@ export function hasLoggedInBefore() {

export function Login() {
const { setUser } = useContext(UserContext);
const { setTeams } = useContext(TeamsContext);
const showWelcome = !hasLoggedInBefore();

const [authProviders, setAuthProviders] = useState<AuthProviderInfo[]>([]);
const [errorMessage, setErrorMessage] = useState<string | undefined>(undefined);
const [ authProviders, setAuthProviders ] = useState<AuthProviderInfo[]>([]);
const [ errorMessage, setErrorMessage ] = useState<string | undefined>(undefined);

useEffect(() => {
(async () => {
Expand All @@ -62,8 +64,12 @@ export function Login() {

const updateUser = async () => {
await getGitpodService().reconnect();
const user = await getGitpodService().server.getLoggedInUser();
const [ user, teams ] = await Promise.all([
getGitpodService().server.getLoggedInUser(),
getGitpodService().server.getTeams(),
]);
setUser(user);
setTeams(teams);
markLoggedIn();
}

Expand Down Expand Up @@ -157,7 +163,7 @@ export function Login() {
</div>
<div className="flex-none mx-auto h-20 text-center">
<span className="text-gray-400">
By signing in, you agree to our <a className="underline underline-thickness-thin underline-offset-small hover:text-gray-600" target="gitpod-terms" href="https://www.gitpod.io/terms/">terms of service</a>.
By signing in, you agree to our <a className="learn-more hover:text-gray-600" target="gitpod-terms" href="https://www.gitpod.io/terms/">terms of service</a>.
</span>
</div>
</div>
Expand Down
Loading