Skip to content

Commit

Permalink
Merge pull request #667 from microsoft/dev
Browse files Browse the repository at this point in the history
July Sprint 1 (Due July 15th) Release
  • Loading branch information
mdeitner authored Jul 15, 2022
2 parents 783d16e + 5ab2709 commit a1160b5
Show file tree
Hide file tree
Showing 80 changed files with 1,993 additions and 911 deletions.
16 changes: 12 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,13 @@ jobs:
env:
API_SOCKET_URL: ${{ secrets.API_SOCKET_URL }}
API_URL: ${{ secrets.API_URL }}
INSTRUMENTATION_KEY: ${{ secrets.WEBAPP_APPINSIGHTS_KEY }}
INSTRUMENTATION_KEY: ${{ secrets.APPINSIGHTS_KEY }}
WEBAPP_ORIGIN: ${{ secrets.WEBAPP_ORIGIN }}
WEBAPP_STORAGE_ACCOUNT: ${{ secrets.WEBAPP_STORAGE_ACCOUNT }}
WEBAPP_STORAGE_KEY: ${{ secrets.WEBAPP_STORAGE_KEY }}
TAKE_PHOTO_MODE_ENABLED: ${{ secrets.TAKE_PHOTO_MODE_ENABLED }}
OFFLINE_MODE_ENABLED: ${{ secrets.OFFLINE_MODE_ENABLED }}
DURABLE_CACHE_ENABLED: ${{ secrets.DURABLE_CACHE_ENABLED }}

deploy-staging:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -117,11 +120,13 @@ jobs:
env:
API_SOCKET_URL: ${{ secrets.API_SOCKET_URL }}
API_URL: ${{ secrets.API_URL }}
INSTRUMENTATION_KEY: ${{ secrets.WEBAPP_APPINSIGHTS_KEY }}
INSTRUMENTATION_KEY: ${{ secrets.APPINSIGHTS_KEY }}
WEBAPP_ORIGIN: ${{ secrets.WEBAPP_ORIGIN }}
WEBAPP_STORAGE_ACCOUNT: ${{ secrets.WEBAPP_STORAGE_ACCOUNT }}
WEBAPP_STORAGE_KEY: ${{ secrets.WEBAPP_STORAGE_KEY }}
TAKE_PHOTO_MODE_ENABLED: ${{ secrets.TAKE_PHOTO_MODE_ENABLED }}
OFFLINE_MODE_ENABLED: ${{ secrets.OFFLINE_MODE_ENABLED }}
DURABLE_CACHE_ENABLED: ${{ secrets.DURABLE_CACHE_ENABLED }}

deploy-demo:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -151,10 +156,13 @@ jobs:
env:
API_SOCKET_URL: ${{ secrets.API_SOCKET_URL }}
API_URL: ${{ secrets.API_URL }}
INSTRUMENTATION_KEY: ${{ secrets.WEBAPP_APPINSIGHTS_KEY }}
INSTRUMENTATION_KEY: ${{ secrets.APPINSIGHTS_KEY }}
WEBAPP_ORIGIN: ${{ secrets.WEBAPP_ORIGIN }}
WEBAPP_STORAGE_ACCOUNT: ${{ secrets.WEBAPP_STORAGE_ACCOUNT }}
WEBAPP_STORAGE_KEY: ${{ secrets.WEBAPP_STORAGE_KEY }}
TAKE_PHOTO_MODE_ENABLED: ${{ secrets.TAKE_PHOTO_MODE_ENABLED }}
OFFLINE_MODE_ENABLED: ${{ secrets.OFFLINE_MODE_ENABLED }}
DURABLE_CACHE_ENABLED: ${{ secrets.DURABLE_CACHE_ENABLED }}

