Skip to content

Commit b9eda6a

Browse files
committed
fix(app): deduplicate create flow source
1 parent 1b2776a commit b9eda6a

1 file changed

Lines changed: 124 additions & 128 deletions

File tree

packages/app/src/docker-git/menu-create-shared.ts

Lines changed: 124 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ export const renderCreateStepLabel = (step: CreateStep, defaults: CreateInputs):
132132

133133
const renderExplicitBooleanChoice = (value: boolean): string => value ? "Y" : "N"
134134

135-
const parseExplicitBooleanChoice = (input: string): boolean | null => {
135+
const parseBooleanChoice = (input: string): boolean | null => {
136136
const normalized = input.trim().toLowerCase()
137137
if (normalized === "y" || normalized === "yes") {
138138
return true
@@ -143,6 +143,8 @@ const parseExplicitBooleanChoice = (input: string): boolean | null => {
143143
return null
144144
}
145145

146+
const parseExplicitBooleanChoice = parseBooleanChoice
147+
146148
const parseExplicitGpuChoice = (
147149
input: string
148150
): GpuMode | null => {
@@ -267,16 +269,7 @@ const parseGpuInput = (
267269
return Either.left(createParseError("gpu must be one of: none, all, yes, no"))
268270
}
269271

270-
const parseYesDefault = (input: string, fallback: boolean): boolean => {
271-
const normalized = input.trim().toLowerCase()
272-
if (normalized === "y" || normalized === "yes") {
273-
return true
274-
}
275-
if (normalized === "n" || normalized === "no") {
276-
return false
277-
}
278-
return fallback
279-
}
272+
const parseYesDefault = (input: string, fallback: boolean): boolean => parseBooleanChoice(input) ?? fallback
280273

281274
const createParseError = (reason: string): ParseError => ({
282275
_tag: "InvalidOption",
@@ -565,6 +558,24 @@ const applyCreateStep = (input: {
565558
Match.exhaustive
566559
)
567560

561+
const applyCreateBufferToValues = (
562+
context: CreateFlowContext,
563+
view: CreateFlowView,
564+
step: CreateStep
565+
): Either.Either<Partial<Mutable<CreateInputs>>, ParseError> => {
566+
const buffer = view.buffer.trim()
567+
const currentDefaults = resolveCreateInputs(context, view.values)
568+
const nextValues: Partial<Mutable<CreateInputs>> = { ...view.values }
569+
const updated = applyCreateStep({
570+
step,
571+
buffer,
572+
currentDefaults,
573+
nextValues,
574+
context
575+
})
576+
return Either.isLeft(updated) ? Either.left(updated.left) : Either.right(nextValues)
577+
}
578+
568579
export const createInitialFlowView = (buffer = ""): CreateFlowView => ({
569580
step: 0,
570581
buffer,
@@ -608,6 +619,27 @@ const nextCreateSettingsStep = (
608619
Match.exhaustive
609620
)
610621

622+
const moveCreateSettingsWithin = (
623+
view: CreateFlowView,
624+
lastStep: number,
625+
direction: CreateSettingsNavigationDirection
626+
): CreateFlowView | null => {
627+
if (view.step < firstCreateSettingsStepIndex || lastStep < firstCreateSettingsStepIndex) {
628+
return null
629+
}
630+
631+
const currentStep = clampCreateSettingsStep(view.step, lastStep)
632+
const step = nextCreateSettingsStep(currentStep, lastStep, direction)
633+
return step === view.step
634+
? view
635+
: {
636+
...view,
637+
step,
638+
buffer: "",
639+
inputError: null
640+
}
641+
}
642+
611643
const booleanChoiceBuffer = (direction: CreateSettingsChoiceDirection): string =>
612644
Match.value(direction).pipe(
613645
Match.when("left", () => "n"),
@@ -671,25 +703,7 @@ export const resolveCreateSettingsChoiceBuffer = (
671703
export const moveCreateSettingsStep = (
672704
view: CreateFlowView,
673705
direction: CreateSettingsNavigationDirection
674-
): CreateFlowView | null => {
675-
const steps = resolveCreateFlowSteps(view.values)
676-
const lastStep = steps.length - 1
677-
if (view.step < firstCreateSettingsStepIndex || lastStep < firstCreateSettingsStepIndex) {
678-
return null
679-
}
680-
681-
const currentStep = clampCreateSettingsStep(view.step, lastStep)
682-
const step = nextCreateSettingsStep(currentStep, lastStep, direction)
683-
if (step === view.step) {
684-
return view
685-
}
686-
return {
687-
...view,
688-
step,
689-
buffer: "",
690-
inputError: null
691-
}
692-
}
706+
): CreateFlowView | null => moveCreateSettingsWithin(view, resolveCreateFlowSteps(view.values).length - 1, direction)
693707

694708
/**
695709
* Moves the selected browser Create settings row over the full display list.
@@ -706,24 +720,57 @@ export const moveCreateSettingsStep = (
706720
export const moveCreateDisplaySettingsStep = (
707721
view: CreateFlowView,
708722
direction: CreateSettingsNavigationDirection
709-
): CreateFlowView | null => {
710-
const steps = resolveCreateDisplaySteps()
711-
const lastStep = steps.length - 1
712-
if (view.step < firstCreateSettingsStepIndex || lastStep < firstCreateSettingsStepIndex) {
713-
return null
714-
}
723+
): CreateFlowView | null => moveCreateSettingsWithin(view, resolveCreateDisplaySteps().length - 1, direction)
715724

716-
const currentStep = clampCreateSettingsStep(view.step, lastStep)
717-
const step = nextCreateSettingsStep(currentStep, lastStep, direction)
718-
if (step === view.step) {
719-
return view
720-
}
721-
return {
722-
...view,
723-
step,
724-
buffer: "",
725-
inputError: null
726-
}
725+
const resolveActiveCreateDisplayStep = (view: CreateFlowView): CreateStep | null => {
726+
const step = resolveCreateDisplaySteps()[view.step]
727+
return view.step < firstCreateSettingsStepIndex || step === undefined ? null : step
728+
}
729+
730+
type ActiveCreateDisplayContext = {
731+
readonly context: CreateFlowContext
732+
readonly step: CreateStep
733+
}
734+
735+
const resolveActiveCreateDisplayContext = (
736+
contextOrCwd: string | CreateFlowContext,
737+
view: CreateFlowView
738+
): ActiveCreateDisplayContext | null => {
739+
const step = resolveActiveCreateDisplayStep(view)
740+
return step === null
741+
? null
742+
: {
743+
context: normalizeCreateFlowContext(contextOrCwd),
744+
step
745+
}
746+
}
747+
748+
const completeCreateFlow = (
749+
context: CreateFlowContext,
750+
values: Partial<CreateInputs>
751+
): AdvanceCreateFlowResult => ({
752+
_tag: "Complete",
753+
inputs: resolveCreateInputs(context, values)
754+
})
755+
756+
const foldAppliedCreateValues = (
757+
appliedValues: Either.Either<Partial<Mutable<CreateInputs>>, ParseError>,
758+
onSuccess: (nextValues: Partial<Mutable<CreateInputs>>) => AdvanceCreateFlowResult
759+
): AdvanceCreateFlowResult =>
760+
Either.isLeft(appliedValues)
761+
? {
762+
_tag: "Error",
763+
error: appliedValues.left
764+
}
765+
: onSuccess(appliedValues.right)
766+
767+
const withActiveCreateDisplayContext = (
768+
contextOrCwd: string | CreateFlowContext,
769+
view: CreateFlowView,
770+
onActive: (active: ActiveCreateDisplayContext) => AdvanceCreateFlowResult | null
771+
): AdvanceCreateFlowResult | null => {
772+
const active = resolveActiveCreateDisplayContext(contextOrCwd, view)
773+
return active === null ? null : onActive(active)
727774
}
728775

729776
/**
@@ -740,32 +787,12 @@ export const moveCreateDisplaySettingsStep = (
740787
export const applyCreateDisplaySettingsStep = (
741788
contextOrCwd: string | CreateFlowContext,
742789
view: CreateFlowView
743-
): AdvanceCreateFlowResult | null => {
744-
const step = resolveCreateDisplaySteps()[view.step]
745-
if (view.step < firstCreateSettingsStepIndex || step === undefined) {
746-
return null
747-
}
748-
749-
const context = normalizeCreateFlowContext(contextOrCwd)
750-
const buffer = view.buffer.trim()
751-
const currentDefaults = resolveCreateInputs(context, view.values)
752-
const nextValues: Partial<Mutable<CreateInputs>> = { ...view.values }
753-
const updated = applyCreateStep({
754-
step,
755-
buffer,
756-
currentDefaults,
757-
nextValues,
758-
context
759-
})
760-
if (Either.isLeft(updated)) {
761-
return {
762-
_tag: "Error",
763-
error: updated.left
764-
}
765-
}
766-
767-
return continueCreateFlow(view.step, nextValues)
768-
}
790+
): AdvanceCreateFlowResult | null =>
791+
withActiveCreateDisplayContext(contextOrCwd, view, (active) =>
792+
foldAppliedCreateValues(
793+
applyCreateBufferToValues(active.context, view, active.step),
794+
(nextValues) => continueCreateFlow(view.step, nextValues)
795+
))
769796

770797
/**
771798
* Completes browser Create settings by applying a non-empty active buffer first.
@@ -781,32 +808,21 @@ export const applyCreateDisplaySettingsStep = (
781808
export const completeCreateDisplaySettingsFlow = (
782809
contextOrCwd: string | CreateFlowContext,
783810
view: CreateFlowView
784-
): AdvanceCreateFlowResult | null => {
785-
const step = resolveCreateDisplaySteps()[view.step]
786-
if (view.step < firstCreateSettingsStepIndex || step === undefined) {
787-
return null
788-
}
789-
790-
const context = normalizeCreateFlowContext(contextOrCwd)
791-
if (view.buffer.trim().length === 0) {
792-
return {
793-
_tag: "Complete",
794-
inputs: resolveCreateInputs(context, view.values)
811+
): AdvanceCreateFlowResult | null =>
812+
withActiveCreateDisplayContext(contextOrCwd, view, (active) => {
813+
if (view.buffer.trim().length === 0) {
814+
return completeCreateFlow(active.context, view.values)
795815
}
796-
}
797816

798-
const applied = applyCreateDisplaySettingsStep(context, view)
799-
if (applied === null || applied._tag === "Error") {
800-
return applied
801-
}
802-
if (applied._tag === "Continue") {
803-
return {
804-
_tag: "Complete",
805-
inputs: resolveCreateInputs(context, applied.view.values)
817+
const applied = applyCreateDisplaySettingsStep(active.context, view)
818+
if (applied === null || applied._tag === "Error") {
819+
return applied
806820
}
807-
}
808-
return applied
809-
}
821+
if (applied._tag === "Continue") {
822+
return completeCreateFlow(active.context, applied.view.values)
823+
}
824+
return applied
825+
})
810826

811827
const resolveNextCreateFlowStep = (
812828
currentStep: CreateStep,
@@ -829,40 +845,20 @@ export const advanceCreateFlow = (
829845
return null
830846
}
831847

832-
const buffer = view.buffer.trim()
833-
const currentDefaults = resolveCreateInputs(context, view.values)
834-
const nextValues: Partial<Mutable<CreateInputs>> = { ...view.values }
835-
const updated = applyCreateStep({
836-
step,
837-
buffer,
838-
currentDefaults,
839-
nextValues,
840-
context
841-
})
842-
if (Either.isLeft(updated)) {
843-
return {
844-
_tag: "Error",
845-
error: updated.left
846-
}
847-
}
848+
return foldAppliedCreateValues(
849+
applyCreateBufferToValues(context, view, step),
850+
(nextValues) => {
851+
if (shouldQuickCreate(step, options)) {
852+
return completeCreateFlow(context, nextValues)
853+
}
848854

849-
if (shouldQuickCreate(step, options)) {
850-
return {
851-
_tag: "Complete",
852-
inputs: resolveCreateInputs(context, nextValues)
855+
const nextSteps = resolveCreateFlowSteps(nextValues)
856+
const nextStep = resolveNextCreateFlowStep(step, view.step, nextSteps)
857+
return nextSteps.length > firstCreateSettingsStepIndex && nextStep < nextSteps.length
858+
? continueCreateFlow(nextStep, nextValues)
859+
: completeCreateFlow(context, nextValues)
853860
}
854-
}
855-
856-
const nextSteps = resolveCreateFlowSteps(nextValues)
857-
const nextStep = resolveNextCreateFlowStep(step, view.step, nextSteps)
858-
if (nextSteps.length > firstCreateSettingsStepIndex && nextStep < nextSteps.length) {
859-
return continueCreateFlow(nextStep, nextValues)
860-
}
861-
862-
return {
863-
_tag: "Complete",
864-
inputs: resolveCreateInputs(context, nextValues)
865-
}
861+
)
866862
}
867863

868864
export const handleAdvanceCreateFlowResult = (

0 commit comments

Comments
 (0)