Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ replace github.com/charmbracelet/bubbletea => github.com/coder/bubbletea v1.2.2-

// Trivy has some issues that we're floating patches for, and will hopefully
// be upstreamed eventually.
replace github.com/aquasecurity/trivy => github.com/coder/trivy v0.0.0-20260309164037-c413f5a2f511
replace github.com/aquasecurity/trivy => github.com/altana-ai/trivy v0.0.0-20260825213047-3916002b18a9

// afero/tarfs has a bug that breaks our usage. A PR has been submitted upstream.
// https://github.com/spf13/afero/pull/487
Expand Down Expand Up @@ -688,3 +688,5 @@ tool (
mvdan.cc/gofumpt
storj.io/drpc/cmd/protoc-gen-go-drpc
)

replace github.com/coder/preview => github.com/altana-ai/preview v1.0.10-0.20260825221013-1efa9355e309
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,10 @@ github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc
github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA=
github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
github.com/altana-ai/preview v1.0.10-0.20260825221013-1efa9355e309 h1:tDGJCw6kgSmbjTZ/1Z+q6NqX2l/7OWBaENzkvE3+kuY=
github.com/altana-ai/preview v1.0.10-0.20260825221013-1efa9355e309/go.mod h1:njbYDy1CBMCXvvt9k4f9y8XNLviYgOJhG2BqXyp5gb8=
github.com/altana-ai/trivy v0.0.0-20260825213047-3916002b18a9 h1:b+5aD+A5OaApd+MM6jCwLb3Ul9s4zJ5jWfd6o4VcT0o=
github.com/altana-ai/trivy v0.0.0-20260825213047-3916002b18a9/go.mod h1:+zF17ZBOdhFWwD3+GkLxZ/vkmKLudoOtt+hgnc1TQpA=
github.com/ammario/tlru v0.4.0 h1:sJ80I0swN3KOX2YxC6w8FbCqpQucWdbb+J36C05FPuU=
github.com/ammario/tlru v0.4.0/go.mod h1:aYzRFu0XLo4KavE9W8Lx7tzjkX+pAApz+NgcKYIFUBQ=
github.com/andybalholm/brotli v1.2.2 h1:HzTuoo2ErYQqf5qvcJInB8uvqSVxRttzkFexPWtnceM=
Expand Down Expand Up @@ -345,8 +349,6 @@ github.com/coder/pq v1.10.5-0.20250807075151-6ad9b0a25151 h1:YAxwg3lraGNRwoQ18H7
github.com/coder/pq v1.10.5-0.20250807075151-6ad9b0a25151/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/coder/pretty v0.0.0-20230908205945-e89ba86370e0 h1:3A0ES21Ke+FxEM8CXx9n47SZOKOpgSE1bbJzlE4qPVs=
github.com/coder/pretty v0.0.0-20230908205945-e89ba86370e0/go.mod h1:5UuS2Ts+nTToAMeOjNlnHFkPahrtDkmpydBen/3wgZc=
github.com/coder/preview v1.0.10-0.20260521153517-34deb0946c4f h1:U6WdJ2l2jalMD3RcCzmlYYYB0m8mkEhmwZXoWwSHLSc=
github.com/coder/preview v1.0.10-0.20260521153517-34deb0946c4f/go.mod h1:e8KzGukwyNOCkrJv8NuY/ToG5PwcE/aN+ktKptZQ5Gw=
github.com/coder/quartz v0.3.0 h1:bUoSEJ77NBfKtUqv6CPSC0AS8dsjqAqqAv7bN02m1mg=
github.com/coder/quartz v0.3.0/go.mod h1:BgE7DOj/8NfvRgvKw0jPLDQH/2Lya2kxcTaNJ8X0rZk=
github.com/coder/retry v1.5.1 h1:iWu8YnD8YqHs3XwqrqsjoBTAVqT9ml6z9ViJ2wlMiqc=
Expand All @@ -361,8 +363,6 @@ github.com/coder/terraform-config-inspect v0.0.0-20250107175719-6d06d90c630e h1:
github.com/coder/terraform-config-inspect v0.0.0-20250107175719-6d06d90c630e/go.mod h1:Gz/z9Hbn+4KSp8A2FBtNszfLSdT2Tn/uAKGuVqqWmDI=
github.com/coder/terraform-provider-coder/v2 v2.19.0 h1:ShiwZiUZ3wyUt4+ccrdWlUKu+24aDgzMLD6Yf6xKtAw=
github.com/coder/terraform-provider-coder/v2 v2.19.0/go.mod h1:MWTw/k+oQxySR4/wZIunBxTlFva8hH6t2hLikTpyomU=
github.com/coder/trivy v0.0.0-20260309164037-c413f5a2f511 h1:wJS3Pk13VuCbV8hjrQRnOBCUwP3Islk91sMvbSdY0Vk=
github.com/coder/trivy v0.0.0-20260309164037-c413f5a2f511/go.mod h1:+zF17ZBOdhFWwD3+GkLxZ/vkmKLudoOtt+hgnc1TQpA=
github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9g=
github.com/coder/websocket v1.8.14/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg=
github.com/coder/wgtunnel v0.2.0 h1:yy9dE9ntoNdx/q98CH9uV2cQk1UEKSwPgITy3Xx+Wiw=
Expand Down
9 changes: 9 additions & 0 deletions site/src/pages/CreateWorkspacePage/CreateWorkspacePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ const CreateWorkspacePage: FC = () => {

const [latestResponse, setLatestResponse] =
useState<DynamicParametersResponse | null>(null);
// True while a dynamic-parameters request is in flight (sent but the matching
// response has not arrived). Used to block workspace creation until the form
// has been reconciled with the server, so a fast click can't submit stale
// parameter values (e.g. a branch that hasn't been applied yet).
const [parametersUpdating, setParametersUpdating] = useState(false);
// The current expected response ID. Starts at -1 because the backend sends
// an initial message when the web socket is connected with -1.
const wsResponseId = useRef<number>(-1);
Expand Down Expand Up @@ -182,6 +187,7 @@ const CreateWorkspacePage: FC = () => {
if (ws.current && ws.current.readyState === WebSocket.OPEN) {
wsResponseId.current = wsResponseId.current + 1;
ws.current.send(JSON.stringify(request));
setParametersUpdating(true);
return true;
}
if (ws.current) {
Expand Down Expand Up @@ -230,6 +236,8 @@ const CreateWorkspacePage: FC = () => {
onMessage: (response: DynamicParametersResponse) => {
if (response.id >= wsResponseId.current) {
setLatestResponse(response);
// The latest request has been reconciled; allow creation.
setParametersUpdating(false);
}
},
onError: (error) => {
Expand Down Expand Up @@ -464,6 +472,7 @@ const CreateWorkspacePage: FC = () => {
}
hasIgnoredUrlParams={hasIgnoredUrlParams}
creatingWorkspace={createWorkspaceMutation.isPending}
parametersUpdating={parametersUpdating}
sendMessage={sendMessage}
onCancel={() => {
navigate(-1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const meta: Meta<typeof CreateWorkspacePageView> = {
canUpdateTemplate: false,
},
presets: [],
parametersUpdating: false,
sendMessage: () => {},
template: MockTemplate,
},
Expand Down
14 changes: 12 additions & 2 deletions site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ interface CreateWorkspacePageViewProps {
owner: TypesGen.MinimalUser,
) => void;
resetMutation: () => void;
// True while a dynamic-parameters request is in flight; blocks submission
// until the form is reconciled with the server.
parametersUpdating: boolean;
sendMessage: (message: Record<string, string>, ownerId?: string) => void;
startPollingExternalAuth: (providerId: string) => void;
owner: TypesGen.MinimalUser;
Expand Down Expand Up @@ -115,6 +118,7 @@ export const CreateWorkspacePageView: FC<CreateWorkspacePageViewProps> = ({
onSubmit,
onCancel,
resetMutation,
parametersUpdating,
sendMessage,
startPollingExternalAuth,
owner,
Expand Down Expand Up @@ -384,6 +388,10 @@ export const CreateWorkspacePageView: FC<CreateWorkspacePageViewProps> = ({

const disabled =
creatingWorkspace ||
// Block submission while parameters are still resolving so a fast click
// can't create a workspace from unreconciled values (e.g. a branch that
// has not been applied yet).
parametersUpdating ||
!hasAllRequiredExternalAuth ||
diagnostics.some((diagnostic) => diagnostic.severity === "error") ||
parameters.some((parameter) =>
Expand Down Expand Up @@ -771,8 +779,10 @@ export const CreateWorkspacePageView: FC<CreateWorkspacePageViewProps> = ({

<div className="flex flex-row justify-end">
<Button type="submit" disabled={disabled}>
<Spinner loading={creatingWorkspace} />
Create workspace
<Spinner loading={creatingWorkspace || parametersUpdating} />
{parametersUpdating && !creatingWorkspace
? "Loading parameters..."
: "Create workspace"}
</Button>
</div>
</form>
Expand Down
Loading