deploy-production:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -184,7 +192,7 @@ jobs:
env:
API_SOCKET_URL: ${{ secrets.API_SOCKET_URL }}
API_URL: ${{ secrets.API_URL }}
INSTRUMENTATION_KEY: ${{ secrets.WEBAPP_APPINSIGHTS_KEY }}
INSTRUMENTATION_KEY: ${{ secrets.APPINSIGHTS_KEY }}
WEBAPP_ORIGIN: ${{ secrets.WEBAPP_ORIGIN }}
WEBAPP_STORAGE_ACCOUNT: ${{ secrets.WEBAPP_STORAGE_ACCOUNT }}
WEBAPP_STORAGE_KEY: ${{ secrets.WEBAPP_STORAGE_KEY }}
2 changes: 1 addition & 1 deletion packages/api/config/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
},
"constants": {
"defaultPageOffset": 0,
"defaultPageLimit": 10
"defaultPageLimit": 1000
},
"security": {
"jwtSecret": null,
Expand Down
2 changes: 1 addition & 1 deletion packages/api/src/db/CollectionBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ export abstract class CollectionBase<Item extends DbIdentified> {

/**
* Finds a set of items
* @param pagination The pagiantion arguments
* @param pagination The pagination arguments
* @param filter The filter criteria to apply, optional
* @returns A DbListItem
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Licensed under the MIT license. See LICENSE file in the project.
*/

import { QueryExportDataArgs, Engagement } from '@cbosuite/schema/dist/provider-types'
import { QueryAllEngagementsArgs, Engagement } from '@cbosuite/schema/dist/provider-types'
import { createGQLEngagement } from '~dto'
import { Interactor, RequestContext } from '~types'
import { sortByDate } from '~utils'
Expand All @@ -15,14 +15,14 @@ import { Telemetry } from '~components/Telemetry'
const QUERY = {}

@singleton()
export class ExportDataInteractor
implements Interactor<unknown, QueryExportDataArgs, Engagement[]>
export class AllEngagementsInteractor
implements Interactor<unknown, QueryAllEngagementsArgs, Engagement[]>
{
public constructor(private engagements: EngagementCollection, private telemetry: Telemetry) {}

public async execute(
_: unknown,
{ orgId }: QueryExportDataArgs,
{ orgId }: QueryAllEngagementsArgs,
ctx: RequestContext
): Promise<Engagement[]> {
// out-of-org users should not export org data
Expand All @@ -31,7 +31,7 @@ export class ExportDataInteractor
}

const result = await this.engagements.items(QUERY, { org_id: orgId })
this.telemetry.trackEvent('ExportData')
this.telemetry.trackEvent('AllEngagements')
return result.items
.sort((a, b) => sortByDate({ date: a.start_date }, { date: b.start_date }))
.map(createGQLEngagement)
Expand Down
21 changes: 12 additions & 9 deletions packages/api/src/interactors/query/GetEngagementsInteractorBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
QueryActiveEngagementsArgs,
EngagementStatus
} from '@cbosuite/schema/dist/provider-types'
import { Condition } from 'mongodb'
import { Condition, FilterQuery } from 'mongodb'
import { Configuration } from '~components/Configuration'
import { EngagementCollection } from '~db/EngagementCollection'
import { DbEngagement } from '~db/types'
Expand All @@ -26,7 +26,7 @@ export abstract class GetEngagementsInteractorBase

public async execute(
_: unknown,
{ orgId, offset, limit }: QueryActiveEngagementsArgs,
{ orgId, userId, offset, limit }: QueryActiveEngagementsArgs,
ctx: RequestContext
): Promise<Engagement[]> {
offset = offset ?? this.config.defaultPageOffset
Expand All @@ -37,13 +37,16 @@ export abstract class GetEngagementsInteractorBase
return empty
}

const result = await this.engagements.items(
{ offset, limit },
{
org_id: orgId,
status: { $nin: [EngagementStatus.Closed, EngagementStatus.Completed] }
}
)
const filter: FilterQuery<DbEngagement> = {
org_id: orgId,
status: { $nin: [EngagementStatus.Closed, EngagementStatus.Completed] }
}

if (userId) {
filter.user_id = { $ne: userId as string }
}

const result = await this.engagements.items({ offset, limit }, filter)

return result.items.sort(this.sortBy).map(createGQLEngagement)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*!
* Copyright (c) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE file in the project.
*/
import {
Engagement,
EngagementStatus,
QueryUserActiveEngagementsArgs
} from '@cbosuite/schema/dist/provider-types'
import { singleton } from 'tsyringe'
import { Configuration } from '~components/Configuration'
import { EngagementCollection } from '~db/EngagementCollection'
import { DbEngagement } from '~db/types'
import { createGQLEngagement } from '~dto'
import { Interactor, RequestContext } from '~types'
import { sortByDate } from '~utils'
import { empty } from '~utils/noop'

@singleton()
export class GetUserActiveEngagementsInteractor
implements Interactor<unknown, QueryUserActiveEngagementsArgs, Engagement[]>
{
public constructor(
protected engagements: EngagementCollection,
protected config: Configuration
) {}

protected sortBy(a: DbEngagement, b: DbEngagement) {
return sortByDate({ date: a.end_date as string }, { date: b.end_date as string })
}
public async execute(
_: unknown,
{ orgId, userId, offset, limit }: QueryUserActiveEngagementsArgs,
ctx: RequestContext
): Promise<Engagement[]> {
offset = offset ?? this.config.defaultPageOffset
limit = limit ?? this.config.defaultPageLimit

// out-of-org users should not see org engagements
if (!ctx.identity?.roles.some((r) => r.org_id === orgId)) {
return empty
}

const result = await this.engagements.items(
{ offset, limit },
{
org_id: orgId,
user_id: userId,
status: { $nin: [EngagementStatus.Closed, EngagementStatus.Completed] }
}
)

return result.items.sort(this.sortBy).map(createGQLEngagement)
}
}
6 changes: 4 additions & 2 deletions packages/api/src/resolvers/resolvers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ import { GetContactInteractor } from '~interactors/query/GetContactInteractor'
import { GetContactsInteractor } from '~interactors/query/GetContactsInteractor'
import { GetEngagementInteractor } from '~interactors/query/GetEngagementInteractor'
import { GetActiveEngagementsInteractor } from '~interactors/query/GetActiveEngagementsInteractor'
import { GetUserActiveEngagementsInteractor } from '~interactors/query/GetUserActiveEngagementsInteractor'
import { GetInactiveEngagementsInteractor } from '~interactors/query/GetInactiveEngagementsInteractor'
import { ExportDataInteractor } from '~interactors/query/ExportDataInteractor'
import { AllEngagementsInteractor } from '~interactors/query/AllEngagementsInteractor'
import { GetServicesInteractor } from '~interactors/query/GetServicesInteractor'
import { GetServicesAnswersInteractor } from '~interactors/query/GetServiceAnswersInteractor'
import { AuthenticateInteractor } from '~interactors/mutation/AuthenticateInteractor'
Expand Down Expand Up @@ -91,8 +92,9 @@ export const resolvers: Resolvers<RequestContext> & IResolvers<any, RequestConte
contacts: use(GetContactsInteractor),
engagement: use(GetEngagementInteractor),
activeEngagements: use(GetActiveEngagementsInteractor),
userActiveEngagements: use(GetUserActiveEngagementsInteractor),
inactiveEngagements: use(GetInactiveEngagementsInteractor),
exportData: use(ExportDataInteractor),
allEngagements: use(AllEngagementsInteractor),
services: use(GetServicesInteractor),
serviceAnswers: use(GetServicesAnswersInteractor)
},
Expand Down
15 changes: 11 additions & 4 deletions packages/schema/schema.gql
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,16 @@ type Query {
#
# Retrieve a list of active engagements
#
activeEngagements(orgId: String!, offset: Int, limit: Int): [Engagement!]! @orgAuth
# If an `userId` is provided, filter out engagements assigned to it.
#
activeEngagements(orgId: String!, userId: String, offset: Int, limit: Int): [Engagement!]!
@orgAuth

#
# Retrieve a list of active engagements assigned to a user
#
userActiveEngagements(orgId: String!, userId: String!, offset: Int, limit: Int): [Engagement!]!
@orgAuth

#
# Retrieve a list of inactive engagements (i.e. Closed, Completed)
Expand All @@ -58,9 +67,7 @@ type Query {
#
# Retrieve a list of engagements
#
# TODO: Rename this to allEngagements
#
exportData(orgId: String!): [Engagement!]! @orgAuth(requires: ADMIN)
allEngagements(orgId: String!): [Engagement!]! @orgAuth(requires: ADMIN)

#
# Retrieve a list of services
Expand Down
3 changes: 3 additions & 0 deletions packages/webapp/config/ci.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
},
"takePhotoMode": {
"enabled": false
},
"durableCache": {
"enabled": false
}
}
}
3 changes: 3 additions & 0 deletions packages/webapp/config/custom-environment-variables.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@
},
"takePhotoMode": {
"enabled": "TAKE_PHOTO_MODE_ENABLED"
},
"durableCache": {
"enabled": "DURABLE_CACHE_ENABLED"
}
}
}
2 changes: 1 addition & 1 deletion packages/webapp/config/development.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"enabled": true
},
"devLogger": {
"enabled": true
"enabled": false
},
"durableCache": {
"enabled": true
Expand Down
5 changes: 5 additions & 0 deletions packages/webapp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,12 @@
"@microsoft/applicationinsights-react-js": "^3.2.4",
"@microsoft/applicationinsights-web": "^2.7.4",
"apollo3-cache-persist": "^0.14.0",
"bcryptjs": "^2.4.3",
"bootstrap": "^5.1.3",
"classnames": "^2.3.1",
"config": "^3.3.7",
"core-js": "^3.21.1",
"crypto-js": "^4.1.1",
"debug": "^4.3.3",
"firebase": "^8.10.1",
"formik": "^2.2.9",
Expand All @@ -59,6 +61,7 @@
"react-paginated-list": "^1.1.5",
"react-router-dom": "^5.3.0",
"react-select": "^4.3.1",
"react-stores": "^5.5.0",
"react-toast-notifications": "^2.5.1",
"react-transition-group": "^4.4.2",
"recoil": "^0.6.1",
Expand All @@ -80,7 +83,9 @@
"@tsconfig/node14": "^1.0.1",
"@types/babel__core": "^7.1.18",
"@types/babel__preset-env": "^7.9.2",
"@types/bcryptjs": "^2.4.2",
"@types/config": "^0.0.41",
"@types/crypto-js": "^4.1.1",
"@types/debug": "^4.1.7",
"@types/express": "^4.17.13",
"@types/jest": "^27.4.1",
Expand Down
46 changes: 40 additions & 6 deletions packages/webapp/src/api/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
import { config } from '~utils/config'
import { InMemoryCache } from '@apollo/client/core'
import localForage from 'localforage'
import { persistCache, LocalForageWrapper } from 'apollo3-cache-persist'
import { persistCache } from 'apollo3-cache-persist'
import { createLogger } from '~utils/createLogger'
import { LocalForageWrapperEncrypted } from './local-forage-encrypted-wrapper'

/**
* Setup the "InMemoryCache" for Apollo.
Expand All @@ -20,13 +21,42 @@ import { createLogger } from '~utils/createLogger'
let isDurableCacheInitialized = false
const isDurableCacheEnabled = Boolean(config.features.durableCache.enabled)
const logger = createLogger('cache')
const cache: InMemoryCache = new InMemoryCache()

export function getCache() {
if (isDurableCacheInitialized) {
const cache: InMemoryCache = new InMemoryCache({
typePolicies: {
Engagement: {
merge: true,
fields: {
actions: {
merge: false
},
user: {
merge: false
}
}
},
Query: {
fields: {
engagement: {
// Cache Redirects
// https://www.apollographql.com/docs/react/caching/advanced-topics#cache-redirects
read(existing, { args, toReference }) {
return toReference({
__typename: 'Engagement',
id: args.id
})
}
}
}
}
}
})

export function getCache(reloadCache = false) {
if (isDurableCacheInitialized && !reloadCache) {
logger('durable cache is enabled')
} else if (!isDurableCacheInitialized && isDurableCacheEnabled) {
persistCache({ cache, storage: new LocalForageWrapper(localForage) })
} else if (isDurableCacheEnabled) {
persistCache({ cache, storage: new LocalForageWrapperEncrypted(localForage) })
.then(() => {
isDurableCacheInitialized = true
logger('durable cache is setup and enabled')
Expand All @@ -37,3 +67,7 @@ export function getCache() {
}
return cache
}

export const isCacheInitialized = (): boolean => {
return isDurableCacheInitialized
}
2 changes: 1 addition & 1 deletion packages/webapp/src/api/createErrorLink.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,6 @@ export function createErrorLink(history: History) {
})
}

const UNAUTHENTICATED = 'UNAUTHENTICATED'
export const UNAUTHENTICATED = 'UNAUTHENTICATED'
const TOKEN_EXPIRED = 'TOKEN_EXPIRED'
const TOKEN_EXPIRED_ERROR = 'TokenExpiredError'
Loading

0 comments on commit a1160b5

Please sign in to comment.