-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3 from usdigitalresponse/kevee/ts-convert
Convert to Typescript, refactor
- Loading branch information
Showing
80 changed files
with
14,167 additions
and
17,199 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
name: Test | ||
on: | ||
- push | ||
|
||
jobs: | ||
test: | ||
runs-on: ubuntu-latest | ||
|
||
steps: | ||
- uses: actions/checkout@v2 | ||
|
||
- name: Setup | ||
run: npm install | ||
|
||
- name: Test | ||
run: npm run test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
# Changelog | ||
|
||
All notable changes to this project will be documented in this file. | ||
|
||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), | ||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). | ||
|
||
## [Unreleased] | ||
|
||
## [0.0.3] - 2022-10-25 | ||
|
||
### Added | ||
|
||
- This changelog :tada: | ||
|
||
### Changed | ||
|
||
- Moved all code to Typescript | ||
- Refactored code to be more readable | ||
- Added automated testing | ||
- Added list to Airtable marketplace in the Readme | ||
|
||
### Fixed | ||
|
||
- Fixed bug where _Date & time_ generator never generated a time | ||
|
||
## [0.0.2] - 2022-10-20 | ||
|
||
### Added | ||
|
||
- Project was published to the Airtable marketplace | ||
|
||
## [0.0.1] - 2022-09-20 | ||
|
||
Initial project |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,4 @@ | ||
{ | ||
"version": "1.0", | ||
"frontendEntry": "./frontend/index.js", | ||
"frontendTestingEntry": "./test/index.js" | ||
"frontendEntry": "./frontend/index.tsx" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
import React from 'react' | ||
import { FormField, Box, colors, Text, Select } from '@airtable/blocks/ui' | ||
import { Table, Field } from '@airtable/blocks/models' | ||
import Sample from './sample' | ||
|
||
interface Props { | ||
table: Table | ||
field: Field | ||
fieldSettings: object | ||
setFieldSettings: (fieldSettings: object) => void | ||
generators: any | ||
} | ||
|
||
/** | ||
* A field select - used to select a generator for a field. | ||
* @returns | ||
*/ | ||
const FieldSelect: React.FC<Props> = ({ | ||
table, | ||
field, | ||
fieldSettings, | ||
setFieldSettings, | ||
generators, | ||
}) => { | ||
const createPermission = table.checkPermissionsForCreateRecord({ | ||
[field.id]: null, | ||
}) | ||
|
||
return ( | ||
<Box | ||
display="flex" | ||
flexWrap="wrap" | ||
flexDirection="row" | ||
key={field.id} | ||
borderBottom="thick" | ||
marginBottom={2} | ||
paddingY={2} | ||
> | ||
<Box width="50%"> | ||
{createPermission.hasPermission ? ( | ||
<FormField label={field.name}> | ||
<Select | ||
value={fieldSettings[field.id]} | ||
onChange={(newValue) => { | ||
const newSettings = { ...fieldSettings } | ||
// @ts-ignore | ||
newSettings[field.id] = newValue | ||
setFieldSettings(newSettings) | ||
}} | ||
options={[ | ||
{ label: 'None', value: false }, | ||
...generators | ||
.filter((generator) => generator.types.includes(field.type)) | ||
.map((generator) => ({ | ||
label: generator.name, | ||
value: generator.id, | ||
})), | ||
]} | ||
/> | ||
</FormField> | ||
) : ( | ||
<Text textColor={colors.RED_DARK_1}> | ||
{ | ||
// @ts-ignore | ||
createPermission.reasonDisplayString | ||
} | ||
</Text> | ||
)} | ||
</Box> | ||
<Box width="50%"> | ||
{fieldSettings[field.id] && ( | ||
<Box marginLeft={4}> | ||
<Sample generatorId={fieldSettings[field.id]} field={field} /> | ||
</Box> | ||
)} | ||
</Box> | ||
</Box> | ||
) | ||
} | ||
|
||
export default FieldSelect |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
import { Box, Button, ConfirmationDialog, useBase } from '@airtable/blocks/ui' | ||
import { Table } from '@airtable/blocks/models' | ||
import generateContent from '../../lib/generators/generate-content' | ||
import GenerateResults from '../results' | ||
import FieldSelect from './field-select' | ||
import NumberOfRecords from './number-records' | ||
import React, { useState } from 'react' | ||
|
||
interface Props { | ||
table: Table | ||
} | ||
|
||
/** | ||
* Main form component. Handles the form state and generates records. | ||
* @returns | ||
*/ | ||
const GenerateRecordForm: React.FC<Props> = ({ table }) => { | ||
const base = useBase() | ||
|
||
const [fieldSettings, setFieldSettings] = useState( | ||
Object.fromEntries(table.fields.map((field) => [field.id, false])) | ||
) | ||
const [numberOfRecords, setNumberOfRecords] = useState(100) | ||
const [isDialogOpen, setIsDialogOpen] = useState(false) | ||
const [isGenerating, setIsGenerating] = useState(false) | ||
const [generated, setGenerated] = useState(0) | ||
const [hasError, setHasError] = useState(false) | ||
|
||
const { generators } = generateContent(base) | ||
|
||
/** | ||
* Generate records callback. Creates a new generator | ||
* object then creates records, updating the status state | ||
* as each record is created. | ||
*/ | ||
const generateRecords = async () => { | ||
const batchSize = 10 | ||
const recordsToInsert = [] | ||
for (let i = 0; i < numberOfRecords; i++) { | ||
const { generate } = generateContent(base) | ||
const record = {} | ||
for (const [fieldId, generatorId] of Object.entries(fieldSettings)) { | ||
if (generatorId) { | ||
record[fieldId] = await generate({ | ||
generatorId, | ||
field: table.getFieldById(fieldId), | ||
}) | ||
} | ||
} | ||
recordsToInsert.push({ fields: record }) | ||
} | ||
let i = 0 | ||
while (i < recordsToInsert.length) { | ||
const recordBatch = recordsToInsert.slice(i, i + batchSize) | ||
await table.createRecordsAsync(recordBatch) | ||
i += recordBatch.length | ||
setGenerated(i) | ||
} | ||
} | ||
|
||
// If we are generating records, return the results component | ||
if (isGenerating) { | ||
return ( | ||
<GenerateResults | ||
generated={generated} | ||
numberOfRecords={numberOfRecords} | ||
onDone={() => { | ||
setIsGenerating(false) | ||
setGenerated(0) | ||
setFieldSettings( | ||
Object.fromEntries(table.fields.map((field) => [field.id, false])) | ||
) | ||
}} | ||
/> | ||
) | ||
} | ||
|
||
// The main form component | ||
|
||
return ( | ||
<Box marginTop={2}> | ||
{isDialogOpen && ( | ||
<ConfirmationDialog | ||
title="Are you sure?" | ||
body={ | ||
<> | ||
This will generate {numberOfRecords} records in{' '} | ||
<strong>{table.name}</strong>. | ||
</> | ||
} | ||
onConfirm={() => { | ||
setIsDialogOpen(false) | ||
setIsGenerating(true) | ||
generateRecords() | ||
}} | ||
onCancel={() => setIsDialogOpen(false)} | ||
/> | ||
)} | ||
<form> | ||
<NumberOfRecords | ||
setHasError={setHasError} | ||
numberOfRecords={numberOfRecords} | ||
setNumberOfRecords={setNumberOfRecords} | ||
/> | ||
<Box marginY={2} paddingY={2} borderTop="thick"> | ||
{table.fields.map((field) => ( | ||
<FieldSelect | ||
key={field.id} | ||
table={table} | ||
field={field} | ||
fieldSettings={fieldSettings} | ||
setFieldSettings={setFieldSettings} | ||
generators={generators} | ||
/> | ||
))} | ||
</Box> | ||
<Box> | ||
<Button | ||
variant="primary" | ||
disabled={hasError} | ||
onClick={() => { | ||
setIsDialogOpen(true) | ||
}} | ||
> | ||
Generate records | ||
</Button> | ||
</Box> | ||
</form> | ||
</Box> | ||
) | ||
} | ||
|
||
export default GenerateRecordForm |
Oops, something went wrong.