Add T prefix for all type defs
This commit is contained in:
parent
db96b95522
commit
264f5aba60
@ -1,6 +0,0 @@
|
|||||||
import {IAction} from './IAction'
|
|
||||||
|
|
||||||
export type GetAction<MyTypes, T extends string> =
|
|
||||||
MyTypes extends IAction<infer U, T>
|
|
||||||
? MyTypes
|
|
||||||
: never
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
import {IAsyncAction} from './IAsyncAction'
|
|
||||||
|
|
||||||
export type GetPendingAction<MyTypes, T extends string> =
|
|
||||||
MyTypes extends IAsyncAction<infer U, T> & {status: 'pending'}
|
|
||||||
? MyTypes
|
|
||||||
: never
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
import {IAsyncAction} from './IAsyncAction'
|
|
||||||
|
|
||||||
export type GetResolvedAction<MyTypes, T extends string> =
|
|
||||||
MyTypes extends IAsyncAction<infer U, T> & {status: 'resolved'}
|
|
||||||
? MyTypes
|
|
||||||
: never
|
|
||||||
@ -2,9 +2,9 @@ import {IPendingAction} from './IPendingAction'
|
|||||||
import {IResolvedAction} from './IResolvedAction'
|
import {IResolvedAction} from './IResolvedAction'
|
||||||
import {IRejectedAction} from './IRejectedAction'
|
import {IRejectedAction} from './IRejectedAction'
|
||||||
|
|
||||||
export type IAsyncStatus = 'pending' | 'resolved' | 'rejected'
|
export type TAsyncStatus = 'pending' | 'resolved' | 'rejected'
|
||||||
|
|
||||||
export type IAsyncAction<T, ActionType extends string> =
|
export type TAsyncAction<T, ActionType extends string> =
|
||||||
IPendingAction<T, ActionType>
|
IPendingAction<T, ActionType>
|
||||||
| IResolvedAction<T, ActionType>
|
| IResolvedAction<T, ActionType>
|
||||||
| IRejectedAction<ActionType>
|
| IRejectedAction<ActionType>
|
||||||
6
packages/client/src/actions/TGetAction.ts
Normal file
6
packages/client/src/actions/TGetAction.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import {IAction} from './IAction'
|
||||||
|
|
||||||
|
export type TGetAction<ActionTypes, T extends string> =
|
||||||
|
ActionTypes extends IAction<infer U, T>
|
||||||
|
? ActionTypes
|
||||||
|
: never
|
||||||
6
packages/client/src/actions/TGetPendingAction.ts
Normal file
6
packages/client/src/actions/TGetPendingAction.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import {TAsyncAction} from './TAsyncAction'
|
||||||
|
|
||||||
|
export type TGetPendingAction<MyTypes, T extends string> =
|
||||||
|
MyTypes extends TAsyncAction<infer U, T> & {status: 'pending'}
|
||||||
|
? MyTypes
|
||||||
|
: never
|
||||||
6
packages/client/src/actions/TGetResolvedAction.ts
Normal file
6
packages/client/src/actions/TGetResolvedAction.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import {TAsyncAction} from './TAsyncAction'
|
||||||
|
|
||||||
|
export type TGetResolvedAction<MyTypes, T extends string> =
|
||||||
|
MyTypes extends TAsyncAction<infer U, T> & {status: 'resolved'}
|
||||||
|
? MyTypes
|
||||||
|
: never
|
||||||
@ -1,9 +1,9 @@
|
|||||||
export * from './GetAction'
|
|
||||||
export * from './GetResolvedAction'
|
|
||||||
export * from './GetPendingAction'
|
|
||||||
export * from './IAction'
|
export * from './IAction'
|
||||||
export * from './IAsyncAction'
|
|
||||||
export * from './IPendingAction'
|
export * from './IPendingAction'
|
||||||
export * from './IRejectedAction'
|
export * from './IRejectedAction'
|
||||||
export * from './IResolvedAction'
|
export * from './IResolvedAction'
|
||||||
export * from './PendingAction'
|
export * from './PendingAction'
|
||||||
|
export * from './TAsyncAction'
|
||||||
|
export * from './TGetAction'
|
||||||
|
export * from './TGetPendingAction'
|
||||||
|
export * from './TGetResolvedAction'
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import {createCRUDActions} from './CRUDActions'
|
import {createCRUDActions} from './CRUDActions'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {AnyAction} from 'redux'
|
import {AnyAction} from 'redux'
|
||||||
import {CRUDReducer, ICRUDMethod} from './'
|
import {CRUDReducer, TCRUDMethod} from './'
|
||||||
import {HTTPClientMock, TestUtils, getError} from '../test-utils'
|
import {HTTPClientMock, TestUtils, getError} from '../test-utils'
|
||||||
import {IMethod} from '@rondo/common'
|
import {TMethod} from '@rondo/common'
|
||||||
import {IPendingAction} from '../actions'
|
import {IPendingAction} from '../actions'
|
||||||
|
|
||||||
describe('CRUD', () => {
|
describe('CRUD', () => {
|
||||||
@ -100,7 +100,7 @@ describe('CRUD', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
function dispatch(
|
function dispatch(
|
||||||
method: ICRUDMethod,
|
method: TCRUDMethod,
|
||||||
action: IPendingAction<unknown, string>,
|
action: IPendingAction<unknown, string>,
|
||||||
) {
|
) {
|
||||||
store.dispatch(action)
|
store.dispatch(action)
|
||||||
@ -109,13 +109,13 @@ describe('CRUD', () => {
|
|||||||
return action
|
return action
|
||||||
}
|
}
|
||||||
|
|
||||||
function getUrl(method: ICRUDMethod) {
|
function getUrl(method: TCRUDMethod) {
|
||||||
return method === 'save' || method === 'findMany'
|
return method === 'save' || method === 'findMany'
|
||||||
? '/one/1/two'
|
? '/one/1/two'
|
||||||
: '/one/1/two/2'
|
: '/one/1/two/2'
|
||||||
}
|
}
|
||||||
|
|
||||||
function getHTTPMethod(method: ICRUDMethod): IMethod {
|
function getHTTPMethod(method: TCRUDMethod): TMethod {
|
||||||
switch (method) {
|
switch (method) {
|
||||||
case 'save':
|
case 'save':
|
||||||
return 'post'
|
return 'post'
|
||||||
@ -131,7 +131,7 @@ describe('CRUD', () => {
|
|||||||
|
|
||||||
describe('Promise rejections', () => {
|
describe('Promise rejections', () => {
|
||||||
const testCases: Array<{
|
const testCases: Array<{
|
||||||
method: ICRUDMethod
|
method: TCRUDMethod
|
||||||
params: any
|
params: any
|
||||||
}> = [{
|
}> = [{
|
||||||
method: 'findOne',
|
method: 'findOne',
|
||||||
@ -203,7 +203,7 @@ describe('CRUD', () => {
|
|||||||
const entity = {id: 100, name: 'test'}
|
const entity = {id: 100, name: 'test'}
|
||||||
|
|
||||||
const testCases: Array<{
|
const testCases: Array<{
|
||||||
method: ICRUDMethod
|
method: TCRUDMethod
|
||||||
params: any
|
params: any
|
||||||
body?: any
|
body?: any
|
||||||
response: any
|
response: any
|
||||||
|
|||||||
@ -1,12 +1,10 @@
|
|||||||
import {ICRUDAction} from './ICRUDAction'
|
import {TCRUDAction} from './TCRUDAction'
|
||||||
import {ICRUDMethod} from './ICRUDMethod'
|
import {TCRUDMethod} from './TCRUDMethod'
|
||||||
import {IHTTPClient, ITypedRequestParams} from '../http'
|
import {IHTTPClient, ITypedRequestParams} from '../http'
|
||||||
import {IRoutes, Filter, OnlyDefined} from '@rondo/common'
|
import {IRoutes, TFilter, TOnlyDefined} from '@rondo/common'
|
||||||
|
|
||||||
export type Optional<T> = T extends {} ? T : undefined
|
type TAction<T, ActionType extends string, Method extends TCRUDMethod> =
|
||||||
|
TFilter<TCRUDAction<T, ActionType>, {method: Method, status: 'pending'}>
|
||||||
type Action<T, ActionType extends string, Method extends ICRUDMethod> =
|
|
||||||
Filter<ICRUDAction<T, ActionType>, {method: Method, status: 'pending'}>
|
|
||||||
|
|
||||||
export class SaveActionCreator<
|
export class SaveActionCreator<
|
||||||
T extends IRoutes,
|
T extends IRoutes,
|
||||||
@ -20,10 +18,10 @@ export class SaveActionCreator<
|
|||||||
readonly type: ActionType,
|
readonly type: ActionType,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
save = (params: OnlyDefined<{
|
save = (params: TOnlyDefined<{
|
||||||
body: T[Route]['post']['body'],
|
body: T[Route]['post']['body'],
|
||||||
params: T[Route]['post']['params'],
|
params: T[Route]['post']['params'],
|
||||||
}>): Action<T[Route]['post']['response'], ActionType, 'save'> => {
|
}>): TAction<T[Route]['post']['response'], ActionType, 'save'> => {
|
||||||
const p = params as any
|
const p = params as any
|
||||||
return {
|
return {
|
||||||
payload: this.http.post(this.route, p.body, p.params),
|
payload: this.http.post(this.route, p.body, p.params),
|
||||||
@ -46,10 +44,10 @@ export class FindOneActionCreator<
|
|||||||
readonly type: ActionType,
|
readonly type: ActionType,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
findOne = (params: OnlyDefined<{
|
findOne = (params: TOnlyDefined<{
|
||||||
query: Optional<T[Route]['get']['query']>,
|
query: T[Route]['get']['query'],
|
||||||
params: T[Route]['get']['params'],
|
params: T[Route]['get']['params'],
|
||||||
}>): Action<T[Route]['get']['response'], ActionType, 'findOne'> => {
|
}>): TAction<T[Route]['get']['response'], ActionType, 'findOne'> => {
|
||||||
const p = params as any
|
const p = params as any
|
||||||
return {
|
return {
|
||||||
payload: this.http.get(this.route, p.query, p.params),
|
payload: this.http.get(this.route, p.query, p.params),
|
||||||
@ -73,10 +71,10 @@ export class UpdateActionCreator<
|
|||||||
readonly type: ActionType,
|
readonly type: ActionType,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
update = (params: OnlyDefined<{
|
update = (params: TOnlyDefined<{
|
||||||
body: T[Route]['put']['body'],
|
body: T[Route]['put']['body'],
|
||||||
params: T[Route]['put']['params'],
|
params: T[Route]['put']['params'],
|
||||||
}>): Action<T[Route]['put']['response'], ActionType, 'update'> => {
|
}>): TAction<T[Route]['put']['response'], ActionType, 'update'> => {
|
||||||
const p = params as any
|
const p = params as any
|
||||||
return {
|
return {
|
||||||
payload: this.http.put(this.route, p.body, p.params),
|
payload: this.http.put(this.route, p.body, p.params),
|
||||||
@ -100,10 +98,10 @@ export class RemoveActionCreator<
|
|||||||
readonly type: ActionType,
|
readonly type: ActionType,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
remove = (params: OnlyDefined<{
|
remove = (params: TOnlyDefined<{
|
||||||
body: Optional<T[Route]['delete']['body']>,
|
body: T[Route]['delete']['body'],
|
||||||
params: T[Route]['delete']['params'],
|
params: T[Route]['delete']['params'],
|
||||||
}>): Action<T[Route]['delete']['response'], ActionType, 'remove'> => {
|
}>): TAction<T[Route]['delete']['response'], ActionType, 'remove'> => {
|
||||||
const p = params as any
|
const p = params as any
|
||||||
return {
|
return {
|
||||||
payload: this.http.delete(this.route, p.body, p.params),
|
payload: this.http.delete(this.route, p.body, p.params),
|
||||||
@ -126,8 +124,8 @@ export class FindManyActionCreator<
|
|||||||
readonly type: ActionType,
|
readonly type: ActionType,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
findMany = (params: OnlyDefined<{
|
findMany = (params: TOnlyDefined<{
|
||||||
query: Optional<T[Route]['get']['query']>,
|
query: T[Route]['get']['query'],
|
||||||
params: T[Route]['get']['params'],
|
params: T[Route]['get']['params'],
|
||||||
}>): {
|
}>): {
|
||||||
payload: Promise<T[Route]['get']['response']>
|
payload: Promise<T[Route]['get']['response']>
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import {IAction, IResolvedAction} from '../actions'
|
import {IAction, IResolvedAction} from '../actions'
|
||||||
import {ICRUDAction} from './ICRUDAction'
|
import {TCRUDAction} from './TCRUDAction'
|
||||||
import {ICRUDMethod} from './ICRUDMethod'
|
import {TCRUDMethod} from './TCRUDMethod'
|
||||||
import {indexBy, without, Filter} from '@rondo/common'
|
import {indexBy, without, TFilter} from '@rondo/common'
|
||||||
|
|
||||||
export interface ICRUDEntity {
|
export interface ICRUDEntity {
|
||||||
readonly id: number
|
readonly id: number
|
||||||
@ -65,7 +65,7 @@ export class CRUDReducer<
|
|||||||
|
|
||||||
handleRejected = (
|
handleRejected = (
|
||||||
state: ICRUDState<T>,
|
state: ICRUDState<T>,
|
||||||
method: ICRUDMethod,
|
method: TCRUDMethod,
|
||||||
error: Error,
|
error: Error,
|
||||||
): ICRUDState<T> => {
|
): ICRUDState<T> => {
|
||||||
return {
|
return {
|
||||||
@ -82,7 +82,7 @@ export class CRUDReducer<
|
|||||||
|
|
||||||
handleLoading = (
|
handleLoading = (
|
||||||
state: ICRUDState<T>,
|
state: ICRUDState<T>,
|
||||||
method: ICRUDMethod,
|
method: TCRUDMethod,
|
||||||
): ICRUDState<T> => {
|
): ICRUDState<T> => {
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
@ -163,7 +163,7 @@ export class CRUDReducer<
|
|||||||
|
|
||||||
reduce = (
|
reduce = (
|
||||||
state: ICRUDState<T> | undefined,
|
state: ICRUDState<T> | undefined,
|
||||||
action: ICRUDAction<T, ActionType>,
|
action: TCRUDAction<T, ActionType>,
|
||||||
): ICRUDState<T> => {
|
): ICRUDState<T> => {
|
||||||
const {defaultState} = this
|
const {defaultState} = this
|
||||||
state = state || defaultState
|
state = state || defaultState
|
||||||
|
|||||||
@ -1,24 +0,0 @@
|
|||||||
import {IAsyncAction} from '../actions'
|
|
||||||
import {ICRUDMethod} from './ICRUDMethod'
|
|
||||||
|
|
||||||
export type ICRUDSaveAction<T, ActionType extends string> =
|
|
||||||
IAsyncAction<T, ActionType> & {method: Extract<ICRUDMethod, 'save'>}
|
|
||||||
|
|
||||||
export type ICRUDUpdateAction<T, ActionType extends string> =
|
|
||||||
IAsyncAction<T, ActionType> & {method: Extract<ICRUDMethod, 'update'>}
|
|
||||||
|
|
||||||
export type ICRUDRemoveAction<T, ActionType extends string> =
|
|
||||||
IAsyncAction<T, ActionType> & {method: Extract<ICRUDMethod, 'remove'>}
|
|
||||||
|
|
||||||
export type ICRUDFindOneAction<T, ActionType extends string> =
|
|
||||||
IAsyncAction<T, ActionType> & {method: Extract<ICRUDMethod, 'findOne'>}
|
|
||||||
|
|
||||||
export type ICRUDFindManyAction<T, ActionType extends string> =
|
|
||||||
IAsyncAction<T[], ActionType> & {method: Extract<ICRUDMethod, 'findMany'>}
|
|
||||||
|
|
||||||
export type ICRUDAction<T, ActionType extends string> =
|
|
||||||
ICRUDSaveAction<T, ActionType>
|
|
||||||
| ICRUDUpdateAction<T, ActionType>
|
|
||||||
| ICRUDRemoveAction<T, ActionType>
|
|
||||||
| ICRUDFindOneAction<T, ActionType>
|
|
||||||
| ICRUDFindManyAction<T, ActionType>
|
|
||||||
@ -1 +0,0 @@
|
|||||||
export type ICRUDMethod = 'save' | 'update' | 'findOne' | 'findMany' | 'remove'
|
|
||||||
24
packages/client/src/crud/TCRUDAction.ts
Normal file
24
packages/client/src/crud/TCRUDAction.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import {TAsyncAction} from '../actions'
|
||||||
|
import {TCRUDMethod} from './TCRUDMethod'
|
||||||
|
|
||||||
|
export type TCRUDSaveAction<T, ActionType extends string> =
|
||||||
|
TAsyncAction<T, ActionType> & {method: Extract<TCRUDMethod, 'save'>}
|
||||||
|
|
||||||
|
export type TCRUDUpdateAction<T, ActionType extends string> =
|
||||||
|
TAsyncAction<T, ActionType> & {method: Extract<TCRUDMethod, 'update'>}
|
||||||
|
|
||||||
|
export type TCRUDRemoveAction<T, ActionType extends string> =
|
||||||
|
TAsyncAction<T, ActionType> & {method: Extract<TCRUDMethod, 'remove'>}
|
||||||
|
|
||||||
|
export type TCRUDFindOneAction<T, ActionType extends string> =
|
||||||
|
TAsyncAction<T, ActionType> & {method: Extract<TCRUDMethod, 'findOne'>}
|
||||||
|
|
||||||
|
export type TCRUDFindManyAction<T, ActionType extends string> =
|
||||||
|
TAsyncAction<T[], ActionType> & {method: Extract<TCRUDMethod, 'findMany'>}
|
||||||
|
|
||||||
|
export type TCRUDAction<T, ActionType extends string> =
|
||||||
|
TCRUDSaveAction<T, ActionType>
|
||||||
|
| TCRUDUpdateAction<T, ActionType>
|
||||||
|
| TCRUDRemoveAction<T, ActionType>
|
||||||
|
| TCRUDFindOneAction<T, ActionType>
|
||||||
|
| TCRUDFindManyAction<T, ActionType>
|
||||||
1
packages/client/src/crud/TCRUDMethod.ts
Normal file
1
packages/client/src/crud/TCRUDMethod.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export type TCRUDMethod = 'save' | 'update' | 'findOne' | 'findMany' | 'remove'
|
||||||
@ -1,4 +1,4 @@
|
|||||||
export * from './CRUDActions'
|
export * from './CRUDActions'
|
||||||
export * from './CRUDReducer'
|
export * from './CRUDReducer'
|
||||||
export * from './ICRUDAction'
|
export * from './TCRUDAction'
|
||||||
export * from './ICRUDMethod'
|
export * from './TCRUDMethod'
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import {GetAction, IAction} from '../actions'
|
import {TGetAction, IAction} from '../actions'
|
||||||
|
|
||||||
export interface ICrumbLink {
|
export interface ICrumbLink {
|
||||||
name: string
|
name: string
|
||||||
@ -10,10 +10,10 @@ export interface ICrumbs {
|
|||||||
current: string
|
current: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CrumbsActionType =
|
export type TCrumbsAction =
|
||||||
IAction<ICrumbs, 'BREADCRUMBS_SET'>
|
IAction<ICrumbs, 'BREADCRUMBS_SET'>
|
||||||
|
|
||||||
type Action<T extends string> = GetAction<CrumbsActionType, T>
|
type Action<T extends string> = TGetAction<TCrumbsAction, T>
|
||||||
|
|
||||||
export class CrumbsActions {
|
export class CrumbsActions {
|
||||||
setCrumbs(breadcrumbs: ICrumbs): Action<'BREADCRUMBS_SET'> {
|
setCrumbs(breadcrumbs: ICrumbs): Action<'BREADCRUMBS_SET'> {
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
import {Crumb} from './Crumb'
|
import {Crumb} from './Crumb'
|
||||||
import {Connector, IStateSelector} from '../redux'
|
import {Connector, TStateSelector} from '../redux'
|
||||||
import {ICrumbsState} from './CrumbsReducer'
|
import {ICrumbsState} from './CrumbsReducer'
|
||||||
import {CrumbsActions} from './CrumbsActions'
|
import {CrumbsActions} from './CrumbsActions'
|
||||||
|
|
||||||
export class CrumbsConnector extends Connector<ICrumbsState> {
|
export class CrumbsConnector extends Connector<ICrumbsState> {
|
||||||
protected readonly breadcrumbsActions = new CrumbsActions()
|
protected readonly breadcrumbsActions = new CrumbsActions()
|
||||||
|
|
||||||
connect<State>(getLocalState: IStateSelector<State, ICrumbsState>) {
|
connect<State>(getLocalState: TStateSelector<State, ICrumbsState>) {
|
||||||
return this.wrap(
|
return this.wrap(
|
||||||
getLocalState,
|
getLocalState,
|
||||||
state => state,
|
state => state,
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import {ICrumbs, CrumbsActionType} from './CrumbsActions'
|
import {ICrumbs, TCrumbsAction} from './CrumbsActions'
|
||||||
|
|
||||||
export interface ICrumbsState extends ICrumbs {
|
export interface ICrumbsState extends ICrumbs {
|
||||||
}
|
}
|
||||||
@ -8,7 +8,7 @@ const defaultState: ICrumbsState = {
|
|||||||
current: 'Home',
|
current: 'Home',
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Crumbs(state = defaultState, action: CrumbsActionType)
|
export function Crumbs(state = defaultState, action: TCrumbsAction)
|
||||||
: ICrumbsState {
|
: ICrumbsState {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case 'BREADCRUMBS_SET':
|
case 'BREADCRUMBS_SET':
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import {IHTTPClient} from './IHTTPClient'
|
import {IHTTPClient} from './IHTTPClient'
|
||||||
import {IHeader} from './IHeader'
|
import {IHeader} from './IHeader'
|
||||||
import {IMethod, IRoutes, URLFormatter} from '@rondo/common'
|
import {TMethod, IRoutes, URLFormatter} from '@rondo/common'
|
||||||
import {IRequest} from './IRequest'
|
import {IRequest} from './IRequest'
|
||||||
import {IResponse} from './IResponse'
|
import {IResponse} from './IResponse'
|
||||||
import {ITypedRequestParams} from './ITypedRequestParams'
|
import {ITypedRequestParams} from './ITypedRequestParams'
|
||||||
@ -31,7 +31,7 @@ export class HTTPClient<T extends IRoutes> implements IHTTPClient<T> {
|
|||||||
|
|
||||||
async request<
|
async request<
|
||||||
P extends keyof T & string,
|
P extends keyof T & string,
|
||||||
M extends IMethod,
|
M extends TMethod,
|
||||||
>(params: ITypedRequestParams<T, P, M>): Promise<T[P][M]['response']> {
|
>(params: ITypedRequestParams<T, P, M>): Promise<T[P][M]['response']> {
|
||||||
|
|
||||||
const url = this.formatter.format(params.path, params.params)
|
const url = this.formatter.format(params.path, params.params)
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
import {IMethod, IRoutes} from '@rondo/common'
|
import {TMethod, IRoutes} from '@rondo/common'
|
||||||
import {ITypedRequestParams} from './ITypedRequestParams'
|
import {ITypedRequestParams} from './ITypedRequestParams'
|
||||||
|
|
||||||
export interface IHTTPClient<T extends IRoutes> {
|
export interface IHTTPClient<T extends IRoutes> {
|
||||||
request<
|
request<
|
||||||
P extends keyof T & string,
|
P extends keyof T & string,
|
||||||
M extends IMethod,
|
M extends TMethod,
|
||||||
>(params: ITypedRequestParams<T, P, M>): Promise<T[P][M]['response']>
|
>(params: ITypedRequestParams<T, P, M>): Promise<T[P][M]['response']>
|
||||||
|
|
||||||
get<P extends keyof T & string>(
|
get<P extends keyof T & string>(
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import {IMethod} from '@rondo/common'
|
import {TMethod} from '@rondo/common'
|
||||||
|
|
||||||
export interface IRequest {
|
export interface IRequest {
|
||||||
method: IMethod,
|
method: TMethod,
|
||||||
url: string,
|
url: string,
|
||||||
params?: {[key: string]: any},
|
params?: {[key: string]: any},
|
||||||
data?: any,
|
data?: any,
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import {IRoutes, IMethod} from '@rondo/common'
|
import {IRoutes, TMethod} from '@rondo/common'
|
||||||
|
|
||||||
export interface ITypedRequestParams<
|
export interface ITypedRequestParams<
|
||||||
T extends IRoutes,
|
T extends IRoutes,
|
||||||
P extends keyof T & string,
|
P extends keyof T & string,
|
||||||
M extends IMethod,
|
M extends TMethod,
|
||||||
> {
|
> {
|
||||||
method: M,
|
method: M,
|
||||||
path: P,
|
path: P,
|
||||||
|
|||||||
@ -1,14 +1,14 @@
|
|||||||
import {GetAction, IAsyncAction, IAction, PendingAction} from '../actions'
|
import {TGetAction, TAsyncAction, IAction, PendingAction} from '../actions'
|
||||||
import {IAPIDef, ICredentials, INewUser, IUser} from '@rondo/common'
|
import {IAPIDef, ICredentials, INewUser, IUser} from '@rondo/common'
|
||||||
import {IHTTPClient} from '../http/IHTTPClient'
|
import {IHTTPClient} from '../http/IHTTPClient'
|
||||||
|
|
||||||
export type LoginActionType =
|
export type TLoginAction =
|
||||||
IAsyncAction<IUser, 'LOGIN'>
|
TAsyncAction<IUser, 'LOGIN'>
|
||||||
| IAsyncAction<unknown, 'LOGIN_LOGOUT'>
|
| TAsyncAction<unknown, 'LOGIN_LOGOUT'>
|
||||||
| IAsyncAction<IUser, 'LOGIN_REGISTER'>
|
| TAsyncAction<IUser, 'LOGIN_REGISTER'>
|
||||||
| IAction<{redirectTo: string}, 'LOGIN_REDIRECT_SET'>
|
| IAction<{redirectTo: string}, 'LOGIN_REDIRECT_SET'>
|
||||||
|
|
||||||
type Action<T extends string> = GetAction<LoginActionType, T>
|
type TAction<T extends string> = TGetAction<TLoginAction, T>
|
||||||
|
|
||||||
export class LoginActions {
|
export class LoginActions {
|
||||||
constructor(protected readonly http: IHTTPClient<IAPIDef>) {}
|
constructor(protected readonly http: IHTTPClient<IAPIDef>) {}
|
||||||
@ -34,7 +34,7 @@ export class LoginActions {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
setRedirectTo = (redirectTo: string): Action<'LOGIN_REDIRECT_SET'> => {
|
setRedirectTo = (redirectTo: string): TAction<'LOGIN_REDIRECT_SET'> => {
|
||||||
return {
|
return {
|
||||||
payload: {redirectTo},
|
payload: {redirectTo},
|
||||||
type: 'LOGIN_REDIRECT_SET',
|
type: 'LOGIN_REDIRECT_SET',
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import {Connector} from '../redux/Connector'
|
import {Connector} from '../redux/Connector'
|
||||||
import {ICredentials} from '@rondo/common'
|
import {ICredentials} from '@rondo/common'
|
||||||
import {ILoginState} from './LoginReducer'
|
import {ILoginState} from './LoginReducer'
|
||||||
import {IStateSelector} from '../redux'
|
import {TStateSelector} from '../redux'
|
||||||
import {LoginActions} from './LoginActions'
|
import {LoginActions} from './LoginActions'
|
||||||
import {LoginForm} from './LoginForm'
|
import {LoginForm} from './LoginForm'
|
||||||
import {bindActionCreators} from 'redux'
|
import {bindActionCreators} from 'redux'
|
||||||
@ -18,7 +18,7 @@ export class LoginConnector extends Connector<ILoginState> {
|
|||||||
super()
|
super()
|
||||||
}
|
}
|
||||||
|
|
||||||
connect<State>(getLocalState: IStateSelector<State, ILoginState>) {
|
connect<State>(getLocalState: TStateSelector<State, ILoginState>) {
|
||||||
return this.wrap(
|
return this.wrap(
|
||||||
getLocalState,
|
getLocalState,
|
||||||
state => ({
|
state => ({
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import {IUser} from '@rondo/common'
|
import {IUser} from '@rondo/common'
|
||||||
import {LoginActionType} from './LoginActions'
|
import {TLoginAction} from './LoginActions'
|
||||||
|
|
||||||
export interface ILoginState {
|
export interface ILoginState {
|
||||||
readonly error: string
|
readonly error: string
|
||||||
@ -17,7 +17,7 @@ const defaultState: ILoginState = {
|
|||||||
|
|
||||||
export function Login(
|
export function Login(
|
||||||
state = defaultState,
|
state = defaultState,
|
||||||
action: LoginActionType,
|
action: TLoginAction,
|
||||||
): ILoginState {
|
): ILoginState {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
// sync actions
|
// sync actions
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import {Connector} from '../redux/Connector'
|
import {Connector} from '../redux/Connector'
|
||||||
import {INewUser} from '@rondo/common'
|
import {INewUser} from '@rondo/common'
|
||||||
import {ILoginState} from './LoginReducer'
|
import {ILoginState} from './LoginReducer'
|
||||||
import {IStateSelector} from '../redux'
|
import {TStateSelector} from '../redux'
|
||||||
import {LoginActions} from './LoginActions'
|
import {LoginActions} from './LoginActions'
|
||||||
import {RegisterForm} from './RegisterForm'
|
import {RegisterForm} from './RegisterForm'
|
||||||
import {bindActionCreators} from 'redux'
|
import {bindActionCreators} from 'redux'
|
||||||
@ -20,7 +20,7 @@ export class RegisterConnector extends Connector<ILoginState> {
|
|||||||
super()
|
super()
|
||||||
}
|
}
|
||||||
|
|
||||||
connect<State>(getLocalState: IStateSelector<State, ILoginState>) {
|
connect<State>(getLocalState: TStateSelector<State, ILoginState>) {
|
||||||
return this.wrap(
|
return this.wrap(
|
||||||
getLocalState,
|
getLocalState,
|
||||||
state => ({
|
state => ({
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import {IStateSelector} from './IStateSelector'
|
import {TStateSelector} from './TStateSelector'
|
||||||
import {connect, Omit} from 'react-redux'
|
import {connect, Omit} from 'react-redux'
|
||||||
import {Dispatch} from 'redux'
|
import {Dispatch} from 'redux'
|
||||||
import {ComponentType} from 'react'
|
import {ComponentType} from 'react'
|
||||||
@ -30,7 +30,7 @@ export abstract class Connector<LocalState> {
|
|||||||
* https://stackoverflow.com/questions/54277411
|
* https://stackoverflow.com/questions/54277411
|
||||||
*/
|
*/
|
||||||
abstract connect<State>(
|
abstract connect<State>(
|
||||||
selectState: IStateSelector<State, LocalState>,
|
selectState: TStateSelector<State, LocalState>,
|
||||||
): ComponentType<any>
|
): ComponentType<any>
|
||||||
|
|
||||||
protected wrap<
|
protected wrap<
|
||||||
@ -39,7 +39,7 @@ export abstract class Connector<LocalState> {
|
|||||||
StateProps extends Partial<Props>,
|
StateProps extends Partial<Props>,
|
||||||
DispatchProps extends Partial<Props>,
|
DispatchProps extends Partial<Props>,
|
||||||
>(
|
>(
|
||||||
getLocalState: IStateSelector<State, LocalState>,
|
getLocalState: TStateSelector<State, LocalState>,
|
||||||
mapStateToProps: (state: LocalState) => StateProps,
|
mapStateToProps: (state: LocalState) => StateProps,
|
||||||
mapDispatchToProps: (dispatch: Dispatch) => DispatchProps,
|
mapDispatchToProps: (dispatch: Dispatch) => DispatchProps,
|
||||||
Component: React.ComponentType<Props>,
|
Component: React.ComponentType<Props>,
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Select and return a part of the state
|
* Select and return a part of the state
|
||||||
*/
|
*/
|
||||||
export type IStateSelector<GlobalState, StateSlice>
|
export type TStateSelector<GlobalState, StateSlice>
|
||||||
= (state: GlobalState) => StateSlice
|
= (state: GlobalState) => StateSlice
|
||||||
@ -1,2 +1,2 @@
|
|||||||
export * from './Connector'
|
export * from './Connector'
|
||||||
export * from './IStateSelector'
|
export * from './TStateSelector'
|
||||||
|
|||||||
@ -3,13 +3,13 @@ import ReactDOM from 'react-dom'
|
|||||||
import {Action} from 'redux'
|
import {Action} from 'redux'
|
||||||
import {IClientConfig} from './IClientConfig'
|
import {IClientConfig} from './IClientConfig'
|
||||||
import {IRenderer} from './IRenderer'
|
import {IRenderer} from './IRenderer'
|
||||||
import {IStoreFactory} from './IStoreFactory'
|
import {TStoreFactory} from './TStoreFactory'
|
||||||
import {Provider} from 'react-redux'
|
import {Provider} from 'react-redux'
|
||||||
import {Router} from 'react-router-dom'
|
import {Router} from 'react-router-dom'
|
||||||
import {createBrowserHistory} from 'history'
|
import {createBrowserHistory} from 'history'
|
||||||
|
|
||||||
export interface IClientRendererParams<State, A extends Action> {
|
export interface IClientRendererParams<State, A extends Action> {
|
||||||
readonly createStore: IStoreFactory<State, A | any>,
|
readonly createStore: TStoreFactory<State, A | any>,
|
||||||
readonly RootComponent: React.ComponentType<{config: IClientConfig}>,
|
readonly RootComponent: React.ComponentType<{config: IClientConfig}>,
|
||||||
readonly target?: HTMLElement
|
readonly target?: HTMLElement
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import React from 'react'
|
|||||||
import {Action} from 'redux'
|
import {Action} from 'redux'
|
||||||
import {IClientConfig} from './IClientConfig'
|
import {IClientConfig} from './IClientConfig'
|
||||||
import {IRenderer} from './IRenderer'
|
import {IRenderer} from './IRenderer'
|
||||||
import {IStoreFactory} from './IStoreFactory'
|
import {TStoreFactory} from './TStoreFactory'
|
||||||
import {Provider} from 'react-redux'
|
import {Provider} from 'react-redux'
|
||||||
import {StaticRouterContext} from 'react-router'
|
import {StaticRouterContext} from 'react-router'
|
||||||
import {StaticRouter} from 'react-router-dom'
|
import {StaticRouter} from 'react-router-dom'
|
||||||
@ -10,7 +10,7 @@ import {renderToNodeStream} from 'react-dom/server'
|
|||||||
|
|
||||||
export class ServerRenderer<State, A extends Action> implements IRenderer {
|
export class ServerRenderer<State, A extends Action> implements IRenderer {
|
||||||
constructor(
|
constructor(
|
||||||
readonly createStore: IStoreFactory<State, A | any>,
|
readonly createStore: TStoreFactory<State, A | any>,
|
||||||
readonly RootComponent: React.ComponentType<{config: IClientConfig}>,
|
readonly RootComponent: React.ComponentType<{config: IClientConfig}>,
|
||||||
) {}
|
) {}
|
||||||
render(url: string, config: IClientConfig, state?: any) {
|
render(url: string, config: IClientConfig, state?: any) {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import {Action, Store} from 'redux'
|
import {Action, Store} from 'redux'
|
||||||
|
|
||||||
// TODO maybe Store should also be typed
|
// TODO maybe Store should also be typed
|
||||||
export type IStoreFactory<State, A extends Action> =
|
export type TStoreFactory<State, A extends Action> =
|
||||||
(state?: State) => Store<State, A | any>
|
(state?: State) => Store<State, A | any>
|
||||||
@ -1,5 +1,5 @@
|
|||||||
export * from './ClientRenderer'
|
export * from './ClientRenderer'
|
||||||
export * from './IClientConfig'
|
export * from './IClientConfig'
|
||||||
export * from './IRenderer'
|
export * from './IRenderer'
|
||||||
export * from './IStoreFactory'
|
export * from './TStoreFactory'
|
||||||
export * from './isClientSide'
|
export * from './isClientSide'
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
import {IAPIDef} from '@rondo/common'
|
import {IAPIDef} from '@rondo/common'
|
||||||
import {GetPendingAction, IAsyncAction, PendingAction} from '../actions'
|
import {TGetPendingAction, TAsyncAction, PendingAction} from '../actions'
|
||||||
import {IHTTPClient} from '../http/IHTTPClient'
|
import {IHTTPClient} from '../http/IHTTPClient'
|
||||||
import {ITeam, IUser, IUserInTeam} from '@rondo/common'
|
import {ITeam, IUser, IUserInTeam} from '@rondo/common'
|
||||||
|
|
||||||
export type TeamActionType =
|
export type TTeamAction =
|
||||||
IAsyncAction<ITeam[], 'TEAMS'>
|
TAsyncAction<ITeam[], 'TEAMS'>
|
||||||
| IAsyncAction<ITeam, 'TEAM_CREATE'>
|
| TAsyncAction<ITeam, 'TEAM_CREATE'>
|
||||||
| IAsyncAction<ITeam, 'TEAM_UPDATE'>
|
| TAsyncAction<ITeam, 'TEAM_UPDATE'>
|
||||||
| IAsyncAction<{id: number}, 'TEAM_REMOVE'>
|
| TAsyncAction<{id: number}, 'TEAM_REMOVE'>
|
||||||
| IAsyncAction<IUserInTeam, 'TEAM_USER_ADD'>
|
| TAsyncAction<IUserInTeam, 'TEAM_USER_ADD'>
|
||||||
| IAsyncAction<{userId: number, teamId: number}, 'TEAM_USER_REMOVE'>
|
| TAsyncAction<{userId: number, teamId: number}, 'TEAM_USER_REMOVE'>
|
||||||
| IAsyncAction<{teamId: number, usersInTeam: IUserInTeam[]}, 'TEAM_USERS'>
|
| TAsyncAction<{teamId: number, usersInTeam: IUserInTeam[]}, 'TEAM_USERS'>
|
||||||
| IAsyncAction<IUser | undefined, 'TEAM_USER_FIND'>
|
| TAsyncAction<IUser | undefined, 'TEAM_USER_FIND'>
|
||||||
|
|
||||||
type Action<T extends string> = GetPendingAction<TeamActionType, T>
|
type Action<T extends string> = TGetPendingAction<TTeamAction, T>
|
||||||
|
|
||||||
export class TeamActions {
|
export class TeamActions {
|
||||||
constructor(protected readonly http: IHTTPClient<IAPIDef>) {}
|
constructor(protected readonly http: IHTTPClient<IAPIDef>) {}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import {Connector} from '../redux/Connector'
|
import {Connector} from '../redux/Connector'
|
||||||
import {IStateSelector} from '../redux'
|
import {TStateSelector} from '../redux'
|
||||||
import {ITeamState} from './TeamReducer'
|
import {ITeamState} from './TeamReducer'
|
||||||
import {TeamActions} from './TeamActions'
|
import {TeamActions} from './TeamActions'
|
||||||
import {TeamManager} from './TeamManager'
|
import {TeamManager} from './TeamManager'
|
||||||
@ -11,7 +11,7 @@ export class TeamConnector extends Connector<ITeamState> {
|
|||||||
super()
|
super()
|
||||||
}
|
}
|
||||||
|
|
||||||
connect<State>(getLocalState: IStateSelector<State, ITeamState>) {
|
connect<State>(getLocalState: TStateSelector<State, ITeamState>) {
|
||||||
const Component = this.wrap(
|
const Component = this.wrap(
|
||||||
getLocalState,
|
getLocalState,
|
||||||
state => ({
|
state => ({
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import {ITeam} from '@rondo/common'
|
|||||||
import {TeamActions} from './TeamActions'
|
import {TeamActions} from './TeamActions'
|
||||||
import {FaPlusSquare, FaCheck, FaEdit} from 'react-icons/fa'
|
import {FaPlusSquare, FaCheck, FaEdit} from 'react-icons/fa'
|
||||||
|
|
||||||
export type ITeamEditorProps = {
|
export type TTeamEditorProps = {
|
||||||
type: 'add'
|
type: 'add'
|
||||||
onAddTeam: TeamActions['createTeam']
|
onAddTeam: TeamActions['createTeam']
|
||||||
} | {
|
} | {
|
||||||
@ -20,8 +20,8 @@ export interface ITeamEditorState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class TeamEditor
|
export class TeamEditor
|
||||||
extends React.PureComponent<ITeamEditorProps, ITeamEditorState> {
|
extends React.PureComponent<TTeamEditorProps, ITeamEditorState> {
|
||||||
constructor(props: ITeamEditorProps) {
|
constructor(props: TTeamEditorProps) {
|
||||||
super(props)
|
super(props)
|
||||||
this.state = {
|
this.state = {
|
||||||
error: '',
|
error: '',
|
||||||
@ -31,7 +31,7 @@ extends React.PureComponent<ITeamEditorProps, ITeamEditorState> {
|
|||||||
getName(team?: ITeam) {
|
getName(team?: ITeam) {
|
||||||
return team ? team.name : ''
|
return team ? team.name : ''
|
||||||
}
|
}
|
||||||
componentWillReceiveProps(nextProps: ITeamEditorProps) {
|
componentWillReceiveProps(nextProps: TTeamEditorProps) {
|
||||||
if (nextProps.type === 'update') {
|
if (nextProps.type === 'update') {
|
||||||
const {team} = nextProps
|
const {team} = nextProps
|
||||||
if (team !== (this.props as any).team) {
|
if (team !== (this.props as any).team) {
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {Button, Panel, PanelHeading, PanelBlock} from 'bloomer'
|
import {Button, Panel, PanelHeading, PanelBlock} from 'bloomer'
|
||||||
import {FaPlus, FaEdit, FaTimes} from 'react-icons/fa'
|
import {FaPlus, FaEdit, FaTimes} from 'react-icons/fa'
|
||||||
import {ITeam, ReadonlyRecord} from '@rondo/common'
|
import {ITeam, TReadonlyRecord} from '@rondo/common'
|
||||||
import {Link} from 'react-router-dom'
|
import {Link} from 'react-router-dom'
|
||||||
import {TeamActions} from './TeamActions'
|
import {TeamActions} from './TeamActions'
|
||||||
import {TeamEditor} from './TeamEditor'
|
import {TeamEditor} from './TeamEditor'
|
||||||
|
|
||||||
export interface ITeamListProps {
|
export interface ITeamListProps {
|
||||||
teamsById: ReadonlyRecord<number, ITeam>,
|
teamsById: TReadonlyRecord<number, ITeam>,
|
||||||
teamIds: ReadonlyArray<number>,
|
teamIds: ReadonlyArray<number>,
|
||||||
onAddTeam: TeamActions['createTeam']
|
onAddTeam: TeamActions['createTeam']
|
||||||
onRemoveTeam: TeamActions['removeTeam']
|
onRemoveTeam: TeamActions['removeTeam']
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {History, Location} from 'history'
|
import {History, Location} from 'history'
|
||||||
import {ITeam, IUserInTeam, ReadonlyRecord} from '@rondo/common'
|
import {ITeam, IUserInTeam, TReadonlyRecord} from '@rondo/common'
|
||||||
import {Panel, PanelBlock, PanelHeading} from 'bloomer'
|
import {Panel, PanelBlock, PanelHeading} from 'bloomer'
|
||||||
import {Route, Switch} from 'react-router-dom'
|
import {Route, Switch} from 'react-router-dom'
|
||||||
import {TeamActions} from './TeamActions'
|
import {TeamActions} from './TeamActions'
|
||||||
@ -24,11 +24,11 @@ export interface ITeamManagerProps {
|
|||||||
fetchUsersInTeam: TeamActions['fetchUsersInTeam']
|
fetchUsersInTeam: TeamActions['fetchUsersInTeam']
|
||||||
findUserByEmail: TeamActions['findUserByEmail']
|
findUserByEmail: TeamActions['findUserByEmail']
|
||||||
|
|
||||||
teamsById: ReadonlyRecord<number, ITeam>
|
teamsById: TReadonlyRecord<number, ITeam>
|
||||||
teamIds: ReadonlyArray<number>
|
teamIds: ReadonlyArray<number>
|
||||||
|
|
||||||
userKeysByTeamId: ReadonlyRecord<number, ReadonlyArray<string>>
|
userKeysByTeamId: TReadonlyRecord<number, ReadonlyArray<string>>
|
||||||
usersByKey: ReadonlyRecord<string, IUserInTeam>
|
usersByKey: TReadonlyRecord<string, IUserInTeam>
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TeamManager extends React.PureComponent<ITeamManagerProps> {
|
export class TeamManager extends React.PureComponent<ITeamManagerProps> {
|
||||||
|
|||||||
@ -1,17 +1,17 @@
|
|||||||
import {
|
import {
|
||||||
ITeam, IUserInTeam, ReadonlyRecord, indexBy, without,
|
ITeam, IUserInTeam, TReadonlyRecord, indexBy, without,
|
||||||
} from '@rondo/common'
|
} from '@rondo/common'
|
||||||
import {TeamActionType} from './TeamActions'
|
import {TTeamAction} from './TeamActions'
|
||||||
import {GetResolvedAction} from '../actions'
|
import {TGetResolvedAction} from '../actions'
|
||||||
|
|
||||||
export interface ITeamState {
|
export interface ITeamState {
|
||||||
readonly error: string
|
readonly error: string
|
||||||
|
|
||||||
readonly teamIds: ReadonlyArray<number>
|
readonly teamIds: ReadonlyArray<number>
|
||||||
readonly teamsById: ReadonlyRecord<number, ITeam>
|
readonly teamsById: TReadonlyRecord<number, ITeam>
|
||||||
|
|
||||||
readonly userKeysByTeamId: ReadonlyRecord<number, ReadonlyArray<string>>
|
readonly userKeysByTeamId: TReadonlyRecord<number, ReadonlyArray<string>>
|
||||||
readonly usersByKey: ReadonlyRecord<string, IUserInTeam>
|
readonly usersByKey: TReadonlyRecord<string, IUserInTeam>
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultState: ITeamState = {
|
const defaultState: ITeamState = {
|
||||||
@ -26,7 +26,7 @@ const defaultState: ITeamState = {
|
|||||||
|
|
||||||
function removeUser(
|
function removeUser(
|
||||||
state: ITeamState,
|
state: ITeamState,
|
||||||
action: GetResolvedAction<TeamActionType, 'TEAM_USER_REMOVE'>,
|
action: TGetResolvedAction<TTeamAction, 'TEAM_USER_REMOVE'>,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
const {payload} = action
|
const {payload} = action
|
||||||
@ -52,7 +52,7 @@ function getUserKey(userInTeam: {userId: number, teamId: number}) {
|
|||||||
return `${userInTeam.teamId}_${userInTeam.userId}`
|
return `${userInTeam.teamId}_${userInTeam.userId}`
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Team(state = defaultState, action: TeamActionType): ITeamState {
|
export function Team(state = defaultState, action: TTeamAction): ITeamState {
|
||||||
switch (action.status) {
|
switch (action.status) {
|
||||||
case 'pending':
|
case 'pending':
|
||||||
return state
|
return state
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {ITeam, IUser, IUserInTeam, ReadonlyRecord} from '@rondo/common'
|
import {ITeam, IUser, IUserInTeam, TReadonlyRecord} from '@rondo/common'
|
||||||
import {TeamActions} from './TeamActions'
|
import {TeamActions} from './TeamActions'
|
||||||
import {FaUser, FaCheck, FaTimes} from 'react-icons/fa'
|
import {FaUser, FaCheck, FaTimes} from 'react-icons/fa'
|
||||||
|
|
||||||
@ -18,8 +18,8 @@ export interface ITeamUsersProps {
|
|||||||
onRemoveUser: TeamActions['removeUser']
|
onRemoveUser: TeamActions['removeUser']
|
||||||
|
|
||||||
team: ITeam
|
team: ITeam
|
||||||
userKeysByTeamId: ReadonlyRecord<number, ReadonlyArray<string>>
|
userKeysByTeamId: TReadonlyRecord<number, ReadonlyArray<string>>
|
||||||
usersByKey: ReadonlyRecord<string, IUserInTeam>
|
usersByKey: TReadonlyRecord<string, IUserInTeam>
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ITeamUserProps {
|
export interface ITeamUserProps {
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import ReactDOM from 'react-dom'
|
import ReactDOM from 'react-dom'
|
||||||
import T from 'react-dom/test-utils'
|
import T from 'react-dom/test-utils'
|
||||||
import {IStateSelector} from '../redux'
|
import {TStateSelector} from '../redux'
|
||||||
import {Provider} from 'react-redux'
|
import {Provider} from 'react-redux'
|
||||||
import {createStore} from '../store'
|
import {createStore} from '../store'
|
||||||
import {
|
import {
|
||||||
@ -15,9 +15,9 @@ import {
|
|||||||
|
|
||||||
interface IRenderParams<State, LocalState> {
|
interface IRenderParams<State, LocalState> {
|
||||||
reducers: ReducersMapObject<State, any>
|
reducers: ReducersMapObject<State, any>
|
||||||
select: IStateSelector<State, LocalState>
|
select: TStateSelector<State, LocalState>
|
||||||
// getComponent: (
|
// getComponent: (
|
||||||
// select: IStateSelector<State, LocalState>) => React.ComponentType<Props>,
|
// select: TStateSelector<State, LocalState>) => React.ComponentType<Props>,
|
||||||
// customJSX?: (
|
// customJSX?: (
|
||||||
// Component: React.ComponentType<Props>,
|
// Component: React.ComponentType<Props>,
|
||||||
// props: Props,
|
// props: Props,
|
||||||
@ -65,7 +65,7 @@ export class TestUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const withComponent = <Props extends {}>(
|
const withComponent = <Props extends {}>(
|
||||||
getComponent: (select: IStateSelector<State, LocalState>) =>
|
getComponent: (select: TStateSelector<State, LocalState>) =>
|
||||||
React.ComponentType<Props>,
|
React.ComponentType<Props>,
|
||||||
) => {
|
) => {
|
||||||
const Component = getComponent(select)
|
const Component = getComponent(select)
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
export type IMethod = 'get'
|
export type TMethod = 'get'
|
||||||
| 'post'
|
| 'post'
|
||||||
| 'put'
|
| 'put'
|
||||||
| 'delete'
|
| 'delete'
|
||||||
|
|||||||
@ -1,2 +0,0 @@
|
|||||||
export type ReadonlyRecord<K extends string | number | symbol, V> =
|
|
||||||
Readonly<Record<K, V>>
|
|
||||||
@ -9,7 +9,6 @@ export * from './IUser'
|
|||||||
export * from './IUser'
|
export * from './IUser'
|
||||||
export * from './IUserInTeam'
|
export * from './IUserInTeam'
|
||||||
export * from './IUserTeam'
|
export * from './IUserTeam'
|
||||||
export * from './ReadonlyRecord'
|
|
||||||
export * from './URLFormatter'
|
export * from './URLFormatter'
|
||||||
export * from './indexBy'
|
export * from './indexBy'
|
||||||
export * from './types'
|
export * from './types'
|
||||||
|
|||||||
@ -1,22 +1,25 @@
|
|||||||
/**
|
/**
|
||||||
* transform unknown into undefined
|
* transform unknown into undefined
|
||||||
*/
|
*/
|
||||||
export type Optional<T> = T extends {} ? T : undefined
|
export type TOptional<T> = T extends {} ? T : undefined
|
||||||
|
|
||||||
export type NonUndefinedPropertyNames<T> = {
|
export type TNonUndefinedPropertyNames<T> = {
|
||||||
[K in keyof T]: T[K] extends undefined ? never: K
|
[K in keyof T]: T[K] extends undefined ? never: K
|
||||||
}[keyof T]
|
}[keyof T]
|
||||||
|
|
||||||
export type OnlyRequired<T> = Pick<T, NonUndefinedPropertyNames<T>>
|
export type TOnlyRequired<T> = Pick<T, TNonUndefinedPropertyNames<T>>
|
||||||
|
|
||||||
export type NonUnknownPropertyNames<T> = {
|
export type TNonUnknownPropertyNames<T> = {
|
||||||
[K in keyof T]: T[K] extends {} ? K : never
|
[K in keyof T]: T[K] extends {} ? K : never
|
||||||
}[keyof T]
|
}[keyof T]
|
||||||
|
|
||||||
export type OnlyDefined<T> = Pick<T, NonUnknownPropertyNames<T>>
|
export type TOnlyDefined<T> = Pick<T, TNonUnknownPropertyNames<T>>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove types from T that are not assignable to U
|
* Remove types from T that are not assignable to U
|
||||||
* https://www.typescriptlang.org/docs/handbook/advanced-types.html
|
* https://www.typescriptlang.org/docs/handbook/advanced-types.html
|
||||||
*/
|
*/
|
||||||
export type Filter<T, U> = T extends U ? T : never
|
export type TFilter<T, U> = T extends U ? T : never
|
||||||
|
|
||||||
|
export type TReadonlyRecord<K extends string | number | symbol, V> =
|
||||||
|
Readonly<Record<K, V>>
|
||||||
|
|||||||
@ -8,12 +8,12 @@ import {
|
|||||||
Repository,
|
Repository,
|
||||||
} from 'typeorm'
|
} from 'typeorm'
|
||||||
|
|
||||||
export type IConnectionGetter = () => Connection
|
export type TConnectionGetter = () => Connection
|
||||||
|
|
||||||
export class TransactionManager implements ITransactionManager {
|
export class TransactionManager implements ITransactionManager {
|
||||||
constructor(
|
constructor(
|
||||||
readonly ns: Namespace,
|
readonly ns: Namespace,
|
||||||
readonly getConnection: IConnectionGetter,
|
readonly getConnection: TConnectionGetter,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
getEntityManager = (): EntityManager => {
|
getEntityManager = (): EntityManager => {
|
||||||
|
|||||||
@ -17,10 +17,10 @@ export function pad(text: string, n: number, trim: boolean) {
|
|||||||
return text
|
return text
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ILogLevel = 'error' | 'warn' | 'info' | 'debug' | 'verbose' | 'off'
|
export type TLogLevel = 'error' | 'warn' | 'info' | 'debug' | 'verbose' | 'off'
|
||||||
|
|
||||||
export interface IEnabledLoggers {
|
export interface IEnabledLoggers {
|
||||||
readonly [key: string]: ILogLevel
|
readonly [key: string]: TLogLevel
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IParams {
|
export interface IParams {
|
||||||
@ -48,9 +48,9 @@ export class LoggerFactory implements ILoggerFactory {
|
|||||||
} = {}) {
|
} = {}) {
|
||||||
const enabledLoggers = logs.split(',').reduce((logConfig, log) => {
|
const enabledLoggers = logs.split(',').reduce((logConfig, log) => {
|
||||||
const [key, value] = log.split(':')
|
const [key, value] = log.split(':')
|
||||||
logConfig[key] = (value || 'info') as ILogLevel
|
logConfig[key] = (value || 'info') as TLogLevel
|
||||||
return logConfig
|
return logConfig
|
||||||
}, {} as {[key: string]: ILogLevel})
|
}, {} as {[key: string]: TLogLevel})
|
||||||
|
|
||||||
const params = opts.split(',').reduce((o, key) => {
|
const params = opts.split(',').reduce((o, key) => {
|
||||||
o[key] = true
|
o[key] = true
|
||||||
@ -70,7 +70,7 @@ export class LoggerFactory implements ILoggerFactory {
|
|||||||
this.getCorrelationId = () => ''
|
this.getCorrelationId = () => ''
|
||||||
}
|
}
|
||||||
|
|
||||||
getLoggerLevel(name: string): ILogLevel {
|
getLoggerLevel(name: string): TLogLevel {
|
||||||
const {enabledLoggers} = this.options
|
const {enabledLoggers} = this.options
|
||||||
const disabled = !!enabledLoggers['-' + name]
|
const disabled = !!enabledLoggers['-' + name]
|
||||||
if (disabled) {
|
if (disabled) {
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
import {Authenticator as A, Passport} from 'passport'
|
import {Authenticator as A, Passport} from 'passport'
|
||||||
import {IUserService} from '../services'
|
import {IUserService} from '../services'
|
||||||
import {Strategy as LocalStrategy} from 'passport-local'
|
import {Strategy as LocalStrategy} from 'passport-local'
|
||||||
import {IHandler} from './IHandler'
|
import {THandler} from './THandler'
|
||||||
import {IMiddleware} from './IMiddleware'
|
import {IMiddleware} from './IMiddleware'
|
||||||
|
|
||||||
export class Authenticator implements IMiddleware {
|
export class Authenticator implements IMiddleware {
|
||||||
|
|
||||||
protected readonly passport: A
|
protected readonly passport: A
|
||||||
readonly handle: IHandler[]
|
readonly handle: THandler[]
|
||||||
|
|
||||||
constructor(protected readonly userService: IUserService) {
|
constructor(protected readonly userService: IUserService) {
|
||||||
this.passport = new Passport() as any
|
this.passport = new Passport() as any
|
||||||
@ -22,7 +22,7 @@ export class Authenticator implements IMiddleware {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
withLogInPromise: IHandler = (req, res, next) => {
|
withLogInPromise: THandler = (req, res, next) => {
|
||||||
req.logInPromise = (user) => {
|
req.logInPromise = (user) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
req.logIn(user, err => {
|
req.logIn(user, err => {
|
||||||
@ -72,7 +72,7 @@ export class Authenticator implements IMiddleware {
|
|||||||
.catch(done)
|
.catch(done)
|
||||||
}
|
}
|
||||||
|
|
||||||
authenticate(strategy: string | string[]): IHandler {
|
authenticate(strategy: string | string[]): THandler {
|
||||||
return (req, res, next) => {
|
return (req, res, next) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.passport.authenticate(strategy, (err: Error, user, info) => {
|
this.passport.authenticate(strategy, (err: Error, user, info) => {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import Csurf from 'csurf'
|
import Csurf from 'csurf'
|
||||||
import {IHandler} from './IHandler'
|
import {THandler} from './THandler'
|
||||||
import {IMiddleware} from './IMiddleware'
|
import {IMiddleware} from './IMiddleware'
|
||||||
import {UrlWithStringQuery} from 'url'
|
import {UrlWithStringQuery} from 'url'
|
||||||
|
|
||||||
@ -9,7 +9,7 @@ export interface ICSRFParams {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class CSRFMiddleware implements IMiddleware {
|
export class CSRFMiddleware implements IMiddleware {
|
||||||
readonly handle: IHandler
|
readonly handle: THandler
|
||||||
|
|
||||||
constructor(readonly params: ICSRFParams) {
|
constructor(readonly params: ICSRFParams) {
|
||||||
this.handle = Csurf({
|
this.handle = Csurf({
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import {IErrorHandler} from './IErrorHandler'
|
import {TErrorHandler} from './TErrorHandler'
|
||||||
import {ILogger} from '../logger/ILogger'
|
import {ILogger} from '../logger/ILogger'
|
||||||
import {IMiddleware} from './IMiddleware'
|
import {IMiddleware} from './IMiddleware'
|
||||||
import {ValidationError} from '../validator'
|
import {ValidationError} from '../validator'
|
||||||
@ -6,7 +6,7 @@ import {ValidationError} from '../validator'
|
|||||||
export class ErrorApiHandler implements IMiddleware {
|
export class ErrorApiHandler implements IMiddleware {
|
||||||
constructor(readonly logger: ILogger) {}
|
constructor(readonly logger: ILogger) {}
|
||||||
|
|
||||||
handle: IErrorHandler = (err, req, res, next) => {
|
handle: TErrorHandler = (err, req, res, next) => {
|
||||||
this.logger.error('%s An API error occurred: %s',
|
this.logger.error('%s An API error occurred: %s',
|
||||||
req.correlationId, err.stack)
|
req.correlationId, err.stack)
|
||||||
const statusCode = this.getStatus(err)
|
const statusCode = this.getStatus(err)
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
import {IMiddleware} from './IMiddleware'
|
|
||||||
import {IErrorHandler} from './IErrorHandler'
|
|
||||||
import {ILogger} from '../logger/ILogger'
|
import {ILogger} from '../logger/ILogger'
|
||||||
|
import {IMiddleware} from './IMiddleware'
|
||||||
|
import {TErrorHandler} from './TErrorHandler'
|
||||||
|
|
||||||
export class ErrorPageHandler implements IMiddleware {
|
export class ErrorPageHandler implements IMiddleware {
|
||||||
constructor(readonly logger: ILogger) {}
|
constructor(readonly logger: ILogger) {}
|
||||||
|
|
||||||
handle: IErrorHandler = (err, req, res, next) => {
|
handle: TErrorHandler = (err, req, res, next) => {
|
||||||
this.logger.error(
|
this.logger.error(
|
||||||
'%s An error occurred: %s',
|
'%s An error occurred: %s',
|
||||||
req.correlationId, err.stack)
|
req.correlationId, err.stack)
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import {IHandler} from './IHandler'
|
import {THandler} from './THandler'
|
||||||
import {IErrorHandler} from './IErrorHandler'
|
import {TErrorHandler} from './TErrorHandler'
|
||||||
|
|
||||||
export interface IMiddleware {
|
export interface IMiddleware {
|
||||||
handle: IHandler | IHandler[] | IErrorHandler
|
handle: THandler | THandler[] | TErrorHandler
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import {IHandler} from './IHandler'
|
import {THandler} from './THandler'
|
||||||
import {ILogger} from '../logger/ILogger'
|
import {ILogger} from '../logger/ILogger'
|
||||||
import {IMiddleware} from './IMiddleware'
|
import {IMiddleware} from './IMiddleware'
|
||||||
import shortid from 'shortid'
|
import shortid from 'shortid'
|
||||||
@ -6,7 +6,7 @@ import shortid from 'shortid'
|
|||||||
export class RequestLogger implements IMiddleware {
|
export class RequestLogger implements IMiddleware {
|
||||||
constructor(protected readonly logger: ILogger) {}
|
constructor(protected readonly logger: ILogger) {}
|
||||||
|
|
||||||
handle: IHandler = (req, res, next) => {
|
handle: THandler = (req, res, next) => {
|
||||||
const start = Date.now()
|
const start = Date.now()
|
||||||
req.correlationId = shortid.generate()
|
req.correlationId = shortid.generate()
|
||||||
res.on('finish', () => {
|
res.on('finish', () => {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import ExpressSession from 'express-session'
|
import ExpressSession from 'express-session'
|
||||||
import {IHandler} from './IHandler'
|
import {THandler} from './THandler'
|
||||||
import {IMiddleware} from './IMiddleware'
|
import {IMiddleware} from './IMiddleware'
|
||||||
import {ISession} from '../session/ISession'
|
import {ISession} from '../session/ISession'
|
||||||
import {ITransactionManager} from '../database/ITransactionManager'
|
import {ITransactionManager} from '../database/ITransactionManager'
|
||||||
@ -15,7 +15,7 @@ export interface ISessionOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class SessionMiddleware implements IMiddleware {
|
export class SessionMiddleware implements IMiddleware {
|
||||||
readonly handle: IHandler
|
readonly handle: THandler
|
||||||
|
|
||||||
constructor(readonly params: ISessionOptions) {
|
constructor(readonly params: ISessionOptions) {
|
||||||
this.handle = ExpressSession({
|
this.handle = ExpressSession({
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import {Request, Response, NextFunction} from 'express'
|
import {Request, Response, NextFunction} from 'express'
|
||||||
|
|
||||||
export type IErrorHandler =
|
export type TErrorHandler =
|
||||||
(err: Error, req: Request, res: Response, next: NextFunction) => any
|
(err: Error, req: Request, res: Response, next: NextFunction) => any
|
||||||
@ -1,3 +1,3 @@
|
|||||||
import {Request, Response, NextFunction} from 'express'
|
import {Request, Response, NextFunction} from 'express'
|
||||||
|
|
||||||
export type IHandler = (req: Request, res: Response, next: NextFunction) => any
|
export type THandler = (req: Request, res: Response, next: NextFunction) => any
|
||||||
@ -1,4 +1,4 @@
|
|||||||
import {Request, Response, NextFunction} from 'express'
|
import {Request, Response, NextFunction} from 'express'
|
||||||
|
|
||||||
export type IPromiseHandler<T> =
|
export type TPromiseHandler<T> =
|
||||||
(req: Request, res: Response, next: NextFunction) => Promise<T>
|
(req: Request, res: Response, next: NextFunction) => Promise<T>
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import shortid from 'shortid'
|
import shortid from 'shortid'
|
||||||
import {IMiddleware} from './IMiddleware'
|
import {IMiddleware} from './IMiddleware'
|
||||||
import {IHandler} from './IHandler'
|
import {THandler} from './THandler'
|
||||||
import {Namespace} from 'cls-hooked'
|
import {Namespace} from 'cls-hooked'
|
||||||
|
|
||||||
export const CORRELATION_ID = 'CORRELATION_ID'
|
export const CORRELATION_ID = 'CORRELATION_ID'
|
||||||
@ -8,7 +8,7 @@ export const CORRELATION_ID = 'CORRELATION_ID'
|
|||||||
export class Transaction implements IMiddleware {
|
export class Transaction implements IMiddleware {
|
||||||
constructor(readonly ns: Namespace) {}
|
constructor(readonly ns: Namespace) {}
|
||||||
|
|
||||||
handle: IHandler = (req, res, next) => {
|
handle: THandler = (req, res, next) => {
|
||||||
const {ns} = this
|
const {ns} = this
|
||||||
ns.bindEmitter(req)
|
ns.bindEmitter(req)
|
||||||
ns.bindEmitter(res)
|
ns.bindEmitter(res)
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
import createError from 'http-errors'
|
import createError from 'http-errors'
|
||||||
import {Request} from 'express'
|
import {Request} from 'express'
|
||||||
import {IHandler} from './IHandler'
|
import {THandler} from './THandler'
|
||||||
|
|
||||||
const isLoggedIn = (req: Request) => !!(req as any).user
|
const isLoggedIn = (req: Request) => !!(req as any).user
|
||||||
|
|
||||||
export const ensureLoggedInApi: IHandler = (req, res, next) => {
|
export const ensureLoggedInApi: THandler = (req, res, next) => {
|
||||||
if (!isLoggedIn(req)) {
|
if (!isLoggedIn(req)) {
|
||||||
next(createError(401))
|
next(createError(401))
|
||||||
return
|
return
|
||||||
@ -12,7 +12,7 @@ export const ensureLoggedInApi: IHandler = (req, res, next) => {
|
|||||||
next()
|
next()
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ensureLoggedInSite = (redirectTo: string): IHandler => {
|
export const ensureLoggedInSite = (redirectTo: string): THandler => {
|
||||||
return function _ensureLoggedInSite(req, res, next) {
|
return function _ensureLoggedInSite(req, res, next) {
|
||||||
if (!isLoggedIn(req)) {
|
if (!isLoggedIn(req)) {
|
||||||
res.redirect(redirectTo)
|
res.redirect(redirectTo)
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import {IHandler} from './IHandler'
|
import {THandler} from './THandler'
|
||||||
import {IPromiseHandler} from './IPromiseHandler'
|
import {TPromiseHandler} from './TPromiseHandler'
|
||||||
|
|
||||||
export function handlePromise<T>(endpoint: IPromiseHandler<T>): IHandler {
|
export function handlePromise<T>(endpoint: TPromiseHandler<T>): THandler {
|
||||||
return (req, res, next) => {
|
return (req, res, next) => {
|
||||||
const promise = endpoint(req, res, next)
|
const promise = endpoint(req, res, next)
|
||||||
promise
|
promise
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
export * from './Authenticator'
|
export * from './Authenticator'
|
||||||
export * from './CSRFMiddleware'
|
export * from './CSRFMiddleware'
|
||||||
export * from './ensureLoggedIn'
|
|
||||||
export * from './ErrorApiHandler'
|
export * from './ErrorApiHandler'
|
||||||
export * from './ErrorPageHandler'
|
export * from './ErrorPageHandler'
|
||||||
export * from './handlePromise'
|
|
||||||
export * from './IErrorHandler'
|
|
||||||
export * from './IHandler'
|
|
||||||
export * from './IMiddleware'
|
export * from './IMiddleware'
|
||||||
export * from './IPromiseHandler'
|
|
||||||
export * from './RequestLogger'
|
export * from './RequestLogger'
|
||||||
export * from './SessionMiddleware'
|
export * from './SessionMiddleware'
|
||||||
|
export * from './TErrorHandler'
|
||||||
|
export * from './THandler'
|
||||||
|
export * from './TPromiseHandler'
|
||||||
export * from './Transaction'
|
export * from './Transaction'
|
||||||
|
export * from './ensureLoggedIn'
|
||||||
|
export * from './handlePromise'
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import express from 'express'
|
import express from 'express'
|
||||||
import {IRoutes, IMethod} from '@rondo/common'
|
import {IRoutes, TMethod} from '@rondo/common'
|
||||||
import {ITypedHandler} from './ITypedHandler'
|
import {TTypedHandler} from './TTypedHandler'
|
||||||
|
|
||||||
export class AsyncRouter<R extends IRoutes> {
|
export class AsyncRouter<R extends IRoutes> {
|
||||||
readonly router: express.Router
|
readonly router: express.Router
|
||||||
@ -11,18 +11,18 @@ export class AsyncRouter<R extends IRoutes> {
|
|||||||
this.use = this.router.use.bind(this.router) as any
|
this.use = this.router.use.bind(this.router) as any
|
||||||
}
|
}
|
||||||
|
|
||||||
protected addRoute<M extends IMethod, P extends keyof R & string>(
|
protected addRoute<M extends TMethod, P extends keyof R & string>(
|
||||||
method: M,
|
method: M,
|
||||||
path: P,
|
path: P,
|
||||||
handler: ITypedHandler<R, P, M>,
|
handler: TTypedHandler<R, P, M>,
|
||||||
) {
|
) {
|
||||||
const addRoute = this.router[method].bind(this.router as any)
|
const addRoute = this.router[method].bind(this.router as any)
|
||||||
|
|
||||||
addRoute(path, this.wrapHandler(handler))
|
addRoute(path, this.wrapHandler(handler))
|
||||||
}
|
}
|
||||||
|
|
||||||
protected wrapHandler<M extends IMethod, P extends keyof R & string>(
|
protected wrapHandler<M extends TMethod, P extends keyof R & string>(
|
||||||
handler: ITypedHandler<R, P, M>,
|
handler: TTypedHandler<R, P, M>,
|
||||||
): express.RequestHandler {
|
): express.RequestHandler {
|
||||||
return (req, res, next) => {
|
return (req, res, next) => {
|
||||||
handler(req, res, next)
|
handler(req, res, next)
|
||||||
@ -35,43 +35,43 @@ export class AsyncRouter<R extends IRoutes> {
|
|||||||
|
|
||||||
get<P extends keyof R & string>(
|
get<P extends keyof R & string>(
|
||||||
path: P,
|
path: P,
|
||||||
handler: ITypedHandler<R, P, 'get'>,
|
handler: TTypedHandler<R, P, 'get'>,
|
||||||
) {
|
) {
|
||||||
this.addRoute('get', path, handler)
|
this.addRoute('get', path, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
post<P extends keyof R & string>(
|
post<P extends keyof R & string>(
|
||||||
path: P,
|
path: P,
|
||||||
handler: ITypedHandler<R, P, 'post'>,
|
handler: TTypedHandler<R, P, 'post'>,
|
||||||
) {
|
) {
|
||||||
this.addRoute('post', path, handler)
|
this.addRoute('post', path, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
put<P extends keyof R & string>(
|
put<P extends keyof R & string>(
|
||||||
path: P, handler: ITypedHandler<R, P, 'put'>,
|
path: P, handler: TTypedHandler<R, P, 'put'>,
|
||||||
) {
|
) {
|
||||||
this.addRoute('put', path, handler)
|
this.addRoute('put', path, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
delete<P extends keyof R & string>(
|
delete<P extends keyof R & string>(
|
||||||
path: P, handler: ITypedHandler<R, P, 'delete'>) {
|
path: P, handler: TTypedHandler<R, P, 'delete'>) {
|
||||||
this.addRoute('delete', path, handler)
|
this.addRoute('delete', path, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
head<P extends keyof R & string>(
|
head<P extends keyof R & string>(
|
||||||
path: P,
|
path: P,
|
||||||
handler: ITypedHandler<R, P, 'head'>,
|
handler: TTypedHandler<R, P, 'head'>,
|
||||||
) {
|
) {
|
||||||
this.addRoute('head', path, handler)
|
this.addRoute('head', path, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
options<P extends keyof R & string>(
|
options<P extends keyof R & string>(
|
||||||
path: P, handler: ITypedHandler<R, P, 'options'>) {
|
path: P, handler: TTypedHandler<R, P, 'options'>) {
|
||||||
this.addRoute('options', path, handler)
|
this.addRoute('options', path, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
patch<P extends keyof R & string>(
|
patch<P extends keyof R & string>(
|
||||||
path: P, handler: ITypedHandler<R, P, 'patch'>) {
|
path: P, handler: TTypedHandler<R, P, 'patch'>) {
|
||||||
this.addRoute('patch', path, handler)
|
this.addRoute('patch', path, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
import express from 'express'
|
import express from 'express'
|
||||||
import {IRoutes, IMethod} from '@rondo/common'
|
import {IRoutes, TMethod} from '@rondo/common'
|
||||||
import {ITypedRequest} from './ITypedRequest'
|
import {ITypedRequest} from './ITypedRequest'
|
||||||
|
|
||||||
export type ITypedHandler<
|
export type TTypedHandler<
|
||||||
R extends IRoutes,
|
R extends IRoutes,
|
||||||
P extends keyof R,
|
P extends keyof R,
|
||||||
M extends IMethod
|
M extends TMethod
|
||||||
> = (
|
> = (
|
||||||
req: ITypedRequest<R[P][M]>,
|
req: ITypedRequest<R[P][M]>,
|
||||||
res: express.Response,
|
res: express.Response,
|
||||||
@ -1,16 +1,16 @@
|
|||||||
import express from 'express'
|
import express from 'express'
|
||||||
import {AsyncRouter} from './AsyncRouter'
|
import {AsyncRouter} from './AsyncRouter'
|
||||||
import {IRoutes, IMethod} from '@rondo/common'
|
import {IRoutes, TMethod} from '@rondo/common'
|
||||||
import {ITransactionManager} from '../database/ITransactionManager'
|
import {ITransactionManager} from '../database/ITransactionManager'
|
||||||
import {ITypedHandler} from './ITypedHandler'
|
import {TTypedHandler} from './TTypedHandler'
|
||||||
|
|
||||||
export class TransactionalRouter<R extends IRoutes> extends AsyncRouter<R> {
|
export class TransactionalRouter<R extends IRoutes> extends AsyncRouter<R> {
|
||||||
constructor(readonly transactionManager: ITransactionManager) {
|
constructor(readonly transactionManager: ITransactionManager) {
|
||||||
super()
|
super()
|
||||||
}
|
}
|
||||||
|
|
||||||
protected wrapHandler<M extends IMethod, P extends keyof R & string>(
|
protected wrapHandler<M extends TMethod, P extends keyof R & string>(
|
||||||
handler: ITypedHandler<R, P, M>,
|
handler: TTypedHandler<R, P, M>,
|
||||||
): express.RequestHandler {
|
): express.RequestHandler {
|
||||||
return async (req, res, next) => {
|
return async (req, res, next) => {
|
||||||
await this.transactionManager
|
await this.transactionManager
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
export * from './AsyncRouter'
|
export * from './AsyncRouter'
|
||||||
export * from './ITypedHandler'
|
export * from './TTypedHandler'
|
||||||
export * from './ITypedRequest'
|
export * from './ITypedRequest'
|
||||||
export * from './TransactionalRouter'
|
export * from './TransactionalRouter'
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import {IHandler} from '../middleware/IHandler'
|
import {THandler} from '../middleware/THandler'
|
||||||
import {AsyncRouter} from '../router'
|
import {AsyncRouter} from '../router'
|
||||||
import {IRoutes} from '@rondo/common'
|
import {IRoutes} from '@rondo/common'
|
||||||
|
|
||||||
export abstract class BaseRoute<T extends IRoutes> {
|
export abstract class BaseRoute<T extends IRoutes> {
|
||||||
readonly handle: IHandler
|
readonly handle: THandler
|
||||||
|
|
||||||
constructor(protected readonly t: AsyncRouter<T>) {
|
constructor(protected readonly t: AsyncRouter<T>) {
|
||||||
this.handle = t.router
|
this.handle = t.router
|
||||||
|
|||||||
@ -9,11 +9,11 @@ type CallbackErr = (err?: any) => void
|
|||||||
export interface ISessionStoreOptions<S extends ISession> {
|
export interface ISessionStoreOptions<S extends ISession> {
|
||||||
readonly ttl: number
|
readonly ttl: number
|
||||||
readonly cleanup: number
|
readonly cleanup: number
|
||||||
readonly getRepository: IRepositoryFactory<S>
|
readonly getRepository: TRepositoryFactory<S>
|
||||||
buildSession(sessionData: SessionData, session: ISession): S
|
buildSession(sessionData: SessionData, session: ISession): S
|
||||||
}
|
}
|
||||||
|
|
||||||
export type IRepositoryFactory<T> = () => Repository<T>
|
export type TRepositoryFactory<T> = () => Repository<T>
|
||||||
|
|
||||||
// TODO casting as any because TypeScript complains. Looks like this is a
|
// TODO casting as any because TypeScript complains. Looks like this is a
|
||||||
// bug in TypeScript 3.2.2
|
// bug in TypeScript 3.2.2
|
||||||
@ -22,7 +22,7 @@ export type IRepositoryFactory<T> = () => Repository<T>
|
|||||||
// https://github.com/Microsoft/TypeScript/issues/21592
|
// https://github.com/Microsoft/TypeScript/issues/21592
|
||||||
export class SessionStore<S extends ISession> extends Store {
|
export class SessionStore<S extends ISession> extends Store {
|
||||||
|
|
||||||
protected readonly getRepository: IRepositoryFactory<S>
|
protected readonly getRepository: TRepositoryFactory<S>
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
protected readonly options: ISessionStoreOptions<S>,
|
protected readonly options: ISessionStoreOptions<S>,
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import supertest from 'supertest'
|
import supertest from 'supertest'
|
||||||
import {
|
import {
|
||||||
IMethod,
|
TMethod,
|
||||||
IRoutes,
|
IRoutes,
|
||||||
URLFormatter,
|
URLFormatter,
|
||||||
} from '@rondo/common'
|
} from '@rondo/common'
|
||||||
@ -13,7 +13,7 @@ interface ITest extends Omit<Omit<supertest.Test, 'then'>, 'catch'> {}
|
|||||||
interface IResponse<
|
interface IResponse<
|
||||||
R extends IRoutes,
|
R extends IRoutes,
|
||||||
P extends keyof R,
|
P extends keyof R,
|
||||||
M extends IMethod,
|
M extends TMethod,
|
||||||
> extends supertest.Response {
|
> extends supertest.Response {
|
||||||
body: R[P][M]['response']
|
body: R[P][M]['response']
|
||||||
header: {[key: string]: string}
|
header: {[key: string]: string}
|
||||||
@ -22,7 +22,7 @@ interface IResponse<
|
|||||||
interface IRequest<
|
interface IRequest<
|
||||||
R extends IRoutes,
|
R extends IRoutes,
|
||||||
P extends keyof R,
|
P extends keyof R,
|
||||||
M extends IMethod,
|
M extends TMethod,
|
||||||
> extends ITest, Promise<IResponse<R, P, M>> {
|
> extends ITest, Promise<IResponse<R, P, M>> {
|
||||||
send(value: R[P][M]['body'] | string): this
|
send(value: R[P][M]['body'] | string): this
|
||||||
expect(status: number, body?: any): this
|
expect(status: number, body?: any): this
|
||||||
@ -37,7 +37,7 @@ interface IRequest<
|
|||||||
interface IRequestOptions<
|
interface IRequestOptions<
|
||||||
R extends IRoutes,
|
R extends IRoutes,
|
||||||
P extends keyof R,
|
P extends keyof R,
|
||||||
M extends IMethod,
|
M extends TMethod,
|
||||||
> {
|
> {
|
||||||
params?: R[P][M]['params'],
|
params?: R[P][M]['params'],
|
||||||
query?: R[P][M]['query'],
|
query?: R[P][M]['query'],
|
||||||
@ -62,7 +62,7 @@ export class RequestTester<R extends IRoutes> {
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
request<M extends IMethod, P extends keyof R & string>(
|
request<M extends TMethod, P extends keyof R & string>(
|
||||||
method: M, path: P, options: IRequestOptions<R, P, 'post'> = {},
|
method: M, path: P, options: IRequestOptions<R, P, 'post'> = {},
|
||||||
)
|
)
|
||||||
: IRequest<R, P, M> {
|
: IRequest<R, P, M> {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user