Skip to content

Conversation

@olgenn
Copy link
Collaborator

@olgenn olgenn commented Jan 14, 2026

Close https://github.com/dstackai/dstack-cloud/issues/373


Note

Implements optional default fleet creation during project setup and introduces a reusable, global confirmation dialog mechanism.

  • Adds Fleets step in the project wizard with FormToggle, fields for fleet_name, fleet_min_instances, fleet_max_instances, and fleet_idle_duration, Yup validation, help panel links, and a confirmation when min instances > 0; on submit, calls applyFleet
  • Extends API and services: new POST project/{name}/fleets/apply (API.PROJECTS.FLEETS_APPLY), useApplyFleetMutation, and supporting fleet types
  • Introduces Redux-based confirmation dialogs: components/ConfirmationDialog/slice, useConfirmationDialog hook, and renders queued dialogs in AppLayout; updates ButtonWithConfirmation and user pages to use standardized dialog content/labels
  • Adds FormToggle component and exports; updates i18n strings for common and project wizard labels; minor UI label tweaks (e.g., "Create" button in projects list)

Written by Cursor Bugbot for commit 3c3ae8c. This will update automatically on new commits. Configure here.

@olgenn olgenn requested a review from peterschmidt85 January 14, 2026 21:45
@olgenn olgenn self-assigned this Jan 14, 2026
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is being reviewed by Cursor Bugbot

Details

You are on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

onDiscard: () => onDiscard(uuid),
}),
);
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmation dialog doesn't close after user confirms

High Severity

The useConfirmationDialog hook wraps onDiscard to close the dialog but doesn't wrap onConfirm. When the user clicks confirm, the original onConfirm callback runs but the dialog remains visible because close(uuid) is never dispatched. The dialog will stay open until the user clicks Cancel or dismisses it manually.

Fix in Cursor Fix in Web

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

onConfirm was implemented in ConfirmationDialof componentd

}
};

const getDefaultFleetSummary = () => {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wizard submit triggered prematurely on Fleets step

Medium Severity

The onSubmit function checks activeStepIndex < 2 but the wizard now has 4 steps (indices 0-3). When on the Fleets step (index 2), pressing Enter triggers onSubmitWizard instead of navigating to Summary. The condition needs to be activeStepIndex < 3 to account for the new step.

Fix in Cursor Fix in Web

return value >= fleet_min_instances;
}),
}),
fleet_idle_duration: yup.string().matches(/^[1-9]\d*[smhdw]$/, 'Invalid duration'),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Idle duration validation rejects documented "0s" value

Medium Severity

The fleet_idle_duration validation regex /^[1-9]\d*[smhdw]$/ requires the first digit to be 1-9, but the description in en.json explicitly lists "0s" as a valid example. Users trying to enter "0s" (immediate termination) will get an "Invalid duration" error despite it being documented as valid.

Fix in Cursor Fix in Web

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"0s" is invalid value, so we used this regular expression

summaryFields.forEach((fieldName) => {
if (formValues[fieldName]) {
result.push(`${t(`projects.edit.${fieldName}`)}: ${formValues[fieldName]}`);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary excludes fleet min instances when zero

Low Severity

The getDefaultFleetSummary function uses if (formValues[fieldName]) which is a truthy check. Since fleet_min_instances defaults to 0 and 0 is falsy, the min instances field won't appear in the summary despite being a valid and common configuration value.

Fix in Cursor Fix in Web

return value >= fleet_min_instances;
}),
}),
fleet_idle_duration: yup.string().matches(/^[1-9]\d*[smhdw]$/, 'Invalid duration'),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Idle duration validation runs when fleet is disabled

Medium Severity

The fleet_idle_duration validation uses unconditional .matches() unlike fleet_min_instances and fleet_max_instances which wrap their validation in .when('enable_default_fleet', { is: true, then: ... }). If a user enters an invalid duration value, then disables the fleet toggle, validation still fails on the hidden field, blocking the wizard with no visible error message.

Fix in Cursor Fix in Web

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants