diff --git a/src/web/src/__tests__/api/workspaceApi.test.tsx b/src/web/src/__tests__/api/workspaceApi.test.tsx
index 7a29547e..0d7058ca 100644
--- a/src/web/src/__tests__/api/workspaceApi.test.tsx
+++ b/src/web/src/__tests__/api/workspaceApi.test.tsx
@@ -97,9 +97,12 @@ describe("Workspace API", () => {
expect(result).toEqual({
name: "test-workspace-1",
- plane: "azure-cli",
+ plane: "data-planetest-workspace-1",
+ resourceProvider: "test-workspace-1",
folder: "/workspaces/test-workspace-1",
- commandTree: {},
+ commandTree: {
+ names: ["aaz"],
+ },
});
});
});
diff --git a/src/web/src/__tests__/components/WSEditorClientConfig.test.tsx b/src/web/src/__tests__/components/WSEditorClientConfig.test.tsx
index 17ddd7db..5a9134be 100644
--- a/src/web/src/__tests__/components/WSEditorClientConfig.test.tsx
+++ b/src/web/src/__tests__/components/WSEditorClientConfig.test.tsx
@@ -54,6 +54,7 @@ describe("WSEditorClientConfigDialog", () => {
beforeEach(() => {
vi.clearAllMocks();
(specsApi.getPlanes as any).mockResolvedValue(mockPlanes);
+ (specsApi.getSwaggerModules as any).mockResolvedValue(["storage", "compute"]);
(specsApi.getResourceProviders as any).mockResolvedValue(mockResourceProviders);
(specsApi.getProviderResources as any).mockResolvedValue(mockProviderResources);
(errorHandlerApi.getErrorMessage as any).mockReturnValue("Mock error message");
@@ -255,7 +256,7 @@ describe("WSEditorClientConfigDialog", () => {
await user.click(updateButton);
await waitFor(() => {
- expect(screen.getByText("Plane is required.")).toBeInTheDocument();
+ expect(screen.getByText("Module is required.")).toBeInTheDocument();
});
});
});
diff --git a/src/web/src/__tests__/integration/WSEditorClientConfig.integration.test.tsx b/src/web/src/__tests__/integration/WSEditorClientConfig.integration.test.tsx
index ace84e2d..010c3201 100644
--- a/src/web/src/__tests__/integration/WSEditorClientConfig.integration.test.tsx
+++ b/src/web/src/__tests__/integration/WSEditorClientConfig.integration.test.tsx
@@ -2,7 +2,6 @@ import { describe, it, expect, vi, beforeEach, beforeAll, afterEach, afterAll }
import { screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { setupServer } from "msw/node";
-import { http, HttpResponse } from "msw";
import { render } from "../test-utils";
import WSEditorClientConfigDialog from "../../views/workspace/components/WSEditor/WSEditorClientConfig";
@@ -71,44 +70,6 @@ describe("WSEditorClientConfigDialog - Integration", () => {
expect(screen.queryByText("Cancel")).not.toBeInTheDocument();
});
- it.skip("should cascade load planes → modules → providers → versions", async () => {
- // @NOTE: skipping this workflow for now, there is servere delay in loading, will revisit once loading states are improved.
- render();
-
- // Switch to the resource property tab
- const resourcePropertyTab = screen.getByRole("tab", { name: /By resource property/i });
- await userEvent.click(resourcePropertyTab);
-
- // --- MODULES ---
- const moduleInput = screen.getByRole("combobox", { name: /Module/i });
- await userEvent.click(moduleInput);
-
- // Wait for the popper to render an option (it will display "storage", not "Microsoft.Storage")
- const storageOption = await screen.findByRole("option", { name: /storage/i });
- await userEvent.click(storageOption);
-
- // --- PROVIDERS ---
- const providerInput = screen.getByRole("combobox", { name: /Resource Provider/i });
- await userEvent.click(providerInput);
-
- // Providers are stripped of common prefix, so if API returned ["Microsoft.Storage"],
- // and `commonPrefix = "Microsoft."`, you’ll actually see "Storage" in the DOM
- const rpOption = await screen.findByRole("option", { name: /Storage/i });
- await userEvent.click(rpOption);
-
- // --- VERSIONS ---
- const versionInput = screen.getByRole("combobox", { name: /API Version/i });
- await userEvent.click(versionInput);
-
- const versionOption = await screen.findByRole("option", { name: /2021-04-01/i });
- await userEvent.click(versionOption);
-
- // Final assertions (all cascades complete)
- expect(moduleInput).toHaveValue("storage");
- expect(providerInput).toHaveValue("Storage");
- expect(versionInput).toHaveValue("2021-04-01");
- });
-
it("should handle API errors gracefully during cascade loading", async () => {
const user = userEvent.setup();
render(
@@ -133,7 +94,7 @@ describe("WSEditorClientConfigDialog - Integration", () => {
});
describe("Complete User Workflows", () => {
- it("should complete template config setup end-to-end", async () => {
+ it("should handle user inputs for relevant fields", async () => {
const user = userEvent.setup();
render();
@@ -163,210 +124,5 @@ describe("WSEditorClientConfigDialog - Integration", () => {
expect(mockOnClose).toHaveBeenCalledWith(true);
});
});
-
- it.skip("should complete resource config setup end-to-end", async () => {
- // @NOTE: revisit once workflows and loading states are improved
- server.use(
- http.get(`*/workspaces${mockWorkspaceUrl}/client-config`, () => {
- return new HttpResponse(null, { status: 404 });
- }),
- http.put(`*/workspaces${mockWorkspaceUrl}/client-config`, async ({ request }) => {
- const body = await request.json();
- expect(body).toEqual({
- templates: undefined,
- cloudMetadata: undefined,
- resource: {
- plane: "azure-cli",
- module: "storage",
- version: "2021-04-01",
- id: "storageAccounts",
- subresource: "properties.primaryEndpoints.blob",
- },
- auth: {
- aad: {
- scopes: ["https://storage.azure.com/.default"],
- },
- },
- });
- return HttpResponse.json({ success: true });
- }),
- );
-
- const user = userEvent.setup();
- render();
-
- await waitFor(() => {
- expect(screen.getByText("By resource property")).toBeInTheDocument();
- });
-
- const resourceTab = screen.getByText("By resource property");
- await user.click(resourceTab);
-
- await waitFor(() => {
- expect(screen.getByRole("combobox", { name: /module/i })).toBeInTheDocument();
- });
-
- const moduleInput = screen.getByRole("combobox", { name: /module/i });
- await user.click(moduleInput);
- await waitFor(() => {
- expect(screen.getByText("storage")).toBeInTheDocument();
- });
- await user.click(screen.getByText("storage"));
-
- await waitFor(() => {
- const rpInput = screen.getByLabelText("Resource Provider");
- expect(rpInput).toBeInTheDocument();
- });
- const rpInput = screen.getByLabelText("Resource Provider");
- await user.click(rpInput);
- await waitFor(() => {
- expect(screen.getByText("Microsoft.Storage")).toBeInTheDocument();
- });
- await user.click(screen.getByText("Microsoft.Storage"));
-
- await waitFor(() => {
- const versionInput = screen.getByLabelText("API Version");
- expect(versionInput).toBeInTheDocument();
- });
- const versionInput = screen.getByLabelText("API Version");
- await user.click(versionInput);
- await waitFor(() => {
- expect(screen.getByText("2021-04-01")).toBeInTheDocument();
- });
- await user.click(screen.getByText("2021-04-01"));
-
- await waitFor(() => {
- const resourceIdInput = screen.getByLabelText("Resource ID");
- expect(resourceIdInput).toBeInTheDocument();
- });
- const resourceIdInput = screen.getByLabelText("Resource ID");
- await user.click(resourceIdInput);
- await waitFor(() => {
- expect(screen.getByText("storageAccounts")).toBeInTheDocument();
- });
- await user.click(screen.getByText("storageAccounts"));
-
- const subresourceInput = screen.getByLabelText("Endpoint Property Index");
- await user.type(subresourceInput, "properties.primaryEndpoints.blob");
-
- const aadScopeInput = screen.getByPlaceholderText(/Input Microsoft Entra\(AAD\) auth Scope/);
- await user.clear(aadScopeInput);
- await user.type(aadScopeInput, "https://storage.azure.com/.default");
-
- const updateButton = screen.getByText("Update");
- await user.click(updateButton);
-
- await waitFor(() => {
- expect(mockOnClose).toHaveBeenCalledWith(true);
- });
- });
-
- it.skip("should handle network errors during submission", async () => {
- // @NOTE: revisit once workflows and loading states are improved
- const user = userEvent.setup();
- render(
- ,
- );
-
- await waitFor(() => {
- expect(document.querySelector("#AzureCloud")).toBeInTheDocument();
- });
-
- const azureCloudInput = document.querySelector("#AzureCloud") as HTMLElement;
- await user.type(azureCloudInput, "https://{vaultName}.vault.azure.net");
-
- const aadScopeInput = screen.getByPlaceholderText(/Input Microsoft Entra\(AAD\) auth Scope/);
- await user.type(aadScopeInput, "https://management.azure.com/.default");
-
- const updateButton = screen.getByText("Update");
- await user.click(updateButton);
-
- await waitFor(() => {
- expect(screen.getByText(/ResponseError:/)).toBeInTheDocument();
- });
-
- expect(mockOnClose).not.toHaveBeenCalled();
- });
-
- it.skip("should handle error recovery - fix validation error and retry", async () => {
- // @NOTE: revisit once workflows and loading states are improved
- server.use(
- http.get(`*/workspaces${mockWorkspaceUrl}/client-config`, () => {
- return new HttpResponse(null, { status: 404 });
- }),
- http.put(`*/workspaces${mockWorkspaceUrl}/client-config`, () => {
- return HttpResponse.json({ success: true });
- }),
- );
-
- const user = userEvent.setup();
- render();
-
- await waitFor(() => {
- expect(screen.getByText("Update")).toBeInTheDocument();
- });
-
- const updateButton = screen.getByText("Update");
- await user.click(updateButton);
-
- await waitFor(() => {
- expect(screen.getByText("Azure Cloud Endpoint Template is required.")).toBeInTheDocument();
- });
-
- const azureCloudInput = document.querySelector("#AzureCloud") as HTMLElement;
- await user.type(azureCloudInput, "https://{vaultName}.vault.azure.net");
-
- const aadScopeInput = screen.getByPlaceholderText(/Input Microsoft Entra\(AAD\) auth Scope/);
- await user.type(aadScopeInput, "https://management.azure.com/.default");
-
- await user.click(updateButton);
-
- await waitFor(() => {
- expect(mockOnClose).toHaveBeenCalledWith(true);
- });
- });
- });
-
- describe("Real-time Validation", () => {
- it.skip("should validate template URLs in real-time", async () => {
- // @NOTE: revisit once error/loading states are cleared up
- const user = userEvent.setup();
- render();
-
- await waitFor(() => {
- expect(document.querySelector("#AzureCloud")).toBeInTheDocument();
- });
-
- const azureCloudInput = document.querySelector("#AzureCloud") as HTMLElement;
- await user.type(azureCloudInput, "invalid-url");
-
- const updateButton = screen.getByText("Update");
- await user.click(updateButton);
-
- await waitFor(
- () => {
- expect(screen.queryByText("Azure Cloud Endpoint Template is invalid.")).not.toBeInTheDocument();
- },
- { timeout: 2000 },
- );
- await user.clear(azureCloudInput);
- await user.type(azureCloudInput, "https://{vaultName}.vault.azure.net");
-
- // Add AAD scope
- const aadScopeInput = screen.getByPlaceholderText(/Input Microsoft Entra\(AAD\) auth Scope/);
- await user.type(aadScopeInput, "https://management.azure.com/.default");
-
- // Should be able to submit now
- await user.click(updateButton);
-
- // Error should clear and submission should proceed
- await waitFor(() => {
- expect(screen.queryByText("Azure Cloud Endpoint Template is invalid.")).not.toBeInTheDocument();
- });
- });
});
});
diff --git a/src/web/src/__tests__/mocks/handlers.ts b/src/web/src/__tests__/mocks/handlers.ts
index 7d4dedf2..1554ef9c 100644
--- a/src/web/src/__tests__/mocks/handlers.ts
+++ b/src/web/src/__tests__/mocks/handlers.ts
@@ -89,37 +89,198 @@ export const handlers = [
http.get("/AAZ/Editor/Workspaces/:name", ({ params }) => {
return HttpResponse.json({
name: params.name,
- plane: "azure-cli",
+ plane: `data-plane${params.name}`,
folder: `/workspaces/${params.name}`,
- commandTree: {},
+ resourceProvider: `${params.name}`,
+ commandTree: {
+ names: ["aaz"],
+ },
});
}),
http.get("/AAZ/Specs/Planes", () => {
return HttpResponse.json([
{
- name: "azure-cli",
- displayName: "Azure CLI",
- moduleOptions: ["storage", "compute", "network"],
+ client: "MgmtClient",
+ displayName: "Control plane",
+ name: "mgmt-plane",
},
{
- name: "azure-cli-extensions",
- displayName: "Azure CLI Extensions",
- moduleOptions: [],
+ client: "DataPlaneClient",
+ displayName: "Data plane",
+ name: "data-plane",
},
]);
}),
- http.get("/AAZ/Specs/Planes/:planeName/Modules", ({ params }) => {
- if (params.planeName === "azure-cli") {
- return HttpResponse.json(["storage", "compute", "network", "keyvault"]);
+ http.get("/AAZ/Specs/Planes/:planeName/Modules", () => {
+ return HttpResponse.json(["storage", "compute", "network", "keyvault"]);
+ }),
+
+ http.get("/Swagger/Specs/mgmt-plane", () => {
+ return HttpResponse.json([
+ { url: "/Swagger/Specs/mgmt-plane/addons", name: "addons" },
+ { url: "/Swagger/Specs/mgmt-plane/compute", name: "compute" },
+ { url: "/Swagger/Specs/mgmt-plane/network", name: "network" },
+ { url: "/Swagger/Specs/mgmt-plane/keyvault", name: "keyvault" },
+ { url: "/Swagger/Specs/mgmt-plane/containerservice", name: "containerservice" },
+ { url: "/Swagger/Specs/mgmt-plane/storage", name: "storage" },
+ ]);
+ }),
+
+ // Resources
+ http.get("/Swagger/Specs/mgmt-plane/:moduleName/ResourceProviders/:rp/Resources", ({ params }) => {
+ let rpName = params.rp + "";
+ switch (rpName?.toLowerCase()) {
+ case "storage":
+ rpName = "Microsoft.Storage";
+ break;
+ case "compute":
+ rpName = "Microsoft.Compute";
+ break;
+ case "network":
+ rpName = "Microsoft.Network";
+ break;
+ case "keyvault":
+ rpName = "Microsoft.KeyVault";
+ break;
+ case "addons":
+ rpName = "Microsoft.Addons";
+ break;
+ }
+
+ switch (rpName) {
+ case "Microsoft.Storage":
+ return HttpResponse.json([
+ {
+ id: "storageAccounts",
+ versions: [
+ { version: "2021-04-01", operations: { read: "GET", write: "PUT", delete: "DELETE", listKeys: "GET" } },
+ { version: "2021-09-01", operations: { read: "GET", write: "PUT", delete: "DELETE", listKeys: "GET" } },
+ { version: "2022-09-01", operations: { read: "GET", write: "PUT", delete: "DELETE", listKeys: "GET" } },
+ { version: "2023-01-01", operations: { read: "GET", write: "PUT", delete: "DELETE", listKeys: "GET" } },
+ ],
+ },
+ {
+ id: "storageAccounts/blobServices",
+ versions: [
+ { version: "2021-04-01", operations: { read: "GET", write: "PUT" } },
+ { version: "2021-09-01", operations: { read: "GET", write: "PUT" } },
+ { version: "2022-09-01", operations: { read: "GET", write: "PUT" } },
+ ],
+ },
+ ]);
+
+ case "Microsoft.Compute":
+ return HttpResponse.json([
+ {
+ id: "virtualMachines",
+ versions: [
+ {
+ version: "2021-03-01",
+ operations: { read: "GET", write: "PUT", delete: "DELETE", start: "POST", stop: "POST" },
+ },
+ {
+ version: "2022-03-01",
+ operations: { read: "GET", write: "PUT", delete: "DELETE", start: "POST", stop: "POST" },
+ },
+ {
+ version: "2023-03-01",
+ operations: { read: "GET", write: "PUT", delete: "DELETE", start: "POST", stop: "POST" },
+ },
+ ],
+ },
+ {
+ id: "disks",
+ versions: [
+ { version: "2021-04-01", operations: { read: "GET", write: "PUT", delete: "DELETE" } },
+ { version: "2022-03-02", operations: { read: "GET", write: "PUT", delete: "DELETE" } },
+ ],
+ },
+ ]);
+
+ case "Microsoft.Network":
+ return HttpResponse.json([
+ {
+ id: "virtualNetworks",
+ versions: [
+ { version: "2021-02-01", operations: { read: "GET", write: "PUT", delete: "DELETE" } },
+ { version: "2022-01-01", operations: { read: "GET", write: "PUT", delete: "DELETE" } },
+ { version: "2023-02-01", operations: { read: "GET", write: "PUT", delete: "DELETE" } },
+ ],
+ },
+ {
+ id: "loadBalancers",
+ versions: [
+ { version: "2021-02-01", operations: { read: "GET", write: "PUT", delete: "DELETE" } },
+ { version: "2022-01-01", operations: { read: "GET", write: "PUT", delete: "DELETE" } },
+ ],
+ },
+ ]);
+
+ case "Microsoft.KeyVault":
+ return HttpResponse.json([
+ {
+ id: "vaults",
+ versions: [
+ { version: "2021-10-01", operations: { read: "GET", write: "PUT", delete: "DELETE" } },
+ { version: "2022-07-01", operations: { read: "GET", write: "PUT", delete: "DELETE" } },
+ { version: "2023-02-01", operations: { read: "GET", write: "PUT", delete: "DELETE" } },
+ ],
+ },
+ ]);
+
+ case "Microsoft.Addons":
+ return HttpResponse.json([
+ {
+ id: "/subscriptions/{}/providers/microsoft.addons/supportproviders/{}/supportplantypes/{}",
+ opGroup: "SupportPlanType",
+ versions: [
+ {
+ version: "2017-05-15",
+ operations: {
+ SupportPlanTypes_CreateOrUpdate: "PUT",
+ SupportPlanTypes_Delete: "DELETE",
+ SupportPlanTypes_Get: "GET",
+ },
+ },
+ {
+ version: "2018-03-01",
+ operations: {
+ SupportPlanTypes_CreateOrUpdate: "PUT",
+ SupportPlanTypes_Delete: "DELETE",
+ SupportPlanTypes_Get: "GET",
+ },
+ },
+ ],
+ },
+ {
+ id: "/subscriptions/{}/providers/microsoft.addons/supportproviders/{}/supportplantypes",
+ opGroup: "CanonicalSupportPlanType",
+ versions: [
+ {
+ version: "2017-05-15",
+ operations: { CanonicalSupportPlanTypes_Get: "GET" },
+ },
+ ],
+ },
+ ]);
+
+ default:
+ return HttpResponse.json([]);
}
- return HttpResponse.json(["extensions-module"]);
}),
- http.get("/Swagger/Specs/:planeName/:moduleName/ResourceProviders", () => {
- const resourceProviders = ["Microsoft.Storage", "Microsoft.Compute", "Microsoft.Network", "Microsoft.KeyVault"];
- return HttpResponse.json(resourceProviders);
+ // Resource providers:
+ http.get("/Swagger/Specs/:planeName/:moduleName/ResourceProviders", ({ params }) => {
+ return HttpResponse.json([
+ {
+ entryFiles: [`specification/${params.moduleName}/Microsoft.BlobStorage/main.tsp`],
+ name: `Microsoft.${params.moduleName}`,
+ type: "TypeSpec",
+ url: `/Swagger/Specs/${params.planeName}/${params.moduleName}/ResourceProviders/${params.moduleName}`,
+ },
+ ]);
}),
http.get("/CLI/Az/Modules", () => {
@@ -229,6 +390,15 @@ export const handlers = [
return HttpResponse.json(response);
}),
+ http.get("/AAZ/Editor/Workspaces/:workspaceName/SwaggerDefault", ({ params }) => {
+ return HttpResponse.json({
+ modNames: [`${params.workspaceName}`],
+ plane: `data-plane:${params.workspaceName}`,
+ rpName: `${params.workspaceName}`,
+ source: "TypeSpec",
+ });
+ }),
+
http.get("/workspace/:name/Resources/*/V/*/Commands", () => {
return HttpResponse.json([
{
diff --git a/src/web/src/views/workspace/components/WSEditor/WSEditor.tsx b/src/web/src/views/workspace/components/WSEditor/WSEditor.tsx
index 316bddd7..da5bfc17 100644
--- a/src/web/src/views/workspace/components/WSEditor/WSEditor.tsx
+++ b/src/web/src/views/workspace/components/WSEditor/WSEditor.tsx
@@ -7,7 +7,7 @@ import WSEditorToolBar from "./WSEditorToolBar";
import WSEditorCommandTree from "./WSEditorCommandTree";
import WSEditorCommandGroupContent from "../WSEditorCommandGroupContent";
import WSEditorCommandContent from "../WSEditorCommandContent";
-import WSEditorClientConfigDialog from "./WSEditorClientConfig";
+import WSEditorClientConfig from "./WSEditorClientConfig";
import type { CommandGroup, Command } from "../../interfaces";
import WSEditorExportDialog from "./WSEditorExportDialog";
import WSEditorDeleteDialog from "./WSEditorDeleteDialog";
@@ -293,7 +293,7 @@ const WSEditor = ({ params }: WSEditorProps) => {
/>
)}
{dialogManager.showClientConfigDialog && (
- void;
}
-interface WSEditorClientConfigDialogState {
- updating: boolean;
- invalidText: string | undefined;
- isAdd: boolean;
-
- endpointType: "template" | "http-operation";
-
- templateAzureCloud: string;
- templateAzureChinaCloud: string;
- templateAzureUSGovernment: string;
- templateAzureGermanCloud: string;
- cloudMetadataSelectorIndex: string;
- cloudMetadataPrefixTemplate: string;
-
- aadAuthScopes: string[];
-
- planes: Plane[];
- planeOptions: string[];
- selectedPlane: string | null;
-
- moduleOptions: string[];
- moduleOptionsCommonPrefix: string;
- selectedModule: string | null;
-
- resourceProviderOptions: string[];
- resourceProviderOptionsCommonPrefix: string;
- selectedResourceProvider: string | null;
-
- versionOptions: string[];
- versionResourceIdMap: SwaggerVersionResourceIdMap;
- selectedVersion: string | null;
-
- resourceIdOptions: string[];
- selectedResourceId: string | null;
- subresource: string;
-}
-
interface SwaggerVersionResourceIdMap {
[version: string]: string[];
}
@@ -99,217 +63,143 @@ const MiddlePadding = styled(Box)(() => ({
height: "1.5vh",
}));
-class WSEditorClientConfigDialog extends React.Component<
- WSEditorClientConfigDialogProps,
- WSEditorClientConfigDialogState
-> {
- constructor(props: WSEditorClientConfigDialogProps) {
- super(props);
- this.state = {
- updating: false,
- invalidText: undefined,
- isAdd: true,
-
- endpointType: "template",
-
- templateAzureCloud: "",
- templateAzureChinaCloud: "",
- templateAzureUSGovernment: "",
- templateAzureGermanCloud: "",
- cloudMetadataSelectorIndex: "",
- cloudMetadataPrefixTemplate: "",
-
- aadAuthScopes: [""],
-
- planes: [],
- planeOptions: [],
- selectedPlane: null,
-
- moduleOptions: [],
- moduleOptionsCommonPrefix: "",
- selectedModule: null,
-
- resourceProviderOptions: [],
- resourceProviderOptionsCommonPrefix: "",
- selectedResourceProvider: null,
-
- versionOptions: [],
- versionResourceIdMap: {},
- selectedVersion: null,
-
- resourceIdOptions: [],
- selectedResourceId: null,
- subresource: "",
- };
- }
-
- componentDidMount(): void {
- this.loadPlanes().then(async () => {
- await this.loadWorkspaceClientConfig();
- const { selectedPlane, selectedModule, selectedResourceProvider, selectedVersion } = this.state;
- await this.onPlaneSelectorUpdate(selectedPlane ?? this.state.planeOptions[0]);
- if (selectedModule) {
- await this.loadResourceProviders(selectedModule);
- }
- if (selectedResourceProvider) {
- await this.loadResources(selectedResourceProvider, selectedVersion);
- }
- });
- }
+const WSEditorClientConfigDialog: React.FC = ({ workspaceUrl, open, onClose }) => {
+ const [updating, setUpdating] = useState(false);
+ const [invalidText, setInvalidText] = useState(undefined);
+ const [isAdd, setIsAdd] = useState(true);
+
+ const [endpointType, setEndpointType] = useState<"template" | "http-operation">("template");
+
+ const [templateAzureCloud, setTemplateAzureCloud] = useState("");
+ const [templateAzureChinaCloud, setTemplateAzureChinaCloud] = useState("");
+ const [templateAzureUSGovernment, setTemplateAzureUSGovernment] = useState("");
+ const [templateAzureGermanCloud, setTemplateAzureGermanCloud] = useState("");
+ const [cloudMetadataSelectorIndex, setCloudMetadataSelectorIndex] = useState("");
+ const [cloudMetadataPrefixTemplate, setCloudMetadataPrefixTemplate] = useState("");
+
+ const [aadAuthScopes, setAadAuthScopes] = useState([""]);
+
+ const [selectedPlane, setSelectedPlane] = useState(null);
+
+ const [moduleOptions, setModuleOptions] = useState([]);
+ const [moduleOptionsCommonPrefix, setModuleOptionsCommonPrefix] = useState("");
+ const [selectedModule, setSelectedModule] = useState(null);
+
+ const [resourceProviderOptions, setResourceProviderOptions] = useState([]);
+ const [resourceProviderOptionsCommonPrefix, setResourceProviderOptionsCommonPrefix] = useState("");
+ const [selectedResourceProvider, setSelectedResourceProvider] = useState(null);
+
+ const [versionOptions, setVersionOptions] = useState([]);
+ const [versionResourceIdMap, setVersionResourceIdMap] = useState({});
+ const [selectedVersion, setSelectedVersion] = useState(null);
- loadPlanes = async () => {
+ const [resourceIdOptions, setResourceIdOptions] = useState([]);
+ const [selectedResourceId, setSelectedResourceId] = useState(null);
+ const [subresource, setSubresource] = useState("");
+
+ const loadPlanes = useCallback(async () => {
try {
- this.setState({
- updating: true,
- });
-
- const planes = await specsApi.getPlanes();
- const planeOptions: string[] = planes.map((v: any) => v.displayName);
- this.setState({
- planes: planes,
- planeOptions: planeOptions,
- updating: false,
- });
- await this.onPlaneSelectorUpdate(planeOptions[0]);
+ setUpdating(true);
+
+ const planesData = await specsApi.getPlanes();
+ setUpdating(false);
+
+ if (planesData.length > 0) {
+ const firstPlane = planesData[0];
+ setSelectedPlane(firstPlane.displayName);
+ await loadSwaggerModules(firstPlane);
+ }
} catch (err: any) {
console.error(err);
const message = errorHandlerApi.getErrorMessage(err);
- this.setState({
- updating: false,
- invalidText: `ResponseError: ${message}`,
- });
+ setUpdating(false);
+ setInvalidText(`ResponseError: ${message}`);
}
- };
+ }, []);
- onPlaneSelectorUpdate = async (planeDisplayName: string | null) => {
- const plane = this.state.planes.find((v) => v.displayName === planeDisplayName) ?? null;
- if (this.state.selectedPlane !== (plane?.displayName ?? null)) {
- if (!plane) {
- return;
- }
- this.setState({
- selectedPlane: plane?.displayName ?? null,
- });
- await this.loadSwaggerModules(plane);
- } else {
- this.setState({
- selectedPlane: plane?.displayName ?? null,
- });
- }
- };
-
- loadSwaggerModules = async (plane: Plane | null) => {
+ const loadSwaggerModules = useCallback(async (plane: Plane | null) => {
if (plane !== null) {
if (plane!.moduleOptions?.length) {
- this.setState({
- moduleOptions: plane!.moduleOptions!,
- moduleOptionsCommonPrefix: `/Swagger/Specs/${plane!.name}/`,
- });
- await this.onModuleSelectionUpdate(null);
+ setModuleOptions(plane!.moduleOptions!);
+ setModuleOptionsCommonPrefix(`/Swagger/Specs/${plane!.name}/`);
+ await onModuleSelectionUpdate(null);
} else {
try {
- this.setState({
- updating: true,
- });
+ setUpdating(true);
const options = await specsApi.getSwaggerModules(plane!.name);
- this.setState((preState) => {
- const planes = preState.planes;
- const index = planes.findIndex((v) => v.name === plane!.name);
- planes[index].moduleOptions = options;
- return {
- ...preState,
- updating: false,
- planes: planes,
- moduleOptions: options,
- moduleOptionsCommonPrefix: `/Swagger/Specs/${plane!.name}/`,
- };
- });
- await this.onModuleSelectionUpdate(null);
+ setUpdating(false);
+ setModuleOptions(options);
+ setModuleOptionsCommonPrefix(`/Swagger/Specs/${plane!.name}/`);
+ await onModuleSelectionUpdate(null);
} catch (err: any) {
console.error(err);
const message = errorHandlerApi.getErrorMessage(err);
- this.setState({
- updating: false,
- invalidText: `ResponseError: ${message}`,
- });
+ setUpdating(false);
+ setInvalidText(`ResponseError: ${message}`);
}
}
} else {
- this.setState({
- moduleOptions: [],
- moduleOptionsCommonPrefix: "",
- });
- await this.onModuleSelectionUpdate(null);
- }
- };
-
- onModuleSelectionUpdate = async (moduleValueUrl: string | null) => {
- if (this.state.selectedModule !== moduleValueUrl) {
- this.setState({
- selectedModule: moduleValueUrl,
- });
- await this.loadResourceProviders(moduleValueUrl);
- } else {
- this.setState({
- selectedModule: moduleValueUrl,
- });
+ setModuleOptions([]);
+ setModuleOptionsCommonPrefix("");
+ await onModuleSelectionUpdate(null);
}
- };
+ }, []);
- loadResourceProviders = async (moduleUrl: string | null) => {
+ const onModuleSelectionUpdate = useCallback(
+ async (moduleValueUrl: string | null) => {
+ if (selectedModule !== moduleValueUrl) {
+ setSelectedModule(moduleValueUrl);
+ await loadResourceProviders(moduleValueUrl);
+ } else {
+ setSelectedModule(moduleValueUrl);
+ }
+ },
+ [selectedModule],
+ );
+
+ const loadResourceProviders = useCallback(async (moduleUrl: string | null) => {
if (moduleUrl !== null) {
try {
- this.setState({
- updating: true,
- });
+ setUpdating(true);
const options = await specsApi.getResourceProviders(moduleUrl);
- const selectedResourceProvider = options.length === 1 ? options[0] : null;
- this.setState({
- updating: false,
- resourceProviderOptions: options,
- resourceProviderOptionsCommonPrefix: `${moduleUrl}/ResourceProviders/`,
- });
- this.onResourceProviderUpdate(selectedResourceProvider);
+ const selectedRP = options.length === 1 ? options[0] : null;
+ setUpdating(false);
+ setResourceProviderOptions(options);
+ setResourceProviderOptionsCommonPrefix(`${moduleUrl}/ResourceProviders/`);
+ onResourceProviderUpdate(selectedRP);
} catch (err: any) {
console.error(err);
const message = errorHandlerApi.getErrorMessage(err);
- this.setState({
- updating: false,
- invalidText: `ResponseError: ${message}`,
- });
+ setUpdating(false);
+ setInvalidText(`ResponseError: ${message}`);
}
} else {
- this.setState({
- resourceProviderOptions: [],
- resourceProviderOptionsCommonPrefix: "",
- });
- this.onResourceProviderUpdate(null);
+ setResourceProviderOptions([]);
+ setResourceProviderOptionsCommonPrefix("");
+ onResourceProviderUpdate(null);
}
- };
-
- onResourceProviderUpdate = async (resourceProviderUrl: string | null) => {
- if (this.state.selectedResourceProvider !== resourceProviderUrl) {
- this.setState({
- selectedResourceProvider: resourceProviderUrl,
- });
- await this.loadResources(resourceProviderUrl, null);
- } else {
- this.setState({
- selectedResourceProvider: resourceProviderUrl,
- });
- }
- };
+ }, []);
+
+ const onResourceProviderUpdate = useCallback(
+ async (resourceProviderUrl: string | null) => {
+ if (selectedResourceProvider !== resourceProviderUrl) {
+ setSelectedResourceProvider(resourceProviderUrl);
+ await loadResources(resourceProviderUrl, null);
+ } else {
+ setSelectedResourceProvider(resourceProviderUrl);
+ }
+ },
+ [selectedResourceProvider],
+ );
- loadResources = async (resourceProviderUrl: string | null, selectVersion: string | null) => {
+ const loadResources = useCallback(async (resourceProviderUrl: string | null, selectVersion: string | null) => {
if (resourceProviderUrl != null) {
- this.setState({
- invalidText: undefined,
- updating: true,
- });
+ setInvalidText(undefined);
+ setUpdating(true);
try {
const resources = await specsApi.getProviderResources(resourceProviderUrl);
- const versionResourceIdMap: SwaggerVersionResourceIdMap = {};
- const versionOptions: string[] = [];
+ const versionResIdMap: SwaggerVersionResourceIdMap = {};
+ const versionOpts: string[] = [];
const resourceIdList: string[] = [];
resources.forEach((resource: any) => {
resourceIdList.push(resource.id);
@@ -324,685 +214,610 @@ class WSEditorClientConfigDialog extends React.Component<
})
.map((v: any) => v.version);
resourceVersions.forEach((v: any) => {
- if (!(v in versionResourceIdMap)) {
- versionResourceIdMap[v] = [];
- versionOptions.push(v);
+ if (!(v in versionResIdMap)) {
+ versionResIdMap[v] = [];
+ versionOpts.push(v);
}
- versionResourceIdMap[v].push(resource.id);
+ versionResIdMap[v].push(resource.id);
});
});
- versionOptions.sort((a, b) => a.localeCompare(b)).reverse();
+ versionOpts.sort((a, b) => a.localeCompare(b)).reverse();
if (
selectVersion === null &&
- (versionOptions.length === 0 || versionOptions.findIndex((v) => v === selectVersion) < 0)
+ (versionOpts.length === 0 || versionOpts.findIndex((v) => v === selectVersion) < 0)
) {
selectVersion = null;
}
- if (!selectVersion && versionOptions.length > 0) {
- selectVersion = versionOptions[0];
+ if (!selectVersion && versionOpts.length > 0) {
+ selectVersion = versionOpts[0];
}
- this.setState({
- updating: false,
- versionResourceIdMap: versionResourceIdMap,
- versionOptions: versionOptions,
- });
- this.onVersionUpdate(selectVersion);
+ setUpdating(false);
+ setVersionResourceIdMap(versionResIdMap);
+ setVersionOptions(versionOpts);
+ onVersionUpdate(selectVersion, versionResIdMap);
} catch (err: any) {
console.error(err);
const message = errorHandlerApi.getErrorMessage(err);
- this.setState({
- invalidText: `ResponseError: ${message}`,
- });
+ setInvalidText(`ResponseError: ${message}`);
}
} else {
- this.setState({
- versionOptions: [],
- });
- this.onVersionUpdate(null);
+ setVersionOptions([]);
+ onVersionUpdate(null);
}
- };
-
- onVersionUpdate = (version: string | null) => {
- this.setState((preState) => {
- let selectedResourceId = preState.selectedResourceId;
- let resourceIdOptions: string[] = [];
- if (version != null) {
- resourceIdOptions = [...preState.versionResourceIdMap[version]].sort((a, b) =>
- a.toString().localeCompare(b.toString()),
- );
- if (selectedResourceId !== null && resourceIdOptions.findIndex((v) => v === selectedResourceId) < 0) {
- selectedResourceId = null;
+ }, []);
+
+ const onVersionUpdate = useCallback(
+ (version: string | null, versionResIdMap?: SwaggerVersionResourceIdMap) => {
+ const mapToUse = versionResIdMap || versionResourceIdMap;
+ let newSelectedResourceId = selectedResourceId;
+ let resourceIdOpts: string[] = [];
+ if (version != null && mapToUse[version]) {
+ resourceIdOpts = [...mapToUse[version]].sort((a, b) => a.toString().localeCompare(b.toString()));
+ if (newSelectedResourceId !== null && resourceIdOpts.findIndex((v) => v === newSelectedResourceId) < 0) {
+ newSelectedResourceId = null;
}
}
- return {
- ...preState,
- resourceIdOptions: resourceIdOptions,
- selectedVersion: version,
- preferredAAZVersion: version,
- selectedResourceId: selectedResourceId,
- };
- });
- };
-
- loadWorkspaceClientConfig = async () => {
- this.setState({ updating: true });
+ setResourceIdOptions(resourceIdOpts);
+ setSelectedVersion(version);
+ setSelectedResourceId(newSelectedResourceId);
+ },
+ [selectedResourceId, versionResourceIdMap],
+ );
+
+ const loadWorkspaceClientConfig = useCallback(async () => {
+ setUpdating(true);
try {
- const clientConfigData = await workspaceApi.getClientConfig(this.props.workspaceUrl);
+ const clientConfigData = await workspaceApi.getClientConfig(workspaceUrl);
const clientConfig: ClientConfig = {
version: clientConfigData.version,
auth: clientConfigData.auth,
};
- let templateAzureCloud = "";
- let templateAzureChinaCloud = "";
- let templateAzureUSGovernment = "";
- let templateAzureGermanCloud = "";
- let cloudMetadataSelectorIndex = "";
- let cloudMetadataPrefixTemplate = "";
- let endpointType: "template" | "http-operation" = "template";
- let selectedPlane: string | null = null;
- let selectedModule: string | null = null;
- let selectedResourceProvider: string | null = null;
- let selectedVersion: string | null = null;
- let selectedResourceId: string | null = null;
- let subresource: string = "";
-
- if (clientConfigData.endpoints.type === "template") {
+ let templateAzureCloudVal = "";
+ let templateAzureChinaCloudVal = "";
+ let templateAzureUSGovernmentVal = "";
+ let templateAzureGermanCloudVal = "";
+ let cloudMetadataSelectorIndexVal = "";
+ let cloudMetadataPrefixTemplateVal = "";
+ let endpointTypeVal: "template" | "http-operation" = "template";
+ let selectedPlaneVal: string | null = null;
+ let selectedModuleVal: string | null = null;
+ let selectedResourceProviderVal: string | null = null;
+ let selectedVersionVal: string | null = null;
+ let selectedResourceIdVal: string | null = null;
+ let subresourceVal: string = "";
+
+ if (clientConfigData.endpoints?.type === "template") {
clientConfig.endpointTemplates = {};
clientConfigData.endpoints.templates.forEach((value: any) => {
clientConfig.endpointTemplates![value.cloud] = value.template;
});
clientConfig.endpointCloudMetadata = clientConfigData.endpoints.cloudMetadata;
- endpointType = "template";
- templateAzureCloud = clientConfig.endpointTemplates!["AzureCloud"] ?? "";
- templateAzureChinaCloud = clientConfig.endpointTemplates!["AzureChinaCloud"] ?? "";
- templateAzureUSGovernment = clientConfig.endpointTemplates!["AzureUSGovernment"] ?? "";
- templateAzureGermanCloud = clientConfig.endpointTemplates!["AzureGermanCloud"] ?? "";
- cloudMetadataSelectorIndex = clientConfig.endpointCloudMetadata?.selectorIndex ?? "";
- cloudMetadataPrefixTemplate = clientConfig.endpointCloudMetadata?.prefixTemplate ?? "";
- } else if (clientConfigData.endpoints.type === "http-operation") {
+ endpointTypeVal = "template";
+ templateAzureCloudVal = clientConfig.endpointTemplates!["AzureCloud"] ?? "";
+ templateAzureChinaCloudVal = clientConfig.endpointTemplates!["AzureChinaCloud"] ?? "";
+ templateAzureUSGovernmentVal = clientConfig.endpointTemplates!["AzureUSGovernment"] ?? "";
+ templateAzureGermanCloudVal = clientConfig.endpointTemplates!["AzureGermanCloud"] ?? "";
+ cloudMetadataSelectorIndexVal = clientConfig.endpointCloudMetadata?.selectorIndex ?? "";
+ cloudMetadataPrefixTemplateVal = clientConfig.endpointCloudMetadata?.prefixTemplate ?? "";
+ } else if (clientConfigData.endpoints?.type === "http-operation") {
clientConfig.endpointResource = clientConfigData.endpoints.resource;
const rpUrl: string = clientConfig.endpointResource!.swagger.split("/Paths/")[0];
const moduleUrl: string = rpUrl.split("/ResourceProviders/")[0];
const planeUrl: string = moduleUrl.split("/")[0];
- selectedResourceProvider = `/Swagger/Specs/${rpUrl}`;
- selectedModule = `/Swagger/Specs/${moduleUrl}`;
- selectedPlane = `/Swagger/Specs/${planeUrl}`;
- selectedVersion = clientConfig.endpointResource!.version;
- selectedResourceId = clientConfig.endpointResource!.id;
- subresource = clientConfig.endpointResource!.subresource ?? "";
- endpointType = "http-operation";
+ selectedResourceProviderVal = `/Swagger/Specs/${rpUrl}`;
+ selectedModuleVal = `/Swagger/Specs/${moduleUrl}`;
+ selectedPlaneVal = `/Swagger/Specs/${planeUrl}`;
+ selectedVersionVal = clientConfig.endpointResource!.version;
+ selectedResourceIdVal = clientConfig.endpointResource!.id;
+ subresourceVal = clientConfig.endpointResource!.subresource ?? "";
+ endpointTypeVal = "http-operation";
}
- this.setState({
- aadAuthScopes: clientConfig.auth.aad.scopes ?? [""],
- endpointType: endpointType,
- templateAzureCloud: templateAzureCloud,
- templateAzureChinaCloud: templateAzureChinaCloud,
- templateAzureUSGovernment: templateAzureUSGovernment,
- templateAzureGermanCloud: templateAzureGermanCloud,
- cloudMetadataSelectorIndex: cloudMetadataSelectorIndex,
- cloudMetadataPrefixTemplate: cloudMetadataPrefixTemplate,
- selectedPlane: selectedPlane,
- selectedModule: selectedModule,
- selectedResourceProvider: selectedResourceProvider,
- selectedVersion: selectedVersion,
- selectedResourceId: selectedResourceId,
- subresource: subresource,
- isAdd: false,
- });
+ setAadAuthScopes(clientConfig.auth.aad.scopes ?? [""]);
+ setEndpointType(endpointTypeVal);
+ setTemplateAzureCloud(templateAzureCloudVal);
+ setTemplateAzureChinaCloud(templateAzureChinaCloudVal);
+ setTemplateAzureUSGovernment(templateAzureUSGovernmentVal);
+ setTemplateAzureGermanCloud(templateAzureGermanCloudVal);
+ setCloudMetadataSelectorIndex(cloudMetadataSelectorIndexVal);
+ setCloudMetadataPrefixTemplate(cloudMetadataPrefixTemplateVal);
+ setSelectedPlane(selectedPlaneVal);
+ setSelectedModule(selectedModuleVal);
+ setSelectedResourceProvider(selectedResourceProviderVal);
+ setSelectedVersion(selectedVersionVal);
+ setSelectedResourceId(selectedResourceIdVal);
+ setSubresource(subresourceVal);
+ setIsAdd(false);
} catch (err: any) {
if (errorHandlerApi.isHttpError(err, 404)) {
- this.setState({
- isAdd: true,
- });
+ setIsAdd(true);
} else {
console.error(err);
const message = errorHandlerApi.getErrorMessage(err);
- this.setState({ invalidText: `ResponseError: ${message}` });
+ setInvalidText(`ResponseError: ${message}`);
}
}
- this.setState({ updating: false });
- };
+ setUpdating(false);
+ }, [workspaceUrl]);
+
+ useEffect(() => {
+ const initializeComponent = async () => {
+ await loadPlanes();
+ await loadWorkspaceClientConfig();
+ };
+
+ if (open) {
+ initializeComponent();
+ }
+ }, [open, loadPlanes, loadWorkspaceClientConfig]);
- handleClose = () => {
- this.props.onClose(false);
- };
+ const handleClose = useCallback(() => {
+ onClose(false);
+ }, [onClose]);
- handleUpdate = async () => {
- let { aadAuthScopes } = this.state;
- const { endpointType } = this.state;
+ const handleUpdate = useCallback(async () => {
+ let currentAadAuthScopes = [...aadAuthScopes];
let templates: ClientEndpointTemplate[] | undefined = undefined;
let resource: ClientEndpointResource | undefined = undefined;
let cloudMetadata: ClientEndpointCloudMetadata | undefined = undefined;
if (endpointType === "template") {
- let { templateAzureCloud, templateAzureChinaCloud, templateAzureGermanCloud, templateAzureUSGovernment } =
- this.state;
- templateAzureCloud = templateAzureCloud.trim();
- if (templateAzureCloud.length < 1) {
- this.setState({
- invalidText: "Azure Cloud Endpoint Template is required.",
- });
+ let currentTemplateAzureCloud = templateAzureCloud.trim();
+ if (currentTemplateAzureCloud.length < 1) {
+ setInvalidText("Azure Cloud Endpoint Template is required.");
return;
}
- templateAzureChinaCloud = templateAzureChinaCloud.trim();
- templateAzureUSGovernment = templateAzureUSGovernment.trim();
- templateAzureGermanCloud = templateAzureGermanCloud.trim();
+ let currentTemplateAzureChinaCloud = templateAzureChinaCloud.trim();
+ let currentTemplateAzureUSGovernment = templateAzureUSGovernment.trim();
+ let currentTemplateAzureGermanCloud = templateAzureGermanCloud.trim();
const templateRegex = /^https:\/\/((\{[a-zA-Z0-9]+\})|([^{}.]+))(.((\{[a-zA-Z0-9]+\})|([^{}.]+)))*(\/)?$/;
- if (!templateRegex.test(templateAzureCloud)) {
- this.setState({
- invalidText: "Azure Cloud Endpoint Template is invalid.",
- });
+ if (!templateRegex.test(currentTemplateAzureCloud)) {
+ setInvalidText("Azure Cloud Endpoint Template is invalid.");
return;
}
- if (templateAzureChinaCloud.length > 0 && !templateRegex.test(templateAzureChinaCloud)) {
- this.setState({
- invalidText: "Azure China Cloud Endpoint Template is invalid.",
- });
+ if (currentTemplateAzureChinaCloud.length > 0 && !templateRegex.test(currentTemplateAzureChinaCloud)) {
+ setInvalidText("Azure China Cloud Endpoint Template is invalid.");
return;
}
- if (templateAzureUSGovernment.length > 0 && !templateRegex.test(templateAzureUSGovernment)) {
- this.setState({
- invalidText: "Azure US Government Endpoint Template is invalid.",
- });
+ if (currentTemplateAzureUSGovernment.length > 0 && !templateRegex.test(currentTemplateAzureUSGovernment)) {
+ setInvalidText("Azure US Government Endpoint Template is invalid.");
return;
}
- if (templateAzureGermanCloud.length > 0 && !templateRegex.test(templateAzureGermanCloud)) {
- this.setState({
- invalidText: "Azure German Cloud Endpoint Template is invalid.",
- });
+ if (currentTemplateAzureGermanCloud.length > 0 && !templateRegex.test(currentTemplateAzureGermanCloud)) {
+ setInvalidText("Azure German Cloud Endpoint Template is invalid.");
return;
}
- templates = [{ cloud: "AzureCloud", template: templateAzureCloud }];
- if (templateAzureChinaCloud.length > 0) {
- templates.push({ cloud: "AzureChinaCloud", template: templateAzureChinaCloud });
+ templates = [{ cloud: "AzureCloud", template: currentTemplateAzureCloud }];
+ if (currentTemplateAzureChinaCloud.length > 0) {
+ templates.push({ cloud: "AzureChinaCloud", template: currentTemplateAzureChinaCloud });
}
- if (templateAzureUSGovernment.length > 0) {
- templates.push({ cloud: "AzureUSGovernment", template: templateAzureUSGovernment });
+ if (currentTemplateAzureUSGovernment.length > 0) {
+ templates.push({ cloud: "AzureUSGovernment", template: currentTemplateAzureUSGovernment });
}
- if (templateAzureGermanCloud.length > 0) {
- templates.push({ cloud: "AzureGermanCloud", template: templateAzureGermanCloud });
+ if (currentTemplateAzureGermanCloud.length > 0) {
+ templates.push({ cloud: "AzureGermanCloud", template: currentTemplateAzureGermanCloud });
}
- let { cloudMetadataSelectorIndex, cloudMetadataPrefixTemplate } = this.state;
- cloudMetadataSelectorIndex = cloudMetadataSelectorIndex.trim();
- cloudMetadataPrefixTemplate = cloudMetadataPrefixTemplate.trim();
- if (cloudMetadataSelectorIndex.length < 1 && cloudMetadataPrefixTemplate.length > 0) {
- this.setState({
- invalidText: "Cloud Metadata Selector Index is required.",
- });
+ let currentCloudMetadataSelectorIndex = cloudMetadataSelectorIndex.trim();
+ let currentCloudMetadataPrefixTemplate = cloudMetadataPrefixTemplate.trim();
+ if (currentCloudMetadataSelectorIndex.length < 1 && currentCloudMetadataPrefixTemplate.length > 0) {
+ setInvalidText("Cloud Metadata Selector Index is required.");
return;
- } else if (cloudMetadataSelectorIndex.length > 0) {
+ } else if (currentCloudMetadataSelectorIndex.length > 0) {
cloudMetadata = {
- selectorIndex: cloudMetadataSelectorIndex,
+ selectorIndex: currentCloudMetadataSelectorIndex,
};
- if (cloudMetadataPrefixTemplate.length > 0) {
- if (!templateRegex.test(cloudMetadataPrefixTemplate)) {
- this.setState({
- invalidText: "Cloud Metadata Prefix is invalid.",
- });
+ if (currentCloudMetadataPrefixTemplate.length > 0) {
+ if (!templateRegex.test(currentCloudMetadataPrefixTemplate)) {
+ setInvalidText("Cloud Metadata Prefix is invalid.");
return;
}
- cloudMetadata.prefixTemplate = cloudMetadataPrefixTemplate;
+ cloudMetadata.prefixTemplate = currentCloudMetadataPrefixTemplate;
}
}
} else if (endpointType === "http-operation") {
- let { subresource } = this.state;
- const {
- selectedPlane,
- selectedModule,
- selectedResourceProvider,
- selectedVersion,
- selectedResourceId,
- moduleOptionsCommonPrefix,
- } = this.state;
- if (!selectedPlane) {
- this.setState({
- invalidText: "Plane is required.",
- });
- return;
- }
+ let currentSubresource = subresource;
if (!selectedModule) {
- this.setState({
- invalidText: "Module is required.",
- });
+ setInvalidText("Module is required.");
return;
}
if (!selectedResourceProvider) {
- this.setState({
- invalidText: "Resource Provider is required.",
- });
+ setInvalidText("Resource Provider is required.");
return;
}
if (!selectedVersion) {
- this.setState({
- invalidText: "API Version is required.",
- });
+ setInvalidText("API Version is required.");
return;
}
if (!selectedResourceId) {
- this.setState({
- invalidText: "Resource ID is required.",
- });
+ setInvalidText("Resource ID is required.");
return;
}
- subresource = subresource.trim();
- if (subresource.length < 1) {
- this.setState({
- invalidText: "Endpoint Property Index is required.",
- });
+ currentSubresource = currentSubresource.trim();
+ if (currentSubresource.length < 1) {
+ setInvalidText("Endpoint Property Index is required.");
return;
}
resource = {
- plane: selectedPlane.replace("/Swagger/Specs/", ""),
+ plane: selectedPlane?.replace("/Swagger/Specs/", "") ?? "",
module: selectedModule.replace(moduleOptionsCommonPrefix, ""),
version: selectedVersion,
id: selectedResourceId,
- subresource: subresource,
+ subresource: currentSubresource,
};
}
- aadAuthScopes = aadAuthScopes.map((scope) => scope.trim()).filter((scope) => scope.length > 0);
- if (aadAuthScopes.length < 1) {
- this.setState({
- invalidText: "MS Entra(AAD) Auth Scopes is required.",
- });
+ currentAadAuthScopes = currentAadAuthScopes.map((scope) => scope.trim()).filter((scope) => scope.length > 0);
+ if (currentAadAuthScopes.length < 1) {
+ setInvalidText("MS Entra(AAD) Auth Scopes is required.");
return;
}
const auth = {
aad: {
- scopes: aadAuthScopes,
+ scopes: currentAadAuthScopes,
},
};
- this.onUpdateClientConfig(templates, cloudMetadata, resource, auth);
- };
-
- onUpdateClientConfig = async (
- templates: ClientEndpointTemplate[] | undefined,
- cloudMetadata: ClientEndpointCloudMetadata | undefined,
- resource: ClientEndpointResource | undefined,
- auth: ClientAuth,
- ) => {
- this.setState({ updating: true });
- try {
- await workspaceApi.updateClientConfig(this.props.workspaceUrl, {
- templates: templates,
- cloudMetadata: cloudMetadata,
- resource: resource,
- auth: auth,
- });
- this.setState({ updating: false });
- this.props.onClose(true);
- } catch (err: any) {
- console.error(err);
- const message = errorHandlerApi.getErrorMessage(err);
- this.setState({ invalidText: `ResponseError: ${message}` });
- this.setState({ updating: false });
- }
- };
-
- onRemoveAadScope = (idx: number) => {
- this.setState((preState) => {
- const aadAuthScopes: string[] = [
- ...preState.aadAuthScopes.slice(0, idx),
- ...preState.aadAuthScopes.slice(idx + 1),
- ];
- if (aadAuthScopes.length === 0) {
- aadAuthScopes.push("");
+ onUpdateClientConfig(templates, cloudMetadata, resource, auth);
+ }, [
+ aadAuthScopes,
+ endpointType,
+ templateAzureCloud,
+ templateAzureChinaCloud,
+ templateAzureUSGovernment,
+ templateAzureGermanCloud,
+ cloudMetadataSelectorIndex,
+ cloudMetadataPrefixTemplate,
+ selectedPlane,
+ selectedModule,
+ selectedResourceProvider,
+ selectedVersion,
+ selectedResourceId,
+ subresource,
+ moduleOptionsCommonPrefix,
+ ]);
+
+ const onUpdateClientConfig = useCallback(
+ async (
+ templates: ClientEndpointTemplate[] | undefined,
+ cloudMetadata: ClientEndpointCloudMetadata | undefined,
+ resource: ClientEndpointResource | undefined,
+ auth: ClientAuth,
+ ) => {
+ setUpdating(true);
+ try {
+ await workspaceApi.updateClientConfig(workspaceUrl, {
+ templates: templates,
+ cloudMetadata: cloudMetadata,
+ resource: resource,
+ auth: auth,
+ });
+ setUpdating(false);
+ onClose(true);
+ } catch (err: any) {
+ console.error(err);
+ const message = errorHandlerApi.getErrorMessage(err);
+ setInvalidText(`ResponseError: ${message}`);
+ setUpdating(false);
}
- return {
- ...preState,
- aadAuthScopes: aadAuthScopes,
- };
- });
- };
-
- onModifyAadScope = (scope: string, idx: number) => {
- this.setState((preState) => {
- return {
- ...preState,
- aadAuthScopes: [...preState.aadAuthScopes.slice(0, idx), scope, ...preState.aadAuthScopes.slice(idx + 1)],
- };
- });
- };
-
- onAddAadScope = () => {
- this.setState((preState) => {
- return {
- ...preState,
- aadAuthScopes: [...preState.aadAuthScopes, ""],
- };
+ },
+ [workspaceUrl, onClose],
+ );
+
+ const onRemoveAadScope = useCallback((idx: number) => {
+ setAadAuthScopes((prev) => {
+ const newScopes = [...prev.slice(0, idx), ...prev.slice(idx + 1)];
+ if (newScopes.length === 0) {
+ newScopes.push("");
+ }
+ return newScopes;
});
- };
-
- buildAadScopeInput = (scope: string, idx: number) => {
- return (
-
- this.onRemoveAadScope(idx)} aria-label="remove">
-
-
- {
- this.onModifyAadScope(event.target.value, idx);
+ }, []);
+
+ const onModifyAadScope = useCallback((scope: string, idx: number) => {
+ setAadAuthScopes((prev) => [...prev.slice(0, idx), scope, ...prev.slice(idx + 1)]);
+ }, []);
+
+ const onAddAadScope = useCallback(() => {
+ setAadAuthScopes((prev) => [...prev, ""]);
+ }, []);
+
+ const buildAadScopeInput = useCallback(
+ (scope: string, idx: number) => {
+ return (
+
-
- );
- };
-
- render() {
- const {
- invalidText,
- updating,
- isAdd,
- aadAuthScopes,
- endpointType,
- templateAzureCloud,
- templateAzureChinaCloud,
- templateAzureUSGovernment,
- templateAzureGermanCloud,
- cloudMetadataSelectorIndex,
- cloudMetadataPrefixTemplate,
- } = this.state;
- const { selectedModule, selectedResourceProvider, selectedVersion, selectedResourceId, subresource } = this.state;
- return (
-
+ );
+};
interface ClientEndpointTemplate {
cloud: string;
diff --git a/src/web/src/views/workspace/components/WSEditor/index.ts b/src/web/src/views/workspace/components/WSEditor/index.ts
index b25ec00e..16668d05 100644
--- a/src/web/src/views/workspace/components/WSEditor/index.ts
+++ b/src/web/src/views/workspace/components/WSEditor/index.ts
@@ -6,4 +6,4 @@ export { default as WSEditorExportDialog } from "./WSEditorExportDialog";
export { default as WSEditorDeleteDialog } from "./WSEditorDeleteDialog";
export { default as WSEditorSwaggerReloadDialog } from "./WSEditorSwaggerReloadDialog";
export { default as WSRenameDialog } from "./WSRenameDialog";
-export { default as WSEditorClientConfigDialog } from "./WSEditorClientConfig";
+export { default as WSEditorClientConfig } from "./WSEditorClientConfig";