-
Notifications
You must be signed in to change notification settings - Fork 0
DRAFT: Feature/ssot #134
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DRAFT: Feature/ssot #134
Conversation
…as single source of truth
…nto feature/ssot
|
|
|
||
| for (const [path, value] of Object.entries(updates)) { | ||
| lodashSet(obj, path, value); | ||
| getCurrentValue: (path) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getRecipeSettingValue
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is path a series of keys?
| }, | ||
|
|
||
| getCurrentValue: (path) => { | ||
| getOriginalValue: (path) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here, recipe setting value
src/components/Dropdown/index.tsx
Outdated
| const { placeholder, options, value, onChange } = props; | ||
| const selectOptions = Object.entries(options).map(([key, value]) => ( | ||
| { | ||
| label: <span>{key}</span>, | ||
| label: <span>{value.displayName}</span>, | ||
| value: key, | ||
| } | ||
| )); | ||
|
|
||
| return ( | ||
| <Select | ||
| defaultValue={undefined} | ||
| value={value} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm pretty sure default value is sufficient here. Try using my changes for this file other than your name change from inputs to manifest
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changing it match your version
src/components/ErrorLogs/index.tsx
Outdated
| @@ -1,19 +1,21 @@ | |||
| import { useState } from "react"; | |||
| import { Button, Drawer } from "antd"; | |||
| import { usePackingData } from "../../state/store"; | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is still too imprecise for me. is it user changes, or the recipe settings or the results?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wrote this as I was reading, now understand what it is, but that was my first impression
src/components/ErrorLogs/index.tsx
Outdated
| const { errorLogs } = props; | ||
| const ErrorLogs = (): JSX.Element => { | ||
| const [viewErrorLogs, setViewErrorLogs] = useState<boolean>(true); | ||
| const {jobStatus, jobLogs: errorLogs} = usePackingData(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
based on this I would say it's resultsMetadata?
src/components/InputSwitch/index.tsx
Outdated
| const editRecipe = useEditRecipe(); | ||
| const getCurrentValue = useGetCurrentValue(); | ||
| const recipeVersion = useCurrentRecipeString(); | ||
| const recipeVersion = useRecipes(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is a little confusing to me. I expect the recipeVersion to be a field in the recipe. and useRecipes() to give you every available recipe
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is just a holdover naming wise, recipes useRecipes does return all available recipes. I'll rename the local variable.
src/components/JSONViewer/index.tsx
Outdated
|
|
||
| const JSONViewer = (props: JSONViewerProps): JSX.Element | null => { | ||
| const { content } = props; | ||
| const currentRecipe = recipes[selectedRecipeId]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should be a selector in state the returns the recipe data. This component should just get the recipe obj either as a prop or as a useCurrentRecipeData hook
src/state/constants.ts
Outdated
|
|
||
| // stable/frozen empty array to prevent re-renders | ||
| export const EMPTY_FIELDS: readonly EditableField[] = Object.freeze([]); | ||
| export const EMPTY_PACKING_DATA: PackingManifest = Object.freeze({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at this again, I would call this packingStatusData, resultsMetaData, resultsStatus etc. just to make it clear this is AFTER you've hit pack and not having to do with inputs to a packing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or responseMetadata
src/state/store.ts
Outdated
| loadAllRecipes: () => void; | ||
| selectRecipe: (recipeId: string) => Promise<void>; | ||
| editRecipe: (recipeId: string, updates: Record<string, string | number>) => void; | ||
| restoreRecipeDefault: (recipeId: string) => void; | ||
| getCurrentValue: (path: string) => string | number | undefined; | ||
| getOriginalValue: (path: string) => string | number | undefined; | ||
| startPacking: ( | ||
| callback: (recipeId: string, configId: string, recipeString: string) => Promise<void> | ||
| ) => Promise<void>; | ||
| startPacking: () => Promise<void>; | ||
| reset: () => void; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this set looks really clear to me now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(other than the ones we commented on together )
| isLoading: false, | ||
| isPacking: false, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
note of what we talked about: can this be one called requestStatus that's an enum of LOADING, PACKING or NONE
| const recipes = await getRecipesFromFirebase(); | ||
| set({ recipes }); | ||
| // make an intial selection | ||
| const firstId = Object.keys(recipes)[0]; | ||
| set(s => (!s.selectedRecipeId && firstId ? { selectedRecipeId: firstId } : {})); | ||
| } finally { | ||
| set({ isLoading: false }); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
note to use my changes here in the merge
| Object.values(inputOptions).forEach(opt => { if (opt?.recipe) ids.add(opt.recipe); }); | ||
| const missing = [...ids].filter(id => !recipes[id]); | ||
| if (!missing.length) return; | ||
| const newEdits = { ...rec.edits }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wouldn't these been the currentEdits?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i'm surprised this isn't just one field at a time. how is a user able to send in multiple edits at once to state?
src/state/store.ts
Outdated
| try { | ||
| await callback(s.selectedRecipeId, configId, recipeString); | ||
| const { response, data } = await submitJob(selectedRecipeId, recipeString, rec.configId); | ||
| set((state) => ({ packingData: { ...state.packingData, jobStatus: JOB_STATUS.SUBMITTED } })); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldnt state.packingData always be empty at this point?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also, you don't have a storeResults action which means this functionality is a little hidden
| const finalStatus = await pollForJobStatus(newJobId, (next) => | ||
| set(state => ({ packingData: { ...state.packingData, jobStatus: next } })) | ||
| ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this pattern makes me feel like jobStatus should be a top level piece of state so you dont have to keep re-writing the rest of this object. but conceptually i see why you grouped them together
| return undefined; | ||
| } | ||
| }, | ||
| reset: () => set(() => ({ ...initialState })), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍🏻
| import { RecipeManifest } from "../types"; | ||
| import { set } from "lodash-es"; | ||
|
|
||
| /** | ||
| * Build a recipe from a default and a set of edits. | ||
| */ | ||
| export const buildCurrentRecipeObject = (recipe: RecipeManifest) => { | ||
| const clone = structuredClone(recipe.defaultRecipeData); | ||
| for (const [path, value] of Object.entries(recipe.edits)) { | ||
| set(clone, path, value); | ||
| } | ||
| return clone; | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why isn't this just in the selectors list?
| export interface RecipeManifest { | ||
| recipeId: string; | ||
| configId: string; | ||
| displayName: string; | ||
| editableFields: EditableField[]; | ||
| defaultRecipeData: ViewableRecipe; | ||
| edits: Record<string, string | number>; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i like this
| } | ||
|
|
||
| export const recipeHasChanged = async (recipeId: string, recipeString: string): Promise<boolean> => { | ||
| const originalRecipe = await getFirebaseRecipe(recipeId); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn't this be in state?
| recipeString: string, | ||
| configId?: string | ||
| ) => { | ||
| let firebaseRecipe = "firebase:recipes/" + selectedRecipeId; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: firebaseRecipePath
meganrm
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great! I suggested a lot of name changes and a few places to move things around
| const querySnapshot = await queryDocumentById(FIRESTORE_COLLECTIONS.RESULTS, jobId); | ||
| return extractSingleDocumentData(querySnapshot, FIRESTORE_FIELDS.URL); | ||
| }; | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this url comes with the status ( on line 114), why do you need to separate it out here?
| })); | ||
| } | ||
| } finally { | ||
| set({ isPacking: false }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
instead of combining this with isLoading like I suggested before, I think this should become packingStatus, and it should be the JOB_STATUS or IDLE
| // Derived selectors | ||
| export const useEditableFields = () => | ||
| useRecipeStore(s => { | ||
| const id = s.selectedRecipeId; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you should use a selector to get other simple parts of state in a compound selector
Recipe strings are gone: recipe objects are in.
Local state and packing functionality lifted out of
App->packingServiceandstoreLot's of props removed in favor of calling store hooks in many components.
A number of components check for their own data and return null rather than handling conditional rendering in parent.
Tests added for
storeandpackingServiceDropdown:
defaultValueremoved,valueprovided by prop.Changed
updatedRecipeStringandupdateRecipObj->editRecipeNo storing original and default recipes in state: store default and updates, build the "current" on the fly.
Packing logic moved into store version of
startPackingto get rid of call back pattern.Firebase util
getPackingInputsDictrefactored asgetRecipesFromFirebase, returnsRecipeManifestdata shape.PackingDataput inRecipeStateRedundancy of
recipesandinputOptionscollapsed and consolidated.PackingInputstype removed,RecipeManifestandPackingManifestadded... naming?Feedback I want:
naming good?
state branches?
too much in state? just right?
Could this be broken up?
Yes but its extra work to make stepping stone PRs that use the wrong or non-final shape of the store.
Changes to dropdown/value could be pulled out.
Problem
Closes #97 Closes #101
Solution
What I/we did to solve this problem
with @pairperson1
Type of change
Please delete options that are not relevant.
Change summary:
Steps to Verify:
Screenshots (optional):
Show-n-tell images/animations here
Keyfiles (delete if not relevant):
Thanks for contributing!