Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
c3f9e63
GitHubLoginDataSource returns logins with avatars
simonbs Jul 25, 2024
4a10be1
Adds missing space
simonbs Jul 25, 2024
d093392
Adds back New Project button
simonbs Jul 25, 2024
5bb7627
Merge branch 'enhancement/githubprojectdatasource-refactor' into enha…
simonbs Jul 25, 2024
61715bd
Merge branch 'enhancement/adds-avatars-to-logins' into feature/new-pr…
simonbs Jul 25, 2024
724e63d
Merge branch 'feature/filter-repositories' into enhancement/adds-avat…
simonbs Jul 25, 2024
9acb346
Merge branch 'enhancement/adds-avatars-to-logins' into feature/new-pr…
simonbs Jul 25, 2024
4fc36ba
Merge branch 'feature/filter-repositories' into enhancement/adds-avat…
simonbs Jul 25, 2024
fd50dc3
Merge branch 'enhancement/adds-avatars-to-logins' into feature/new-pr…
simonbs Jul 25, 2024
90134be
Reverts GitHubLogin type
simonbs Jul 25, 2024
a8a4af4
Adds NewProjectPage
simonbs Jul 25, 2024
af18ca6
Streamlines imports in tests
simonbs Jul 26, 2024
e41031c
Removes unneeded file
simonbs Jul 26, 2024
beca053
Removes unused types
simonbs Jul 26, 2024
fb700c0
Removes InvalidSessionPage
simonbs Jul 26, 2024
b269445
Rearchitects app to share sidebar in layout
simonbs Jul 26, 2024
af44f64
Removes _old_sidebar
simonbs Jul 26, 2024
de45dd9
Fixes linting errors
simonbs Jul 26, 2024
e503107
Moves sidebar types to internal
simonbs Jul 26, 2024
ff8651e
Truncates texts
simonbs Jul 26, 2024
ec4c86d
Removes unused comment
simonbs Jul 26, 2024
4da59f4
Removes extraneous whitspace
simonbs Jul 26, 2024
b8d077b
Reorders imports
simonbs Jul 26, 2024
0066059
Adds back header
simonbs Jul 26, 2024
6f7020c
Fixes toolbar being force shown
simonbs Jul 26, 2024
321f3dd
Moves canToggleSidebar to layout
simonbs Jul 26, 2024
8cc81c2
Uses React.ReactNode
simonbs Jul 26, 2024
0ab2896
Fixes linting warning
simonbs Jul 26, 2024
d18a6e2
Hides header when no project is selected
simonbs Jul 26, 2024
ddb0aff
Fixes sidebar not visible
simonbs Jul 26, 2024
3ed34f4
Merge branch 'feature/filter-repositories' into enhancement/restructu…
simonbs Jul 26, 2024
f02a2d8
Merge branch 'develop' into enhancement/restructure-layout
simonbs Jul 29, 2024
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 .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ POSTGRESQL_PASSWORD=
POSTGRESQL_DB=shape-docs
REPOSITORY_NAME_SUFFIX=-openapi
HIDDEN_REPOSITORIES=
NEW_PROJECT_TEMPLATE_REPOSITORY=shapehq/starter-openapi
GITHUB_WEBHOOK_SECRET=preshared secret also put in app configuration in GitHub
GITHUB_WEBHOK_REPOSITORY_ALLOWLIST=
GITHUB_WEBHOK_REPOSITORY_DISALLOWLIST=
Expand Down
2 changes: 1 addition & 1 deletion __test__/auth/AuthjsAccountsOAuthTokenRepository.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AuthjsAccountsOAuthTokenRepository } from "../../src/features/auth/domain"
import { AuthjsAccountsOAuthTokenRepository } from "@/features/auth/domain"

test("It gets token for user ID and provider", async () => {
let queryUserId: string | undefined
Expand Down
2 changes: 1 addition & 1 deletion __test__/auth/CompositeLogOutHandler.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CompositeLogOutHandler } from "../../src/features/auth/domain"
import { CompositeLogOutHandler } from "@/features/auth/domain"

test("It invokes all log out handlers", async () => {
let didCallLogOutHandler1 = false
Expand Down
2 changes: 1 addition & 1 deletion __test__/auth/ErrorIgnoringLogOutHandler.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ErrorIgnoringLogOutHandler } from "../../src/features/auth/domain"
import { ErrorIgnoringLogOutHandler } from "@/features/auth/domain"

test("It ignores errors", async () => {
const sut = new ErrorIgnoringLogOutHandler({
Expand Down
2 changes: 1 addition & 1 deletion __test__/auth/LockingAccessTokenRefresher.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { LockingOAuthTokenRefresher } from "../../src/features/auth/domain"
import { LockingOAuthTokenRefresher } from "@/features/auth/domain"

test("It acquires a lock", async () => {
let didAcquireLock = false
Expand Down
2 changes: 1 addition & 1 deletion __test__/auth/LogInHandler.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { LogInHandler } from "../../src/features/auth/domain"
import { LogInHandler } from "@/features/auth/domain"

test("It disallows logging in when account is undefined", async () => {
const sut = new LogInHandler({
Expand Down
2 changes: 1 addition & 1 deletion __test__/auth/OAuthTokenDataSource.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { OAuthTokenDataSource } from "../../src/features/auth/domain"
import { OAuthTokenDataSource } from "@/features/auth/domain"

test("It reads OAuth token for user's ID", async () => {
let readUserId: string | undefined
Expand Down
2 changes: 1 addition & 1 deletion __test__/auth/OAuthTokenRepository.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { OAuthTokenRepository } from "../../src/features/auth/domain"
import { OAuthTokenRepository } from "@/features/auth/domain"

test("It reads the auth token for the specified user", async () => {
let readProvider: string | undefined
Expand Down
2 changes: 1 addition & 1 deletion __test__/auth/OAuthTokenSessionValidator.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { OAuthTokenSessionValidator, SessionValidity } from "../../src/features/auth/domain"
import { OAuthTokenSessionValidator, SessionValidity } from "@/features/auth/domain"

test("It reads the access token", async () => {
let didReadOAuthToken = false
Expand Down
2 changes: 1 addition & 1 deletion __test__/auth/PersistingOAuthTokenRefresher.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { PersistingOAuthTokenRefresher, OAuthToken } from "../../src/features/auth/domain"
import { PersistingOAuthTokenRefresher, OAuthToken } from "@/features/auth/domain"

test("It refreshes OAuth token using provided refresh token", async () => {
let usedRefreshToken: string | undefined
Expand Down
2 changes: 1 addition & 1 deletion __test__/auth/UserDataCleanUpLogOutHandler.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { UserDataCleanUpLogOutHandler } from "../../src/features/auth/domain"
import { UserDataCleanUpLogOutHandler } from "@/features/auth/domain"

test("It deletes data for the read user ID", async () => {
let deletedUserId: string | undefined
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { OAuthTokenRefreshingGitHubClient } from "@/common"
import {
OAuthTokenRefreshingGitHubClient,
GraphQLQueryRequest,
GetRepositoryContentRequest,
GetPullRequestCommentsRequest,
AddCommentToPullRequestRequest
} from "@/common/github/IGitHubClient"
} from "@/common"

test("It forwards a GraphQL request", async () => {
let forwardedRequest: GraphQLQueryRequest | undefined
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import listFromCommaSeparatedString from "@/common/utils/listFromCommaSeparatedString"
import { listFromCommaSeparatedString } from "@/common"

test("It returns an empty list given undefined", async () => {
const result = listFromCommaSeparatedString(undefined)
Expand Down
2 changes: 1 addition & 1 deletion __test__/common/utils/saneParseInt.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import saneParseInt from "@/common/utils/saneParseInt"
import { saneParseInt } from "@/common"

test("It parses an integer", async () => {
// @ts-ignore
Expand Down
2 changes: 1 addition & 1 deletion __test__/hooks/FilteringPullRequestEventHandler.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FilteringPullRequestEventHandler } from "../../src/features/hooks/domain"
import { FilteringPullRequestEventHandler } from "@/features/hooks/domain"

test("It calls pullRequestOpened(_:) when event is included", async () => {
let didCall = false
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { PostCommentPullRequestEventHandler } from "../../src/features/hooks/domain"
import { PostCommentPullRequestEventHandler } from "@/features/hooks/domain"

test("It comments when opening a pull request", async () => {
let didComment = false
Expand Down
2 changes: 1 addition & 1 deletion __test__/hooks/PullRequestCommenter.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { PullRequestCommenter } from "../../src/features/hooks/domain"
import { PullRequestCommenter } from "@/features/hooks/domain"

test("It adds comment when none exist", async () => {
let didAddComment = false
Expand Down
2 changes: 1 addition & 1 deletion __test__/hooks/RepositoryNameEventFilter.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { RepositoryNameEventFilter } from "../../src/features/hooks/domain"
import { RepositoryNameEventFilter } from "@/features/hooks/domain"

test("It does not include repositories that do not have the \"-openapi\" suffix", async () => {
const sut = new RepositoryNameEventFilter({
Expand Down
2 changes: 1 addition & 1 deletion __test__/projects/CachingProjectDataSource.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Project, CachingProjectDataSource } from "../../src/features/projects/domain"
import { Project, CachingProjectDataSource } from "@/features/projects/domain"

test("It caches projects read from the data source", async () => {
const projects: Project[] = [{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FilteringGitHubRepositoryDataSource } from "../../src/features/projects/domain"
import { FilteringGitHubRepositoryDataSource } from "@/features/projects/domain"

test("It returns all repositories when no hidden repositories are provided", async () => {
const sut = new FilteringGitHubRepositoryDataSource({
Expand Down
4 changes: 1 addition & 3 deletions __test__/projects/GitHubProjectDataSource.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import {
GitHubProjectDataSource
} from "../../src/features/projects/data"
import { GitHubProjectDataSource } from "@/features/projects/data"

test("It loads repositories from data source", async () => {
let didLoadRepositories = false
Expand Down
4 changes: 1 addition & 3 deletions __test__/projects/GitHubRepositoryDataSource.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import {
GitHubRepositoryDataSource
} from "../../src/features/projects/data"
import { GitHubRepositoryDataSource } from "@/features/projects/data"

test("It loads repositories from data source", async () => {
let didLoadRepositories = false
Expand Down
2 changes: 1 addition & 1 deletion __test__/projects/ProjectConfigParser.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ProjectConfigParser } from "../../src/features/projects/domain"
import { ProjectConfigParser } from "@/features/projects/domain"

test("It parses an empty string", async () => {
const sut = new ProjectConfigParser()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { getSelection } from "../../src/features/projects/domain"
import { getProjectSelectionFromPath } from "@/features/projects/domain"

test("It selects the first project when there is only one project and path is empty", () => {
const sut = getSelection({
const sut = getProjectSelectionFromPath({
path: "",
projects: [{
id: "foo",
Expand All @@ -28,7 +28,7 @@ test("It selects the first project when there is only one project and path is em
})

test("It selects the first version and specification of the specified project", () => {
const sut = getSelection({
const sut = getProjectSelectionFromPath({
path: "/acme/bar",
projects: [{
id: "foo",
Expand Down Expand Up @@ -71,7 +71,7 @@ test("It selects the first version and specification of the specified project",
})

test("It selects the first specification of the specified project and version", () => {
const sut = getSelection({
const sut = getProjectSelectionFromPath({
path: "/acme/bar/baz2",
projects: [{
id: "foo",
Expand Down Expand Up @@ -110,7 +110,7 @@ test("It selects the first specification of the specified project and version",
})

test("It selects the specification of the specified version", () => {
const sut = getSelection({
const sut = getProjectSelectionFromPath({
path: "/acme/bar/baz2",
projects: [{
id: "foo",
Expand Down Expand Up @@ -153,7 +153,7 @@ test("It selects the specification of the specified version", () => {
})

test("It selects the specified project, version, and specification", () => {
const sut = getSelection({
const sut = getProjectSelectionFromPath({
path: "/acme/bar/baz2/hello2",
projects: [{
id: "foo",
Expand Down Expand Up @@ -196,7 +196,7 @@ test("It selects the specified project, version, and specification", () => {
})

test("It returns a undefined project, version, and specification when the selected project cannot be found", () => {
const sut = getSelection({
const sut = getProjectSelectionFromPath({
path: "/acme/foo",
projects: [{
id: "bar",
Expand All @@ -213,7 +213,7 @@ test("It returns a undefined project, version, and specification when the select
})

test("It returns a undefined version and specification when the selected version cannot be found", () => {
const sut = getSelection({
const sut = getProjectSelectionFromPath({
path: "/acme/foo/bar",
projects: [{
id: "foo",
Expand All @@ -236,7 +236,7 @@ test("It returns a undefined version and specification when the selected version
})

test("It returns a undefined specification when the selected specification cannot be found", () => {
const sut = getSelection({
const sut = getProjectSelectionFromPath({
path: "/acme/foo/bar/baz",
projects: [{
id: "foo",
Expand All @@ -263,7 +263,7 @@ test("It returns a undefined specification when the selected specification canno
})

test("It moves specification ID to version ID if needed", () => {
const sut = getSelection({
const sut = getProjectSelectionFromPath({
path: "/acme/foo/bar/baz",
projects: [{
id: "foo",
Expand Down
2 changes: 1 addition & 1 deletion __test__/projects/projectNavigator.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ProjectNavigator } from "../../src/features/projects/domain"
import { ProjectNavigator } from "@/features/projects/domain"

test("It navigates to the correct path", async () => {
let pushedPath: string | undefined
Expand Down
2 changes: 1 addition & 1 deletion __test__/projects/updateWindowTitle.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { updateWindowTitle } from "../../src/features/projects/domain"
import { updateWindowTitle } from "@/features/projects/domain"

test("It uses default title when there is no selection", async () => {
const store: { title: string } = { title: "" }
Expand Down
23 changes: 23 additions & 0 deletions src/app/(authed)/(home)/[[...slug]]/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
"use client"

import SecondarySplitHeader from "@/features/sidebar/view/SecondarySplitHeader"
import TrailingToolbarItem from "@/features/projects/view/toolbar/TrailingToolbarItem"
import MobileToolbar from "@/features/projects/view/toolbar/MobileToolbar"
import { useProjectSelection } from "@/features/projects/data"

export default function Page({ children }: { children: React.ReactNode }) {
const { project } = useProjectSelection()
if (!project) {
return <></>
}
return (
<>
<SecondarySplitHeader mobileToolbar=<MobileToolbar/>>
<TrailingToolbarItem/>
</SecondarySplitHeader>
<main style={{ flexGrow: "1", overflowY: "auto" }}>
{children}
</main>
</>
)
}
43 changes: 43 additions & 0 deletions src/app/(authed)/(home)/[[...slug]]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"use client"

import { useContext, useEffect } from "react"
import { ProjectsContainerContext } from "@/common"
import DelayedLoadingIndicator from "@/common/ui/DelayedLoadingIndicator"
import ErrorMessage from "@/common/ui/ErrorMessage"
import { updateWindowTitle } from "@/features/projects/domain"
import { useProjectSelection } from "@/features/projects/data"
import Documentation from "@/features/projects/view/Documentation"

export default function Page() {
const { error, isLoading } = useContext(ProjectsContainerContext)
const { project, version, specification, navigateToSelectionIfNeeded } = useProjectSelection()
// Ensure the URL reflects the current selection of project, version, and specification.
useEffect(() => {
navigateToSelectionIfNeeded()
}, [project, version, specification, navigateToSelectionIfNeeded])
// Update the window title to match selected project.
const siteName = process.env.NEXT_PUBLIC_SHAPE_DOCS_TITLE || ""
useEffect(() => {
updateWindowTitle({
storage: document,
defaultTitle: siteName,
project,
version,
specification
})
}, [siteName, project, version, specification])
if (project && version && specification) {
return <Documentation url={specification.url}/>
} else if (project && !version) {
return <ErrorMessage text="The selected branch or tag was not found."/>
} else if (project && !specification) {
return <ErrorMessage text="The selected specification was not found."/>
} else if (isLoading) {
return <DelayedLoadingIndicator/>
} else if (error) {
return <ErrorMessage text={error.message}/>
} else {
// No project is selected so we will not show anything.
return <></>
}
}
36 changes: 36 additions & 0 deletions src/app/(authed)/(home)/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"use client"

import { useContext } from "react"
import { SplitView } from "@/features/sidebar/view"
import { useProjects, useProjectSelection } from "@/features/projects/data"
import {
ProjectsContainerContext,
ServerSideCachedProjectsContext
} from "@/common"

export default function Layout({ children }: { children: React.ReactNode }) {
const { projects, error, isLoading } = useProjects()
// Update projects provided to child components, using cached projects from the server if needed.
const serverSideCachedProjects = useContext(ServerSideCachedProjectsContext)
const newProjectsContainer = { projects, error, isLoading }
if (isLoading && serverSideCachedProjects) {
newProjectsContainer.isLoading = false
newProjectsContainer.projects = serverSideCachedProjects
}
return (
<ProjectsContainerContext.Provider value={newProjectsContainer}>
<SplitViewWrapper>
{children}
</SplitViewWrapper>
</ProjectsContainerContext.Provider>
)
}

const SplitViewWrapper = ({ children }: { children: React.ReactNode }) => {
const { project } = useProjectSelection()
return (
<SplitView canToggleSidebar={project !== undefined}>
{children}
</SplitView>
)
}
Loading