Skip to content
This repository has been archived by the owner on Aug 1, 2022. It is now read-only.

Commit

Permalink
fix(ui): fix various routing issues (#595)
Browse files Browse the repository at this point in the history
* Revert "refactor(ui): move all repository browsing state into store (#564)"
This reverts commit 3f05ff8.

* Fix README doesn't always show up
* Get rid of Svelte a11y warnings
* Bring back the commit teaser
* Add specs for showing project README functionality
* Update ui/Screen/Project/Source.svelte
Co-authored-by: Alexander Simmerl <a.simmerl@gmail.com>

* Simplify File component
* Fix revision selection bug
This fixes a bug where the revision of the previously selected project
would be shown when navigating to a new project.

* Make prettier happy
Co-authored-by: Alexander Simmerl <a.simmerl@gmail.com>
  • Loading branch information
rudolfs committed Jun 25, 2020
1 parent c3d4938 commit df7cfdc
Show file tree
Hide file tree
Showing 9 changed files with 151 additions and 65 deletions.
51 changes: 51 additions & 0 deletions cypress/integration/project_source_browsing.spec.js
Expand Up @@ -18,6 +18,7 @@ context("commit browsing", () => {
cy.contains("91b69e0").click();
cy.contains("91b69e00cd8e5a07e20942e9e4457d83ce7a3ff1").should("exist");
});

it("shows the commit history for another branch", () => {
cy.pick("revision-selector").click();
cy.get('[data-branch="dev"][data-repo-handle="cloudhead"]').click();
Expand Down Expand Up @@ -108,6 +109,56 @@ context("source code browsing", () => {
});

context("page view", () => {
context("when we're looking at the project root", () => {
context("when there is a README file", () => {
it("shows the README file", () => {
// It contains the commit teaser for the latest commit.
cy.pick("project-screen", "commit-teaser").contains("223aaf8");
cy.pick("project-screen", "commit-teaser").contains(
"Merge pull request #4"
);
cy.pick("project-screen", "commit-teaser").contains(
"Alexander Simmerl"
);

cy.pick("project-screen", "file-source").contains("README.md");
cy.pick("project-screen", "file-source").contains(
"This repository is a data source for the Upstream front-end tests and the radicle-surf unit tests."
);

// Going to a different path and then switching back to the root path
// shows the README again.
cy.pick("source-tree").within(() => {
cy.contains(".i-am-well-hidden").click();
});
cy.pick("project-screen", "file-source").contains(
"Monadic / .i-am-well-hidden"
);
cy.pick("project-screen", "file-source").contains("Monadic").click();
cy.pick("project-screen", "file-source").contains("README.md");

cy.pick("source-tree").within(() => {
cy.contains(".i-too-am-hidden").click();
});
cy.pick("project-screen", "file-source").contains(
"Monadic / .i-too-am-hidden"
);
cy.pick("topbar", "project-avatar").contains("Monadic").click();
cy.pick("project-screen", "file-source").contains("README.md");

// Switching between different revisions shows the correct README
cy.pick("revision-selector").click();
cy.get(
'.revision-dropdown [data-branch="dev"][data-repo-handle="cloudhead"]'
).click();
cy.pick("project-screen", "file-source").contains("README.md");
cy.pick("project-screen", "file-source").contains(
"This repository is a data source for the Upstream front-end tests."
);
});
});
});

context("revision selector", () => {
it("allows switching to a different branch", () => {
cy.pick("revision-selector").click();
Expand Down
1 change: 1 addition & 0 deletions ui/DesignSystem/Component/HorizontalMenu/MenuItem.svelte
Expand Up @@ -41,6 +41,7 @@
}
</style>

<!-- svelte-ignore a11y-missing-attribute -->
<a data-cy={title} use:link={href}>
{#if active}
<div class="icon">
Expand Down
33 changes: 23 additions & 10 deletions ui/DesignSystem/Component/SourceBrowser/File.svelte
@@ -1,7 +1,15 @@
<script>
import { link } from "svelte-spa-router";
import * as path from "../../../src/path.ts";
import { ObjectType } from "../../../src/source.ts";
import { Icon } from "../../Primitive";
export let projectId = null;
export let filePath = null;
export let name = null;
export let currentRevision = null;
export let active = false;
</script>

Expand All @@ -15,14 +23,6 @@
line-height: 1.5em;
flex: 1;
width: 100%;
display: flex;
border-radius: 4px;
white-space: nowrap;
user-select: none;
}
.file:hover {
background-color: var(--color-foreground-level-1);
}
/* prevent icon from shrinking when the filename is long */
Expand All @@ -34,6 +34,15 @@
margin-left: 0.25rem;
}
a {
display: flex;
border-radius: 4px;
}
a:hover {
background-color: var(--color-foreground-level-1);
}
.active {
color: var(--color-foreground);
background-color: var(--color-foreground-level-1);
Expand All @@ -45,7 +54,11 @@
}
</style>

<div class="file" class:active on:click>
<a
class="file"
class:active
href={path.projectSource(projectId, currentRevision, ObjectType.Blob, filePath)}
use:link>
<Icon.File />
<span class="file-name">{name}</span>
</div>
</a>
25 changes: 8 additions & 17 deletions ui/DesignSystem/Component/SourceBrowser/Folder.svelte
Expand Up @@ -3,7 +3,6 @@
currentPath,
currentRevision,
tree,
updateParams,
ObjectType,
} from "../../../src/source.ts";
Expand All @@ -19,20 +18,12 @@
export let expanded = false;
export let toplevel = false;
const toggleFolder = () => {
const toggle = () => {
expanded = !expanded;
};
const onFileClick = filePath => {
updateParams({
path: filePath,
projectId: projectId,
revision: $currentRevision,
type: ObjectType.Blob,
});
};
$: store = tree(projectId, $currentRevision, prefix);
$: active = prefix === $currentPath;
</script>

<style>
Expand Down Expand Up @@ -69,8 +60,8 @@

<Remote {store} let:data={tree}>
{#if !toplevel}
<div class="folder" on:click={toggleFolder}>
<span class:expanded style="height: 24px">
<div class="folder" on:click={toggle}>
<span class:expanded class:active style="height: 24px">
<Icon.Chevron dataCy={`expand-${name}`} />
</span>
<span class="folder-name">{name}</span>
Expand All @@ -87,11 +78,11 @@
prefix={`${entry.path}/`} />
{:else}
<File
name={entry.info.name}
active={entry.path === $currentPath}
on:click={() => {
onFileClick(entry.path);
}} />
{projectId}
filePath={entry.path}
name={entry.info.name}
currentRevision={$currentRevision} />
{/if}
{/each}
{/if}
Expand Down
5 changes: 5 additions & 0 deletions ui/Screen/Project.svelte
Expand Up @@ -5,6 +5,8 @@
import * as path from "../src/path.ts";
import { fetch, project as store } from "../src/project.ts";
import { updateParams } from "../src/source.ts";
import {
AdditionalActionsDropdown,
HorizontalMenu,
Expand Down Expand Up @@ -109,6 +111,9 @@
}
fetch({ id: params.id });
// Unset the current selected revision when navigating to a new repository.
updateParams({ revision: "" });
</script>

<SidebarLayout
Expand Down
56 changes: 27 additions & 29 deletions ui/Screen/Project/Source.svelte
@@ -1,14 +1,13 @@
<script>
import { getContext } from "svelte";
import { link } from "svelte-spa-router";
import { link, location } from "svelte-spa-router";
import { format } from "timeago.js";
import * as path from "../../src/path.ts";
import { project as projectStore } from "../../src/project.ts";
import {
currentPath,
currentRevision,
currentObjectType,
fetchRevisions,
object as objectStore,
ObjectType,
Expand All @@ -17,12 +16,12 @@
updateParams,
} from "../../src/source.ts";
import { Code, Icon, Text, Title } from "../../DesignSystem/Primitive";
import { Remote, Copyable } from "../../DesignSystem/Component";
import { Code, Flex, Icon, Text, Title } from "../../DesignSystem/Primitive";
import { Copyable, Placeholder, Remote } from "../../DesignSystem/Component";
import FileSource from "../../DesignSystem/Component/SourceBrowser/FileSource.svelte";
import Readme from "../../DesignSystem/Component/SourceBrowser/Readme.svelte";
import CommitTeaser from "../../DesignSystem/Component/SourceBrowser/CommitTeaser.svelte";
import Readme from "../../DesignSystem/Component/SourceBrowser/Readme.svelte";
import Folder from "../../DesignSystem/Component/SourceBrowser/Folder.svelte";
import RevisionSelector from "../../DesignSystem/Component/SourceBrowser/RevisionSelector.svelte";
Expand All @@ -32,10 +31,10 @@
const updateRevision = (projectId, revision) => {
updateParams({
path: getPath($currentPath),
path: path.extractProjectSourceObjectPath($location),
projectId: projectId,
revision: revision,
type: getObjectType($currentObjectType),
type: path.extractProjectSourceObjectType($location),
});
};
Expand All @@ -54,21 +53,14 @@
return current !== "" ? current : metadata.defaultBranch;
};
const getPath = current => {
return current !== "" ? current : "";
};
const getObjectType = current => {
return current !== "" ? current : ObjectType.Tree;
};
$: updateParams({
path: path.extractProjectSourceObjectPath($location),
projectId: id,
revision: getRevision($currentRevision),
type: path.extractProjectSourceObjectType($location),
});
$: readmeStore = readme(id, getRevision($currentRevision));
// Fetch users and revisions for repository selector
fetchRevisions({ projectId: id });
// Set the initial routing information on page load
updateRevision(id, getRevision($currentRevision));
</script>

<style>
Expand Down Expand Up @@ -189,6 +181,7 @@
<div class="repo-stat-item">
<Icon.Commit />
<Text style="margin: 0 8px;">
<!-- svelte-ignore a11y-missing-attribute -->
<a
data-cy="commits-button"
use:link={path.projectCommits(project.id, $currentRevision)}>
Expand Down Expand Up @@ -220,7 +213,7 @@
rootPath={path.projectSource(project.id)}
projectName={project.metadata.name}
projectId={project.id} />
{:else if object.info.objectType === ObjectType.Tree}
{:else if object.path === ''}
<!-- Repository root -->
<div class="commit-header">
<CommitTeaser
Expand All @@ -231,15 +224,20 @@
timestamp={format(object.info.lastCommit.committerTime * 1000)}
style="height: 100%" />
</div>
{/if}
</Remote>

<!-- Readme -->
<Remote store={readmeStore} let:data={readme}>
{#if readme}
<Readme content={readme.content} path={readme.path} />
{:else}
<!-- TODO: Placeholder for when projects don't have a README -->
<!-- Readme -->
<Remote
store={readme(id, getRevision($currentRevision))}
let:data={readme}>
{#if readme}
<Readme content={readme.content} path={readme.path} />
{:else}
<Flex align="center">
<Placeholder style="width: 300px; height: 100px" />
<Text>No readme found placeholder.</Text>
</Flex>
{/if}
</Remote>
{/if}
</Remote>
</div>
Expand Down
1 change: 1 addition & 0 deletions ui/src/config.ts
@@ -1,3 +1,4 @@
export const DEFAULT_PROJECT_REVISION = "master";
export const HIDDEN_BRANCHES = ["rad/contributor", "rad/project"];
export const DEFAULT_BRANCH_FOR_NEW_PROJECTS = "master";
export const NOTIFICATION_TIMEOUT = 5000; // ms
37 changes: 35 additions & 2 deletions ui/src/path.ts
@@ -1,5 +1,12 @@
import regexparam from "regexparam";

import * as config from "./config";
import { ObjectType } from "./source";

const PROJECT_SOURCE_PATH_MATCH = new RegExp(
`/source/(.*)/(${ObjectType.Blob}|${ObjectType.Tree})/(.*)`
);

export const search = (): string => "/search";
export const settings = (): string => "/settings";

Expand Down Expand Up @@ -30,8 +37,19 @@ export const projectIssues = (id: string): string => `/projects/${id}/issues`;
export const projectIssue = (id: string): string => `/projects/${id}/issue`;
export const projectRevisions = (id: string): string =>
`/projects/${id}/revisions`;
export const projectSource = (id: string): string => {
return `/projects/${id}/source`;
export const projectSource = (
id: string,
revision: string,
objectType: string,
path: string
): string => {
if (revision && path) {
return `/projects/${id}/source/${revision}/${objectType}/${
objectType === ObjectType.Tree ? `${path}/` : path
}`;
} else {
return `/projects/${id}/source`;
}
};
export const projectCommit = (id: string, hash: string): string =>
`/projects/${id}/commit/${hash}`;
Expand All @@ -50,3 +68,18 @@ export const active = (
): boolean => {
return regexparam(path, loose).pattern.test(location);
};

export const extractProjectSourceRevision = (location: string): string => {
const rev = PROJECT_SOURCE_PATH_MATCH.exec(location);
return rev === null ? config.DEFAULT_PROJECT_REVISION : rev[1];
};

export const extractProjectSourceObjectPath = (location: string): string => {
const path = PROJECT_SOURCE_PATH_MATCH.exec(location);
return path === null ? "" : path[3];
};

export const extractProjectSourceObjectType = (location: string): string => {
const type = PROJECT_SOURCE_PATH_MATCH.exec(location);
return type === null ? ObjectType.Tree : type[2];
};

0 comments on commit df7cfdc

Please sign in to comment.