Skip to content

Commit 054a220

Browse files
committed
feat: create dynamic parameter component
1 parent 6a6e1ec commit 054a220

File tree

8 files changed

+832
-91
lines changed

8 files changed

+832
-91
lines changed

site/src/api/typesParameter.ts

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
// Code generated by 'guts'. DO NOT EDIT.
2+
3+
// From types/diagnostics.go
4+
export type DiagnosticSeverityString = "error" | "warning";
5+
6+
export const DiagnosticSeverityStrings: DiagnosticSeverityString[] = [
7+
"error",
8+
"warning",
9+
];
10+
11+
// From types/diagnostics.go
12+
export type Diagnostics = readonly FriendlyDiagnostic[];
13+
14+
// From types/diagnostics.go
15+
export interface FriendlyDiagnostic {
16+
readonly severity: DiagnosticSeverityString;
17+
readonly summary: string;
18+
readonly detail: string;
19+
}
20+
21+
// From types/value.go
22+
export interface NullHCLString {
23+
readonly value: string;
24+
readonly valid: boolean;
25+
}
26+
27+
// From types/parameter.go
28+
export interface Parameter extends ParameterData {
29+
readonly value: NullHCLString;
30+
readonly diagnostics: Diagnostics;
31+
}
32+
33+
// From types/parameter.go
34+
export interface ParameterData {
35+
readonly name: string;
36+
readonly display_name: string;
37+
readonly description: string;
38+
readonly type: ParameterType;
39+
// this is likely an enum in an external package "github.com/coder/terraform-provider-coder/v2/provider.ParameterFormType"
40+
readonly form_type: string;
41+
// empty interface{} type, falling back to unknown
42+
readonly styling: unknown;
43+
readonly mutable: boolean;
44+
readonly default_value: NullHCLString;
45+
readonly icon: string;
46+
readonly options: readonly ParameterOption[];
47+
readonly validations: readonly ParameterValidation[];
48+
readonly required: boolean;
49+
readonly order: number;
50+
readonly ephemeral: boolean;
51+
}
52+
53+
// From types/parameter.go
54+
export interface ParameterOption {
55+
readonly name: string;
56+
readonly description: string;
57+
readonly value: NullHCLString;
58+
readonly icon: string;
59+
}
60+
61+
// From types/enum.go
62+
export type ParameterType = "bool" | "list(string)" | "number" | "string";
63+
64+
export const ParameterTypes: ParameterType[] = [
65+
"bool",
66+
"list(string)",
67+
"number",
68+
"string",
69+
];
70+
71+
// From types/parameter.go
72+
export interface ParameterValidation {
73+
readonly validation_error: string;
74+
readonly validation_regex: string | null;
75+
readonly validation_min: number | null;
76+
readonly validation_max: number | null;
77+
readonly validation_monotonic: string | null;
78+
readonly validation_invalid: boolean | null;
79+
}
80+
81+
// From web/session.go
82+
export interface Request {
83+
readonly id: number;
84+
readonly inputs: Record<string, string>;
85+
}
86+
87+
// From web/session.go
88+
export interface Response {
89+
readonly id: number;
90+
readonly diagnostics: Diagnostics;
91+
readonly parameters: readonly Parameter[];
92+
}
93+
94+
// From web/session.go
95+
export interface SessionInputs {
96+
readonly PlanPath: string;
97+
readonly User: WorkspaceOwner;
98+
}
99+
100+
// From types/parameter.go
101+
export const ValidationMonotonicDecreasing = "decreasing";
102+
103+
// From types/parameter.go
104+
export const ValidationMonotonicIncreasing = "increasing";
105+
106+
// From types/owner.go
107+
export interface WorkspaceOwner {
108+
readonly id: string;
109+
readonly name: string;
110+
readonly full_name: string;
111+
readonly email: string;
112+
readonly ssh_public_key: string;
113+
readonly groups: readonly string[];
114+
readonly session_token: string;
115+
readonly oidc_access_token: string;
116+
readonly login_type: string;
117+
readonly rbac_roles: readonly WorkspaceOwnerRBACRole[];
118+
}
119+
120+
// From types/owner.go
121+
export interface WorkspaceOwnerRBACRole {
122+
readonly name: string;
123+
readonly org_id: string;
124+
}

site/src/components/Checkbox/Checkbox.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ import * as React from "react";
88

99
import { cn } from "utils/cn";
1010

11+
/**
12+
* To allow for an indeterminate state the checkbox must be controlled, otherwise the checked prop would remain undefined
13+
*/
1114
export const Checkbox = React.forwardRef<
1215
React.ElementRef<typeof CheckboxPrimitive.Root>,
1316
React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>

