Skip to content

Commit

Permalink
API integrations + simplify design (#46)
Browse files Browse the repository at this point in the history
  • Loading branch information
tan-nhu committed Oct 25, 2022
1 parent 2d897c4 commit c8b978a
Show file tree
Hide file tree
Showing 90 changed files with 8,546 additions and 5,809 deletions.
11 changes: 2 additions & 9 deletions web/config/moduleFederation.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,8 @@ module.exports = {
},
exposes: {
'./App': './src/App.tsx',
'./Welcome': './src/views/Welcome/Welcome.tsx',
'./Repos': './src/views/Repos/Repos.tsx',
'./RepoFiles': './src/views/RepoFiles/RepoFiles.tsx',
'./RepoFileDetails': './src/views/RepoFileDetails/RepoFileDetails.tsx',
'./RepoCommits': './src/views/RepoCommits/RepoCommits.tsx',
'./RepoCommitDetails': './src/views/RepoCommitDetails/RepoCommitDetails.tsx',
'./RepoPullRequests': './src/views/RepoPullRequests/RepoPullRequests.tsx',
'./RepoPullRequestDetails': './src/views/RepoPullRequestDetails/RepoPullRequestDetails.tsx',
'./RepoSettings': './src/views/RepoSettings/RepoSettings.tsx'
'./RepositoriesListing': './src/pages/RepositoriesListing/RepositoriesListing.tsx',
'./Repository': './src/pages/Repository/Repository.tsx'
},
shared: {
formik: packageJSON.dependencies['formik'],
Expand Down
66 changes: 64 additions & 2 deletions web/config/webpack.dev.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const devConfig = {
hot: true,
host: 'localhost',
historyApiFallback: true,
port: 3001,
port: 3020,
proxy: {
'/api': {
target: targetLocalHost ? 'http:https://localhost:3000' : baseUrl,
Expand Down Expand Up @@ -64,7 +64,69 @@ const devConfig = {
}),
new MonacoWebpackPlugin({
// available options are documented at https://github.com/Microsoft/monaco-editor-webpack-plugin#options
languages: ['yaml', 'json']
languages: [
'abap',
'apex',
'azcli',
'bat',
'cameligo',
'clojure',
'coffee',
'cpp',
'csharp',
'csp',
'css',
'dockerfile',
'fsharp',
'go',
'graphql',
'handlebars',
'html',
'ini',
'java',
'javascript',
'json',
'kotlin',
'less',
'lua',
'markdown',
'mips',
'msdax',
'mysql',
'objective-c',
'pascal',
'pascaligo',
'perl',
'pgsql',
'php',
'postiats',
'powerquery',
'powershell',
'pug',
'python',
'r',
'razor',
'redis',
'redshift',
'restructuredtext',
'ruby',
'rust',
'sb',
'scheme',
'scss',
'shell',
'solidity',
'sophia',
'sql',
'st',
'swift',
'tcl',
'twig',
'typescript',
'vb',
'xml',
'yaml'
]
})
// new ForkTsCheckerWebpackPlugin()
// new WatchIgnorePlugin({
Expand Down
4 changes: 3 additions & 1 deletion web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
"@harness/use-modal": ">=1.1.0",
"@popperjs/core": "^2.4.2",
"@projectstorm/react-diagrams-core": "^6.6.0",
"@uiw/react-markdown-preview": "^4.1.0",
"@uiw/react-markdown-preview": "^4.1.2",
"@urql/exchange-request-policy": "^0.1.3",
"anser": "^2.0.1",
"classnames": "^2.2.6",
Expand All @@ -64,6 +64,7 @@
"idb": "^5.0.4",
"immer": "^9.0.6",
"jsonc-parser": "^2.0.2",
"lang-map": "^0.4.0",
"lodash-es": "^4.17.15",
"marked": "^4.0.12",
"masonry-layout": "^4.2.2",
Expand All @@ -82,6 +83,7 @@
"react-contenteditable": "^3.3.5",
"react-dom": "^17.0.2",
"react-draggable": "^4.4.2",
"react-join": "^1.1.4",
"react-lottie-player": "^1.4.0",
"react-markdown": "^8.0.3",
"react-monaco-editor": "^0.34.0",
Expand Down
23 changes: 9 additions & 14 deletions web/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type { AppProps } from 'AppProps'
import { buildResfulReactRequestOptions, handle401 } from 'AppUtils'
import { RouteDestinations } from 'RouteDestinations'
import { useAPIToken } from 'hooks/useAPIToken'
import { routes as _routes } from 'RouteDefinitions'
import { languageLoader } from './framework/strings/languageLoader'
import type { LanguageRecord } from './framework/strings/languageLoader'
import { StringsContextProvider } from './framework/strings/StringsContextProvider'
Expand All @@ -19,37 +20,31 @@ FocusStyleManager.onlyShowFocusOnTabs()

const App: React.FC<AppProps> = React.memo(function App({
standalone = false,
accountId = '',
space = '',
routes = _routes,
lang = 'en',
apiToken,
on401 = handle401,
children,
hooks = {},
components = {}
}: AppProps) {
const [strings, setStrings] = useState<LanguageRecord>()
const [token, setToken] = useAPIToken(apiToken)
const token = useAPIToken()
const getRequestOptions = useCallback(
(): Partial<RequestInit> => buildResfulReactRequestOptions(hooks.useGetToken?.() || apiToken || token),
[apiToken, token, hooks]
) // eslint-disable-line react-hooks/exhaustive-deps
(): Partial<RequestInit> => buildResfulReactRequestOptions(hooks.useGetToken?.() || token),
[token, hooks]
)

useEffect(() => {
languageLoader(lang).then(setStrings)
}, [lang, setStrings])

useEffect(() => {
if (!apiToken) {
setToken(token)
}
}, [apiToken, token, setToken])

return strings ? (
<StringsContextProvider initialStrings={strings}>
<AppErrorBoundary>
<AppContextProvider value={{ standalone, accountId, lang, on401, hooks, components }}>
<AppContextProvider value={{ standalone, space, routes, lang, on401, hooks, components }}>
<RestfulProvider
base="/"
base={standalone ? '/' : '/scm'}
requestOptions={getRequestOptions}
queryParams={{}}
queryParamStringifyOptions={{ skipNulls: true }}
Expand Down
10 changes: 9 additions & 1 deletion web/src/AppContext.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { useState, useContext } from 'react'
import React, { useState, useContext, useEffect } from 'react'
import { noop } from 'lodash-es'
import type { AppProps } from 'AppProps'
import { routes } from 'RouteDefinitions'

interface AppContextProps extends AppProps {
setAppContext: (value: Partial<AppProps>) => void
Expand All @@ -9,6 +10,7 @@ interface AppContextProps extends AppProps {
const AppContext = React.createContext<AppContextProps>({
standalone: true,
setAppContext: noop,
routes,
hooks: {},
components: {}
})
Expand All @@ -19,6 +21,12 @@ export const AppContextProvider: React.FC<{ value: AppProps }> = React.memo(func
}) {
const [appStates, setAppStates] = useState<AppProps>(initialValue)

useEffect(() => {
if (initialValue.space && initialValue.space !== appStates.space) {
setAppStates({ ...appStates, ...initialValue })
}
}, [initialValue, appStates])

return (
<AppContext.Provider
value={{
Expand Down
11 changes: 6 additions & 5 deletions web/src/AppProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type React from 'react'
import type * as History from 'history'
import type { PermissionOptionsMenuButtonProps } from 'components/Permissions/PermissionsOptionsMenuButton'
import type { Unknown } from 'utils/Utils'
import type { SCMRoutes } from 'RouteDefinitions'
import type { LangLocale } from './framework/strings/languageLoader'

/**
Expand All @@ -28,15 +29,15 @@ export interface AppProps {
/** App children. When provided, children is a remote view which will be mounted under App contexts */
children?: React.ReactNode

/** Active account id when app is embedded */
accountId?: string
/** Active space when app is embedded */
space?: string

/** Routing utlis (used to generate app specific URLs) */
routes: SCMRoutes

/** Language to use in the app, default is 'en' */
lang?: LangLocale

/** API token to be used in Restful React */
apiToken?: string

/** 401 handler. Used in parent app to override 401 handling from child app */
on401?: () => void

Expand Down
141 changes: 65 additions & 76 deletions web/src/RouteDefinitions.ts
Original file line number Diff line number Diff line change
@@ -1,88 +1,77 @@
interface PathProps {
accountId: string
orgIdentifier: string
projectIdentifier: string
export interface SCMPathProps {
space?: string
repoName?: string
branchName?: string
filePath?: string
pullRequestId?: string
commitId?: string
gitRef?: string
resourcePath?: string
}

interface QueryProps {}
export interface SCMQueryProps {
branch?: string
filePath?: string
}

export const pathProps: Readonly<Required<PathProps>> = {
accountId: ':accountId',
orgIdentifier: ':orgIdentifier',
projectIdentifier: ':projectIdentifier',
export const pathProps: Readonly<Required<SCMPathProps>> = {
space: ':space',
repoName: ':repoName',
branchName: ':branchName',
filePath: ':filePath',
pullRequestId: ':pullRequestId',
commitId: ':commitId'
gitRef: ':gitRef*',
resourcePath: ':resourcePath'
}

function withAccountId<T>(fn: (args: T) => string) {
return (params: T & { accountId: string }): string => {
const path = fn(params)
return `/account/${params.accountId}/${path.replace(/^\//, '')}`
}
// function withAccountId<T>(fn: (args: T) => string) {
// return (params: T & { accountId: string }): string => {
// const path = fn(params)
// return `/account/${params.accountId}/${path.replace(/^\//, '')}`
// }
// }

// function withQueryParams(path: string, params: Record<string, string>): string {
// return Object.entries(params).every(([key, value]) => ':' + key === value)
// ? path
// : [
// path,
// Object.entries(params)
// .reduce((value, entry) => {
// value.push(entry.join('='))
// return value
// }, [] as string[])
// .join('&')
// ].join('?')
// }

export interface SCMRoutes {
toSignIn: () => string
toSignUp: () => string
toSCMRepositoriesListing: ({ space }: { space: string }) => string
toSCMRepository: ({
repoPath,
gitRef,
resourcePath
}: {
repoPath: string
gitRef?: string
resourcePath?: string
}) => string
}

export default {
export const routes: SCMRoutes = {
toSignIn: (): string => '/signin',
toSignUp: (): string => '/signup',

toSCM: withAccountId(() => `/scm`),
toSCMHome: withAccountId(() => `/scm/home`),
toSCMRepos: withAccountId(
({ orgIdentifier, projectIdentifier }: PathProps) =>
`/scm/orgs/${orgIdentifier}/projects/${projectIdentifier}/repos`
),
toSCMRepoSettings: withAccountId(
({ orgIdentifier, projectIdentifier, repoName }: RequireField<PathProps, 'repoName'>) =>
`/scm/orgs/${orgIdentifier}/projects/${projectIdentifier}/repos/${repoName}/settings`
),
toSCMFiles: withAccountId(
({ orgIdentifier, projectIdentifier, repoName, branchName }: RequireField<PathProps, 'repoName' | 'branchName'>) =>
`/scm/orgs/${orgIdentifier}/projects/${projectIdentifier}/repos/${repoName}/branches/${branchName}`
),
toSCMFileDetails: withAccountId(
({
orgIdentifier,
projectIdentifier,
repoName,
branchName,
filePath
}: RequireField<PathProps, 'repoName' | 'branchName' | 'filePath'>) =>
`/scm/orgs/${orgIdentifier}/projects/${projectIdentifier}/repos/${repoName}/branches/${branchName}/files/${filePath}`
),
toSCMPullRequests: withAccountId(
({ orgIdentifier, projectIdentifier, repoName, branchName }: RequireField<PathProps, 'repoName' | 'branchName'>) =>
`/scm/orgs/${orgIdentifier}/projects/${projectIdentifier}/repos/${repoName}/branches/${branchName}/pull-requests`
),
toSCMPullRequestDetails: withAccountId(
({
orgIdentifier,
projectIdentifier,
repoName,
branchName,
pullRequestId
}: RequireField<PathProps, 'repoName' | 'branchName' | 'pullRequestId'>) =>
`/scm/orgs/${orgIdentifier}/projects/${projectIdentifier}/repos/${repoName}/branches/${branchName}/pull-requests/${pullRequestId}`
),
toSCMCommits: withAccountId(
({ orgIdentifier, projectIdentifier, repoName, branchName }: RequireField<PathProps, 'repoName' | 'branchName'>) =>
`/scm/orgs/${orgIdentifier}/projects/${projectIdentifier}/repos/${repoName}/branches/${branchName}/commits`
),
toSCMCommitDetails: withAccountId(
({
orgIdentifier,
projectIdentifier,
repoName,
branchName,
commitId
}: RequireField<PathProps, 'repoName' | 'branchName' | 'commitId'>) =>
`/scm/orgs/${orgIdentifier}/projects/${projectIdentifier}/repos/${repoName}/branches/${branchName}/commits/${commitId}`
)
toSCMRepositoriesListing: ({ space }: { space: string }) => {
const [accountId, orgIdentifier, projectIdentifier] = space.split('/')
return `/account/${accountId}/code/${orgIdentifier}/${projectIdentifier}`
},
toSCMRepository: ({
repoPath,
gitRef,
resourcePath
}: {
repoPath: string
gitRef?: string
resourcePath?: string
}) => {
const [accountId, orgIdentifier, projectIdentifier, repoName] = repoPath.split('/')
return `/account/${accountId}/code/${orgIdentifier}/${projectIdentifier}/${repoName}${gitRef ? '/' + gitRef : ''}${
resourcePath ? '/~/' + resourcePath : ''
}`
}
}
Loading

0 comments on commit c8b978a

Please sign in to comment.