Skip to content

Commit

Permalink
Improve front page
Browse files Browse the repository at this point in the history
  • Loading branch information
davidje13 committed Dec 2, 2024
1 parent 009ba78 commit 3758ae8
Show file tree
Hide file tree
Showing 43 changed files with 814 additions and 824 deletions.
8 changes: 4 additions & 4 deletions e2e/pages/RetroCreate.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { By, WebDriver } from 'selenium-webdriver';
import { Page } from './common/Page';
import { Retro } from './Retro';
import { RetroList } from './RetroList';
import { Welcome } from './Welcome';

export class RetroCreate extends Page {
private slug?: string;
Expand All @@ -10,10 +10,10 @@ export class RetroCreate extends Page {
super(driver, '/create', '.page-retro-create');
}

public async clickListRetros() {
await this.click(By.linkText('My Retros'));
public async clickAccount() {
await this.click(By.linkText('Account'));

return new RetroList(this.driver).wait();
return new Welcome(this.driver).wait();
}

public setName(name: string) {
Expand Down
47 changes: 0 additions & 47 deletions e2e/pages/RetroList.ts

This file was deleted.

64 changes: 52 additions & 12 deletions e2e/pages/Welcome.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Page } from './common/Page';
import { RetroCreate } from './RetroCreate';
import { SsoLogin } from './SsoLogin';
import { Security } from './Security';
import { RetroList } from './RetroList';
import { Retro } from './Retro';

export class Welcome extends Page {
public constructor(driver: WebDriver) {
Expand All @@ -14,31 +14,53 @@ export class Welcome extends Page {
return this.getHeader().getText();
}

public async clickCreateRetro() {
await this.click(By.css('.link-create'));
public async getRetroNames(): Promise<string[]> {
const items = await this.getRetroItems();
return Promise.all(items.map((item) => item.getText()));
}

return new RetroCreate(this.driver).wait();
public async clickRetroNamed(name: string) {
const names = await this.getRetroNames();
const index = names.indexOf(name);
if (index === -1) {
throw new Error(`No retro named ${name}`);
}

const item = await this.getRetroItemAtIndex(index);
await item.click();

return new Retro(this.driver, 'unknown').wait();
}

public async clickListRetros() {
await this.click(By.linkText('My Retros'));
public async clickCreateRetro() {
await this.click(By.css('.link-create'));

return new RetroList(this.driver).wait();
return new RetroCreate(this.driver).wait();
}

public async clickLoginWithGoogle() {
public async clickLoginWithGoogle<K extends keyof typeof LoginTargets>(
expectation: K,
): Promise<SsoLogin<InstanceType<(typeof LoginTargets)[K]>>> {
await this.click(By.css('.sso-google'));

return new SsoLogin<RetroCreate>(this.driver, RetroCreate).wait();
return new SsoLogin(
this.driver,
LoginTargets[expectation] as any,
).wait() as any;
}

public async loginAs(userName: string) {
const ssoLogin = await this.clickLoginWithGoogle();
public async loginAs<K extends keyof typeof LoginTargets>(
userName: string,
expectation: K,
): Promise<InstanceType<(typeof LoginTargets)[K]>> {
const ssoLogin = await this.clickLoginWithGoogle(expectation);
return await ssoLogin.loginAs(userName);
}

public async clickSecurity() {
const element = this.findElement(By.css('.link-security'));
const element = this.findElement(
By.linkText('Privacy & Security information'),
);
// avoid opening a new tab, as this is difficult to manage
await this.driver.executeScript(
'arguments[0].setAttribute("target", "_self");',
Expand All @@ -49,7 +71,25 @@ export class Welcome extends Page {
return new Security(this.driver).wait();
}

private getRetroItems() {
return this.findElements(By.css('.retro-link'));
}

private async getRetroItemAtIndex(index: number) {
const items = await this.getRetroItems();
const item = items[index];
if (!item) {
throw new Error(`No retro item at index ${index}`);
}
return item;
}

private getHeader() {
return this.findElement(By.css('h1'));
}
}

const LoginTargets = {
hasRetros: Welcome,
noRetros: RetroCreate,
};
24 changes: 11 additions & 13 deletions e2e/tests/basicflow.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { getDownloadedBytes, Mbps } from '../helpers/downloadProfiler';
import { type Welcome } from '../pages/Welcome';
import { type Password } from '../pages/Password';
import { type RetroCreate } from '../pages/RetroCreate';
import { type RetroList } from '../pages/RetroList';
import { type Retro } from '../pages/Retro';
import { type RetroArchiveList } from '../pages/RetroArchiveList';
import { type RetroArchive } from '../pages/RetroArchive';
Expand Down Expand Up @@ -53,7 +52,7 @@ describe('Refacto', { stopAtFirstFailure: true, timeout }, () => {
});

it('triggers a login flow when requested', async () => {
const ssoLogin = await welcome.clickLoginWithGoogle();
const ssoLogin = await welcome.clickLoginWithGoogle('noRetros');
await ssoLogin.setIdentifier(userName);
create = await ssoLogin.submit();
});
Expand Down Expand Up @@ -207,29 +206,28 @@ describe('Refacto', { stopAtFirstFailure: true, timeout }, () => {

describe('retro list', { stopAtFirstFailure: true }, () => {
const retroName = 'My Retro Renamed';
let retroList: RetroList;
let welcome: Welcome;

it('prompts to log in when loaded', async () => {
const welcome = await user1.navigateToWelcome();
const retroCreate = await welcome.loginAs(userName);
retroList = await retroCreate.clickListRetros();
welcome = await user1.navigateToWelcome();
welcome = await welcome.loginAs(userName, 'hasRetros');
});

it('displays retros created by the current user', async () => {
expect(await retroList.getRetroNames()).toEqual([retroName]);
expect(await welcome.getRetroNames()).toEqual([retroName]);
});

it('loads linked retros without needing a password', async () => {
retro = await retroList.clickRetroNamed(retroName);
retro = await welcome.clickRetroNamed(retroName);
expect(await retro.getActionItemLabels()).toEqual(['another action']);
});

it('does not list retros from other users', async () => {
const welcome = await user1.navigateToWelcome();
const retroCreate = await welcome.loginAs('nobody');
retroList = await retroCreate.clickListRetros();
it('navigates directly to retro creation if user has no retros', async () => {
welcome = await user1.navigateToWelcome();
const retroCreate = await welcome.loginAs('nobody', 'noRetros');

expect(await retroList.getRetroNames()).toEqual([]);
welcome = await retroCreate.clickAccount();
expect(await welcome.getRetroNames()).toEqual([]);
});
});

Expand Down
5 changes: 0 additions & 5 deletions frontend/src/components/App.less
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,6 @@ button {
article {
background: @beige-back;
border-bottom: 1px solid #ffffff; /* prevent background clipping */

> p {
margin: 64px 32px;
text-align: center;
}
}

a:link,
Expand Down
5 changes: 3 additions & 2 deletions frontend/src/components/App.test.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import { Router } from 'wouter';
import staticLocationHook from 'wouter/static-location';
import { render } from 'flexible-testing-library-react';
import { act, render } from 'flexible-testing-library-react';

import { App } from './App';

describe('App', () => {
it('renders without error', () => {
it('renders without error', async () => {
render(
<Router hook={staticLocationHook('/', { record: true })}>
<App />
</Router>,
);
await act(() => Promise.resolve()); // slug existence update
});
});
17 changes: 3 additions & 14 deletions frontend/src/components/App.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ComponentType, FC, ReactNode } from 'react';
import type { FC, ReactNode } from 'react';
import { Route, Switch } from 'wouter';
import { RedirectRoute } from './RedirectRoute';
import { Footer } from './Footer';
Expand All @@ -7,10 +7,7 @@ import { RetroRouter } from './RetroRouter';
import { WelcomePage } from './welcome/WelcomePage';
import { SecurityPage } from './security/SecurityPage';
import { RetroCreatePage } from './retro-create/RetroCreatePage';
import { RetroImportPage } from './retro-create/RetroImportPage';
import { RetroListPage } from './retro-list/RetroListPage';
import { NotFoundPage } from './not-found/NotFoundPage';
import { useUserToken } from '../hooks/data/useUserToken';
import './App.less';

export const App: FC = () => (
Expand All @@ -22,7 +19,7 @@ export const App: FC = () => (
)}
</Route>
<Route path="/">
<SwitchLoggedIn yes={RetroListPage} no={WelcomePage} />
<WelcomePage />
</Route>
<Route path="/security">
<SecurityPage />
Expand All @@ -31,7 +28,7 @@ export const App: FC = () => (
<RetroCreatePage />
</Route>
<Route path="/create/import">
<RetroImportPage />
<RetroCreatePage showImport />
</Route>
<Route path="/retros/:slug/:rest*">
{({ slug = '' }) => <RetroRouter slug={decodeURIComponent(slug)} />}
Expand All @@ -48,11 +45,3 @@ export const App: FC = () => (
<Footer />
</>
);

const SwitchLoggedIn: FC<{
yes: ComponentType<{ userToken: string }>;
no: ComponentType;
}> = ({ yes: Yes, no: No }) => {
const [userToken] = useUserToken();
return userToken ? <Yes userToken={userToken} /> : <No />;
};
5 changes: 4 additions & 1 deletion frontend/src/components/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ export const Footer = memo(() => (
>
GitLab
</a>
)
{') - '}
<a href="/security" target="_blank" rel="noopener noreferrer">
Privacy &amp; Security information
</a>
</footer>
));
4 changes: 2 additions & 2 deletions frontend/src/components/RetroRouter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Route, Switch, useLocation } from 'wouter';
import { type Retro } from '../shared/api-entities';
import { type RetroDispatch } from '../api/RetroTracker';
import { retroTracker, slugTracker } from '../api/api';
import { RetroCreatePage } from './retro-create/RetroCreatePage';
import { RetroNotFoundPage } from './retro-not-found/RetroNotFoundPage';
import { PasswordPage } from './password/PasswordPage';
import { RetroPage } from './retro/RetroPage';
import { ArchiveListPage } from './archive-list/ArchiveListPage';
Expand Down Expand Up @@ -93,7 +93,7 @@ export const RetroRouter: FC<PropsT> = ({ slug }) => {
);

if (slugError === 'not found') {
return <RetroCreatePage defaultSlug={slug} />;
return <RetroNotFoundPage slug={slug} />;
}

const error = slugError || retroTokenError;
Expand Down
14 changes: 8 additions & 6 deletions frontend/src/components/archive-list/ArchiveListPage.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { memo } from 'react';
import { type RetroPagePropsT } from '../RetroRouter';
import { Header } from '../common/Header';
import { Loader } from '../common/Loader';
import { LoadingError, LoadingIndicator } from '../common/Loader';
import { ApiDownload } from '../common/ApiDownload';
import { useArchiveList } from '../../hooks/data/useArchiveList';
import { ArchiveList } from './ArchiveList';
Expand All @@ -22,11 +22,13 @@ export const ArchiveListPage = memo(({ retroToken, retro }: PropsT) => {
action: `/retros/${encodeURIComponent(retro.slug)}`,
}}
/>
<Loader
error={archivesError}
Component={ArchiveList}
componentProps={archives ? { slug: retro.slug, archives } : null}
/>
{archivesError ? (
<LoadingError error={archivesError} />
) : !archives ? (
<LoadingIndicator />
) : (
<ArchiveList slug={retro.slug} archives={archives} />
)}
<div className="extra-links">
<ApiDownload
url={`retros/${encodeURIComponent(retro.id)}/export/json`}
Expand Down
Loading

0 comments on commit 3758ae8

Please sign in to comment.