From b29b8e130d8073092aa6a8ffa23a3295cc5851c4 Mon Sep 17 00:00:00 2001 From: Atul Varma Date: Tue, 5 Mar 2019 07:10:05 -0500 Subject: [PATCH 01/17] Add a commondatabuilder tool. --- common-data/config.ts | 14 ++++ commondatabuilder.js | 3 + frontend/commondatabuilder/cli.ts | 22 +++++ .../commondatabuilder/commondatabuilder.ts | 84 +++++++++++++++++++ .../tests/commondatabuilder.test.ts | 39 +++++++++ 5 files changed, 162 insertions(+) create mode 100644 common-data/config.ts create mode 100644 commondatabuilder.js create mode 100644 frontend/commondatabuilder/cli.ts create mode 100644 frontend/commondatabuilder/commondatabuilder.ts create mode 100644 frontend/commondatabuilder/tests/commondatabuilder.test.ts diff --git a/common-data/config.ts b/common-data/config.ts new file mode 100644 index 000000000..fa05f764a --- /dev/null +++ b/common-data/config.ts @@ -0,0 +1,14 @@ +import { DjangoChoicesTypescriptConfig } from '../frontend/commondatabuilder/commondatabuilder'; + +const config: DjangoChoicesTypescriptConfig = { + rootDir: __dirname, + files: [ + { + jsonFilename: 'issue-choices.json', + enumName: 'IssueChoice', + exportLabels: true, + } + ] +}; + +export default config; diff --git a/commondatabuilder.js b/commondatabuilder.js new file mode 100644 index 000000000..1b727684c --- /dev/null +++ b/commondatabuilder.js @@ -0,0 +1,3 @@ +require('./frontend/webpack/babel-register'); + +require('./frontend/commondatabuilder/cli').run(); diff --git a/frontend/commondatabuilder/cli.ts b/frontend/commondatabuilder/cli.ts new file mode 100644 index 000000000..2a9371b48 --- /dev/null +++ b/frontend/commondatabuilder/cli.ts @@ -0,0 +1,22 @@ +import { argvHasOption } from "../querybuilder/util"; +import ourConfig from "../../common-data/config"; +import { createDjangoChoicesTypescriptFiles } from "./commondatabuilder"; + +const VERSION = '0.1.0'; + +export function run() { + if (argvHasOption('-h', '--help')) { + console.log(`usage: ${process.argv[1]} [OPTIONS]\n`); + console.log(`options:\n`); + console.log(' -h / --help Show this help'); + console.log(' -v / --version Show the version number'); + process.exit(0); + } + + if (argvHasOption('-v', '--version')) { + console.log(`commondatabuilder version ${VERSION}`); + process.exit(0); + } + + createDjangoChoicesTypescriptFiles(ourConfig); +} diff --git a/frontend/commondatabuilder/commondatabuilder.ts b/frontend/commondatabuilder/commondatabuilder.ts new file mode 100644 index 000000000..b13dc875e --- /dev/null +++ b/frontend/commondatabuilder/commondatabuilder.ts @@ -0,0 +1,84 @@ +import * as fs from 'fs'; +import * as path from 'path'; + +import { DjangoChoices } from "../lib/common-data"; + +type CreateOptions = { + exportLabels: boolean +}; + +const defaultOptions: CreateOptions = { exportLabels: true }; + +export type DjangoChoicesTypescriptConfig = { + rootDir: string, + files: DjangoChoicesTypescriptFileConfig[] +}; + +export type DjangoChoicesTypescriptFileConfig = { + jsonFilename: string, + enumName: string, + exportLabels: boolean +}; + +function replaceExt(filename: string, ext: string) { + // https://stackoverflow.com/a/5953384 + return filename.substr(0, filename.lastIndexOf(".")) + ext; +} + +export function createDjangoChoicesTypescriptFiles( + config: DjangoChoicesTypescriptConfig, + dryRun: boolean = false +) { + config.files.forEach(fileConfig => { + const infile = path.join(config.rootDir, fileConfig.jsonFilename); + const choices = JSON.parse(fs.readFileSync(infile, { + encoding: 'utf-8' + })) as DjangoChoices; + const ts = createDjangoChoicesTypescript(choices, fileConfig.enumName, { + exportLabels: fileConfig.exportLabels + }); + const outfilename = replaceExt(fileConfig.jsonFilename, '.ts'); + const outfile = path.join(config.rootDir, outfilename); + if (!dryRun) { + console.log(`Writing ${outfilename}.`); + fs.writeFileSync(outfile, ts, { encoding: 'utf-8' }); + } + }); +} + +export function createDjangoChoicesTypescript( + choices: DjangoChoices, + name: string, + options: Partial = {} +): string { + const { exportLabels } = Object.assign({}, defaultOptions, options); + const lines = [ + `// This file was auto-generated by commondatabuilder.`, + `// Please don't edit it.\n`, + `export enum ${name} {` + ]; + for (let choice of choices) { + const name = choice[0]; + lines.push(` ${name} = "${name}",`); + } + lines.push('}\n'); + lines.push( + `export type ${name}Labels = {`, + ` [k in ${name}]: string;`, + `};\n` + ); + if (exportLabels) { + lines.push( + `export function get${name}Labels(): ${name}Labels {`, + ` return {` + ); + for (let [name, label] of choices) { + lines.push(` ${name}: ${JSON.stringify(label)},`); + } + lines.push( + ' };', + '}\n' + ); + } + return lines.join('\n'); +} diff --git a/frontend/commondatabuilder/tests/commondatabuilder.test.ts b/frontend/commondatabuilder/tests/commondatabuilder.test.ts new file mode 100644 index 000000000..a9877aa3d --- /dev/null +++ b/frontend/commondatabuilder/tests/commondatabuilder.test.ts @@ -0,0 +1,39 @@ +import { createDjangoChoicesTypescript, createDjangoChoicesTypescriptFiles } from "../commondatabuilder"; + +import ourConfig from "../../../common-data/config"; + +const EXPECTED_TS = `// This file was auto-generated by commondatabuilder. +// Please don't edit it. + +export enum BoroughChoice { + BROOKLYN = "BROOKLYN", +} + +export type BoroughChoiceLabels = { + [k in BoroughChoice]: string; +}; + +export function getBoroughChoiceLabels(): BoroughChoiceLabels { + return { + BROOKLYN: "Brooklyn", + }; +} +`; + +describe('commondatabuilder', () => { + it('creates django choice typescript', () => { + const ts = createDjangoChoicesTypescript([['BROOKLYN', 'Brooklyn']], 'BoroughChoice'); + expect(ts).toEqual(EXPECTED_TS); + }); + + it('only exports labels if configured to', () => { + expect(createDjangoChoicesTypescript([], 'Foo')).toMatch(/getFooLabels/); + expect(createDjangoChoicesTypescript([], 'Foo', { + exportLabels: false + })).not.toMatch(/getFooLabels/); + }); + + it('works with our common data configuration', () => { + createDjangoChoicesTypescriptFiles(ourConfig, true); + }); +}); From 659de4a9c9b9ea1662e8d5a5c85265c9020a3202 Mon Sep 17 00:00:00 2001 From: Atul Varma Date: Tue, 5 Mar 2019 08:23:58 -0500 Subject: [PATCH 02/17] Add a filterOut option to choice configs. --- common-data/config.ts | 1 + frontend/commondatabuilder/commondatabuilder.ts | 10 +++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/common-data/config.ts b/common-data/config.ts index fa05f764a..0fa4dab63 100644 --- a/common-data/config.ts +++ b/common-data/config.ts @@ -7,6 +7,7 @@ const config: DjangoChoicesTypescriptConfig = { jsonFilename: 'issue-choices.json', enumName: 'IssueChoice', exportLabels: true, + filterOut: /^LANDLORD__/ } ] }; diff --git a/frontend/commondatabuilder/commondatabuilder.ts b/frontend/commondatabuilder/commondatabuilder.ts index b13dc875e..918358d07 100644 --- a/frontend/commondatabuilder/commondatabuilder.ts +++ b/frontend/commondatabuilder/commondatabuilder.ts @@ -1,7 +1,7 @@ import * as fs from 'fs'; import * as path from 'path'; -import { DjangoChoices } from "../lib/common-data"; +import { DjangoChoices, filterDjangoChoices } from "../lib/common-data"; type CreateOptions = { exportLabels: boolean @@ -17,7 +17,8 @@ export type DjangoChoicesTypescriptConfig = { export type DjangoChoicesTypescriptFileConfig = { jsonFilename: string, enumName: string, - exportLabels: boolean + exportLabels: boolean, + filterOut?: RegExp|string[], }; function replaceExt(filename: string, ext: string) { @@ -31,9 +32,12 @@ export function createDjangoChoicesTypescriptFiles( ) { config.files.forEach(fileConfig => { const infile = path.join(config.rootDir, fileConfig.jsonFilename); - const choices = JSON.parse(fs.readFileSync(infile, { + let choices = JSON.parse(fs.readFileSync(infile, { encoding: 'utf-8' })) as DjangoChoices; + if (fileConfig.filterOut) { + choices = filterDjangoChoices(choices, fileConfig.filterOut); + } const ts = createDjangoChoicesTypescript(choices, fileConfig.enumName, { exportLabels: fileConfig.exportLabels }); From 06696a4df04ca94190a32f04ed6549c55e3bbff1 Mon Sep 17 00:00:00 2001 From: Atul Varma Date: Tue, 5 Mar 2019 08:24:39 -0500 Subject: [PATCH 03/17] Add commondatabuilder.js smoke test. --- .circleci/config.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 3418f5f4c..6c857e45b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -40,8 +40,9 @@ jobs: command: | node --version - # This is intended as a smoke test. + # These are intended as smoke tests. node querybuilder.js --version + node commondatabuilder.js --version npm run build npm test -- --runInBand From 5d0c0cfb98ae2513f5566c159d25daae06ffec19 Mon Sep 17 00:00:00 2001 From: Atul Varma Date: Tue, 5 Mar 2019 09:47:23 -0500 Subject: [PATCH 04/17] ok apollo codegen reverted its regression or something --- frontend/lib/queries/AccessDatesMutation.ts | 1 - frontend/lib/queries/AllSessionInfo.ts | 1 - frontend/lib/queries/ExampleMutation.ts | 1 - frontend/lib/queries/GenerateHPActionPDFMutation.ts | 1 - frontend/lib/queries/GetHPActionUploadStatus.ts | 1 - frontend/lib/queries/IssueAreaMutation.ts | 1 - frontend/lib/queries/LandlordDetailsMutation.ts | 1 - frontend/lib/queries/LetterRequestMutation.ts | 1 - frontend/lib/queries/LoginMutation.ts | 1 - frontend/lib/queries/LogoutMutation.ts | 1 - frontend/lib/queries/OnboardingStep1Mutation.ts | 1 - frontend/lib/queries/OnboardingStep2Mutation.ts | 1 - frontend/lib/queries/OnboardingStep3Mutation.ts | 1 - frontend/lib/queries/OnboardingStep4Mutation.ts | 1 - 14 files changed, 14 deletions(-) diff --git a/frontend/lib/queries/AccessDatesMutation.ts b/frontend/lib/queries/AccessDatesMutation.ts index 676de79ee..7e3e0d685 100644 --- a/frontend/lib/queries/AccessDatesMutation.ts +++ b/frontend/lib/queries/AccessDatesMutation.ts @@ -1,7 +1,6 @@ // This file was automatically generated and should not be edited. /* tslint:disable */ -/* eslint-disable */ // This file was automatically generated and should not be edited. import { AccessDatesInput } from "./globalTypes"; diff --git a/frontend/lib/queries/AllSessionInfo.ts b/frontend/lib/queries/AllSessionInfo.ts index 57a979b2a..695ffd284 100644 --- a/frontend/lib/queries/AllSessionInfo.ts +++ b/frontend/lib/queries/AllSessionInfo.ts @@ -1,7 +1,6 @@ // This file was automatically generated and should not be edited. /* tslint:disable */ -/* eslint-disable */ // This file was automatically generated and should not be edited. import { OnboardingInfoSignupIntent, LetterRequestMailChoice, HPUploadStatus } from "./globalTypes"; diff --git a/frontend/lib/queries/ExampleMutation.ts b/frontend/lib/queries/ExampleMutation.ts index 02bd7c5ef..2d69b2179 100644 --- a/frontend/lib/queries/ExampleMutation.ts +++ b/frontend/lib/queries/ExampleMutation.ts @@ -1,7 +1,6 @@ // This file was automatically generated and should not be edited. /* tslint:disable */ -/* eslint-disable */ // This file was automatically generated and should not be edited. import { ExampleInput } from "./globalTypes"; diff --git a/frontend/lib/queries/GenerateHPActionPDFMutation.ts b/frontend/lib/queries/GenerateHPActionPDFMutation.ts index 54c3b4c4f..67b164b8b 100644 --- a/frontend/lib/queries/GenerateHPActionPDFMutation.ts +++ b/frontend/lib/queries/GenerateHPActionPDFMutation.ts @@ -1,7 +1,6 @@ // This file was automatically generated and should not be edited. /* tslint:disable */ -/* eslint-disable */ // This file was automatically generated and should not be edited. import { GeneratePDFInput, HPUploadStatus } from "./globalTypes"; diff --git a/frontend/lib/queries/GetHPActionUploadStatus.ts b/frontend/lib/queries/GetHPActionUploadStatus.ts index 98aa07270..1d4c2a382 100644 --- a/frontend/lib/queries/GetHPActionUploadStatus.ts +++ b/frontend/lib/queries/GetHPActionUploadStatus.ts @@ -1,7 +1,6 @@ // This file was automatically generated and should not be edited. /* tslint:disable */ -/* eslint-disable */ // This file was automatically generated and should not be edited. import { HPUploadStatus } from "./globalTypes"; diff --git a/frontend/lib/queries/IssueAreaMutation.ts b/frontend/lib/queries/IssueAreaMutation.ts index a1895426f..f33f8d282 100644 --- a/frontend/lib/queries/IssueAreaMutation.ts +++ b/frontend/lib/queries/IssueAreaMutation.ts @@ -1,7 +1,6 @@ // This file was automatically generated and should not be edited. /* tslint:disable */ -/* eslint-disable */ // This file was automatically generated and should not be edited. import { IssueAreaInput } from "./globalTypes"; diff --git a/frontend/lib/queries/LandlordDetailsMutation.ts b/frontend/lib/queries/LandlordDetailsMutation.ts index b1d5e890a..725b1c4a6 100644 --- a/frontend/lib/queries/LandlordDetailsMutation.ts +++ b/frontend/lib/queries/LandlordDetailsMutation.ts @@ -1,7 +1,6 @@ // This file was automatically generated and should not be edited. /* tslint:disable */ -/* eslint-disable */ // This file was automatically generated and should not be edited. import { LandlordDetailsInput } from "./globalTypes"; diff --git a/frontend/lib/queries/LetterRequestMutation.ts b/frontend/lib/queries/LetterRequestMutation.ts index a2b607c2b..293ec3392 100644 --- a/frontend/lib/queries/LetterRequestMutation.ts +++ b/frontend/lib/queries/LetterRequestMutation.ts @@ -1,7 +1,6 @@ // This file was automatically generated and should not be edited. /* tslint:disable */ -/* eslint-disable */ // This file was automatically generated and should not be edited. import { LetterRequestInput, LetterRequestMailChoice } from "./globalTypes"; diff --git a/frontend/lib/queries/LoginMutation.ts b/frontend/lib/queries/LoginMutation.ts index 20fbe6442..d60219d52 100644 --- a/frontend/lib/queries/LoginMutation.ts +++ b/frontend/lib/queries/LoginMutation.ts @@ -2,7 +2,6 @@ import * as AllSessionInfo from './AllSessionInfo' /* tslint:disable */ -/* eslint-disable */ // This file was automatically generated and should not be edited. import { LoginInput, OnboardingInfoSignupIntent, LetterRequestMailChoice, HPUploadStatus } from "./globalTypes"; diff --git a/frontend/lib/queries/LogoutMutation.ts b/frontend/lib/queries/LogoutMutation.ts index e8b1b70b8..bb7295b4b 100644 --- a/frontend/lib/queries/LogoutMutation.ts +++ b/frontend/lib/queries/LogoutMutation.ts @@ -2,7 +2,6 @@ import * as AllSessionInfo from './AllSessionInfo' /* tslint:disable */ -/* eslint-disable */ // This file was automatically generated and should not be edited. import { LogoutInput, OnboardingInfoSignupIntent, LetterRequestMailChoice, HPUploadStatus } from "./globalTypes"; diff --git a/frontend/lib/queries/OnboardingStep1Mutation.ts b/frontend/lib/queries/OnboardingStep1Mutation.ts index 3b7b576a0..8b80992e5 100644 --- a/frontend/lib/queries/OnboardingStep1Mutation.ts +++ b/frontend/lib/queries/OnboardingStep1Mutation.ts @@ -1,7 +1,6 @@ // This file was automatically generated and should not be edited. /* tslint:disable */ -/* eslint-disable */ // This file was automatically generated and should not be edited. import { OnboardingStep1Input } from "./globalTypes"; diff --git a/frontend/lib/queries/OnboardingStep2Mutation.ts b/frontend/lib/queries/OnboardingStep2Mutation.ts index 7b8b198c6..9231331eb 100644 --- a/frontend/lib/queries/OnboardingStep2Mutation.ts +++ b/frontend/lib/queries/OnboardingStep2Mutation.ts @@ -1,7 +1,6 @@ // This file was automatically generated and should not be edited. /* tslint:disable */ -/* eslint-disable */ // This file was automatically generated and should not be edited. import { OnboardingStep2Input } from "./globalTypes"; diff --git a/frontend/lib/queries/OnboardingStep3Mutation.ts b/frontend/lib/queries/OnboardingStep3Mutation.ts index c67e26fc5..f0b91e133 100644 --- a/frontend/lib/queries/OnboardingStep3Mutation.ts +++ b/frontend/lib/queries/OnboardingStep3Mutation.ts @@ -1,7 +1,6 @@ // This file was automatically generated and should not be edited. /* tslint:disable */ -/* eslint-disable */ // This file was automatically generated and should not be edited. import { OnboardingStep3Input } from "./globalTypes"; diff --git a/frontend/lib/queries/OnboardingStep4Mutation.ts b/frontend/lib/queries/OnboardingStep4Mutation.ts index 2276e1cee..253570b3b 100644 --- a/frontend/lib/queries/OnboardingStep4Mutation.ts +++ b/frontend/lib/queries/OnboardingStep4Mutation.ts @@ -2,7 +2,6 @@ import * as AllSessionInfo from './AllSessionInfo' /* tslint:disable */ -/* eslint-disable */ // This file was automatically generated and should not be edited. import { OnboardingStep4Input, OnboardingInfoSignupIntent, LetterRequestMailChoice, HPUploadStatus } from "./globalTypes"; From 7f8a0082555a449c381bb02538e1caa00bf6bb37 Mon Sep 17 00:00:00 2001 From: Atul Varma Date: Tue, 5 Mar 2019 09:47:36 -0500 Subject: [PATCH 05/17] pwaaiejgpojeg --- common-data/borough-choices.ts | 24 ++ common-data/config.ts | 5 + common-data/issue-choices.ts | 272 +++++++++++++++++++ frontend/lib/boroughs.ts | 17 -- frontend/lib/common-data.ts | 19 ++ frontend/lib/geo-autocomplete.tsx | 4 +- frontend/lib/pages/onboarding-step-1.tsx | 8 +- frontend/lib/tests/boroughs.test.ts | 8 - frontend/lib/tests/geo-autocomplete.test.tsx | 2 +- 9 files changed, 328 insertions(+), 31 deletions(-) create mode 100644 common-data/borough-choices.ts create mode 100644 common-data/issue-choices.ts delete mode 100644 frontend/lib/boroughs.ts delete mode 100644 frontend/lib/tests/boroughs.test.ts diff --git a/common-data/borough-choices.ts b/common-data/borough-choices.ts new file mode 100644 index 000000000..46b418c50 --- /dev/null +++ b/common-data/borough-choices.ts @@ -0,0 +1,24 @@ +// This file was auto-generated by commondatabuilder. +// Please don't edit it. + +export enum BoroughChoice { + BROOKLYN = "BROOKLYN", + QUEENS = "QUEENS", + BRONX = "BRONX", + MANHATTAN = "MANHATTAN", + STATEN_ISLAND = "STATEN_ISLAND", +} + +export type BoroughChoiceLabels = { + [k in BoroughChoice]: string; +}; + +export function getBoroughChoiceLabels(): BoroughChoiceLabels { + return { + BROOKLYN: "Brooklyn", + QUEENS: "Queens", + BRONX: "Bronx", + MANHATTAN: "Manhattan", + STATEN_ISLAND: "Staten Island", + }; +} diff --git a/common-data/config.ts b/common-data/config.ts index 0fa4dab63..cb6d5ef48 100644 --- a/common-data/config.ts +++ b/common-data/config.ts @@ -8,6 +8,11 @@ const config: DjangoChoicesTypescriptConfig = { enumName: 'IssueChoice', exportLabels: true, filterOut: /^LANDLORD__/ + }, + { + jsonFilename: 'borough-choices.json', + enumName: 'BoroughChoice', + exportLabels: true, } ] }; diff --git a/common-data/issue-choices.ts b/common-data/issue-choices.ts new file mode 100644 index 000000000..47d92fdf2 --- /dev/null +++ b/common-data/issue-choices.ts @@ -0,0 +1,272 @@ +// This file was auto-generated by commondatabuilder. +// Please don't edit it. + +export enum IssueChoice { + HOME__MICE = "HOME__MICE", + HOME__RATS = "HOME__RATS", + HOME__COCKROACHES = "HOME__COCKROACHES", + HOME__NO_GAS = "HOME__NO_GAS", + HOME__NO_HEAT = "HOME__NO_HEAT", + HOME__NO_HOT_WATER = "HOME__NO_HOT_WATER", + HOME__NO_COLD_WATER = "HOME__NO_COLD_WATER", + HOME__NO_SMOKE_DETECTOR = "HOME__NO_SMOKE_DETECTOR", + HOME__SMOKE_DETECTOR_DEFECTIVE = "HOME__SMOKE_DETECTOR_DEFECTIVE", + HOME__FLOOR = "HOME__FLOOR", + HOME__PAINTING = "HOME__PAINTING", + HOME__FRONT_DOOR_DEFECTIVE = "HOME__FRONT_DOOR_DEFECTIVE", + HOME__FRONT_DOOR_BROKEN = "HOME__FRONT_DOOR_BROKEN", + HOME__DOOR_LOCK_DEFECTIVE = "HOME__DOOR_LOCK_DEFECTIVE", + HOME__DOOR_LOCK_BROKEN = "HOME__DOOR_LOCK_BROKEN", + HOME__DOORBELL_DEFECTIVE = "HOME__DOORBELL_DEFECTIVE", + HOME__DOORBELL_BROKEN = "HOME__DOORBELL_BROKEN", + HOME__BUZZER_DEFECTIVE = "HOME__BUZZER_DEFECTIVE", + HOME__BUZZER_BROKEN = "HOME__BUZZER_BROKEN", + BEDROOMS__PAINT = "BEDROOMS__PAINT", + BEDROOMS__WALLS = "BEDROOMS__WALLS", + BEDROOMS__MOLD_ON_WALLS = "BEDROOMS__MOLD_ON_WALLS", + BEDROOMS__WATER_DAMAGE = "BEDROOMS__WATER_DAMAGE", + BEDROOMS__LOOSE_FLOOR = "BEDROOMS__LOOSE_FLOOR", + BEDROOMS__BASEBOARDS_DEFECTIVE = "BEDROOMS__BASEBOARDS_DEFECTIVE", + BEDROOMS__WINDOW_GLASS_BROKEN = "BEDROOMS__WINDOW_GLASS_BROKEN", + BEDROOMS__WINDOW_FRAME_DEFECTIVE = "BEDROOMS__WINDOW_FRAME_DEFECTIVE", + BEDROOMS__DOOR = "BEDROOMS__DOOR", + BEDROOMS__RADIATORS = "BEDROOMS__RADIATORS", + BEDROOMS__CEILING = "BEDROOMS__CEILING", + BEDROOMS__CEILING_LEAKING = "BEDROOMS__CEILING_LEAKING", + BEDROOMS__ELECTRICITY = "BEDROOMS__ELECTRICITY", + BEDROOMS__WIRING_EXPOSED = "BEDROOMS__WIRING_EXPOSED", + BEDROOMS__OUTLETS = "BEDROOMS__OUTLETS", + KITCHEN__MOLD = "KITCHEN__MOLD", + KITCHEN__WATER = "KITCHEN__WATER", + KITCHEN__PAINT = "KITCHEN__PAINT", + KITCHEN__WALLS = "KITCHEN__WALLS", + KITCHEN__LOOSE_FLOOR = "KITCHEN__LOOSE_FLOOR", + KITCHEN__BASEBOARDS_DEFECTIVE = "KITCHEN__BASEBOARDS_DEFECTIVE", + KITCHEN__WINDOW_GLASS_BROKEN = "KITCHEN__WINDOW_GLASS_BROKEN", + KITCHEN__WINDOW_FRAME_DEFECTIVE = "KITCHEN__WINDOW_FRAME_DEFECTIVE", + KITCHEN__DOOR = "KITCHEN__DOOR", + KITCHEN__RADIATORS = "KITCHEN__RADIATORS", + KITCHEN__CEILING = "KITCHEN__CEILING", + KITCHEN__CEILING_LEAKING = "KITCHEN__CEILING_LEAKING", + KITCHEN__ELECTRICITY = "KITCHEN__ELECTRICITY", + KITCHEN__WIRING_EXPOSED = "KITCHEN__WIRING_EXPOSED", + KITCHEN__OUTLETS = "KITCHEN__OUTLETS", + KITCHEN__REFRIGERATOR = "KITCHEN__REFRIGERATOR", + KITCHEN__REFRIGERATOR_BROKEN = "KITCHEN__REFRIGERATOR_BROKEN", + KITCHEN__STOVE = "KITCHEN__STOVE", + KITCHEN__STOVE_BROKEN = "KITCHEN__STOVE_BROKEN", + KITCHEN__SINK = "KITCHEN__SINK", + KITCHEN__FAUCET_LEAKING = "KITCHEN__FAUCET_LEAKING", + KITCHEN__NO_FAUCET = "KITCHEN__NO_FAUCET", + KITCHEN__FAUCET_NOT_WORKING = "KITCHEN__FAUCET_NOT_WORKING", + KITCHEN__WATER_PRESSURE = "KITCHEN__WATER_PRESSURE", + KITCHEN__PIPES = "KITCHEN__PIPES", + KITCHEN__DRAIN = "KITCHEN__DRAIN", + LIVING_ROOM__MOLD = "LIVING_ROOM__MOLD", + LIVING_ROOM__WATER = "LIVING_ROOM__WATER", + LIVING_ROOM__PAINT = "LIVING_ROOM__PAINT", + LIVING_ROOM__WALLS = "LIVING_ROOM__WALLS", + LIVING_ROOM__LOOSE_FLOOR = "LIVING_ROOM__LOOSE_FLOOR", + LIVING_ROOM__BASEBOARDS_DEFECTIVE = "LIVING_ROOM__BASEBOARDS_DEFECTIVE", + LIVING_ROOM__WINDOW_GLASS_BROKEN = "LIVING_ROOM__WINDOW_GLASS_BROKEN", + LIVING_ROOM__WINDOW_FRAME_DEFECTIVE = "LIVING_ROOM__WINDOW_FRAME_DEFECTIVE", + LIVING_ROOM__DOOR = "LIVING_ROOM__DOOR", + LIVING_ROOM__RADIATORS = "LIVING_ROOM__RADIATORS", + LIVING_ROOM__CEILING = "LIVING_ROOM__CEILING", + LIVING_ROOM__CEILING_LEAKING = "LIVING_ROOM__CEILING_LEAKING", + LIVING_ROOM__ELECTRICITY = "LIVING_ROOM__ELECTRICITY", + LIVING_ROOM__WIRING_EXPOSED = "LIVING_ROOM__WIRING_EXPOSED", + LIVING_ROOM__OUTLETS = "LIVING_ROOM__OUTLETS", + BATHROOMS__MOLD = "BATHROOMS__MOLD", + BATHROOMS__WATER = "BATHROOMS__WATER", + BATHROOMS__PAINT = "BATHROOMS__PAINT", + BATHROOMS__WALLS = "BATHROOMS__WALLS", + BATHROOMS__LOOSE_FLOOR = "BATHROOMS__LOOSE_FLOOR", + BATHROOMS__BASEBOARDS_DEFECTIVE = "BATHROOMS__BASEBOARDS_DEFECTIVE", + BATHROOMS__WINDOW_GLASS_BROKEN = "BATHROOMS__WINDOW_GLASS_BROKEN", + BATHROOMS__WINDOW_FRAME_DEFECTIVE = "BATHROOMS__WINDOW_FRAME_DEFECTIVE", + BATHROOMS__DOOR = "BATHROOMS__DOOR", + BATHROOMS__RADIATORS = "BATHROOMS__RADIATORS", + BATHROOMS__CEILING = "BATHROOMS__CEILING", + BATHROOMS__CEILING_LEAKING = "BATHROOMS__CEILING_LEAKING", + BATHROOMS__ELECTRICITY = "BATHROOMS__ELECTRICITY", + BATHROOMS__WIRING_EXPOSED = "BATHROOMS__WIRING_EXPOSED", + BATHROOMS__OUTLETS = "BATHROOMS__OUTLETS", + BATHROOMS__TOILET = "BATHROOMS__TOILET", + BATHROOMS__TOILET_LEAKING = "BATHROOMS__TOILET_LEAKING", + BATHROOMS__SINK = "BATHROOMS__SINK", + BATHROOMS__SINK_FAUCET_LEAKING = "BATHROOMS__SINK_FAUCET_LEAKING", + BATHROOMS__SINK_NO_FAUCET = "BATHROOMS__SINK_NO_FAUCET", + BATHROOMS__SINK_FAUCET_NOT_WORKING = "BATHROOMS__SINK_FAUCET_NOT_WORKING", + BATHROOMS__SINK_WATER_PRESSURE = "BATHROOMS__SINK_WATER_PRESSURE", + BATHROOMS__SINK_PIPES = "BATHROOMS__SINK_PIPES", + BATHROOMS__SINK_DRAIN = "BATHROOMS__SINK_DRAIN", + BATHROOMS__TUB = "BATHROOMS__TUB", + BATHROOMS__TUB_FAUCET_LEAKING = "BATHROOMS__TUB_FAUCET_LEAKING", + BATHROOMS__TUB_NO_FAUCET = "BATHROOMS__TUB_NO_FAUCET", + BATHROOMS__TUB_FAUCET_NOT_WORKING = "BATHROOMS__TUB_FAUCET_NOT_WORKING", + BATHROOMS__TUB_PIPES = "BATHROOMS__TUB_PIPES", + BATHROOMS__TUB_DRAIN = "BATHROOMS__TUB_DRAIN", + BATHROOMS__SHOWER_MOLD = "BATHROOMS__SHOWER_MOLD", + BATHROOMS__SHOWER_WATER_PRESSURE = "BATHROOMS__SHOWER_WATER_PRESSURE", + BATHROOMS__SHOWER_PIPES = "BATHROOMS__SHOWER_PIPES", + BATHROOMS__SHOWER = "BATHROOMS__SHOWER", + BATHROOMS__SHOWER_FAUCET_LEAKING = "BATHROOMS__SHOWER_FAUCET_LEAKING", + BATHROOMS__SHOWER_NO_FAUCET = "BATHROOMS__SHOWER_NO_FAUCET", + BATHROOMS__SHOWER_DRAIN = "BATHROOMS__SHOWER_DRAIN", + PUBLIC_AREAS__PAINTING_OVERDUE = "PUBLIC_AREAS__PAINTING_OVERDUE", + PUBLIC_AREAS__PAINT = "PUBLIC_AREAS__PAINT", + PUBLIC_AREAS__NO_HEAT = "PUBLIC_AREAS__NO_HEAT", + PUBLIC_AREAS__NO_HOT_WATER = "PUBLIC_AREAS__NO_HOT_WATER", + PUBLIC_AREAS__WATER_PRESSURE = "PUBLIC_AREAS__WATER_PRESSURE", + PUBLIC_AREAS__RUSTY_WATER = "PUBLIC_AREAS__RUSTY_WATER", + PUBLIC_AREAS__WIRING_EXPOSED = "PUBLIC_AREAS__WIRING_EXPOSED", + PUBLIC_AREAS__ELECTRICAL_CURRENT = "PUBLIC_AREAS__ELECTRICAL_CURRENT", + PUBLIC_AREAS__BUGS = "PUBLIC_AREAS__BUGS", + PUBLIC_AREAS__PESTS = "PUBLIC_AREAS__PESTS", + PUBLIC_AREAS__FUMES = "PUBLIC_AREAS__FUMES", + PUBLIC_AREAS__SMOKE_DETECTORS = "PUBLIC_AREAS__SMOKE_DETECTORS", + PUBLIC_AREAS__WINDOW_GUARDS = "PUBLIC_AREAS__WINDOW_GUARDS", + PUBLIC_AREAS__ILLEGAL_APARTMENTS = "PUBLIC_AREAS__ILLEGAL_APARTMENTS", + PUBLIC_AREAS__NO_SUPER = "PUBLIC_AREAS__NO_SUPER", + PUBLIC_AREAS__RENT_RECEIPTS = "PUBLIC_AREAS__RENT_RECEIPTS", + PUBLIC_AREAS__INCOMPLETE_RENT_RECEIPTS = "PUBLIC_AREAS__INCOMPLETE_RENT_RECEIPTS", +} + +export type IssueChoiceLabels = { + [k in IssueChoice]: string; +}; + +export function getIssueChoiceLabels(): IssueChoiceLabels { + return { + HOME__MICE: "Mice", + HOME__RATS: "Rats", + HOME__COCKROACHES: "Cockroaches", + HOME__NO_GAS: "No Gas", + HOME__NO_HEAT: "No Heat", + HOME__NO_HOT_WATER: "No Hot Water", + HOME__NO_COLD_WATER: "No Cold Water", + HOME__NO_SMOKE_DETECTOR: "No Smoke Detector", + HOME__SMOKE_DETECTOR_DEFECTIVE: "Smoke Detector Defective", + HOME__FLOOR: "Floor Sags", + HOME__PAINTING: "Apartment Needs Painting (every 3 years)", + HOME__FRONT_DOOR_DEFECTIVE: "Front Door Defective", + HOME__FRONT_DOOR_BROKEN: "Front Door Broken", + HOME__DOOR_LOCK_DEFECTIVE: "Door Lock Defective", + HOME__DOOR_LOCK_BROKEN: "Door Lock Broken", + HOME__DOORBELL_DEFECTIVE: "Doorbell Defective", + HOME__DOORBELL_BROKEN: "Doorbell Broken", + HOME__BUZZER_DEFECTIVE: "Buzzer Defective", + HOME__BUZZER_BROKEN: "Buzzer Broken", + BEDROOMS__PAINT: "Peeling paint", + BEDROOMS__WALLS: "Cracked walls", + BEDROOMS__MOLD_ON_WALLS: "Mold on Walls", + BEDROOMS__WATER_DAMAGE: "Water Damage", + BEDROOMS__LOOSE_FLOOR: "Loose Floor", + BEDROOMS__BASEBOARDS_DEFECTIVE: "Baseboards Defective", + BEDROOMS__WINDOW_GLASS_BROKEN: "Window Glass Broken", + BEDROOMS__WINDOW_FRAME_DEFECTIVE: "Window Frame Defective", + BEDROOMS__DOOR: "Door Broken", + BEDROOMS__RADIATORS: "Radiators/Risers Defective", + BEDROOMS__CEILING: "Ceiling Falling/Fell", + BEDROOMS__CEILING_LEAKING: "Ceiling Leaking", + BEDROOMS__ELECTRICITY: "Electricity defective", + BEDROOMS__WIRING_EXPOSED: "Electric wiring exposed", + BEDROOMS__OUTLETS: "Outlets defective", + KITCHEN__MOLD: "Mold on walls", + KITCHEN__WATER: "Water damage", + KITCHEN__PAINT: "Peeling Paint", + KITCHEN__WALLS: "Cracked walls", + KITCHEN__LOOSE_FLOOR: "Loose Floor", + KITCHEN__BASEBOARDS_DEFECTIVE: "Baseboards Defective", + KITCHEN__WINDOW_GLASS_BROKEN: "Window Glass Broken", + KITCHEN__WINDOW_FRAME_DEFECTIVE: "Window Frame Defective", + KITCHEN__DOOR: "Door Broken", + KITCHEN__RADIATORS: "Radiators/Risers Defective", + KITCHEN__CEILING: "Ceiling Falling/Fell", + KITCHEN__CEILING_LEAKING: "Ceiling Leaking", + KITCHEN__ELECTRICITY: "Electricity defective", + KITCHEN__WIRING_EXPOSED: "Electric wiring exposed", + KITCHEN__OUTLETS: "Outlets defective", + KITCHEN__REFRIGERATOR: "Refrigerator Defective", + KITCHEN__REFRIGERATOR_BROKEN: "Refrigerator Broken", + KITCHEN__STOVE: "Stove Defective", + KITCHEN__STOVE_BROKEN: "Stove Broken", + KITCHEN__SINK: "Cracked Sink", + KITCHEN__FAUCET_LEAKING: "Leaky Faucet", + KITCHEN__NO_FAUCET: "Faucets not installed", + KITCHEN__FAUCET_NOT_WORKING: "Faucets not working", + KITCHEN__WATER_PRESSURE: "Inadequate Water pressure", + KITCHEN__PIPES: "Pipes Leaking", + KITCHEN__DRAIN: "Drain Stoppage", + LIVING_ROOM__MOLD: "Mold on walls", + LIVING_ROOM__WATER: "Water damage", + LIVING_ROOM__PAINT: "Peeling paint", + LIVING_ROOM__WALLS: "Cracked walls", + LIVING_ROOM__LOOSE_FLOOR: "Loose Floor", + LIVING_ROOM__BASEBOARDS_DEFECTIVE: "Baseboards Defective", + LIVING_ROOM__WINDOW_GLASS_BROKEN: "Window Glass Broken", + LIVING_ROOM__WINDOW_FRAME_DEFECTIVE: "Window Frame Defective", + LIVING_ROOM__DOOR: "Door Broken", + LIVING_ROOM__RADIATORS: "Radiators/Risers Defective", + LIVING_ROOM__CEILING: "Ceiling Falling/Fell", + LIVING_ROOM__CEILING_LEAKING: "Ceiling Leaking", + LIVING_ROOM__ELECTRICITY: "Electricity defective", + LIVING_ROOM__WIRING_EXPOSED: "Electric wiring exposed", + LIVING_ROOM__OUTLETS: "Outlets defective", + BATHROOMS__MOLD: "Mold on walls", + BATHROOMS__WATER: "Water damage", + BATHROOMS__PAINT: "Peeling paint", + BATHROOMS__WALLS: "Cracked walls", + BATHROOMS__LOOSE_FLOOR: "Loose Floor", + BATHROOMS__BASEBOARDS_DEFECTIVE: "Baseboards Defective", + BATHROOMS__WINDOW_GLASS_BROKEN: "Window Glass Broken", + BATHROOMS__WINDOW_FRAME_DEFECTIVE: "Window Frame Defective", + BATHROOMS__DOOR: "Door Broken", + BATHROOMS__RADIATORS: "Radiators/Risers Defective", + BATHROOMS__CEILING: "Ceiling Falling/Fell", + BATHROOMS__CEILING_LEAKING: "Ceiling Leaking", + BATHROOMS__ELECTRICITY: "Electricity defective", + BATHROOMS__WIRING_EXPOSED: "Electric wiring exposed", + BATHROOMS__OUTLETS: "Outlets defective", + BATHROOMS__TOILET: "Toilet not working", + BATHROOMS__TOILET_LEAKING: "Toilet leaking", + BATHROOMS__SINK: "Sink: Cracked Sink", + BATHROOMS__SINK_FAUCET_LEAKING: "Sink: Leaky Faucet", + BATHROOMS__SINK_NO_FAUCET: "Sink: Faucets not installed", + BATHROOMS__SINK_FAUCET_NOT_WORKING: "Sink: Faucets not working", + BATHROOMS__SINK_WATER_PRESSURE: "Sink: Inadequate Water pressure", + BATHROOMS__SINK_PIPES: "Sink: Pipes Leaking", + BATHROOMS__SINK_DRAIN: "Sink: Drain Stoppage", + BATHROOMS__TUB: "Bathtub: Cracked Tub", + BATHROOMS__TUB_FAUCET_LEAKING: "Bathtub: Leaky Faucet", + BATHROOMS__TUB_NO_FAUCET: "Bathtub: Faucets not installed", + BATHROOMS__TUB_FAUCET_NOT_WORKING: "Bathtub: Faucets not working", + BATHROOMS__TUB_PIPES: "Bathtub: Pipes Leaking", + BATHROOMS__TUB_DRAIN: "Bathtub: Drain Stoppage", + BATHROOMS__SHOWER_MOLD: "Shower: Mold on walls", + BATHROOMS__SHOWER_WATER_PRESSURE: "Shower: Wall tiles cracked", + BATHROOMS__SHOWER_PIPES: "Shower: Wall tiles missing", + BATHROOMS__SHOWER: "Shower: Not Working", + BATHROOMS__SHOWER_FAUCET_LEAKING: "Shower: Inadequate Water pressure", + BATHROOMS__SHOWER_NO_FAUCET: "Shower: Leaky shower head", + BATHROOMS__SHOWER_DRAIN: "Shower: Drain Stoppage", + PUBLIC_AREAS__PAINTING_OVERDUE: "Painting overdue (3 years)", + PUBLIC_AREAS__PAINT: "Peeling/flaking paint", + PUBLIC_AREAS__NO_HEAT: "No Heat", + PUBLIC_AREAS__NO_HOT_WATER: "No Hot Water", + PUBLIC_AREAS__WATER_PRESSURE: "Inadequate water pressure", + PUBLIC_AREAS__RUSTY_WATER: "Rusty water", + PUBLIC_AREAS__WIRING_EXPOSED: "Electric wiring exposed", + PUBLIC_AREAS__ELECTRICAL_CURRENT: "Weak electrical current (lights dim)", + PUBLIC_AREAS__BUGS: "Bug Infestation", + PUBLIC_AREAS__PESTS: "Rats/Mice", + PUBLIC_AREAS__FUMES: "Fumes/smoke entering apartment", + PUBLIC_AREAS__SMOKE_DETECTORS: "Missing/broken smoke/Co2 detector", + PUBLIC_AREAS__WINDOW_GUARDS: "Window guards missing", + PUBLIC_AREAS__ILLEGAL_APARTMENTS: "Illegal apartments in basement", + PUBLIC_AREAS__NO_SUPER: "Inadequate / no super service", + PUBLIC_AREAS__RENT_RECEIPTS: "No rent receipts given", + PUBLIC_AREAS__INCOMPLETE_RENT_RECEIPTS: "Rent receipts incomplete (no date/ NYC address for landlord, etc.)", + }; +} diff --git a/frontend/lib/boroughs.ts b/frontend/lib/boroughs.ts deleted file mode 100644 index 0250931dc..000000000 --- a/frontend/lib/boroughs.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { safeGetDjangoChoiceLabel } from "./common-data"; - -type BoroughDjangoChoice = [BoroughChoice, string]; - -export const BOROUGH_CHOICES = require('../../common-data/borough-choices.json') as BoroughDjangoChoice[]; - -export enum BoroughChoice { - MANHATTAN = 'MANHATTAN', - BRONX = 'BRONX', - BROOKLYN = 'BROOKLYN', - QUEENS = 'QUEENS', - STATEN_ISLAND = 'STATEN_ISLAND' -} - -export function getBoroughLabel(borough: string): string|null { - return safeGetDjangoChoiceLabel(BOROUGH_CHOICES, borough); -} diff --git a/frontend/lib/common-data.ts b/frontend/lib/common-data.ts index bc07260ec..efa62c54a 100644 --- a/frontend/lib/common-data.ts +++ b/frontend/lib/common-data.ts @@ -95,3 +95,22 @@ export function allCapsToSlug(value: string): string { export function slugToAllCaps(value: string): string { return value.toUpperCase().replace(/-/g, '_'); } + +type StringMapping = { + [k in T]: string +}; + +export function toDjangoChoices(enumObj: StringMapping, labels: StringMapping): [string, string][] { + const result = []; + for (let k in enumObj) { + result.push([k, labels[k]] as [string, string]); + } + return result; +} + +export function toEnumKey(enumObj: T, key: string): (keyof typeof enumObj)|undefined { + if (key in enumObj) { + return key as keyof typeof enumObj; + } + return undefined; +} diff --git a/frontend/lib/geo-autocomplete.tsx b/frontend/lib/geo-autocomplete.tsx index b6f9b137e..3f79786ce 100644 --- a/frontend/lib/geo-autocomplete.tsx +++ b/frontend/lib/geo-autocomplete.tsx @@ -2,7 +2,7 @@ import React from 'react'; import Downshift, { ControllerStateAndHelpers, DownshiftInterface } from 'downshift'; import classnames from 'classnames'; import autobind from 'autobind-decorator'; -import { BoroughChoice, getBoroughLabel } from './boroughs'; +import { BoroughChoice, getBoroughChoiceLabels } from '../../common-data/borough-choices'; import { WithFormFieldErrors, formatErrors } from './form-errors'; import { bulmaClasses } from './bulma'; import { awesomeFetch, createAbortController } from './fetch'; @@ -213,7 +213,7 @@ export class GeoAutocomplete extends React.Component { const onboardingStep1 = props.session.onboardingStep1 || blankInitialState; - const borough = getBoroughLabel(onboardingStep1.borough) || ''; + const boroughKey = toEnumKey(BoroughChoice, onboardingStep1.borough); + const borough = boroughKey ? getBoroughChoiceLabels()[boroughKey] : ''; return ( ( @@ -123,7 +125,7 @@ class OnboardingStep1WithoutContexts extends React.Component ); diff --git a/frontend/lib/tests/boroughs.test.ts b/frontend/lib/tests/boroughs.test.ts deleted file mode 100644 index 7c0f2ad1e..000000000 --- a/frontend/lib/tests/boroughs.test.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { BoroughChoice, BOROUGH_CHOICES } from "../boroughs"; -import { validateDjangoChoices } from "../common-data"; - -test('BoroughChoice has valid choices', () => { - for (let choice in BoroughChoice) { - validateDjangoChoices(BOROUGH_CHOICES, [choice, BoroughChoice[choice]]); - } -}); diff --git a/frontend/lib/tests/geo-autocomplete.test.tsx b/frontend/lib/tests/geo-autocomplete.test.tsx index f6becf34c..232a2803a 100644 --- a/frontend/lib/tests/geo-autocomplete.test.tsx +++ b/frontend/lib/tests/geo-autocomplete.test.tsx @@ -1,7 +1,7 @@ import React from 'react'; import ReactTestingLibraryPal from './rtl-pal'; import { GeoAutocomplete, geoSearchResultsToAutocompleteItems, geoAutocompleteItemToString } from '../geo-autocomplete'; -import { BoroughChoice } from '../boroughs'; +import { BoroughChoice } from '../../../common-data/borough-choices'; import { createMockFetch } from './mock-fetch'; import { FakeGeoResults } from './util'; import { KEY_TAB } from '../key-codes'; From 0dee8e703e68778eb7c1f51ce4e964490b77670a Mon Sep 17 00:00:00 2001 From: Atul Varma Date: Tue, 5 Mar 2019 10:34:54 -0500 Subject: [PATCH 06/17] Don't use enums, they are super confusing --- common-data/borough-choices.ts | 20 +- common-data/issue-area-choices.ts | 26 ++ common-data/issue-choices.ts | 268 +++++++++--------- .../commondatabuilder/commondatabuilder.ts | 22 +- .../commondatabuilder.test.ts.snap | 29 ++ .../tests/commondatabuilder.test.ts | 20 +- frontend/lib/common-data.ts | 15 +- frontend/lib/geo-autocomplete.tsx | 10 +- frontend/lib/pages/onboarding-step-1.tsx | 13 +- frontend/lib/tests/geo-autocomplete.test.tsx | 3 +- 10 files changed, 237 insertions(+), 189 deletions(-) create mode 100644 common-data/issue-area-choices.ts create mode 100644 frontend/commondatabuilder/tests/__snapshots__/commondatabuilder.test.ts.snap diff --git a/common-data/borough-choices.ts b/common-data/borough-choices.ts index 46b418c50..157d1a24c 100644 --- a/common-data/borough-choices.ts +++ b/common-data/borough-choices.ts @@ -1,12 +1,20 @@ // This file was auto-generated by commondatabuilder. // Please don't edit it. -export enum BoroughChoice { - BROOKLYN = "BROOKLYN", - QUEENS = "QUEENS", - BRONX = "BRONX", - MANHATTAN = "MANHATTAN", - STATEN_ISLAND = "STATEN_ISLAND", +export type BoroughChoice = "BROOKLYN"|"QUEENS"|"BRONX"|"MANHATTAN"|"STATEN_ISLAND"; + +export const BoroughChoices: BoroughChoice[] = [ + "BROOKLYN", + "QUEENS", + "BRONX", + "MANHATTAN", + "STATEN_ISLAND" +]; + +const BoroughChoiceSet: Set = new Set(BoroughChoices); + +export function isBoroughChoice(choice: string): choice is BoroughChoice { + return BoroughChoiceSet.has(choice); } export type BoroughChoiceLabels = { diff --git a/common-data/issue-area-choices.ts b/common-data/issue-area-choices.ts new file mode 100644 index 000000000..514291194 --- /dev/null +++ b/common-data/issue-area-choices.ts @@ -0,0 +1,26 @@ +// This file was auto-generated by commondatabuilder. +// Please don't edit it. + +export enum IssueAreaChoice { + HOME = "HOME", + BEDROOMS = "BEDROOMS", + KITCHEN = "KITCHEN", + LIVING_ROOM = "LIVING_ROOM", + BATHROOMS = "BATHROOMS", + PUBLIC_AREAS = "PUBLIC_AREAS", +} + +export type IssueAreaChoiceLabels = { + [k in IssueAreaChoice]: string; +}; + +export function getIssueAreaChoiceLabels(): IssueAreaChoiceLabels { + return { + HOME: "Entire home and hallways", + BEDROOMS: "Bedrooms", + KITCHEN: "Kitchen", + LIVING_ROOM: "Living room", + BATHROOMS: "Bathrooms", + PUBLIC_AREAS: "Public areas", + }; +} diff --git a/common-data/issue-choices.ts b/common-data/issue-choices.ts index 47d92fdf2..4aa913db6 100644 --- a/common-data/issue-choices.ts +++ b/common-data/issue-choices.ts @@ -1,136 +1,144 @@ // This file was auto-generated by commondatabuilder. // Please don't edit it. -export enum IssueChoice { - HOME__MICE = "HOME__MICE", - HOME__RATS = "HOME__RATS", - HOME__COCKROACHES = "HOME__COCKROACHES", - HOME__NO_GAS = "HOME__NO_GAS", - HOME__NO_HEAT = "HOME__NO_HEAT", - HOME__NO_HOT_WATER = "HOME__NO_HOT_WATER", - HOME__NO_COLD_WATER = "HOME__NO_COLD_WATER", - HOME__NO_SMOKE_DETECTOR = "HOME__NO_SMOKE_DETECTOR", - HOME__SMOKE_DETECTOR_DEFECTIVE = "HOME__SMOKE_DETECTOR_DEFECTIVE", - HOME__FLOOR = "HOME__FLOOR", - HOME__PAINTING = "HOME__PAINTING", - HOME__FRONT_DOOR_DEFECTIVE = "HOME__FRONT_DOOR_DEFECTIVE", - HOME__FRONT_DOOR_BROKEN = "HOME__FRONT_DOOR_BROKEN", - HOME__DOOR_LOCK_DEFECTIVE = "HOME__DOOR_LOCK_DEFECTIVE", - HOME__DOOR_LOCK_BROKEN = "HOME__DOOR_LOCK_BROKEN", - HOME__DOORBELL_DEFECTIVE = "HOME__DOORBELL_DEFECTIVE", - HOME__DOORBELL_BROKEN = "HOME__DOORBELL_BROKEN", - HOME__BUZZER_DEFECTIVE = "HOME__BUZZER_DEFECTIVE", - HOME__BUZZER_BROKEN = "HOME__BUZZER_BROKEN", - BEDROOMS__PAINT = "BEDROOMS__PAINT", - BEDROOMS__WALLS = "BEDROOMS__WALLS", - BEDROOMS__MOLD_ON_WALLS = "BEDROOMS__MOLD_ON_WALLS", - BEDROOMS__WATER_DAMAGE = "BEDROOMS__WATER_DAMAGE", - BEDROOMS__LOOSE_FLOOR = "BEDROOMS__LOOSE_FLOOR", - BEDROOMS__BASEBOARDS_DEFECTIVE = "BEDROOMS__BASEBOARDS_DEFECTIVE", - BEDROOMS__WINDOW_GLASS_BROKEN = "BEDROOMS__WINDOW_GLASS_BROKEN", - BEDROOMS__WINDOW_FRAME_DEFECTIVE = "BEDROOMS__WINDOW_FRAME_DEFECTIVE", - BEDROOMS__DOOR = "BEDROOMS__DOOR", - BEDROOMS__RADIATORS = "BEDROOMS__RADIATORS", - BEDROOMS__CEILING = "BEDROOMS__CEILING", - BEDROOMS__CEILING_LEAKING = "BEDROOMS__CEILING_LEAKING", - BEDROOMS__ELECTRICITY = "BEDROOMS__ELECTRICITY", - BEDROOMS__WIRING_EXPOSED = "BEDROOMS__WIRING_EXPOSED", - BEDROOMS__OUTLETS = "BEDROOMS__OUTLETS", - KITCHEN__MOLD = "KITCHEN__MOLD", - KITCHEN__WATER = "KITCHEN__WATER", - KITCHEN__PAINT = "KITCHEN__PAINT", - KITCHEN__WALLS = "KITCHEN__WALLS", - KITCHEN__LOOSE_FLOOR = "KITCHEN__LOOSE_FLOOR", - KITCHEN__BASEBOARDS_DEFECTIVE = "KITCHEN__BASEBOARDS_DEFECTIVE", - KITCHEN__WINDOW_GLASS_BROKEN = "KITCHEN__WINDOW_GLASS_BROKEN", - KITCHEN__WINDOW_FRAME_DEFECTIVE = "KITCHEN__WINDOW_FRAME_DEFECTIVE", - KITCHEN__DOOR = "KITCHEN__DOOR", - KITCHEN__RADIATORS = "KITCHEN__RADIATORS", - KITCHEN__CEILING = "KITCHEN__CEILING", - KITCHEN__CEILING_LEAKING = "KITCHEN__CEILING_LEAKING", - KITCHEN__ELECTRICITY = "KITCHEN__ELECTRICITY", - KITCHEN__WIRING_EXPOSED = "KITCHEN__WIRING_EXPOSED", - KITCHEN__OUTLETS = "KITCHEN__OUTLETS", - KITCHEN__REFRIGERATOR = "KITCHEN__REFRIGERATOR", - KITCHEN__REFRIGERATOR_BROKEN = "KITCHEN__REFRIGERATOR_BROKEN", - KITCHEN__STOVE = "KITCHEN__STOVE", - KITCHEN__STOVE_BROKEN = "KITCHEN__STOVE_BROKEN", - KITCHEN__SINK = "KITCHEN__SINK", - KITCHEN__FAUCET_LEAKING = "KITCHEN__FAUCET_LEAKING", - KITCHEN__NO_FAUCET = "KITCHEN__NO_FAUCET", - KITCHEN__FAUCET_NOT_WORKING = "KITCHEN__FAUCET_NOT_WORKING", - KITCHEN__WATER_PRESSURE = "KITCHEN__WATER_PRESSURE", - KITCHEN__PIPES = "KITCHEN__PIPES", - KITCHEN__DRAIN = "KITCHEN__DRAIN", - LIVING_ROOM__MOLD = "LIVING_ROOM__MOLD", - LIVING_ROOM__WATER = "LIVING_ROOM__WATER", - LIVING_ROOM__PAINT = "LIVING_ROOM__PAINT", - LIVING_ROOM__WALLS = "LIVING_ROOM__WALLS", - LIVING_ROOM__LOOSE_FLOOR = "LIVING_ROOM__LOOSE_FLOOR", - LIVING_ROOM__BASEBOARDS_DEFECTIVE = "LIVING_ROOM__BASEBOARDS_DEFECTIVE", - LIVING_ROOM__WINDOW_GLASS_BROKEN = "LIVING_ROOM__WINDOW_GLASS_BROKEN", - LIVING_ROOM__WINDOW_FRAME_DEFECTIVE = "LIVING_ROOM__WINDOW_FRAME_DEFECTIVE", - LIVING_ROOM__DOOR = "LIVING_ROOM__DOOR", - LIVING_ROOM__RADIATORS = "LIVING_ROOM__RADIATORS", - LIVING_ROOM__CEILING = "LIVING_ROOM__CEILING", - LIVING_ROOM__CEILING_LEAKING = "LIVING_ROOM__CEILING_LEAKING", - LIVING_ROOM__ELECTRICITY = "LIVING_ROOM__ELECTRICITY", - LIVING_ROOM__WIRING_EXPOSED = "LIVING_ROOM__WIRING_EXPOSED", - LIVING_ROOM__OUTLETS = "LIVING_ROOM__OUTLETS", - BATHROOMS__MOLD = "BATHROOMS__MOLD", - BATHROOMS__WATER = "BATHROOMS__WATER", - BATHROOMS__PAINT = "BATHROOMS__PAINT", - BATHROOMS__WALLS = "BATHROOMS__WALLS", - BATHROOMS__LOOSE_FLOOR = "BATHROOMS__LOOSE_FLOOR", - BATHROOMS__BASEBOARDS_DEFECTIVE = "BATHROOMS__BASEBOARDS_DEFECTIVE", - BATHROOMS__WINDOW_GLASS_BROKEN = "BATHROOMS__WINDOW_GLASS_BROKEN", - BATHROOMS__WINDOW_FRAME_DEFECTIVE = "BATHROOMS__WINDOW_FRAME_DEFECTIVE", - BATHROOMS__DOOR = "BATHROOMS__DOOR", - BATHROOMS__RADIATORS = "BATHROOMS__RADIATORS", - BATHROOMS__CEILING = "BATHROOMS__CEILING", - BATHROOMS__CEILING_LEAKING = "BATHROOMS__CEILING_LEAKING", - BATHROOMS__ELECTRICITY = "BATHROOMS__ELECTRICITY", - BATHROOMS__WIRING_EXPOSED = "BATHROOMS__WIRING_EXPOSED", - BATHROOMS__OUTLETS = "BATHROOMS__OUTLETS", - BATHROOMS__TOILET = "BATHROOMS__TOILET", - BATHROOMS__TOILET_LEAKING = "BATHROOMS__TOILET_LEAKING", - BATHROOMS__SINK = "BATHROOMS__SINK", - BATHROOMS__SINK_FAUCET_LEAKING = "BATHROOMS__SINK_FAUCET_LEAKING", - BATHROOMS__SINK_NO_FAUCET = "BATHROOMS__SINK_NO_FAUCET", - BATHROOMS__SINK_FAUCET_NOT_WORKING = "BATHROOMS__SINK_FAUCET_NOT_WORKING", - BATHROOMS__SINK_WATER_PRESSURE = "BATHROOMS__SINK_WATER_PRESSURE", - BATHROOMS__SINK_PIPES = "BATHROOMS__SINK_PIPES", - BATHROOMS__SINK_DRAIN = "BATHROOMS__SINK_DRAIN", - BATHROOMS__TUB = "BATHROOMS__TUB", - BATHROOMS__TUB_FAUCET_LEAKING = "BATHROOMS__TUB_FAUCET_LEAKING", - BATHROOMS__TUB_NO_FAUCET = "BATHROOMS__TUB_NO_FAUCET", - BATHROOMS__TUB_FAUCET_NOT_WORKING = "BATHROOMS__TUB_FAUCET_NOT_WORKING", - BATHROOMS__TUB_PIPES = "BATHROOMS__TUB_PIPES", - BATHROOMS__TUB_DRAIN = "BATHROOMS__TUB_DRAIN", - BATHROOMS__SHOWER_MOLD = "BATHROOMS__SHOWER_MOLD", - BATHROOMS__SHOWER_WATER_PRESSURE = "BATHROOMS__SHOWER_WATER_PRESSURE", - BATHROOMS__SHOWER_PIPES = "BATHROOMS__SHOWER_PIPES", - BATHROOMS__SHOWER = "BATHROOMS__SHOWER", - BATHROOMS__SHOWER_FAUCET_LEAKING = "BATHROOMS__SHOWER_FAUCET_LEAKING", - BATHROOMS__SHOWER_NO_FAUCET = "BATHROOMS__SHOWER_NO_FAUCET", - BATHROOMS__SHOWER_DRAIN = "BATHROOMS__SHOWER_DRAIN", - PUBLIC_AREAS__PAINTING_OVERDUE = "PUBLIC_AREAS__PAINTING_OVERDUE", - PUBLIC_AREAS__PAINT = "PUBLIC_AREAS__PAINT", - PUBLIC_AREAS__NO_HEAT = "PUBLIC_AREAS__NO_HEAT", - PUBLIC_AREAS__NO_HOT_WATER = "PUBLIC_AREAS__NO_HOT_WATER", - PUBLIC_AREAS__WATER_PRESSURE = "PUBLIC_AREAS__WATER_PRESSURE", - PUBLIC_AREAS__RUSTY_WATER = "PUBLIC_AREAS__RUSTY_WATER", - PUBLIC_AREAS__WIRING_EXPOSED = "PUBLIC_AREAS__WIRING_EXPOSED", - PUBLIC_AREAS__ELECTRICAL_CURRENT = "PUBLIC_AREAS__ELECTRICAL_CURRENT", - PUBLIC_AREAS__BUGS = "PUBLIC_AREAS__BUGS", - PUBLIC_AREAS__PESTS = "PUBLIC_AREAS__PESTS", - PUBLIC_AREAS__FUMES = "PUBLIC_AREAS__FUMES", - PUBLIC_AREAS__SMOKE_DETECTORS = "PUBLIC_AREAS__SMOKE_DETECTORS", - PUBLIC_AREAS__WINDOW_GUARDS = "PUBLIC_AREAS__WINDOW_GUARDS", - PUBLIC_AREAS__ILLEGAL_APARTMENTS = "PUBLIC_AREAS__ILLEGAL_APARTMENTS", - PUBLIC_AREAS__NO_SUPER = "PUBLIC_AREAS__NO_SUPER", - PUBLIC_AREAS__RENT_RECEIPTS = "PUBLIC_AREAS__RENT_RECEIPTS", - PUBLIC_AREAS__INCOMPLETE_RENT_RECEIPTS = "PUBLIC_AREAS__INCOMPLETE_RENT_RECEIPTS", +export type IssueChoice = "HOME__MICE"|"HOME__RATS"|"HOME__COCKROACHES"|"HOME__NO_GAS"|"HOME__NO_HEAT"|"HOME__NO_HOT_WATER"|"HOME__NO_COLD_WATER"|"HOME__NO_SMOKE_DETECTOR"|"HOME__SMOKE_DETECTOR_DEFECTIVE"|"HOME__FLOOR"|"HOME__PAINTING"|"HOME__FRONT_DOOR_DEFECTIVE"|"HOME__FRONT_DOOR_BROKEN"|"HOME__DOOR_LOCK_DEFECTIVE"|"HOME__DOOR_LOCK_BROKEN"|"HOME__DOORBELL_DEFECTIVE"|"HOME__DOORBELL_BROKEN"|"HOME__BUZZER_DEFECTIVE"|"HOME__BUZZER_BROKEN"|"BEDROOMS__PAINT"|"BEDROOMS__WALLS"|"BEDROOMS__MOLD_ON_WALLS"|"BEDROOMS__WATER_DAMAGE"|"BEDROOMS__LOOSE_FLOOR"|"BEDROOMS__BASEBOARDS_DEFECTIVE"|"BEDROOMS__WINDOW_GLASS_BROKEN"|"BEDROOMS__WINDOW_FRAME_DEFECTIVE"|"BEDROOMS__DOOR"|"BEDROOMS__RADIATORS"|"BEDROOMS__CEILING"|"BEDROOMS__CEILING_LEAKING"|"BEDROOMS__ELECTRICITY"|"BEDROOMS__WIRING_EXPOSED"|"BEDROOMS__OUTLETS"|"KITCHEN__MOLD"|"KITCHEN__WATER"|"KITCHEN__PAINT"|"KITCHEN__WALLS"|"KITCHEN__LOOSE_FLOOR"|"KITCHEN__BASEBOARDS_DEFECTIVE"|"KITCHEN__WINDOW_GLASS_BROKEN"|"KITCHEN__WINDOW_FRAME_DEFECTIVE"|"KITCHEN__DOOR"|"KITCHEN__RADIATORS"|"KITCHEN__CEILING"|"KITCHEN__CEILING_LEAKING"|"KITCHEN__ELECTRICITY"|"KITCHEN__WIRING_EXPOSED"|"KITCHEN__OUTLETS"|"KITCHEN__REFRIGERATOR"|"KITCHEN__REFRIGERATOR_BROKEN"|"KITCHEN__STOVE"|"KITCHEN__STOVE_BROKEN"|"KITCHEN__SINK"|"KITCHEN__FAUCET_LEAKING"|"KITCHEN__NO_FAUCET"|"KITCHEN__FAUCET_NOT_WORKING"|"KITCHEN__WATER_PRESSURE"|"KITCHEN__PIPES"|"KITCHEN__DRAIN"|"LIVING_ROOM__MOLD"|"LIVING_ROOM__WATER"|"LIVING_ROOM__PAINT"|"LIVING_ROOM__WALLS"|"LIVING_ROOM__LOOSE_FLOOR"|"LIVING_ROOM__BASEBOARDS_DEFECTIVE"|"LIVING_ROOM__WINDOW_GLASS_BROKEN"|"LIVING_ROOM__WINDOW_FRAME_DEFECTIVE"|"LIVING_ROOM__DOOR"|"LIVING_ROOM__RADIATORS"|"LIVING_ROOM__CEILING"|"LIVING_ROOM__CEILING_LEAKING"|"LIVING_ROOM__ELECTRICITY"|"LIVING_ROOM__WIRING_EXPOSED"|"LIVING_ROOM__OUTLETS"|"BATHROOMS__MOLD"|"BATHROOMS__WATER"|"BATHROOMS__PAINT"|"BATHROOMS__WALLS"|"BATHROOMS__LOOSE_FLOOR"|"BATHROOMS__BASEBOARDS_DEFECTIVE"|"BATHROOMS__WINDOW_GLASS_BROKEN"|"BATHROOMS__WINDOW_FRAME_DEFECTIVE"|"BATHROOMS__DOOR"|"BATHROOMS__RADIATORS"|"BATHROOMS__CEILING"|"BATHROOMS__CEILING_LEAKING"|"BATHROOMS__ELECTRICITY"|"BATHROOMS__WIRING_EXPOSED"|"BATHROOMS__OUTLETS"|"BATHROOMS__TOILET"|"BATHROOMS__TOILET_LEAKING"|"BATHROOMS__SINK"|"BATHROOMS__SINK_FAUCET_LEAKING"|"BATHROOMS__SINK_NO_FAUCET"|"BATHROOMS__SINK_FAUCET_NOT_WORKING"|"BATHROOMS__SINK_WATER_PRESSURE"|"BATHROOMS__SINK_PIPES"|"BATHROOMS__SINK_DRAIN"|"BATHROOMS__TUB"|"BATHROOMS__TUB_FAUCET_LEAKING"|"BATHROOMS__TUB_NO_FAUCET"|"BATHROOMS__TUB_FAUCET_NOT_WORKING"|"BATHROOMS__TUB_PIPES"|"BATHROOMS__TUB_DRAIN"|"BATHROOMS__SHOWER_MOLD"|"BATHROOMS__SHOWER_WATER_PRESSURE"|"BATHROOMS__SHOWER_PIPES"|"BATHROOMS__SHOWER"|"BATHROOMS__SHOWER_FAUCET_LEAKING"|"BATHROOMS__SHOWER_NO_FAUCET"|"BATHROOMS__SHOWER_DRAIN"|"PUBLIC_AREAS__PAINTING_OVERDUE"|"PUBLIC_AREAS__PAINT"|"PUBLIC_AREAS__NO_HEAT"|"PUBLIC_AREAS__NO_HOT_WATER"|"PUBLIC_AREAS__WATER_PRESSURE"|"PUBLIC_AREAS__RUSTY_WATER"|"PUBLIC_AREAS__WIRING_EXPOSED"|"PUBLIC_AREAS__ELECTRICAL_CURRENT"|"PUBLIC_AREAS__BUGS"|"PUBLIC_AREAS__PESTS"|"PUBLIC_AREAS__FUMES"|"PUBLIC_AREAS__SMOKE_DETECTORS"|"PUBLIC_AREAS__WINDOW_GUARDS"|"PUBLIC_AREAS__ILLEGAL_APARTMENTS"|"PUBLIC_AREAS__NO_SUPER"|"PUBLIC_AREAS__RENT_RECEIPTS"|"PUBLIC_AREAS__INCOMPLETE_RENT_RECEIPTS"; + +export const IssueChoices: IssueChoice[] = [ + "HOME__MICE", + "HOME__RATS", + "HOME__COCKROACHES", + "HOME__NO_GAS", + "HOME__NO_HEAT", + "HOME__NO_HOT_WATER", + "HOME__NO_COLD_WATER", + "HOME__NO_SMOKE_DETECTOR", + "HOME__SMOKE_DETECTOR_DEFECTIVE", + "HOME__FLOOR", + "HOME__PAINTING", + "HOME__FRONT_DOOR_DEFECTIVE", + "HOME__FRONT_DOOR_BROKEN", + "HOME__DOOR_LOCK_DEFECTIVE", + "HOME__DOOR_LOCK_BROKEN", + "HOME__DOORBELL_DEFECTIVE", + "HOME__DOORBELL_BROKEN", + "HOME__BUZZER_DEFECTIVE", + "HOME__BUZZER_BROKEN", + "BEDROOMS__PAINT", + "BEDROOMS__WALLS", + "BEDROOMS__MOLD_ON_WALLS", + "BEDROOMS__WATER_DAMAGE", + "BEDROOMS__LOOSE_FLOOR", + "BEDROOMS__BASEBOARDS_DEFECTIVE", + "BEDROOMS__WINDOW_GLASS_BROKEN", + "BEDROOMS__WINDOW_FRAME_DEFECTIVE", + "BEDROOMS__DOOR", + "BEDROOMS__RADIATORS", + "BEDROOMS__CEILING", + "BEDROOMS__CEILING_LEAKING", + "BEDROOMS__ELECTRICITY", + "BEDROOMS__WIRING_EXPOSED", + "BEDROOMS__OUTLETS", + "KITCHEN__MOLD", + "KITCHEN__WATER", + "KITCHEN__PAINT", + "KITCHEN__WALLS", + "KITCHEN__LOOSE_FLOOR", + "KITCHEN__BASEBOARDS_DEFECTIVE", + "KITCHEN__WINDOW_GLASS_BROKEN", + "KITCHEN__WINDOW_FRAME_DEFECTIVE", + "KITCHEN__DOOR", + "KITCHEN__RADIATORS", + "KITCHEN__CEILING", + "KITCHEN__CEILING_LEAKING", + "KITCHEN__ELECTRICITY", + "KITCHEN__WIRING_EXPOSED", + "KITCHEN__OUTLETS", + "KITCHEN__REFRIGERATOR", + "KITCHEN__REFRIGERATOR_BROKEN", + "KITCHEN__STOVE", + "KITCHEN__STOVE_BROKEN", + "KITCHEN__SINK", + "KITCHEN__FAUCET_LEAKING", + "KITCHEN__NO_FAUCET", + "KITCHEN__FAUCET_NOT_WORKING", + "KITCHEN__WATER_PRESSURE", + "KITCHEN__PIPES", + "KITCHEN__DRAIN", + "LIVING_ROOM__MOLD", + "LIVING_ROOM__WATER", + "LIVING_ROOM__PAINT", + "LIVING_ROOM__WALLS", + "LIVING_ROOM__LOOSE_FLOOR", + "LIVING_ROOM__BASEBOARDS_DEFECTIVE", + "LIVING_ROOM__WINDOW_GLASS_BROKEN", + "LIVING_ROOM__WINDOW_FRAME_DEFECTIVE", + "LIVING_ROOM__DOOR", + "LIVING_ROOM__RADIATORS", + "LIVING_ROOM__CEILING", + "LIVING_ROOM__CEILING_LEAKING", + "LIVING_ROOM__ELECTRICITY", + "LIVING_ROOM__WIRING_EXPOSED", + "LIVING_ROOM__OUTLETS", + "BATHROOMS__MOLD", + "BATHROOMS__WATER", + "BATHROOMS__PAINT", + "BATHROOMS__WALLS", + "BATHROOMS__LOOSE_FLOOR", + "BATHROOMS__BASEBOARDS_DEFECTIVE", + "BATHROOMS__WINDOW_GLASS_BROKEN", + "BATHROOMS__WINDOW_FRAME_DEFECTIVE", + "BATHROOMS__DOOR", + "BATHROOMS__RADIATORS", + "BATHROOMS__CEILING", + "BATHROOMS__CEILING_LEAKING", + "BATHROOMS__ELECTRICITY", + "BATHROOMS__WIRING_EXPOSED", + "BATHROOMS__OUTLETS", + "BATHROOMS__TOILET", + "BATHROOMS__TOILET_LEAKING", + "BATHROOMS__SINK", + "BATHROOMS__SINK_FAUCET_LEAKING", + "BATHROOMS__SINK_NO_FAUCET", + "BATHROOMS__SINK_FAUCET_NOT_WORKING", + "BATHROOMS__SINK_WATER_PRESSURE", + "BATHROOMS__SINK_PIPES", + "BATHROOMS__SINK_DRAIN", + "BATHROOMS__TUB", + "BATHROOMS__TUB_FAUCET_LEAKING", + "BATHROOMS__TUB_NO_FAUCET", + "BATHROOMS__TUB_FAUCET_NOT_WORKING", + "BATHROOMS__TUB_PIPES", + "BATHROOMS__TUB_DRAIN", + "BATHROOMS__SHOWER_MOLD", + "BATHROOMS__SHOWER_WATER_PRESSURE", + "BATHROOMS__SHOWER_PIPES", + "BATHROOMS__SHOWER", + "BATHROOMS__SHOWER_FAUCET_LEAKING", + "BATHROOMS__SHOWER_NO_FAUCET", + "BATHROOMS__SHOWER_DRAIN", + "PUBLIC_AREAS__PAINTING_OVERDUE", + "PUBLIC_AREAS__PAINT", + "PUBLIC_AREAS__NO_HEAT", + "PUBLIC_AREAS__NO_HOT_WATER", + "PUBLIC_AREAS__WATER_PRESSURE", + "PUBLIC_AREAS__RUSTY_WATER", + "PUBLIC_AREAS__WIRING_EXPOSED", + "PUBLIC_AREAS__ELECTRICAL_CURRENT", + "PUBLIC_AREAS__BUGS", + "PUBLIC_AREAS__PESTS", + "PUBLIC_AREAS__FUMES", + "PUBLIC_AREAS__SMOKE_DETECTORS", + "PUBLIC_AREAS__WINDOW_GUARDS", + "PUBLIC_AREAS__ILLEGAL_APARTMENTS", + "PUBLIC_AREAS__NO_SUPER", + "PUBLIC_AREAS__RENT_RECEIPTS", + "PUBLIC_AREAS__INCOMPLETE_RENT_RECEIPTS" +]; + +const IssueChoiceSet: Set = new Set(IssueChoices); + +export function isIssueChoice(choice: string): choice is IssueChoice { + return IssueChoiceSet.has(choice); } export type IssueChoiceLabels = { diff --git a/frontend/commondatabuilder/commondatabuilder.ts b/frontend/commondatabuilder/commondatabuilder.ts index 918358d07..01a7d635e 100644 --- a/frontend/commondatabuilder/commondatabuilder.ts +++ b/frontend/commondatabuilder/commondatabuilder.ts @@ -59,19 +59,23 @@ export function createDjangoChoicesTypescript( const lines = [ `// This file was auto-generated by commondatabuilder.`, `// Please don't edit it.\n`, - `export enum ${name} {` ]; - for (let choice of choices) { - const name = choice[0]; - lines.push(` ${name} = "${name}",`); - } - lines.push('}\n'); + const choiceKeys = choices.map(choice => choice[0]); + const quotedChoiceKeys = choiceKeys.map(key => JSON.stringify(key)); + lines.push(`export type ${name} = ${quotedChoiceKeys.join('|')};\n`); + lines.push(`export const ${name}s: ${name}[] = ${JSON.stringify(choiceKeys, null, 2)};\n`); + lines.push(`const ${name}Set: Set = new Set(${name}s);\n`); lines.push( - `export type ${name}Labels = {`, - ` [k in ${name}]: string;`, - `};\n` + `export function is${name}(choice: string): choice is ${name} {`, + ` return ${name}Set.has(choice);`, + `}\n` ); if (exportLabels) { + lines.push( + `export type ${name}Labels = {`, + ` [k in ${name}]: string;`, + `};\n` + ); lines.push( `export function get${name}Labels(): ${name}Labels {`, ` return {` diff --git a/frontend/commondatabuilder/tests/__snapshots__/commondatabuilder.test.ts.snap b/frontend/commondatabuilder/tests/__snapshots__/commondatabuilder.test.ts.snap new file mode 100644 index 000000000..7b8a1e505 --- /dev/null +++ b/frontend/commondatabuilder/tests/__snapshots__/commondatabuilder.test.ts.snap @@ -0,0 +1,29 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`commondatabuilder creates django choice typescript 1`] = ` +"// This file was auto-generated by commondatabuilder. +// Please don't edit it. + +export type BoroughChoice = \\"BROOKLYN\\"; + +export const BoroughChoices: BoroughChoice[] = [ + \\"BROOKLYN\\" +]; + +const BoroughChoiceSet: Set = new Set(BoroughChoices); + +export function isBoroughChoice(choice: string): choice is BoroughChoice { + return BoroughChoiceSet.has(choice); +} + +export type BoroughChoiceLabels = { + [k in BoroughChoice]: string; +}; + +export function getBoroughChoiceLabels(): BoroughChoiceLabels { + return { + BROOKLYN: \\"Brooklyn\\", + }; +} +" +`; diff --git a/frontend/commondatabuilder/tests/commondatabuilder.test.ts b/frontend/commondatabuilder/tests/commondatabuilder.test.ts index a9877aa3d..36d489b77 100644 --- a/frontend/commondatabuilder/tests/commondatabuilder.test.ts +++ b/frontend/commondatabuilder/tests/commondatabuilder.test.ts @@ -2,28 +2,10 @@ import { createDjangoChoicesTypescript, createDjangoChoicesTypescriptFiles } fro import ourConfig from "../../../common-data/config"; -const EXPECTED_TS = `// This file was auto-generated by commondatabuilder. -// Please don't edit it. - -export enum BoroughChoice { - BROOKLYN = "BROOKLYN", -} - -export type BoroughChoiceLabels = { - [k in BoroughChoice]: string; -}; - -export function getBoroughChoiceLabels(): BoroughChoiceLabels { - return { - BROOKLYN: "Brooklyn", - }; -} -`; - describe('commondatabuilder', () => { it('creates django choice typescript', () => { const ts = createDjangoChoicesTypescript([['BROOKLYN', 'Brooklyn']], 'BoroughChoice'); - expect(ts).toEqual(EXPECTED_TS); + expect(ts).toMatchSnapshot(); }); it('only exports labels if configured to', () => { diff --git a/frontend/lib/common-data.ts b/frontend/lib/common-data.ts index efa62c54a..0794e497e 100644 --- a/frontend/lib/common-data.ts +++ b/frontend/lib/common-data.ts @@ -100,17 +100,6 @@ type StringMapping = { [k in T]: string }; -export function toDjangoChoices(enumObj: StringMapping, labels: StringMapping): [string, string][] { - const result = []; - for (let k in enumObj) { - result.push([k, labels[k]] as [string, string]); - } - return result; -} - -export function toEnumKey(enumObj: T, key: string): (keyof typeof enumObj)|undefined { - if (key in enumObj) { - return key as keyof typeof enumObj; - } - return undefined; +export function toDjangoChoices(choices: T[], labels: StringMapping): [string, string][] { + return choices.map(choice => [choice, labels[choice]] as [string, string]); } diff --git a/frontend/lib/geo-autocomplete.tsx b/frontend/lib/geo-autocomplete.tsx index 3f79786ce..40be23e57 100644 --- a/frontend/lib/geo-autocomplete.tsx +++ b/frontend/lib/geo-autocomplete.tsx @@ -12,11 +12,11 @@ import { GeoSearchBoroughGid, GeoSearchResults, GeoSearchRequester } from './geo function boroughGidToChoice(gid: GeoSearchBoroughGid): BoroughChoice { switch (gid) { - case GeoSearchBoroughGid.Manhattan: return BoroughChoice.MANHATTAN; - case GeoSearchBoroughGid.Bronx: return BoroughChoice.BRONX; - case GeoSearchBoroughGid.Brooklyn: return BoroughChoice.BROOKLYN; - case GeoSearchBoroughGid.Queens: return BoroughChoice.QUEENS; - case GeoSearchBoroughGid.StatenIsland: return BoroughChoice.STATEN_ISLAND; + case GeoSearchBoroughGid.Manhattan: return 'MANHATTAN'; + case GeoSearchBoroughGid.Bronx: return 'BRONX'; + case GeoSearchBoroughGid.Brooklyn: return 'BROOKLYN'; + case GeoSearchBoroughGid.Queens: return 'QUEENS'; + case GeoSearchBoroughGid.StatenIsland: return 'STATEN_ISLAND'; } throw new Error(`No borough found for ${gid}!`); diff --git a/frontend/lib/pages/onboarding-step-1.tsx b/frontend/lib/pages/onboarding-step-1.tsx index a7e3e392e..12573bb6a 100644 --- a/frontend/lib/pages/onboarding-step-1.tsx +++ b/frontend/lib/pages/onboarding-step-1.tsx @@ -15,10 +15,10 @@ import { withAppContext, AppContextType } from '../app-context'; import { LogoutMutation } from '../queries/LogoutMutation'; import { bulmaClasses } from '../bulma'; import { GeoAutocomplete } from '../geo-autocomplete'; -import { getBoroughChoiceLabels, BoroughChoice } from '../../../common-data/borough-choices'; +import { getBoroughChoiceLabels, BoroughChoice, isBoroughChoice, BoroughChoices } from '../../../common-data/borough-choices'; import { ProgressiveEnhancement, ProgressiveEnhancementContext } from '../progressive-enhancement'; import { OutboundLink } from '../google-analytics'; -import { toEnumKey, toDjangoChoices } from '../common-data'; +import { toDjangoChoices } from '../common-data'; const blankInitialState: OnboardingStep1Input = { firstName: '', @@ -78,8 +78,11 @@ export function PrivacyInfoModal(): JSX.Element { export const ConfirmAddressModal = withAppContext((props: AppContextType & { toStep2: string }): JSX.Element => { const onboardingStep1 = props.session.onboardingStep1 || blankInitialState; - const boroughKey = toEnumKey(BoroughChoice, onboardingStep1.borough); - const borough = boroughKey ? getBoroughChoiceLabels()[boroughKey] : ''; + let borough = ''; + + if (isBoroughChoice(onboardingStep1.borough)) { + borough = getBoroughChoiceLabels()[onboardingStep1.borough]; + } return ( ( @@ -125,7 +128,7 @@ class OnboardingStep1WithoutContexts extends React.Component ); diff --git a/frontend/lib/tests/geo-autocomplete.test.tsx b/frontend/lib/tests/geo-autocomplete.test.tsx index 232a2803a..5cf72afed 100644 --- a/frontend/lib/tests/geo-autocomplete.test.tsx +++ b/frontend/lib/tests/geo-autocomplete.test.tsx @@ -1,7 +1,6 @@ import React from 'react'; import ReactTestingLibraryPal from './rtl-pal'; import { GeoAutocomplete, geoSearchResultsToAutocompleteItems, geoAutocompleteItemToString } from '../geo-autocomplete'; -import { BoroughChoice } from '../../../common-data/borough-choices'; import { createMockFetch } from './mock-fetch'; import { FakeGeoResults } from './util'; import { KEY_TAB } from '../key-codes'; @@ -111,7 +110,7 @@ describe("GeoAutocomplete", () => { it('converts autocomplete items to strings', () => { expect(geoAutocompleteItemToString({ - borough: BoroughChoice.MANHATTAN, + borough: 'MANHATTAN', address: '150 COURT STREET' })).toEqual('150 COURT STREET, Manhattan'); expect(geoAutocompleteItemToString(null)).toEqual(''); From c3d81026d50fd4dbce66422f05bb51b3a74e713c Mon Sep 17 00:00:00 2001 From: Atul Varma Date: Tue, 5 Mar 2019 10:39:04 -0500 Subject: [PATCH 07/17] Um, upgrade apollo i guess? --- package-lock.json | 396 +++++++++++++++++++++++++++------------------- package.json | 2 +- 2 files changed, 235 insertions(+), 163 deletions(-) diff --git a/package-lock.json b/package-lock.json index ed6728125..a1da62b7d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1180,9 +1180,9 @@ } }, "@heroku-cli/color": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/@heroku-cli/color/-/color-1.1.14.tgz", - "integrity": "sha512-2JYy//YE2YINTe21hpdVMBNc7aYFkgDeY9JUz/BCjFZmYLn0UjGaCc4BpTcMGXNJwuqoUenw2WGOFGHsJqlIDw==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/@heroku-cli/color/-/color-1.1.13.tgz", + "integrity": "sha512-+ZTyxx5SkHjnzrnHC7Xn5sYM7Llljj5fYb7+9TOIBgZ1HKBuet9Q57rvCHOJ8dWZWqwgDiASZKzDkq3NMniKpQ==", "dev": true, "requires": { "ansi-styles": "^3.2.1", @@ -1230,14 +1230,14 @@ } }, "@oclif/command": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/@oclif/command/-/command-1.5.10.tgz", - "integrity": "sha512-zZdPHKj7u7d50XIcWer0x/YriL8c3NHPZCNhqA/RP62Bg9BgmvLAdn1dJ8YuxxNrhFCv+DmTyukyCYGLle+eNQ==", + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@oclif/command/-/command-1.5.4.tgz", + "integrity": "sha512-R76o9r2nMYLmpiRyEGDyIlwWIs5n+7aL6TncnqHCtjk990bN4ax5GyKf1S/+vw+2GswwOzNJ/wvxy5gbB3QZbg==", "dev": true, "requires": { "@oclif/errors": "^1.2.2", - "@oclif/parser": "^3.7.2", - "debug": "^4.1.1", + "@oclif/parser": "^3.6.1", + "debug": "^4.1.0", "semver": "^5.6.0" }, "dependencies": { @@ -1330,9 +1330,9 @@ "dev": true }, "@oclif/parser": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/@oclif/parser/-/parser-3.7.2.tgz", - "integrity": "sha512-ssYXztaf9TuOGCJQOYMg62L1Q4y2lB4wZORWng+Iy0ckP2A6IUnQy97V8YjAJkkohYZOu3Mga8LGfQcf+xdIIw==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@oclif/parser/-/parser-3.7.0.tgz", + "integrity": "sha512-CtRbCBJQ8prt9o3nCTSRi/UEw68t7mUf19vu3QKbh6sGc6BkD7OAX6Hfjxif636LSlR+N8eh3PELw9SxHdJcbQ==", "dev": true, "requires": { "@oclif/linewrap": "^1.0.0", @@ -1544,6 +1544,16 @@ "json-parse-better-errors": "^1.0.1" } }, + "password-prompt": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/password-prompt/-/password-prompt-1.1.2.tgz", + "integrity": "sha512-bpuBhROdrhuN3E7G/koAju0WjVw9/uQOG5Co5mokNj0MiOSBVZS1JTwM4zl55hu0WFmIEFvO9cU9sJQiBIYeIA==", + "dev": true, + "requires": { + "ansi-escapes": "^3.1.0", + "cross-spawn": "^6.0.5" + } + }, "semver": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", @@ -1562,32 +1572,21 @@ } }, "@oclif/plugin-warn-if-update-available": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@oclif/plugin-warn-if-update-available/-/plugin-warn-if-update-available-1.7.0.tgz", - "integrity": "sha512-Nwyz3BJ8RhsfQ+OmFSsJSPIfn5YJqMrCzPh72Zgo2jqIjKIBWD8N9vTTe4kZlpeUUn77SyXFfwlBQbNCL5OEuQ==", + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@oclif/plugin-warn-if-update-available/-/plugin-warn-if-update-available-1.5.4.tgz", + "integrity": "sha512-WRLofKh7eejSlHx6N10kOddAzdftgBYRI7SwzEznDe67AijJo8uboUQUh3Emk8g3iLV77GkXP8FU49W5klmrdg==", "dev": true, "requires": { - "@oclif/command": "^1.5.10", - "@oclif/config": "^1.12.8", + "@oclif/command": "^1.5.3", + "@oclif/config": "^1.8.7", "@oclif/errors": "^1.2.2", "chalk": "^2.4.1", "debug": "^4.1.0", "fs-extra": "^7.0.0", "http-call": "^5.2.2", - "lodash.template": "^4.4.0", "semver": "^5.6.0" }, "dependencies": { - "@oclif/config": { - "version": "1.12.8", - "resolved": "https://registry.npmjs.org/@oclif/config/-/config-1.12.8.tgz", - "integrity": "sha512-NNJ0lMowYwmfdoiwswfN9PKO71mGe031kgx9MVcp0nrMNzafO/Xa4Xw7tSzpeal7+wZRsrg/Xt6p4VfCK3UqLw==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "tslib": "^1.9.3" - } - }, "semver": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", @@ -2237,9 +2236,9 @@ } }, "apollo": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/apollo/-/apollo-2.5.1.tgz", - "integrity": "sha512-+LFKO+u/t6ZLljU40igVKLg4dnyifryP3STTfOJZCo4dN7QJCSJC7YiorZBmnOHXQuyGMSmw7WOB0WYwe8niOQ==", + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/apollo/-/apollo-2.5.3.tgz", + "integrity": "sha512-4t6BMycKLz0Djg21KD/yIgVqmu3dP3nRaOa3GpbbMpnQpppNeYZzlqEIsjN4UAmHIj4EwNNIqw4p9iUA7Cl5VQ==", "dev": true, "requires": { "@apollographql/apollo-tools": "0.3.3", @@ -2250,14 +2249,14 @@ "@oclif/plugin-not-found": "^1.0.9", "@oclif/plugin-plugins": "^1.7.2", "@oclif/plugin-warn-if-update-available": "^1.3.9", - "apollo-codegen-core": "0.32.6", - "apollo-codegen-flow": "0.32.6", - "apollo-codegen-scala": "0.33.2", - "apollo-codegen-swift": "0.32.6", - "apollo-codegen-typescript": "0.32.7", + "apollo-codegen-core": "0.32.8", + "apollo-codegen-flow": "0.32.8", + "apollo-codegen-scala": "0.33.4", + "apollo-codegen-swift": "0.32.8", + "apollo-codegen-typescript": "0.32.9", "apollo-engine-reporting": "0.2.2", "apollo-env": "0.3.3", - "apollo-language-server": "1.5.0", + "apollo-language-server": "1.5.2", "chalk": "^2.4.1", "cli-ux": "^4.3.0", "env-ci": "^3.0.0", @@ -2296,105 +2295,105 @@ } }, "apollo-codegen-core": { - "version": "0.32.6", - "resolved": "https://registry.npmjs.org/apollo-codegen-core/-/apollo-codegen-core-0.32.6.tgz", - "integrity": "sha512-hJ7w8KH+mEFxO4FKexDYPK4j4MILuW5YDMebVdR63Q0aYcdGbDUF1cceYnNUmeZOeMxkzY+xo8dJWcLp/goNNA==", + "version": "0.32.8", + "resolved": "https://registry.npmjs.org/apollo-codegen-core/-/apollo-codegen-core-0.32.8.tgz", + "integrity": "sha512-SQ2YqhkZC4U5RuUGb6vQ84FFDYfssvemPHTHwk2kwq2N/6pu7z2xJX86Hy4iimhpuzHSfKQAqKe9GtID01qnhw==", "dev": true, "requires": { "@babel/generator": "7.1.3", "@babel/parser": "^7.1.3", - "@babel/types": "7.3.2", + "@babel/types": "7.3.4", "apollo-env": "0.3.3", - "apollo-language-server": "1.5.0", + "apollo-language-server": "1.5.2", "ast-types": "^0.12.0", "common-tags": "^1.5.1", "recast": "^0.17.0" }, "dependencies": { "@babel/types": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.2.tgz", - "integrity": "sha512-3Y6H8xlUlpbGR+XvawiH0UXehqydTmNmEpozWcXymqwcrwYAl5KMvKtQ+TF6f6E08V6Jur7v/ykdDSF+WDEIXQ==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", + "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", "dev": true, "requires": { "esutils": "^2.0.2", - "lodash": "^4.17.10", + "lodash": "^4.17.11", "to-fast-properties": "^2.0.0" } } } }, "apollo-codegen-flow": { - "version": "0.32.6", - "resolved": "https://registry.npmjs.org/apollo-codegen-flow/-/apollo-codegen-flow-0.32.6.tgz", - "integrity": "sha512-M39euhP+zo74YreNdIAcZiQPv291/Q29F8q6eN+PZy286G/tx2Sut6jR+8JGv8boBmvFrgcw2VWkOiEIKL2tCw==", + "version": "0.32.8", + "resolved": "https://registry.npmjs.org/apollo-codegen-flow/-/apollo-codegen-flow-0.32.8.tgz", + "integrity": "sha512-kjiioXt/cAPWGlmhhJxWKOZgJk0jhSbNDo1HAoXYvRRaymuYAvr+R2q5xU0ey36O+Rmj4FrgqhLNrqv7AD3G3Q==", "dev": true, "requires": { - "@babel/types": "7.3.2", - "apollo-codegen-core": "0.32.6", + "@babel/types": "7.3.4", + "apollo-codegen-core": "0.32.8", "apollo-env": "0.3.3", "change-case": "^3.0.1", "inflected": "^2.0.3" }, "dependencies": { "@babel/types": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.2.tgz", - "integrity": "sha512-3Y6H8xlUlpbGR+XvawiH0UXehqydTmNmEpozWcXymqwcrwYAl5KMvKtQ+TF6f6E08V6Jur7v/ykdDSF+WDEIXQ==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", + "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", "dev": true, "requires": { "esutils": "^2.0.2", - "lodash": "^4.17.10", + "lodash": "^4.17.11", "to-fast-properties": "^2.0.0" } } } }, "apollo-codegen-scala": { - "version": "0.33.2", - "resolved": "https://registry.npmjs.org/apollo-codegen-scala/-/apollo-codegen-scala-0.33.2.tgz", - "integrity": "sha512-ud9YnQYL9yh2VWLeY7255FsvV36Na590LWTsSB5EUPyVwcuPiuqUMtHHM2Nbye3MfQ6t2APwgxPyfi27T4azwQ==", + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/apollo-codegen-scala/-/apollo-codegen-scala-0.33.4.tgz", + "integrity": "sha512-pGY8n0c2q3J8O+wSakR4yGZw4YXjWXN76Kcj2AvpRUncD6JyttpJgwSjrjqRe1+AncoJvR7DKrP/yqg3mVmp5A==", "dev": true, "requires": { - "apollo-codegen-core": "0.32.6", + "apollo-codegen-core": "0.32.8", "apollo-env": "0.3.3", "change-case": "^3.0.1", "inflected": "^2.0.3" } }, "apollo-codegen-swift": { - "version": "0.32.6", - "resolved": "https://registry.npmjs.org/apollo-codegen-swift/-/apollo-codegen-swift-0.32.6.tgz", - "integrity": "sha512-m2QM7YAS5fmiVyrIa1MZnohdHUcBDdDSHu3XvDdK1axHYTPaGCKCMozK3WPdnLypYD1ABWuDu4rTt/dK1WcIyA==", + "version": "0.32.8", + "resolved": "https://registry.npmjs.org/apollo-codegen-swift/-/apollo-codegen-swift-0.32.8.tgz", + "integrity": "sha512-kimXKiIuukytBZlStLBLDc5spS0ur+UiCT/PB7XrBm03MjqCh34ILHQ27ebpN98asi5kFD28ClI5W09D7N7YWw==", "dev": true, "requires": { - "apollo-codegen-core": "0.32.6", + "apollo-codegen-core": "0.32.8", "apollo-env": "0.3.3", "change-case": "^3.0.1", "inflected": "^2.0.3" } }, "apollo-codegen-typescript": { - "version": "0.32.7", - "resolved": "https://registry.npmjs.org/apollo-codegen-typescript/-/apollo-codegen-typescript-0.32.7.tgz", - "integrity": "sha512-RUXhsyxjIAkfnYet0wwRDXPGHGzV7xj+KBMtxNBCHWAYYJJIOu33rGV2bB+qh23TQ14Ol51m8Zsgb6yqITJGfg==", + "version": "0.32.9", + "resolved": "https://registry.npmjs.org/apollo-codegen-typescript/-/apollo-codegen-typescript-0.32.9.tgz", + "integrity": "sha512-R/KS/UyPT566zHAOFMGL+EUnUImoTa/MXtyPmZUbQ/pbims0gunfCi07ddVmNBaitFTfaW2/dLvgObKgeH8Czw==", "dev": true, "requires": { - "@babel/types": "7.3.2", - "apollo-codegen-core": "0.32.6", + "@babel/types": "7.3.4", + "apollo-codegen-core": "0.32.8", "apollo-env": "0.3.3", "change-case": "^3.0.1", "inflected": "^2.0.3" }, "dependencies": { "@babel/types": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.2.tgz", - "integrity": "sha512-3Y6H8xlUlpbGR+XvawiH0UXehqydTmNmEpozWcXymqwcrwYAl5KMvKtQ+TF6f6E08V6Jur7v/ykdDSF+WDEIXQ==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", + "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", "dev": true, "requires": { "esutils": "^2.0.2", - "lodash": "^4.17.10", + "lodash": "^4.17.11", "to-fast-properties": "^2.0.0" } } @@ -2450,17 +2449,17 @@ "dev": true }, "node-fetch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.3.0.tgz", - "integrity": "sha512-MOd8pV3fxENbryESLgVIeaGKrdl+uaYhCSSVkjeOb/31/njTpcis5aWfdqgNlHIrKOLRbMnfPINPOML2CIFeXA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.2.0.tgz", + "integrity": "sha512-OayFWziIxiHY8bCUyLX6sTpDH8Jsbp4FfYd1j1f7vZyfgkcOnAyM4oQR16f8a0s7Gl/viMGRey8eScYk4V4EZA==", "dev": true } } }, "apollo-language-server": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/apollo-language-server/-/apollo-language-server-1.5.0.tgz", - "integrity": "sha512-oasgJqgfBofpenCa86thWrLcALTviZqI85AiPA9JrY0JItDt8HA3m9wFkDFYkxK9vxOh23d+aVpbSFb9wxTIdQ==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/apollo-language-server/-/apollo-language-server-1.5.2.tgz", + "integrity": "sha512-xn6sUrORQDkwrMFThshkgjAYWeD/Nbkul9scOhfre3VVewRKPGlutL9/nSyMPf3fAZnzUNaDcOihVf3Jg3cgkw==", "dev": true, "requires": { "@apollographql/apollo-tools": "0.3.3", @@ -2512,9 +2511,15 @@ "path-is-absolute": "^1.0.0" } }, + "graphql-tag": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.10.1.tgz", + "integrity": "sha512-jApXqWBzNXQ8jYa/HLkZJaVw9jgwNqZkywa2zfFn16Iv1Zb7ELNHkJaXHR7Quvd5SIGsy6Ny7SUKATgnu05uEg==", + "dev": true + }, "minimist": { "version": "1.2.0", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true }, @@ -2530,12 +2535,13 @@ } }, "apollo-link": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/apollo-link/-/apollo-link-1.2.8.tgz", - "integrity": "sha512-lfzGRxhK9RmiH3HPFi7TIEBhhDY9M5a2ZDnllcfy5QDk7cCQHQ1WQArcw1FK0g1B+mV4Kl72DSrlvZHZJEolrA==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/apollo-link/-/apollo-link-1.2.3.tgz", + "integrity": "sha512-iL9yS2OfxYhigme5bpTbmRyC+Htt6tyo2fRMHT3K1XRL/C5IQDDz37OjpPy4ndx7WInSvfSZaaOTKFja9VWqSw==", "dev": true, "requires": { - "zen-observable-ts": "^0.8.15" + "apollo-utilities": "^1.0.0", + "zen-observable-ts": "^0.8.10" } }, "apollo-link-context": { @@ -2545,6 +2551,26 @@ "dev": true, "requires": { "apollo-link": "^1.2.8" + }, + "dependencies": { + "apollo-link": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/apollo-link/-/apollo-link-1.2.8.tgz", + "integrity": "sha512-lfzGRxhK9RmiH3HPFi7TIEBhhDY9M5a2ZDnllcfy5QDk7cCQHQ1WQArcw1FK0g1B+mV4Kl72DSrlvZHZJEolrA==", + "dev": true, + "requires": { + "zen-observable-ts": "^0.8.15" + } + }, + "zen-observable-ts": { + "version": "0.8.15", + "resolved": "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-0.8.15.tgz", + "integrity": "sha512-sXKPWiw6JszNEkRv5dQ+lQCttyjHM2Iks74QU5NP8mMPS/NrzTlHDr780gf/wOBqmHkPO6NCLMlsa+fAQ8VE8w==", + "dev": true, + "requires": { + "zen-observable": "^0.8.0" + } + } } }, "apollo-link-error": { @@ -2555,16 +2581,36 @@ "requires": { "apollo-link": "^1.2.8", "apollo-link-http-common": "^0.2.10" + }, + "dependencies": { + "apollo-link": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/apollo-link/-/apollo-link-1.2.8.tgz", + "integrity": "sha512-lfzGRxhK9RmiH3HPFi7TIEBhhDY9M5a2ZDnllcfy5QDk7cCQHQ1WQArcw1FK0g1B+mV4Kl72DSrlvZHZJEolrA==", + "dev": true, + "requires": { + "zen-observable-ts": "^0.8.15" + } + }, + "zen-observable-ts": { + "version": "0.8.15", + "resolved": "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-0.8.15.tgz", + "integrity": "sha512-sXKPWiw6JszNEkRv5dQ+lQCttyjHM2Iks74QU5NP8mMPS/NrzTlHDr780gf/wOBqmHkPO6NCLMlsa+fAQ8VE8w==", + "dev": true, + "requires": { + "zen-observable": "^0.8.0" + } + } } }, "apollo-link-http": { - "version": "1.5.11", - "resolved": "https://registry.npmjs.org/apollo-link-http/-/apollo-link-http-1.5.11.tgz", - "integrity": "sha512-wDG+I9UmpfaZRPIvTYBgkvqiCgmz6yWgvuzW/S24Q4r4Xrfe6sLpg2FmarhtdP+hdN+IXTLbFNCZ+Trgfpifow==", + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/apollo-link-http/-/apollo-link-http-1.5.5.tgz", + "integrity": "sha512-C5N6N/mRwmepvtzO27dgMEU3MMtRKSqcljBkYNZmWwH11BxkUQ5imBLPM3V4QJXNE7NFuAQAB5PeUd4ligivTQ==", "dev": true, "requires": { - "apollo-link": "^1.2.8", - "apollo-link-http-common": "^0.2.10" + "apollo-link": "^1.2.3", + "apollo-link-http-common": "^0.2.5" } }, "apollo-link-http-common": { @@ -2574,6 +2620,26 @@ "dev": true, "requires": { "apollo-link": "^1.2.8" + }, + "dependencies": { + "apollo-link": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/apollo-link/-/apollo-link-1.2.8.tgz", + "integrity": "sha512-lfzGRxhK9RmiH3HPFi7TIEBhhDY9M5a2ZDnllcfy5QDk7cCQHQ1WQArcw1FK0g1B+mV4Kl72DSrlvZHZJEolrA==", + "dev": true, + "requires": { + "zen-observable-ts": "^0.8.15" + } + }, + "zen-observable-ts": { + "version": "0.8.15", + "resolved": "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-0.8.15.tgz", + "integrity": "sha512-sXKPWiw6JszNEkRv5dQ+lQCttyjHM2Iks74QU5NP8mMPS/NrzTlHDr780gf/wOBqmHkPO6NCLMlsa+fAQ8VE8w==", + "dev": true, + "requires": { + "zen-observable": "^0.8.0" + } + } } }, "apollo-link-ws": { @@ -2583,6 +2649,26 @@ "dev": true, "requires": { "apollo-link": "^1.2.8" + }, + "dependencies": { + "apollo-link": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/apollo-link/-/apollo-link-1.2.8.tgz", + "integrity": "sha512-lfzGRxhK9RmiH3HPFi7TIEBhhDY9M5a2ZDnllcfy5QDk7cCQHQ1WQArcw1FK0g1B+mV4Kl72DSrlvZHZJEolrA==", + "dev": true, + "requires": { + "zen-observable-ts": "^0.8.15" + } + }, + "zen-observable-ts": { + "version": "0.8.15", + "resolved": "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-0.8.15.tgz", + "integrity": "sha512-sXKPWiw6JszNEkRv5dQ+lQCttyjHM2Iks74QU5NP8mMPS/NrzTlHDr780gf/wOBqmHkPO6NCLMlsa+fAQ8VE8w==", + "dev": true, + "requires": { + "zen-observable": "^0.8.0" + } + } } }, "apollo-server-caching": { @@ -2604,9 +2690,9 @@ } }, "yallist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", - "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz", + "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=", "dev": true } } @@ -2683,9 +2769,9 @@ } }, "yallist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", - "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz", + "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=", "dev": true } } @@ -2701,9 +2787,9 @@ }, "dependencies": { "node-fetch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.3.0.tgz", - "integrity": "sha512-MOd8pV3fxENbryESLgVIeaGKrdl+uaYhCSSVkjeOb/31/njTpcis5aWfdqgNlHIrKOLRbMnfPINPOML2CIFeXA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.2.0.tgz", + "integrity": "sha512-OayFWziIxiHY8bCUyLX6sTpDH8Jsbp4FfYd1j1f7vZyfgkcOnAyM4oQR16f8a0s7Gl/viMGRey8eScYk4V4EZA==", "dev": true } } @@ -2742,13 +2828,12 @@ } }, "apollo-utilities": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/apollo-utilities/-/apollo-utilities-1.1.3.tgz", - "integrity": "sha512-pF9abhiClX5gfj/WFWZh8DiI33nOLGxRhXH9ZMquaM1V8bhq1WLFPt2QjShWH3kGQVeIGUK+FQefnhe+ZaaAYg==", + "version": "1.0.23", + "resolved": "https://registry.npmjs.org/apollo-utilities/-/apollo-utilities-1.0.23.tgz", + "integrity": "sha512-RW65kZZxSEysvzm5YBrNU6SvE+Z62VQ+lpxYX/3d9pZYsMBkaMdfr3OnUwGKt/MqUsDfUb/LLoXpMRhKukMpeQ==", "dev": true, "requires": { - "fast-json-stable-stringify": "^2.0.0", - "tslib": "^1.9.3" + "fast-json-stable-stringify": "^2.0.0" } }, "append-transform": { @@ -3678,9 +3763,9 @@ } }, "change-case": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/change-case/-/change-case-3.1.0.tgz", - "integrity": "sha512-2AZp7uJZbYEzRPsFoa+ijKdvp9zsrnnt6+yFokfwEpeJm0xuJDVoxiRCAaTzyJND8GJkofo2IcKWaUZ/OECVzw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/change-case/-/change-case-3.0.2.tgz", + "integrity": "sha512-Mww+SLF6MZ0U6kdg11algyKd5BARbyM4TbFBepwowYSR5ClfQGCGtxNXgykpN0uF/bstWeaGDT4JWaDh8zWAHA==", "dev": true, "requires": { "camel-case": "^3.0.0", @@ -3869,9 +3954,9 @@ } }, "cli-ux": { - "version": "4.9.3", - "resolved": "https://registry.npmjs.org/cli-ux/-/cli-ux-4.9.3.tgz", - "integrity": "sha512-/1owvF0SZ5Gn54cgrikJ0QskgTzeg30HGjkmjFoaHDJzAqFpuX1DBpFR8aLvsE1J5s9MgeYRENQK4BFwOag5VA==", + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/cli-ux/-/cli-ux-4.9.1.tgz", + "integrity": "sha512-0CPt5GrpZl/iDpiHnhs7ReqX3a8iNBG6vYvwsnFRfQgD/jEyLZfaoChybKWFSg9pQ5ZisKOfA0cLoNlKIk2Lvw==", "dev": true, "requires": { "@oclif/errors": "^1.2.2", @@ -3881,7 +3966,7 @@ "ansi-styles": "^3.2.1", "cardinal": "^2.1.1", "chalk": "^2.4.1", - "clean-stack": "^2.0.0", + "clean-stack": "^1.3.0", "extract-stack": "^1.0.0", "fs-extra": "^7.0.0", "hyperlinker": "^1.0.0", @@ -3893,8 +3978,7 @@ "strip-ansi": "^5.0.0", "supports-color": "^5.5.0", "supports-hyperlinks": "^1.0.1", - "treeify": "^1.1.0", - "tslib": "^1.9.3" + "treeify": "^1.1.0" }, "dependencies": { "ansi-regex": { @@ -3903,12 +3987,6 @@ "integrity": "sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w==", "dev": true }, - "clean-stack": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.0.0.tgz", - "integrity": "sha512-VEoL9Qh7I8s8iHnV53DaeWSt8NJ0g3khMfK6NiCPB7H657juhro+cSw2O88uo3bo0c0X5usamtXk0/Of0wXa5A==", - "dev": true - }, "indent-string": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", @@ -4783,9 +4861,9 @@ "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=" }, "env-ci": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/env-ci/-/env-ci-3.2.0.tgz", - "integrity": "sha512-TFjNiDlXrL8/pfHswdvJGEZzJcq3aBPb8Eka83hlGLwuNw9F9BC9S9ETlkfkItLRT9k5JgpGgeP+rL6/3cEbcw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/env-ci/-/env-ci-3.1.0.tgz", + "integrity": "sha512-+yFT8QX8W9bee0/fuzKvqt2vEhWvU3FXZ1P5xbveDq/EqcYLh4e0QNE16okUS3pawALDGXE9eCJPVeWY0/ilQA==", "dev": true, "requires": { "execa": "^1.0.0", @@ -6147,9 +6225,9 @@ "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" }, "graphql": { - "version": "14.1.1", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-14.1.1.tgz", - "integrity": "sha512-C5zDzLqvfPAgTtP8AUPIt9keDabrdRAqSWjj2OPRKrKxI9Fb65I36s1uCs1UUBFnSWTdO7hyHi7z1ZbwKMKF6Q==", + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-14.0.2.tgz", + "integrity": "sha512-gUC4YYsaiSJT1h40krG3J+USGlwhzNTXSb4IOZljn9ag5Tj+RkoXrWp+Kh7WyE3t1NCfab5kzCuxBIvOMERMXw==", "dev": true, "requires": { "iterall": "^1.2.2" @@ -6174,9 +6252,9 @@ } }, "graphql-tag": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.10.1.tgz", - "integrity": "sha512-jApXqWBzNXQ8jYa/HLkZJaVw9jgwNqZkywa2zfFn16Iv1Zb7ELNHkJaXHR7Quvd5SIGsy6Ny7SUKATgnu05uEg==", + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.10.0.tgz", + "integrity": "sha512-9FD6cw976TLLf9WYIUPCaaTpniawIjHWZSwIRZSjrfufJamcXbVVYfN2TWvJYbw0Xf2JjYbl1/f2+wDnBVw3/w==", "dev": true }, "graphql-tools": { @@ -6205,24 +6283,18 @@ }, "dependencies": { "http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.1.tgz", + "integrity": "sha512-jWEUgtZWGSMba9I1N3gc1HmvpBUaNC9vDdA46yScAdp+C5rdEuKWUBLWTQpW9FwSWSbYYs++b6SDCxf9UEJzfw==", "dev": true, "requires": { "depd": "~1.1.2", "inherits": "2.0.3", - "setprototypeof": "1.1.1", + "setprototypeof": "1.1.0", "statuses": ">= 1.5.0 < 2", "toidentifier": "1.0.0" } }, - "setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", - "dev": true - }, "statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", @@ -6392,9 +6464,9 @@ } }, "heroku-cli-util": { - "version": "8.0.11", - "resolved": "https://registry.npmjs.org/heroku-cli-util/-/heroku-cli-util-8.0.11.tgz", - "integrity": "sha512-cApMBbrfAhFTKs/loXm7zkWRC4kOH1VHoqU5WNgzs2TGKJqQI3QYvxITKE+8iC1Gb1xAy0BCqdGgzx8t7EoeWQ==", + "version": "8.0.10", + "resolved": "https://registry.npmjs.org/heroku-cli-util/-/heroku-cli-util-8.0.10.tgz", + "integrity": "sha512-NMcdnX3y2N+efhRGeZvBokmBtDdggtrgRb3pozhyrR2+5LmzKkDLONK/MfjvwrpAUP2MXPu8UkxJDnM/SAGlxA==", "dev": true, "requires": { "@heroku-cli/color": "^1.1.3", @@ -6404,7 +6476,7 @@ "chalk": "^2.4.1", "co": "^4.6.0", "got": "^8.3.1", - "heroku-client": "^3.0.7", + "heroku-client": "^3.0.6", "lodash": "^4.17.10", "netrc-parser": "^3.1.4", "opn": "^3.0.3", @@ -6415,9 +6487,9 @@ } }, "heroku-client": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/heroku-client/-/heroku-client-3.0.7.tgz", - "integrity": "sha512-wL8d3ufIWGzL8B2U7oPzN+SdcMt6LPqA/x4nb9pDG45IXpr8KO+N4dvX4Vycgn0WrJVDfQnQ1juctJsUwuoeww==", + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/heroku-client/-/heroku-client-3.0.6.tgz", + "integrity": "sha512-1FKLb5ngGTMwUh67DPiYmv+TaKasTfZSYHno/Kx0goE6Fqutec3WILCHPmOfw9LTGnRjL9/Pmi5BNmu9GwNFNA==", "dev": true, "requires": { "is-retry-allowed": "^1.0.0", @@ -6501,9 +6573,9 @@ "dev": true }, "http-call": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/http-call/-/http-call-5.2.3.tgz", - "integrity": "sha512-IkwGruHVHATmnonLKMGX5tkpM0KSn/C240o8/OfBsESRaJacykSia+akhD0d3fljQ5rQPXtBvSrVShAsj+EOUQ==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/http-call/-/http-call-5.2.2.tgz", + "integrity": "sha512-DMEU+vvbrvt7n1BYPacbvtSwUmIgORP7HphTmKFqt1wBVeGi/+ADe7KkfyKAcnpa9HEoVaPWdfpOKy7fNeLdiw==", "dev": true, "requires": { "content-type": "^1.0.4", @@ -6705,7 +6777,7 @@ }, "into-stream": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-3.1.0.tgz", + "resolved": "http://registry.npmjs.org/into-stream/-/into-stream-3.1.0.tgz", "integrity": "sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY=", "dev": true, "requires": { @@ -9185,7 +9257,7 @@ }, "opn": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/opn/-/opn-3.0.3.tgz", + "resolved": "http://registry.npmjs.org/opn/-/opn-3.0.3.tgz", "integrity": "sha1-ttmec5n3jWXDuq/+8fsojpuFJDo=", "dev": true, "requires": { @@ -9278,7 +9350,7 @@ }, "p-cancelable": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.4.1.tgz", + "resolved": "http://registry.npmjs.org/p-cancelable/-/p-cancelable-0.4.1.tgz", "integrity": "sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ==", "dev": true }, @@ -9420,9 +9492,9 @@ "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=" }, "password-prompt": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/password-prompt/-/password-prompt-1.1.2.tgz", - "integrity": "sha512-bpuBhROdrhuN3E7G/koAju0WjVw9/uQOG5Co5mokNj0MiOSBVZS1JTwM4zl55hu0WFmIEFvO9cU9sJQiBIYeIA==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/password-prompt/-/password-prompt-1.0.7.tgz", + "integrity": "sha1-jid0jTQAvJyRQNWt5wXft6632Ro=", "dev": true, "requires": { "ansi-escapes": "^3.1.0", @@ -9705,7 +9777,7 @@ }, "query-string": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", + "resolved": "http://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", "dev": true, "requires": { @@ -11511,9 +11583,9 @@ } }, "ts-node": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz", - "integrity": "sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.0.tgz", + "integrity": "sha512-klJsfswHP0FuOLsvBZ/zzCfUvakOSSxds78mVeK7I+qP76YWtxf16hEZsp3U+b0kIo82R5UatGFeblYMqabb2Q==", "dev": true, "requires": { "arrify": "^1.0.0", @@ -11528,7 +11600,7 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true } @@ -12565,15 +12637,15 @@ "dev": true }, "zen-observable": { - "version": "0.8.13", - "resolved": "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.13.tgz", - "integrity": "sha512-fa+6aDUVvavYsefZw0zaZ/v3ckEtMgCFi30sn91SEZea4y/6jQp05E3omjkX91zV6RVdn15fqnFZ6RKjRGbp2g==", + "version": "0.8.10", + "resolved": "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.10.tgz", + "integrity": "sha512-UXEh0ekA/QWYI2NkLHc5IH0V1FstIN4qGVlVvq0DQAS3oR72mofYHkjJ2f4ysMKRAziwnACzg3c0ZuG+SMDu8w==", "dev": true }, "zen-observable-ts": { - "version": "0.8.15", - "resolved": "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-0.8.15.tgz", - "integrity": "sha512-sXKPWiw6JszNEkRv5dQ+lQCttyjHM2Iks74QU5NP8mMPS/NrzTlHDr780gf/wOBqmHkPO6NCLMlsa+fAQ8VE8w==", + "version": "0.8.10", + "resolved": "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-0.8.10.tgz", + "integrity": "sha512-5vqMtRggU/2GhePC9OU4sYEWOdvmayp2k3gjPf4F0mXwB3CSbbNznfDUvDJx9O2ZTa1EIXdJhPchQveFKwNXPQ==", "dev": true, "requires": { "zen-observable": "^0.8.0" diff --git a/package.json b/package.json index 910432645..9ea922be6 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "@types/webpack": "4.4.17", "@types/webpack-bundle-analyzer": "2.13.0", "@types/webpack-node-externals": "1.6.3", - "apollo": "2.5.1", + "apollo": "2.5.3", "chalk": "2.4.1", "chokidar": "2.0.4", "concurrently": "3.6.1", From 92e87b1e5dc558af68dd2796b3f0773b95b8df2d Mon Sep 17 00:00:00 2001 From: Atul Varma Date: Tue, 5 Mar 2019 10:50:04 -0500 Subject: [PATCH 08/17] Run querybuilder.js --force. --- frontend/lib/queries/AccessDatesMutation.ts | 1 + frontend/lib/queries/AllSessionInfo.ts | 1 + frontend/lib/queries/ExampleMutation.ts | 1 + frontend/lib/queries/GenerateHPActionPDFMutation.ts | 1 + frontend/lib/queries/GetHPActionUploadStatus.ts | 1 + frontend/lib/queries/IssueAreaMutation.ts | 1 + frontend/lib/queries/LandlordDetailsMutation.ts | 1 + frontend/lib/queries/LetterRequestMutation.ts | 1 + frontend/lib/queries/LoginMutation.ts | 1 + frontend/lib/queries/LogoutMutation.ts | 1 + frontend/lib/queries/OnboardingStep1Mutation.ts | 1 + frontend/lib/queries/OnboardingStep2Mutation.ts | 1 + frontend/lib/queries/OnboardingStep3Mutation.ts | 1 + frontend/lib/queries/OnboardingStep4Mutation.ts | 1 + 14 files changed, 14 insertions(+) diff --git a/frontend/lib/queries/AccessDatesMutation.ts b/frontend/lib/queries/AccessDatesMutation.ts index 7e3e0d685..676de79ee 100644 --- a/frontend/lib/queries/AccessDatesMutation.ts +++ b/frontend/lib/queries/AccessDatesMutation.ts @@ -1,6 +1,7 @@ // This file was automatically generated and should not be edited. /* tslint:disable */ +/* eslint-disable */ // This file was automatically generated and should not be edited. import { AccessDatesInput } from "./globalTypes"; diff --git a/frontend/lib/queries/AllSessionInfo.ts b/frontend/lib/queries/AllSessionInfo.ts index 695ffd284..57a979b2a 100644 --- a/frontend/lib/queries/AllSessionInfo.ts +++ b/frontend/lib/queries/AllSessionInfo.ts @@ -1,6 +1,7 @@ // This file was automatically generated and should not be edited. /* tslint:disable */ +/* eslint-disable */ // This file was automatically generated and should not be edited. import { OnboardingInfoSignupIntent, LetterRequestMailChoice, HPUploadStatus } from "./globalTypes"; diff --git a/frontend/lib/queries/ExampleMutation.ts b/frontend/lib/queries/ExampleMutation.ts index 2d69b2179..02bd7c5ef 100644 --- a/frontend/lib/queries/ExampleMutation.ts +++ b/frontend/lib/queries/ExampleMutation.ts @@ -1,6 +1,7 @@ // This file was automatically generated and should not be edited. /* tslint:disable */ +/* eslint-disable */ // This file was automatically generated and should not be edited. import { ExampleInput } from "./globalTypes"; diff --git a/frontend/lib/queries/GenerateHPActionPDFMutation.ts b/frontend/lib/queries/GenerateHPActionPDFMutation.ts index 67b164b8b..54c3b4c4f 100644 --- a/frontend/lib/queries/GenerateHPActionPDFMutation.ts +++ b/frontend/lib/queries/GenerateHPActionPDFMutation.ts @@ -1,6 +1,7 @@ // This file was automatically generated and should not be edited. /* tslint:disable */ +/* eslint-disable */ // This file was automatically generated and should not be edited. import { GeneratePDFInput, HPUploadStatus } from "./globalTypes"; diff --git a/frontend/lib/queries/GetHPActionUploadStatus.ts b/frontend/lib/queries/GetHPActionUploadStatus.ts index 1d4c2a382..98aa07270 100644 --- a/frontend/lib/queries/GetHPActionUploadStatus.ts +++ b/frontend/lib/queries/GetHPActionUploadStatus.ts @@ -1,6 +1,7 @@ // This file was automatically generated and should not be edited. /* tslint:disable */ +/* eslint-disable */ // This file was automatically generated and should not be edited. import { HPUploadStatus } from "./globalTypes"; diff --git a/frontend/lib/queries/IssueAreaMutation.ts b/frontend/lib/queries/IssueAreaMutation.ts index f33f8d282..a1895426f 100644 --- a/frontend/lib/queries/IssueAreaMutation.ts +++ b/frontend/lib/queries/IssueAreaMutation.ts @@ -1,6 +1,7 @@ // This file was automatically generated and should not be edited. /* tslint:disable */ +/* eslint-disable */ // This file was automatically generated and should not be edited. import { IssueAreaInput } from "./globalTypes"; diff --git a/frontend/lib/queries/LandlordDetailsMutation.ts b/frontend/lib/queries/LandlordDetailsMutation.ts index 725b1c4a6..b1d5e890a 100644 --- a/frontend/lib/queries/LandlordDetailsMutation.ts +++ b/frontend/lib/queries/LandlordDetailsMutation.ts @@ -1,6 +1,7 @@ // This file was automatically generated and should not be edited. /* tslint:disable */ +/* eslint-disable */ // This file was automatically generated and should not be edited. import { LandlordDetailsInput } from "./globalTypes"; diff --git a/frontend/lib/queries/LetterRequestMutation.ts b/frontend/lib/queries/LetterRequestMutation.ts index 293ec3392..a2b607c2b 100644 --- a/frontend/lib/queries/LetterRequestMutation.ts +++ b/frontend/lib/queries/LetterRequestMutation.ts @@ -1,6 +1,7 @@ // This file was automatically generated and should not be edited. /* tslint:disable */ +/* eslint-disable */ // This file was automatically generated and should not be edited. import { LetterRequestInput, LetterRequestMailChoice } from "./globalTypes"; diff --git a/frontend/lib/queries/LoginMutation.ts b/frontend/lib/queries/LoginMutation.ts index d60219d52..20fbe6442 100644 --- a/frontend/lib/queries/LoginMutation.ts +++ b/frontend/lib/queries/LoginMutation.ts @@ -2,6 +2,7 @@ import * as AllSessionInfo from './AllSessionInfo' /* tslint:disable */ +/* eslint-disable */ // This file was automatically generated and should not be edited. import { LoginInput, OnboardingInfoSignupIntent, LetterRequestMailChoice, HPUploadStatus } from "./globalTypes"; diff --git a/frontend/lib/queries/LogoutMutation.ts b/frontend/lib/queries/LogoutMutation.ts index bb7295b4b..e8b1b70b8 100644 --- a/frontend/lib/queries/LogoutMutation.ts +++ b/frontend/lib/queries/LogoutMutation.ts @@ -2,6 +2,7 @@ import * as AllSessionInfo from './AllSessionInfo' /* tslint:disable */ +/* eslint-disable */ // This file was automatically generated and should not be edited. import { LogoutInput, OnboardingInfoSignupIntent, LetterRequestMailChoice, HPUploadStatus } from "./globalTypes"; diff --git a/frontend/lib/queries/OnboardingStep1Mutation.ts b/frontend/lib/queries/OnboardingStep1Mutation.ts index 8b80992e5..3b7b576a0 100644 --- a/frontend/lib/queries/OnboardingStep1Mutation.ts +++ b/frontend/lib/queries/OnboardingStep1Mutation.ts @@ -1,6 +1,7 @@ // This file was automatically generated and should not be edited. /* tslint:disable */ +/* eslint-disable */ // This file was automatically generated and should not be edited. import { OnboardingStep1Input } from "./globalTypes"; diff --git a/frontend/lib/queries/OnboardingStep2Mutation.ts b/frontend/lib/queries/OnboardingStep2Mutation.ts index 9231331eb..7b8b198c6 100644 --- a/frontend/lib/queries/OnboardingStep2Mutation.ts +++ b/frontend/lib/queries/OnboardingStep2Mutation.ts @@ -1,6 +1,7 @@ // This file was automatically generated and should not be edited. /* tslint:disable */ +/* eslint-disable */ // This file was automatically generated and should not be edited. import { OnboardingStep2Input } from "./globalTypes"; diff --git a/frontend/lib/queries/OnboardingStep3Mutation.ts b/frontend/lib/queries/OnboardingStep3Mutation.ts index f0b91e133..c67e26fc5 100644 --- a/frontend/lib/queries/OnboardingStep3Mutation.ts +++ b/frontend/lib/queries/OnboardingStep3Mutation.ts @@ -1,6 +1,7 @@ // This file was automatically generated and should not be edited. /* tslint:disable */ +/* eslint-disable */ // This file was automatically generated and should not be edited. import { OnboardingStep3Input } from "./globalTypes"; diff --git a/frontend/lib/queries/OnboardingStep4Mutation.ts b/frontend/lib/queries/OnboardingStep4Mutation.ts index 253570b3b..2276e1cee 100644 --- a/frontend/lib/queries/OnboardingStep4Mutation.ts +++ b/frontend/lib/queries/OnboardingStep4Mutation.ts @@ -2,6 +2,7 @@ import * as AllSessionInfo from './AllSessionInfo' /* tslint:disable */ +/* eslint-disable */ // This file was automatically generated and should not be edited. import { OnboardingStep4Input, OnboardingInfoSignupIntent, LetterRequestMailChoice, HPUploadStatus } from "./globalTypes"; From ad32c81e9f61eeb8fdc38cf6d7247a7a8472b3e5 Mon Sep 17 00:00:00 2001 From: Atul Varma Date: Tue, 5 Mar 2019 10:52:20 -0500 Subject: [PATCH 09/17] Tell users to pass --force to querybuilder on test failure. --- frontend/querybuilder/tests/querybuilder.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/querybuilder/tests/querybuilder.test.ts b/frontend/querybuilder/tests/querybuilder.test.ts index eea4be3d8..b281f3d7b 100644 --- a/frontend/querybuilder/tests/querybuilder.test.ts +++ b/frontend/querybuilder/tests/querybuilder.test.ts @@ -18,7 +18,7 @@ describe('querybuilder', () => { const actual = fs.readFileSync(query.tsCodePath, { encoding: 'utf-8' }); if (expected != actual) { - throw new Error('GraphQL queries have changed, please re-run "node querybuilder.js".'); + throw new Error('GraphQL queries have changed, please re-run "node querybuilder.js --force".'); } }); }); From a1f75b104f5813fd1be4802a7ec2516fb4d66267 Mon Sep 17 00:00:00 2001 From: Atul Varma Date: Tue, 5 Mar 2019 11:55:05 -0500 Subject: [PATCH 10/17] Convert issue choices to use typescript files. --- common-data/config.ts | 6 ++++ common-data/issue-area-choices.ts | 22 ++++++++---- frontend/lib/common-data.ts | 4 +-- frontend/lib/issue-search.tsx | 34 +++++++++++-------- frontend/lib/issues.ts | 27 +++++++-------- frontend/lib/pages/issue-pages.tsx | 27 ++++++++------- frontend/lib/tests/issues.test.ts | 2 +- frontend/lib/tests/pages/issue-pages.test.tsx | 4 +-- tsconfig.json | 1 + 9 files changed, 75 insertions(+), 52 deletions(-) diff --git a/common-data/config.ts b/common-data/config.ts index cb6d5ef48..04bf065a2 100644 --- a/common-data/config.ts +++ b/common-data/config.ts @@ -9,6 +9,12 @@ const config: DjangoChoicesTypescriptConfig = { exportLabels: true, filterOut: /^LANDLORD__/ }, + { + jsonFilename: 'issue-area-choices.json', + enumName: 'IssueAreaChoice', + exportLabels: true, + filterOut: ['LANDLORD'] + }, { jsonFilename: 'borough-choices.json', enumName: 'BoroughChoice', diff --git a/common-data/issue-area-choices.ts b/common-data/issue-area-choices.ts index 514291194..561064916 100644 --- a/common-data/issue-area-choices.ts +++ b/common-data/issue-area-choices.ts @@ -1,13 +1,21 @@ // This file was auto-generated by commondatabuilder. // Please don't edit it. -export enum IssueAreaChoice { - HOME = "HOME", - BEDROOMS = "BEDROOMS", - KITCHEN = "KITCHEN", - LIVING_ROOM = "LIVING_ROOM", - BATHROOMS = "BATHROOMS", - PUBLIC_AREAS = "PUBLIC_AREAS", +export type IssueAreaChoice = "HOME"|"BEDROOMS"|"KITCHEN"|"LIVING_ROOM"|"BATHROOMS"|"PUBLIC_AREAS"; + +export const IssueAreaChoices: IssueAreaChoice[] = [ + "HOME", + "BEDROOMS", + "KITCHEN", + "LIVING_ROOM", + "BATHROOMS", + "PUBLIC_AREAS" +]; + +const IssueAreaChoiceSet: Set = new Set(IssueAreaChoices); + +export function isIssueAreaChoice(choice: string): choice is IssueAreaChoice { + return IssueAreaChoiceSet.has(choice); } export type IssueAreaChoiceLabels = { diff --git a/frontend/lib/common-data.ts b/frontend/lib/common-data.ts index 0794e497e..8ff8e66eb 100644 --- a/frontend/lib/common-data.ts +++ b/frontend/lib/common-data.ts @@ -100,6 +100,6 @@ type StringMapping = { [k in T]: string }; -export function toDjangoChoices(choices: T[], labels: StringMapping): [string, string][] { - return choices.map(choice => [choice, labels[choice]] as [string, string]); +export function toDjangoChoices(choices: T[], labels: StringMapping): [T, string][] { + return choices.map(choice => [choice, labels[choice]] as [T, string]); } diff --git a/frontend/lib/issue-search.tsx b/frontend/lib/issue-search.tsx index b417e74bf..39ed2690a 100644 --- a/frontend/lib/issue-search.tsx +++ b/frontend/lib/issue-search.tsx @@ -1,8 +1,9 @@ import React from 'react'; import classnames from 'classnames'; -import { issueArea, ISSUE_CHOICES, ISSUE_AREA_CHOICES } from './issues'; -import { getDjangoChoiceLabel } from './common-data'; +import { issueArea } from './issues'; import Downshift, { DownshiftInterface, ControllerStateAndHelpers } from 'downshift'; +import { getIssueChoiceLabels, IssueChoices } from '../../common-data/issue-choices'; +import { getIssueAreaChoiceLabels } from '../../common-data/issue-area-choices'; interface IssueAutocompleteItem { value: string; @@ -14,21 +15,26 @@ interface IssueAutocompleteItem { const IssueDownshift = Downshift as DownshiftInterface; -const ALL_AUTOCOMPLETE_ITEMS: IssueAutocompleteItem[] = ISSUE_CHOICES.map(([value, label]) => { - const areaValue = issueArea(value); - const areaLabel = getDjangoChoiceLabel(ISSUE_AREA_CHOICES, areaValue); - return { - value, - label, - areaValue, - areaLabel, - searchableText: [areaLabel.toLowerCase(), '-', label.toLowerCase()].join(' ') - } -}); +function getAllAutocompleteitems(): IssueAutocompleteItem[] { + const issueLabels = getIssueChoiceLabels(); + const issueAreaLabels = getIssueAreaChoiceLabels(); + return IssueChoices.map(value => { + const areaValue = issueArea(value); + const areaLabel = issueAreaLabels[areaValue]; + const label = issueLabels[value]; + return { + value, + label, + areaValue, + areaLabel, + searchableText: [areaLabel.toLowerCase(), '-', label.toLowerCase()].join(' ') + } + }); +} function filterAutocompleteItems(searchString: string): IssueAutocompleteItem[] { searchString = searchString.toLowerCase(); - return ALL_AUTOCOMPLETE_ITEMS.filter(item => + return getAllAutocompleteitems().filter(item => item.searchableText.indexOf(searchString) !== -1); } diff --git a/frontend/lib/issues.ts b/frontend/lib/issues.ts index 272050cd9..814b59c65 100644 --- a/frontend/lib/issues.ts +++ b/frontend/lib/issues.ts @@ -1,24 +1,20 @@ -import { DjangoChoices, filterDjangoChoices } from "./common-data"; +import { DjangoChoices } from "./common-data"; import { AllSessionInfo_customIssues } from "./queries/AllSessionInfo"; +import { IssueAreaChoice } from "../../common-data/issue-area-choices"; +import { IssueChoice, IssueChoices, getIssueChoiceLabels } from "../../common-data/issue-choices"; -export const ISSUE_AREA_CHOICES = filterDjangoChoices( - require('../../common-data/issue-area-choices.json'), ['LANDLORD']); - -export const ISSUE_CHOICES = filterDjangoChoices( - require('../../common-data/issue-choices.json'), /^LANDLORD__/); - -export function customIssueForArea(area: string, customIssues: AllSessionInfo_customIssues[]): string { +export function customIssueForArea(area: IssueAreaChoice, customIssues: AllSessionInfo_customIssues[]): string { for (let ci of customIssues) { if (ci.area === area) return ci.description; } return ''; } -export function issueArea(issue: string): string { - return issue.split('__')[0]; +export function issueArea(issue: IssueChoice): IssueAreaChoice { + return issue.split('__')[0] as IssueAreaChoice; } -export function areaIssueCount(area: string, issues: string[], customIssues: AllSessionInfo_customIssues[]): number { +export function areaIssueCount(area: IssueAreaChoice, issues: IssueChoice[], customIssues: AllSessionInfo_customIssues[]): number { return issues.reduce((total, issue) => issueArea(issue) === area ? total + 1 : total, 0) + customIssues.reduce((total, ci) => @@ -26,10 +22,13 @@ export function areaIssueCount(area: string, issues: string[], customIssues: All 0); } -export function issuesForArea(area: string, issues: string[]): string[] { +export function issuesForArea(area: IssueAreaChoice, issues: IssueChoice[]): IssueChoice[] { return issues.filter(issue => issueArea(issue) === area); } -export function issueChoicesForArea(area: string): DjangoChoices { - return ISSUE_CHOICES.filter(([value, label]) => issueArea(value) === area); +export function issueChoicesForArea(area: IssueAreaChoice): DjangoChoices { + const labels = getIssueChoiceLabels(); + return IssueChoices + .filter(choice => issueArea(choice) === area) + .map(choice => [choice, labels[choice]] as [string, string]); } diff --git a/frontend/lib/pages/issue-pages.tsx b/frontend/lib/pages/issue-pages.tsx index c1b4f9bf2..c25c1f587 100644 --- a/frontend/lib/pages/issue-pages.tsx +++ b/frontend/lib/pages/issue-pages.tsx @@ -1,6 +1,6 @@ import React from 'react'; import classnames from 'classnames'; -import { safeGetDjangoChoiceLabel, allCapsToSlug, slugToAllCaps } from "../common-data"; +import { allCapsToSlug, slugToAllCaps, toDjangoChoices } from "../common-data"; import Page from '../page'; import { IssuesRouteInfo, IssuesRouteAreaProps } from '../routes'; import { Switch, Route } from 'react-router'; @@ -15,11 +15,13 @@ import { MultiCheckboxFormField, TextareaFormField, HiddenFormField } from '../f import { NextButton, BackButton } from "../buttons"; import { AllSessionInfo } from '../queries/AllSessionInfo'; import { SimpleProgressiveEnhancement } from '../progressive-enhancement'; -import { issueChoicesForArea, ISSUE_AREA_CHOICES, issuesForArea, customIssueForArea, areaIssueCount } from '../issues'; +import { issueChoicesForArea, issuesForArea, customIssueForArea, areaIssueCount } from '../issues'; import { doesAreaMatchSearch, IssueAutocomplete } from '../issue-search'; import { ga } from '../google-analytics'; import ISSUE_AREA_SVGS from '../svg/issues'; import { assertNotUndefined } from '../util'; +import { IssueAreaChoice, isIssueAreaChoice, getIssueAreaChoiceLabels, IssueAreaChoices } from '../../../common-data/issue-area-choices'; +import { IssueChoice } from '../../../common-data/issue-choices'; const checkSvg = require('../svg/check-solid.svg') as JSX.Element; @@ -29,7 +31,7 @@ type IssuesAreaPropsWithCtx = IssuesRouteAreaProps & { export class IssuesArea extends React.Component { @autobind - renderForm(ctx: FormContext, area: string): JSX.Element { + renderForm(ctx: FormContext, area: IssueAreaChoice): JSX.Element { return ( @@ -55,15 +57,15 @@ export class IssuesArea extends React.Component { render() { const area = slugToAllCaps(this.props.match.params.area); - const label = safeGetDjangoChoiceLabel(ISSUE_AREA_CHOICES, area); + if (!isIssueAreaChoice(area)) { + return ; + } + const label = getIssueAreaChoiceLabels()[area]; const getInitialState = (session: AllSessionInfo): IssueAreaInput => ({ area, - issues: issuesForArea(area, session.issues), + issues: issuesForArea(area, session.issues as IssueChoice[]), other: customIssueForArea(area, session.customIssues) }); - if (label === null) { - return ; - } const svg = assertNotUndefined(ISSUE_AREA_SVGS[area]); return ( @@ -90,7 +92,7 @@ export function getIssueLabel(count: number): string { } type IssueAreaLinkProps = { - area: string; + area: IssueAreaChoice; label: string; isHighlighted?: boolean; routes: IssuesRouteInfo; @@ -102,7 +104,7 @@ function IssueAreaLink(props: IssueAreaLinkProps): JSX.Element { return ( {(ctx) => { - const count = areaIssueCount(area, ctx.session.issues, ctx.session.customIssues); + const count = areaIssueCount(area, ctx.session.issues as IssueChoice[], ctx.session.customIssues); const url = props.routes.area.create(allCapsToSlug(area)); const actionLabel = count === 0 ? 'Add issues' : 'Add or remove issues'; const title = `${actionLabel} for ${label}`; @@ -176,7 +178,7 @@ class IssuesHome extends React.Component { this.state = { searchText: '' }; } - renderColumnForArea(area: string, label: string): JSX.Element { + renderColumnForArea(area: IssueAreaChoice, label: string): JSX.Element { return
{ } render() { + const labels = getIssueAreaChoiceLabels(); return (
@@ -206,7 +209,7 @@ class IssuesHome extends React.Component { {this.renderAutocomplete()} - {groupByTwo(ISSUE_AREA_CHOICES).map(([a, b], i) => ( + {groupByTwo(toDjangoChoices(IssueAreaChoices, labels)).map(([a, b], i) => (
{this.renderColumnForArea(...a)} {b && this.renderColumnForArea(...b)} diff --git a/frontend/lib/tests/issues.test.ts b/frontend/lib/tests/issues.test.ts index 4d66f529c..e5dca7e2d 100644 --- a/frontend/lib/tests/issues.test.ts +++ b/frontend/lib/tests/issues.test.ts @@ -10,7 +10,7 @@ test('areaIssueCount() works', () => { expect(areaIssueCount('HOME', ['HOME__MICE'], [{ area: 'HOME', description: 'boop' }])).toBe(2); - expect(areaIssueCount('HOME', ['BEDROOMS_PAINT'], [])).toBe(0); + expect(areaIssueCount('HOME', ['BEDROOMS__PAINT'], [])).toBe(0); expect(areaIssueCount('HOME', [], [{ area: 'BEDROOMS', description: 'boop' }])).toBe(0); diff --git a/frontend/lib/tests/pages/issue-pages.test.tsx b/frontend/lib/tests/pages/issue-pages.test.tsx index 34a5aa262..6fb804f66 100644 --- a/frontend/lib/tests/pages/issue-pages.test.tsx +++ b/frontend/lib/tests/pages/issue-pages.test.tsx @@ -5,8 +5,8 @@ import Routes from '../../routes'; import { AppTesterPal } from '../app-tester-pal'; import { IssueAreaInput } from '../../queries/globalTypes'; import { IssueAreaMutation_output } from '../../queries/IssueAreaMutation'; -import { ISSUE_AREA_CHOICES } from '../../issues'; import ISSUE_AREA_SVGS from '../../svg/issues'; +import { IssueAreaChoices } from '../../../../common-data/issue-area-choices'; const routes = Routes.loc.issues; @@ -63,7 +63,7 @@ test('getIssueLabel() works', () => { }); test('issue area images exist', () => { - ISSUE_AREA_CHOICES.forEach(([area, _]) => { + IssueAreaChoices.forEach(area => { const svg = ISSUE_AREA_SVGS[area]; if (!svg) { throw new Error(`Expected ISSUE_AREA_SVGS.${area} to exist`); diff --git a/tsconfig.json b/tsconfig.json index 77cd45982..3c5c6c8c9 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,7 @@ { "include": [ "webpack.config.js", + "common-data", "frontend", "twofactor/static", "findhelp/static", From 26a118cb9ad90f89963d4937f39d5ef284812b93 Mon Sep 17 00:00:00 2001 From: Atul Varma Date: Tue, 5 Mar 2019 12:08:17 -0500 Subject: [PATCH 11/17] Migrate lease choices to typescript. --- common-data/config.ts | 6 ++++ common-data/lease-choices.ts | 32 +++++++++++++++++++ frontend/lib/pages/onboarding-step-3.tsx | 13 ++++---- .../tests/pages/onboarding-step-3.test.tsx | 14 ++++---- 4 files changed, 51 insertions(+), 14 deletions(-) create mode 100644 common-data/lease-choices.ts diff --git a/common-data/config.ts b/common-data/config.ts index 04bf065a2..db1267f8b 100644 --- a/common-data/config.ts +++ b/common-data/config.ts @@ -19,6 +19,12 @@ const config: DjangoChoicesTypescriptConfig = { jsonFilename: 'borough-choices.json', enumName: 'BoroughChoice', exportLabels: true, + }, + { + jsonFilename: 'lease-choices.json', + enumName: 'LeaseChoice', + exportLabels: true, + filterOut: ['NOT_SURE'] } ] }; diff --git a/common-data/lease-choices.ts b/common-data/lease-choices.ts new file mode 100644 index 000000000..aa6036c5c --- /dev/null +++ b/common-data/lease-choices.ts @@ -0,0 +1,32 @@ +// This file was auto-generated by commondatabuilder. +// Please don't edit it. + +export type LeaseChoice = "RENT_STABILIZED"|"MARKET_RATE"|"NYCHA"|"OTHER"|"NO_LEASE"; + +export const LeaseChoices: LeaseChoice[] = [ + "RENT_STABILIZED", + "MARKET_RATE", + "NYCHA", + "OTHER", + "NO_LEASE" +]; + +const LeaseChoiceSet: Set = new Set(LeaseChoices); + +export function isLeaseChoice(choice: string): choice is LeaseChoice { + return LeaseChoiceSet.has(choice); +} + +export type LeaseChoiceLabels = { + [k in LeaseChoice]: string; +}; + +export function getLeaseChoiceLabels(): LeaseChoiceLabels { + return { + RENT_STABILIZED: "Rent Stabilized/Rent Controlled", + MARKET_RATE: "Market Rate", + NYCHA: "NYCHA Housing Development", + OTHER: "Other (Mitchell Lama, COOP/Condo, House, HUD, etc.)", + NO_LEASE: "I don't have a lease", + }; +} diff --git a/frontend/lib/pages/onboarding-step-3.tsx b/frontend/lib/pages/onboarding-step-3.tsx index 8829b2a3a..3a8d984d6 100644 --- a/frontend/lib/pages/onboarding-step-3.tsx +++ b/frontend/lib/pages/onboarding-step-3.tsx @@ -7,15 +7,13 @@ import { Link, Route } from 'react-router-dom'; import { NextButton, BackButton } from "../buttons"; import { IconLink } from "../icon-link"; import { CheckboxFormField, RadiosFormField } from '../form-fields'; -import { filterDjangoChoices, ReactDjangoChoices } from '../common-data'; +import { ReactDjangoChoices } from '../common-data'; import { OnboardingStep3Mutation } from '../queries/OnboardingStep3Mutation'; import { Modal, BackOrUpOneDirLevel } from '../modal'; import { twoTuple } from '../util'; import { glueToLastWord } from '../word-glue'; import { OnboardingRouteInfo } from '../routes'; - -export const LEASE_CHOICES = filterDjangoChoices( - require('../../../common-data/lease-choices.json'), ['NOT_SURE']); +import { getLeaseChoiceLabels, LeaseChoices, LeaseChoice } from '../../../common-data/lease-choices'; const blankInitialState: OnboardingStep3Input = { leaseType: '', @@ -62,7 +60,7 @@ export function LeaseLearnMoreModal(props: { children: any, title: string }): JS type LeaseModalInfo = { route: string; - leaseType: string; + leaseType: LeaseChoice; component: () => JSX.Element; }; @@ -172,7 +170,10 @@ export default class OnboardingStep3 extends React.Component twoTuple(info.leaseType, info))); - this.leaseChoicesWithInfo = LEASE_CHOICES.map(([value, label]) => { + const leaseLabels = getLeaseChoiceLabels(); + + this.leaseChoicesWithInfo = LeaseChoices.map(value => { + const label = leaseLabels[value]; const info = leaseLearnMoreModalMap.get(value); const title = `Learn more about ${label} leases`; diff --git a/frontend/lib/tests/pages/onboarding-step-3.test.tsx b/frontend/lib/tests/pages/onboarding-step-3.test.tsx index 231421b3b..ad6d8d8b7 100644 --- a/frontend/lib/tests/pages/onboarding-step-3.test.tsx +++ b/frontend/lib/tests/pages/onboarding-step-3.test.tsx @@ -1,11 +1,11 @@ import React from 'react'; -import OnboardingStep3, { LEASE_CHOICES } from '../../pages/onboarding-step-3'; -import { validateDjangoChoices, getDjangoChoiceLabel } from '../../common-data'; +import OnboardingStep3 from '../../pages/onboarding-step-3'; import { AppTesterPal } from '../app-tester-pal'; import { OnboardingStep3Mutation_output } from '../../queries/OnboardingStep3Mutation'; import { escapeRegExp } from '../util'; import Routes from '../../routes'; +import { getLeaseChoiceLabels } from '../../../../common-data/lease-choices'; const PROPS = { @@ -17,9 +17,11 @@ const STEP_3 = new OnboardingStep3(PROPS); describe('onboarding step 3 page', () => { afterEach(AppTesterPal.cleanup); + const labels = getLeaseChoiceLabels(); + STEP_3.leaseLearnMoreModals.forEach(info => { const { leaseType } = info; - const label = getDjangoChoiceLabel(LEASE_CHOICES, leaseType); + const label = labels[leaseType]; it(`displays learn more modal for ${label}`, async () => { const pal = new AppTesterPal(); @@ -31,7 +33,7 @@ describe('onboarding step 3 page', () => { STEP_3.leaseModals.forEach(info => { const { leaseType } = info; - const label = getDjangoChoiceLabel(LEASE_CHOICES, leaseType); + const label = labels[leaseType]; it(`displays modal when user chooses "${label}"`, async () => { const pal = new AppTesterPal(); @@ -51,7 +53,3 @@ describe('onboarding step 3 page', () => { }); }); }); - -test('Lease types are valid', () => { - validateDjangoChoices(LEASE_CHOICES, STEP_3.allLeaseModals.map(info => info.leaseType)); -}); From b47fd68870fda6d1e107fbdaf1fbcac11f22460b Mon Sep 17 00:00:00 2001 From: Atul Varma Date: Tue, 5 Mar 2019 12:23:24 -0500 Subject: [PATCH 12/17] Move functions to commondatabuilder. --- .../commondatabuilder/commondatabuilder.ts | 52 +++++++++++++++- .../tests/commondatabuilder.test.ts | 21 ++++++- frontend/lib/common-data.ts | 59 +++---------------- frontend/lib/tests/common-data.test.ts | 29 ++++----- frontend/lib/tests/signup-intent.test.tsx | 11 ---- 5 files changed, 90 insertions(+), 82 deletions(-) diff --git a/frontend/commondatabuilder/commondatabuilder.ts b/frontend/commondatabuilder/commondatabuilder.ts index 01a7d635e..576725a78 100644 --- a/frontend/commondatabuilder/commondatabuilder.ts +++ b/frontend/commondatabuilder/commondatabuilder.ts @@ -1,7 +1,7 @@ import * as fs from 'fs'; import * as path from 'path'; -import { DjangoChoices, filterDjangoChoices } from "../lib/common-data"; +import { DjangoChoices } from "../lib/common-data"; type CreateOptions = { exportLabels: boolean @@ -21,6 +21,56 @@ export type DjangoChoicesTypescriptFileConfig = { filterOut?: RegExp|string[], }; +/** + * Retrieve the human-readable label for a choice, given its machine-readable value. + * + * Return null if the choice is invalid. + */ +export function safeGetDjangoChoiceLabel(choices: DjangoChoices, value: string): string|null { + for (let [v, label] of choices) { + if (v === value) return label; + } + return null; +} + +/** + * Validate that the given values are valid choices. + * + * This is intended to be used in tests. It should be removed from + * production bundles via tree-shaking. + */ +export function validateDjangoChoices(choices: DjangoChoices, values: string[]) { + values.forEach(value => { + getDjangoChoiceLabel(choices, value); + }); +} + +/** + * Filter out the given values from either the given list of choices, or anything + * that matches the given regular expression. + */ +export function filterDjangoChoices(choices: DjangoChoices, values: string[]|RegExp): DjangoChoices { + if (Array.isArray(values)) { + validateDjangoChoices(choices, values); + return choices.filter(([value, _]) => !values.includes(value)); + } else { + return choices.filter(([value, _]) => !values.test(value)); + } +} + +/** + * Retrieve the human-readable label for a choice, given its machine-readable value. + * + * Throw an exception if the choice is invalid. + */ +export function getDjangoChoiceLabel(choices: DjangoChoices, value: string): string { + const result = safeGetDjangoChoiceLabel(choices, value); + if (result === null) { + throw new Error(`Unable to find label for value ${value}`); + } + return result; +} + function replaceExt(filename: string, ext: string) { // https://stackoverflow.com/a/5953384 return filename.substr(0, filename.lastIndexOf(".")) + ext; diff --git a/frontend/commondatabuilder/tests/commondatabuilder.test.ts b/frontend/commondatabuilder/tests/commondatabuilder.test.ts index 36d489b77..ef45bd702 100644 --- a/frontend/commondatabuilder/tests/commondatabuilder.test.ts +++ b/frontend/commondatabuilder/tests/commondatabuilder.test.ts @@ -1,6 +1,7 @@ -import { createDjangoChoicesTypescript, createDjangoChoicesTypescriptFiles } from "../commondatabuilder"; +import { createDjangoChoicesTypescript, createDjangoChoicesTypescriptFiles, getDjangoChoiceLabel, validateDjangoChoices, filterDjangoChoices } from "../commondatabuilder"; import ourConfig from "../../../common-data/config"; +import { DjangoChoices } from "../../lib/common-data"; describe('commondatabuilder', () => { it('creates django choice typescript', () => { @@ -19,3 +20,21 @@ describe('commondatabuilder', () => { createDjangoChoicesTypescriptFiles(ourConfig, true); }); }); + +test('getDjangoChoiceLabel() works', () => { + expect(getDjangoChoiceLabel([['BLAH', 'boop']], 'BLAH')).toBe('boop'); + expect(() => getDjangoChoiceLabel([['BLAH', 'boop']], 'NOPE')) + .toThrow('Unable to find label for value NOPE'); +}); + +test("validateDjangoChoices() works", () => { + expect(validateDjangoChoices([['BLAH', 'boop']], ['BLAH'])).toBeUndefined(); + expect(() => validateDjangoChoices([['BLAH', 'boop']], ['NOPE'])) + .toThrow('Unable to find label for value NOPE'); +}); + +test("filterDjangoChoices() works", () => { + const choices: DjangoChoices = [["FOO", "Foo"], ["BAR", "Bar"]]; + expect(filterDjangoChoices(choices, ["FOO"])).toEqual([["BAR", "Bar"]]); + expect(filterDjangoChoices(choices, /^BA/)).toEqual([["FOO", "Foo"]]); +}); diff --git a/frontend/lib/common-data.ts b/frontend/lib/common-data.ts index 8ff8e66eb..5d25be82c 100644 --- a/frontend/lib/common-data.ts +++ b/frontend/lib/common-data.ts @@ -27,58 +27,6 @@ export type ReactDjangoChoice = [string, string|JSX.Element]; export type ReactDjangoChoices = ReactDjangoChoice[]; -/** - * Retrieve the human-readable label for a choice, given its machine-readable value. - * - * Throw an exception if the choice is invalid. - */ -export function getDjangoChoiceLabel(choices: DjangoChoices, value: string): string { - const result = safeGetDjangoChoiceLabel(choices, value); - if (result === null) { - throw new Error(`Unable to find label for value ${value}`); - } - return result; -} - -/** - * Filter out the given values from either the given list of choices, or anything - * that matches the given regular expression. - */ -export function filterDjangoChoices(choices: DjangoChoices, values: string[]|RegExp): DjangoChoices { - if (Array.isArray(values)) { - if (process.env.NODE_ENV !== 'production') { - validateDjangoChoices(choices, values); - } - return choices.filter(([value, _]) => !values.includes(value)); - } else { - return choices.filter(([value, _]) => !values.test(value)); - } -} - -/** - * Retrieve the human-readable label for a choice, given its machine-readable value. - * - * Return null if the choice is invalid. - */ -export function safeGetDjangoChoiceLabel(choices: DjangoChoices, value: string): string|null { - for (let [v, label] of choices) { - if (v === value) return label; - } - return null; -} - -/** - * Validate that the given values are valid choices. - * - * This is intended to be used in tests. It should be removed from - * production bundles via tree-shaking. - */ -export function validateDjangoChoices(choices: DjangoChoices, values: string[]) { - values.forEach(value => { - getDjangoChoiceLabel(choices, value); - }); -} - /** * Convert an all-caps value, like 'FOO_BAR', to an * all-lowercase slug-friendly value, like 'foo-bar'. @@ -100,6 +48,13 @@ type StringMapping = { [k in T]: string }; +/** + * This combines a list of values to choose from with their + * labels into a list of DjangoChoices. + * + * @param choices A list of values to choose from. + * @param labels A mapping from values to their labels. + */ export function toDjangoChoices(choices: T[], labels: StringMapping): [T, string][] { return choices.map(choice => [choice, labels[choice]] as [T, string]); } diff --git a/frontend/lib/tests/common-data.test.ts b/frontend/lib/tests/common-data.test.ts index 808ee5a34..ea113fa16 100644 --- a/frontend/lib/tests/common-data.test.ts +++ b/frontend/lib/tests/common-data.test.ts @@ -1,16 +1,4 @@ -import { getDjangoChoiceLabel, validateDjangoChoices, allCapsToSlug, slugToAllCaps, filterDjangoChoices, DjangoChoices } from "../common-data"; - -test('getDjangoChoiceLabel() works', () => { - expect(getDjangoChoiceLabel([['BLAH', 'boop']], 'BLAH')).toBe('boop'); - expect(() => getDjangoChoiceLabel([['BLAH', 'boop']], 'NOPE')) - .toThrow('Unable to find label for value NOPE'); -}); - -test("validateDjangoChoices() works", () => { - expect(validateDjangoChoices([['BLAH', 'boop']], ['BLAH'])).toBeUndefined(); - expect(() => validateDjangoChoices([['BLAH', 'boop']], ['NOPE'])) - .toThrow('Unable to find label for value NOPE'); -}); +import { allCapsToSlug, slugToAllCaps, toDjangoChoices } from "../common-data"; test("allCapsToSlug() works", () => { expect(allCapsToSlug('BOOP_BLAP_BONK')).toBe('boop-blap-bonk'); @@ -20,8 +8,15 @@ test("slugToAllCaps() works", () => { expect(slugToAllCaps('boop-blap-bonk')).toBe('BOOP_BLAP_BONK'); }); -test("filterDjangoChoices() works", () => { - const choices: DjangoChoices = [["FOO", "Foo"], ["BAR", "Bar"]]; - expect(filterDjangoChoices(choices, ["FOO"])).toEqual([["BAR", "Bar"]]); - expect(filterDjangoChoices(choices, /^BA/)).toEqual([["FOO", "Foo"]]); +test("toDjangoChoices() works", () => { + type Blarg = 'foo'|'bar'; + const blargs: Blarg[] = ['foo', 'bar']; + const blargLabels = { + foo: 'hi', + bar: 'there' + }; + expect(toDjangoChoices(blargs, blargLabels)).toEqual([ + ['foo', 'hi'], + ['bar', 'there'] + ]); }); diff --git a/frontend/lib/tests/signup-intent.test.tsx b/frontend/lib/tests/signup-intent.test.tsx index c5574f944..f65c2c7f9 100644 --- a/frontend/lib/tests/signup-intent.test.tsx +++ b/frontend/lib/tests/signup-intent.test.tsx @@ -1,18 +1,7 @@ -import { validateDjangoChoices } from "../common-data"; import { OnboardingInfoSignupIntent } from "../queries/globalTypes"; import { signupIntentFromOnboardingInfo, DEFAULT_SIGNUP_INTENT_CHOICE, getOnboardingRouteForIntent } from "../signup-intent"; import { AppTesterPal } from "./app-tester-pal"; -type SignupIntentDjangoChoice = [OnboardingInfoSignupIntent, string]; - -const SIGNUP_INTENT_CHOICES = require('../../../common-data/signup-intent-choices.json') as SignupIntentDjangoChoice[]; - -test('OnboardingInfoSignupIntent has valid choices', () => { - for (let choice in OnboardingInfoSignupIntent) { - validateDjangoChoices(SIGNUP_INTENT_CHOICES, [choice, OnboardingInfoSignupIntent[choice]]); - } -}); - test('signupIntentFromOnboardingInfo() works', () => { expect(signupIntentFromOnboardingInfo(null)).toStrictEqual(DEFAULT_SIGNUP_INTENT_CHOICE); expect(signupIntentFromOnboardingInfo({ signupIntent: 'boop' } as any)).toBe('boop'); From 254e4c7d5c91989c1729eb4bc9d15a07245566ec Mon Sep 17 00:00:00 2001 From: Atul Varma Date: Tue, 5 Mar 2019 12:25:08 -0500 Subject: [PATCH 13/17] Rename enumName to typeName. --- common-data/config.ts | 8 ++++---- frontend/commondatabuilder/commondatabuilder.ts | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/common-data/config.ts b/common-data/config.ts index db1267f8b..1e6a77b86 100644 --- a/common-data/config.ts +++ b/common-data/config.ts @@ -5,24 +5,24 @@ const config: DjangoChoicesTypescriptConfig = { files: [ { jsonFilename: 'issue-choices.json', - enumName: 'IssueChoice', + typeName: 'IssueChoice', exportLabels: true, filterOut: /^LANDLORD__/ }, { jsonFilename: 'issue-area-choices.json', - enumName: 'IssueAreaChoice', + typeName: 'IssueAreaChoice', exportLabels: true, filterOut: ['LANDLORD'] }, { jsonFilename: 'borough-choices.json', - enumName: 'BoroughChoice', + typeName: 'BoroughChoice', exportLabels: true, }, { jsonFilename: 'lease-choices.json', - enumName: 'LeaseChoice', + typeName: 'LeaseChoice', exportLabels: true, filterOut: ['NOT_SURE'] } diff --git a/frontend/commondatabuilder/commondatabuilder.ts b/frontend/commondatabuilder/commondatabuilder.ts index 576725a78..b2018ae94 100644 --- a/frontend/commondatabuilder/commondatabuilder.ts +++ b/frontend/commondatabuilder/commondatabuilder.ts @@ -16,7 +16,7 @@ export type DjangoChoicesTypescriptConfig = { export type DjangoChoicesTypescriptFileConfig = { jsonFilename: string, - enumName: string, + typeName: string, exportLabels: boolean, filterOut?: RegExp|string[], }; @@ -88,7 +88,7 @@ export function createDjangoChoicesTypescriptFiles( if (fileConfig.filterOut) { choices = filterDjangoChoices(choices, fileConfig.filterOut); } - const ts = createDjangoChoicesTypescript(choices, fileConfig.enumName, { + const ts = createDjangoChoicesTypescript(choices, fileConfig.typeName, { exportLabels: fileConfig.exportLabels }); const outfilename = replaceExt(fileConfig.jsonFilename, '.ts'); From 55f0173e0ae068cd6fba8601cb8d26e315c98f53 Mon Sep 17 00:00:00 2001 From: Atul Varma Date: Tue, 5 Mar 2019 12:35:18 -0500 Subject: [PATCH 14/17] Appease codeclimate. --- .codeclimate.yml | 2 + .../commondatabuilder/commondatabuilder.ts | 50 +++++++++++++------ 2 files changed, 36 insertions(+), 16 deletions(-) diff --git a/.codeclimate.yml b/.codeclimate.yml index edd3c9a31..df3e8b926 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -7,6 +7,8 @@ exclude_patterns: - "frontend/lib/queries/*" # These are auto-generated by Django, ignore them. - "**/migrations/*" + # These are auto-generated by commondatabuilder, ignore them. + - "common-data/*-choices.ts" checks: similar-code: diff --git a/frontend/commondatabuilder/commondatabuilder.ts b/frontend/commondatabuilder/commondatabuilder.ts index b2018ae94..de1bc6e77 100644 --- a/frontend/commondatabuilder/commondatabuilder.ts +++ b/frontend/commondatabuilder/commondatabuilder.ts @@ -100,6 +100,39 @@ export function createDjangoChoicesTypescriptFiles( }); } +/** + * Return a list of TypeScript lines that create a function + * which returns a mapping from choice values to their labels. + * + * Note that this is a function rather than a constant because + * we want to be able to add code that localizes the + * labels at runtime if needed. + */ +function createLabelExporter(choices: DjangoChoices, name: string): string[] { + const lines = []; + lines.push( + `export type ${name}Labels = {`, + ` [k in ${name}]: string;`, + `};\n` + ); + lines.push( + `export function get${name}Labels(): ${name}Labels {`, + ` return {` + ); + for (let [name, label] of choices) { + lines.push(` ${name}: ${JSON.stringify(label)},`); + } + lines.push( + ' };', + '}\n' + ); + return lines; +} + +/** + * Return a list of TypeScript lines that define a type + * and some helper functions for the given Django choices. + */ export function createDjangoChoicesTypescript( choices: DjangoChoices, name: string, @@ -121,22 +154,7 @@ export function createDjangoChoicesTypescript( `}\n` ); if (exportLabels) { - lines.push( - `export type ${name}Labels = {`, - ` [k in ${name}]: string;`, - `};\n` - ); - lines.push( - `export function get${name}Labels(): ${name}Labels {`, - ` return {` - ); - for (let [name, label] of choices) { - lines.push(` ${name}: ${JSON.stringify(label)},`); - } - lines.push( - ' };', - '}\n' - ); + lines.push(...createLabelExporter(choices, name)); } return lines.join('\n'); } From 4fb9389b92b69511917e524682a6c2f74a61eadb Mon Sep 17 00:00:00 2001 From: Atul Varma Date: Tue, 5 Mar 2019 14:00:23 -0500 Subject: [PATCH 15/17] Add docs. --- README.md | 18 +++++++++++++ .../commondatabuilder/commondatabuilder.ts | 25 ++++++++++++++----- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index df533671e..8b397c990 100644 --- a/README.md +++ b/README.md @@ -114,6 +114,24 @@ For the Node front-end: other value for development. * See [frontend/webpack/webpack-defined-globals.d.ts](frontend/webpack/webpack-defined-globals.d.ts) for more values. +## Common data + +Some data that is shared between the front-end and back-end is +in the [`common-data/`](common-data/) directory. The +back-end generally reads this data in JSON format, while the +front-end reads a TypeScript file that is generated from +the JSON. + +A utility called `commondatabuilder` is used to generate the +TypeScript file. To execute it, run: + +``` +node commondatabuilder.js +``` + +You will need to run this whenever you make any changes to +the underlying JSON files. + ## GraphQL The communication between server and client occurs via [GraphQL][] diff --git a/frontend/commondatabuilder/commondatabuilder.ts b/frontend/commondatabuilder/commondatabuilder.ts index de1bc6e77..8a4052df7 100644 --- a/frontend/commondatabuilder/commondatabuilder.ts +++ b/frontend/commondatabuilder/commondatabuilder.ts @@ -3,21 +3,28 @@ import * as path from 'path'; import { DjangoChoices } from "../lib/common-data"; -type CreateOptions = { - exportLabels: boolean -}; - -const defaultOptions: CreateOptions = { exportLabels: true }; - export type DjangoChoicesTypescriptConfig = { + /** The root directory from which to read JSON files and write TS files. */ rootDir: string, + + /** The files to convert from JSON to TS. */ files: DjangoChoicesTypescriptFileConfig[] }; export type DjangoChoicesTypescriptFileConfig = { + /** The JSON file to convert to TS. */ jsonFilename: string, + + /** The name of the TS type to generate. */ typeName: string, + + /** Whether to export the labels in the JSON file to TS. */ exportLabels: boolean, + + /** + * Filter out the given values from either the given list of choices, or anything + * that matches the given regular expression. + */ filterOut?: RegExp|string[], }; @@ -129,6 +136,12 @@ function createLabelExporter(choices: DjangoChoices, name: string): string[] { return lines; } +type CreateOptions = { + exportLabels: boolean +}; + +const defaultOptions: CreateOptions = { exportLabels: true }; + /** * Return a list of TypeScript lines that define a type * and some helper functions for the given Django choices. From 5200a6e21e2502bfcd11fe8653470f5dc0c15623 Mon Sep 17 00:00:00 2001 From: Atul Varma Date: Tue, 5 Mar 2019 14:10:31 -0500 Subject: [PATCH 16/17] Add test to ensure common data is synced. --- .../commondatabuilder/commondatabuilder.ts | 18 ++++++++++++------ .../tests/commondatabuilder.test.ts | 13 ++++++++++--- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/frontend/commondatabuilder/commondatabuilder.ts b/frontend/commondatabuilder/commondatabuilder.ts index 8a4052df7..02a733131 100644 --- a/frontend/commondatabuilder/commondatabuilder.ts +++ b/frontend/commondatabuilder/commondatabuilder.ts @@ -83,11 +83,16 @@ function replaceExt(filename: string, ext: string) { return filename.substr(0, filename.lastIndexOf(".")) + ext; } +type DjangoChoiceTypescriptFile = { + tsPath: string, + ts: string +}; + export function createDjangoChoicesTypescriptFiles( config: DjangoChoicesTypescriptConfig, dryRun: boolean = false -) { - config.files.forEach(fileConfig => { +): DjangoChoiceTypescriptFile[] { + return config.files.map(fileConfig => { const infile = path.join(config.rootDir, fileConfig.jsonFilename); let choices = JSON.parse(fs.readFileSync(infile, { encoding: 'utf-8' @@ -98,12 +103,13 @@ export function createDjangoChoicesTypescriptFiles( const ts = createDjangoChoicesTypescript(choices, fileConfig.typeName, { exportLabels: fileConfig.exportLabels }); - const outfilename = replaceExt(fileConfig.jsonFilename, '.ts'); - const outfile = path.join(config.rootDir, outfilename); + const tsFilename = replaceExt(fileConfig.jsonFilename, '.ts'); + const tsPath = path.join(config.rootDir, tsFilename); if (!dryRun) { - console.log(`Writing ${outfilename}.`); - fs.writeFileSync(outfile, ts, { encoding: 'utf-8' }); + console.log(`Writing ${tsFilename}.`); + fs.writeFileSync(tsPath, ts, { encoding: 'utf-8' }); } + return { tsPath, ts }; }); } diff --git a/frontend/commondatabuilder/tests/commondatabuilder.test.ts b/frontend/commondatabuilder/tests/commondatabuilder.test.ts index ef45bd702..47162643e 100644 --- a/frontend/commondatabuilder/tests/commondatabuilder.test.ts +++ b/frontend/commondatabuilder/tests/commondatabuilder.test.ts @@ -1,5 +1,6 @@ -import { createDjangoChoicesTypescript, createDjangoChoicesTypescriptFiles, getDjangoChoiceLabel, validateDjangoChoices, filterDjangoChoices } from "../commondatabuilder"; +import * as fs from 'fs'; +import { createDjangoChoicesTypescript, createDjangoChoicesTypescriptFiles, getDjangoChoiceLabel, validateDjangoChoices, filterDjangoChoices } from "../commondatabuilder"; import ourConfig from "../../../common-data/config"; import { DjangoChoices } from "../../lib/common-data"; @@ -15,9 +16,15 @@ describe('commondatabuilder', () => { exportLabels: false })).not.toMatch(/getFooLabels/); }); +}); - it('works with our common data configuration', () => { - createDjangoChoicesTypescriptFiles(ourConfig, true); +it('current common data JSON files are synced with TS files', () => { + const files = createDjangoChoicesTypescriptFiles(ourConfig, true); + files.forEach(({ ts, tsPath }) => { + const currentTs = fs.readFileSync(tsPath, { encoding: 'utf-8' }); + if (currentTs !== ts) { + throw new Error('Common data has changed, please re-run "node commondatabuilder.js".'); + } }); }); From 292ad00a072166de0d21ca1499750a9063758406 Mon Sep 17 00:00:00 2001 From: Atul Varma Date: Tue, 5 Mar 2019 16:55:14 -0500 Subject: [PATCH 17/17] Add more docs. --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 8b397c990..f70b4a447 100644 --- a/README.md +++ b/README.md @@ -132,6 +132,10 @@ node commondatabuilder.js You will need to run this whenever you make any changes to the underlying JSON files. +If you need to add a new common data file, see +[`common-data/config.ts`](common-data/config.ts), which +defines how the conversion from JSON to TypeScript occurs. + ## GraphQL The communication between server and client occurs via [GraphQL][]