site/src/components/MultiSelectCombobox/MultiSelectCombobox.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,9 +203,18 @@ export const MultiSelectCombobox = forwardRef<
203203
const [open, setOpen] = useState(false);
204204
const [onScrollbar, setOnScrollbar] = useState(false);
205205
const [isLoading, setIsLoading] = useState(false);
206-
const dropdownRef = useRef<HTMLDivElement>(null); // Added this
206+
const dropdownRef = useRef<HTMLDivElement>(null);
207207

208-
const [selected, setSelected] = useState<Option[]>(value || []);
208+
const getInitialSelectedOptions = () => {
209+
if (arrayDefaultOptions && arrayDefaultOptions.length > 0) {
210+
return arrayDefaultOptions;
211+
}
212+
return [];
213+
};
214+
215+
const [selected, setSelected] = useState<Option[]>(
216+
getInitialSelectedOptions,
217+
);
209218
const [options, setOptions] = useState<GroupOption>(
210219
transitionToGroupOption(arrayDefaultOptions, groupBy),
211220
);

site/src/components/RadioGroup/RadioGroup.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export const RadioGroupItem = React.forwardRef<
3434
focus:outline-none focus-visible:ring-2 focus-visible:ring-content-link
3535
focus-visible:ring-offset-4 focus-visible:ring-offset-surface-primary
3636
disabled:cursor-not-allowed disabled:opacity-25 disabled:border-surface-invert-primary
37-
hover:border-border-hover`,
37+
hover:border-border-hover data-[state=checked]:border-border-hover`,
3838
className,
3939
)}
4040
{...props}

site/src/hooks/useWebsocket.ts

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
// This file is temporary until we have a proper websocket implementation for dynamic parameters
2+
import { useCallback, useEffect, useRef, useState } from "react";
3+
4+
export function useWebSocket<T>(
5+
url: string,
6+
testdata: string,
7+
user: string,
8+
plan: string,
9+
) {
10+
const [message, setMessage] = useState<T | null>(null);
11+
const [connectionStatus, setConnectionStatus] = useState<
12+
"connecting" | "connected" | "disconnected"
13+
>("connecting");
14+
const wsRef = useRef<WebSocket | null>(null);
15+
const urlRef = useRef(url);
16+
17+
const connectWebSocket = useCallback(() => {
18+
try {
19+
const ws = new WebSocket(urlRef.current);
20+
wsRef.current = ws;
21+
setConnectionStatus("connecting");
22+
23+
ws.onopen = () => {
24+
// console.log("Connected to WebSocket");
25+
setConnectionStatus("connected");
26+
ws.send(JSON.stringify({}));
27+
};
28+
29+
ws.onmessage = (event) => {
30+
try {
31+
const data: T = JSON.parse(event.data);
32+
// console.log("Received message:", data);
33+
setMessage(data);
34+
} catch (err) {
35+
console.error("Invalid JSON from server: ", event.data);
36+
console.error("Error: ", err);
37+
}
38+
};
39+
40+
ws.onerror = (event) => {
41+
console.error("WebSocket error:", event);
42+
};
43+
44+
ws.onclose = (event) => {
45+
// console.log(
46+
// `WebSocket closed with code ${event.code}. Reason: ${event.reason}`,
47+
// );
48+
setConnectionStatus("disconnected");
49+
};
50+
} catch (error) {
51+
console.error("Failed to create WebSocket connection:", error);
52+
setConnectionStatus("disconnected");
53+
}
54+
}, []);
55+
56+
useEffect(() => {
57+
if (!testdata) {
58+
return;
59+
}
60+
61+
setMessage(null);
62+
setConnectionStatus("connecting");
63+
64+
const createConnection = () => {
65+
urlRef.current = url;
66+
connectWebSocket();
67+
};
68+
69+
if (wsRef.current) {
70+
wsRef.current.close();
71+
wsRef.current = null;
72+
}
73+
74+
const timeoutId = setTimeout(createConnection, 100);
75+
76+
return () => {
77+
clearTimeout(timeoutId);
78+
if (wsRef.current) {
79+
wsRef.current.close();
80+
wsRef.current = null;
81+
}
82+
};
83+
}, [testdata, connectWebSocket, url]);
84+
85+
const sendMessage = (data: unknown) => {
86+
if (wsRef.current && wsRef.current.readyState === WebSocket.OPEN) {
87+
wsRef.current.send(JSON.stringify(data));
88+
} else {
89+
console.warn("Cannot send message: WebSocket is not connected");
90+
}
91+
};
92+
93+
return { message, sendMessage, connectionStatus };
94+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy