зеркало из https://github.com/Azure/BatchExplorer.git
StorageAccountService using authenticated requests
This commit is contained in:
Родитель
55e0746f8e
Коммит
66dd10d76e
|
@ -12,6 +12,7 @@ import { DependencyName } from "@batch/ui-common/lib/environment";
|
|||
import { DefaultFormLayoutProvider, DefaultParameterTypeResolver } from "@batch/ui-react/lib/components/form";
|
||||
import { ConsoleLogger } from "@batch/ui-common/lib/logging";
|
||||
import { BrowserDependencyName } from "@batch/ui-react";
|
||||
import { StorageAccountServiceImpl } from "@batch/ui-service";
|
||||
import { registerIcons } from "app/config";
|
||||
import {
|
||||
AuthorizationHttpService,
|
||||
|
@ -75,6 +76,8 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||
[DependencyName.Localizer]: () => new StandardLocalizer(),
|
||||
[DependencyName.HttpClient]:
|
||||
() => new BatchExplorerHttpClient(authService),
|
||||
[BrowserDependencyName.StorageAccountService]:
|
||||
() => new StorageAccountServiceImpl(),
|
||||
[BrowserDependencyName.ParameterTypeResolver]:
|
||||
() => new DefaultParameterTypeResolver(),
|
||||
[BrowserDependencyName.FormLayoutProvider]:
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
export {
|
||||
getEnvironment,
|
||||
initEnvironment,
|
||||
initMockEnvironment,
|
||||
destroyEnvironment,
|
||||
} from "./environment/environment-util";
|
||||
export {
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
"jest": "^27.1.0",
|
||||
"jest-axe": "^5.0.1",
|
||||
"jest-junit": "^12.2.0",
|
||||
"jest-mock-extended": "^2.0.6",
|
||||
"ts-jest": "^27.0.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
@ -3102,6 +3103,19 @@
|
|||
"node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/jest-mock-extended": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/jest-mock-extended/-/jest-mock-extended-2.0.6.tgz",
|
||||
"integrity": "sha512-KoDdjqwIp2phaOWB0hr4O+9HF7hIJx7O+Reefi3iGrNhUpzVkod9UozYTSanvbNvjFYIEH6noA2tIjc8IDpadw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ts-essentials": "^7.0.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"jest": "^24.0.0 || ^25.0.0 || ^26.0.0 || ^27.0.0 || ^28.0.0",
|
||||
"typescript": "^3.0.0 || ^4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/jest-pnp-resolver": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz",
|
||||
|
@ -4454,6 +4468,15 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-essentials": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-7.0.3.tgz",
|
||||
"integrity": "sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ==",
|
||||
"dev": true,
|
||||
"peerDependencies": {
|
||||
"typescript": ">=3.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-jest": {
|
||||
"version": "27.1.4",
|
||||
"resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.1.4.tgz",
|
||||
|
@ -7222,6 +7245,15 @@
|
|||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"jest-mock-extended": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/jest-mock-extended/-/jest-mock-extended-2.0.6.tgz",
|
||||
"integrity": "sha512-KoDdjqwIp2phaOWB0hr4O+9HF7hIJx7O+Reefi3iGrNhUpzVkod9UozYTSanvbNvjFYIEH6noA2tIjc8IDpadw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ts-essentials": "^7.0.3"
|
||||
}
|
||||
},
|
||||
"jest-pnp-resolver": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz",
|
||||
|
@ -8257,6 +8289,12 @@
|
|||
"punycode": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"ts-essentials": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-7.0.3.tgz",
|
||||
"integrity": "sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ==",
|
||||
"dev": true
|
||||
},
|
||||
"ts-jest": {
|
||||
"version": "27.1.4",
|
||||
"resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.1.4.tgz",
|
||||
|
|
|
@ -68,7 +68,6 @@
|
|||
"react-dom": ">=16.13.1 <17.0.0",
|
||||
"tslib": "~2.3.1"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"@batch/common-config": "^1.0.0",
|
||||
"@batch/ui-common": "^1.0.0",
|
||||
|
@ -84,6 +83,7 @@
|
|||
"jest": "^27.1.0",
|
||||
"jest-axe": "^5.0.1",
|
||||
"jest-junit": "^12.2.0",
|
||||
"jest-mock-extended": "^2.0.6",
|
||||
"ts-jest": "^27.0.5"
|
||||
},
|
||||
"files": [
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { render, screen } from "@testing-library/react";
|
||||
import { render, screen, waitFor } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import * as React from "react";
|
||||
import { initMockBrowserEnvironment } from "../../../environment";
|
||||
import { runAxe } from "../../../test-util/a11y";
|
||||
|
@ -23,6 +24,20 @@ describe("Dropdown form control", () => {
|
|||
const ddEl = screen.getByRole("combobox");
|
||||
expect(ddEl).toBeDefined();
|
||||
|
||||
const user = userEvent.setup();
|
||||
user.click(ddEl);
|
||||
await waitFor(() =>
|
||||
expect(ddEl.getAttribute("aria-expanded")).toBe("true")
|
||||
);
|
||||
|
||||
const options = screen.getAllByRole("option");
|
||||
expect(options.length).toEqual(3);
|
||||
expect(options.map((option) => option.textContent)).toEqual([
|
||||
"ace",
|
||||
"king",
|
||||
"queen",
|
||||
]);
|
||||
|
||||
expect(
|
||||
await runAxe(container, {
|
||||
rules: {
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
import { Parameter } from "@batch/ui-common";
|
||||
import { createForm, Form } from "@batch/ui-common/lib/form";
|
||||
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { UserEvent } from "@testing-library/user-event/dist/types/setup";
|
||||
import * as React from "react";
|
||||
import { initMockBrowserEnvironment } from "../../../environment";
|
||||
import { runAxe } from "../../../test-util/a11y";
|
||||
import {
|
||||
StorageAccountDropdown,
|
||||
} from "../parameter-type";
|
||||
|
||||
/* KLUDGE: the parameter has to be called "subscriptionId" until we can specify
|
||||
* dependencies in parameter types
|
||||
*/
|
||||
type FakeFormValues = {
|
||||
subscriptionId?: string;
|
||||
storageAccountId?: string;
|
||||
};
|
||||
|
||||
describe("Parameter type tests", () => {
|
||||
let user: UserEvent;
|
||||
let form: Form<FakeFormValues>;
|
||||
let subParam: Parameter<FakeFormValues, "subscriptionId">;
|
||||
beforeEach(() => {
|
||||
initMockBrowserEnvironment();
|
||||
user = userEvent.setup();
|
||||
form = createForm<FakeFormValues>({ values: {} });
|
||||
subParam = form.param("subscriptionId", "string");
|
||||
});
|
||||
|
||||
describe("StorageAccountDropdown", () => {
|
||||
let storageParam: Parameter<FakeFormValues, "storageAccountId">;
|
||||
beforeEach(() => {
|
||||
storageParam = form.param("storageAccountId", "string");
|
||||
});
|
||||
|
||||
test("simple dropdown", async () => {
|
||||
render(<StorageAccountDropdown param={storageParam} />);
|
||||
const element = screen.getByRole("combobox");
|
||||
await user.click(element);
|
||||
await waitFor(() => expectElementEnabled(element));
|
||||
expect(screen.queryAllByRole("option")).toEqual([]);
|
||||
});
|
||||
|
||||
test("dropdown with subscription", async () => {
|
||||
render(
|
||||
<>
|
||||
<SubscriptionDropdown param={subParam} />
|
||||
<StorageAccountDropdown param={storageParam} />
|
||||
</>
|
||||
);
|
||||
const subDropdown = screen.getByRole("combobox", {
|
||||
name: /subscriptionId/,
|
||||
});
|
||||
const storageDropdown = screen.getByRole("combobox", {
|
||||
name: /storageAccountId/,
|
||||
});
|
||||
await user.click(subDropdown);
|
||||
await waitFor(() => {
|
||||
expectElementEnabled(subDropdown);
|
||||
expectElementEnabled(storageDropdown);
|
||||
});
|
||||
selectOption(0);
|
||||
await user.click(storageDropdown);
|
||||
|
||||
let storageAccounts = await screen.findAllByRole("option");
|
||||
|
||||
// Data served by FakeStorageAccountService
|
||||
expect(storageAccounts.length).toEqual(3);
|
||||
expect(storageAccounts[0].textContent).toEqual("Storage A");
|
||||
|
||||
await user.click(subDropdown); // Reopen sub dropdown
|
||||
selectOption(2);
|
||||
await user.click(storageDropdown);
|
||||
|
||||
storageAccounts = await screen.findAllByRole("option");
|
||||
|
||||
expect(storageAccounts.length).toEqual(4);
|
||||
expect(storageAccounts[0].textContent).toEqual("Storage F");
|
||||
});
|
||||
|
||||
test("bad subscription shows error", async () => {
|
||||
render(
|
||||
<>
|
||||
<SubscriptionDropdown param={subParam} />
|
||||
<StorageAccountDropdown param={storageParam} />
|
||||
</>
|
||||
);
|
||||
const subDropdown = screen.getByRole("combobox", {
|
||||
name: /subscriptionId/,
|
||||
});
|
||||
const storageDropdown = screen.getByRole("combobox", {
|
||||
name: /storageAccountId/,
|
||||
});
|
||||
await user.click(subDropdown);
|
||||
await waitFor(() => {
|
||||
expectElementEnabled(subDropdown);
|
||||
expectElementEnabled(storageDropdown);
|
||||
});
|
||||
selectOption(4); // Bad subscription
|
||||
expect(screen.getByText("Bad Subscription")).toBeDefined();
|
||||
|
||||
await user.click(storageDropdown);
|
||||
|
||||
expect(await screen.queryAllByRole("option")).toEqual([]);
|
||||
expect(
|
||||
screen.getByText("Error: No storage accounts in subscription.")
|
||||
).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const expectElementEnabled = (element: HTMLElement) =>
|
||||
expect(element.className).not.toContain("is-disabled");
|
||||
|
||||
const selectOption = (index: number) =>
|
||||
fireEvent.click(screen.getAllByRole("option")[index]);
|
|
@ -1,10 +1,16 @@
|
|||
import { ParameterType as CommonParameterType } from "@batch/ui-common";
|
||||
import {
|
||||
Parameter,
|
||||
ParameterType as CommonParameterType,
|
||||
} from "@batch/ui-common";
|
||||
import { inject } from "@batch/ui-common/lib/environment";
|
||||
import { FormValues, ValidationStatus } from "@batch/ui-common/lib/form";
|
||||
import { StorageAccount, StorageAccountService } from "@batch/ui-service";
|
||||
import * as React from "react";
|
||||
import { Parameter } from "@batch/ui-common";
|
||||
import { TextField } from "./text-field";
|
||||
import { Dropdown } from "./dropdown";
|
||||
import { useEffect, useState } from "react";
|
||||
import { BrowserDependencyName } from "../..";
|
||||
import { useAsyncEffect, useUniqueId } from "../../hooks";
|
||||
import { FormValues } from "@batch/ui-common/lib/form";
|
||||
import { Dropdown } from "./dropdown";
|
||||
import { TextField } from "./text-field";
|
||||
|
||||
enum ExtendedParameterType {
|
||||
BatchAccountName = "BatchAccountName",
|
||||
|
@ -99,7 +105,7 @@ export class DefaultParameterTypeResolver implements ParameterTypeResolver {
|
|||
);
|
||||
case ParameterType.StorageAccountId:
|
||||
return (
|
||||
<StringParamTextField
|
||||
<StorageAccountDropdown
|
||||
id={id}
|
||||
key={param.name}
|
||||
param={param}
|
||||
|
@ -107,7 +113,7 @@ export class DefaultParameterTypeResolver implements ParameterTypeResolver {
|
|||
);
|
||||
case ParameterType.SubscriptionId:
|
||||
return (
|
||||
<SubscriptionIdParamDropdown
|
||||
<SubscriptionDropdown
|
||||
id={id}
|
||||
key={param.name}
|
||||
param={param}
|
||||
|
@ -157,6 +163,68 @@ export function StringParamTextField<
|
|||
);
|
||||
}
|
||||
|
||||
export function StorageAccountDropdown<
|
||||
V extends FormValues,
|
||||
K extends Extract<keyof V, string>
|
||||
>(props: ParamControlProps<V, K>): JSX.Element {
|
||||
const { param } = props;
|
||||
const value = param.value == null ? undefined : String(param.value);
|
||||
|
||||
const [loading, setLoading] = useState<boolean>(true);
|
||||
const [storageAccounts, setStorageAccounts] = useState<StorageAccount[]>(
|
||||
[]
|
||||
);
|
||||
const id = useUniqueId("form-control", props.id);
|
||||
const service: StorageAccountService = inject(
|
||||
BrowserDependencyName.StorageAccountService
|
||||
);
|
||||
const form = param.parentForm;
|
||||
const [subscriptionId, setSubscriptionId] = useState<string>(
|
||||
form.values.subscriptionId as string
|
||||
);
|
||||
const [validationStatus, setValidationStatus] =
|
||||
useState<ValidationStatus | null>();
|
||||
|
||||
useAsyncEffect(async () => {
|
||||
let accounts: StorageAccount[] = [];
|
||||
try {
|
||||
if (subscriptionId) {
|
||||
accounts = await service.list(subscriptionId);
|
||||
}
|
||||
setValidationStatus(null);
|
||||
} catch (error) {
|
||||
setValidationStatus(new ValidationStatus("error", error + ""));
|
||||
} finally {
|
||||
setStorageAccounts(accounts);
|
||||
setLoading(false);
|
||||
}
|
||||
}, [subscriptionId]);
|
||||
|
||||
useEffect(() => {
|
||||
const handler = form.onChange((values: FormValues) =>
|
||||
setSubscriptionId(values.subscriptionId as string)
|
||||
);
|
||||
return () => form.removeOnChange(handler);
|
||||
});
|
||||
|
||||
const options = storageAccounts.map((sub) => {
|
||||
return { value: sub.id, label: sub.name };
|
||||
});
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
id={id}
|
||||
label={param.label}
|
||||
disabled={loading || param.disabled}
|
||||
options={options}
|
||||
placeholder={param.placeholder}
|
||||
value={value}
|
||||
validationStatus={validationStatus ?? param.validationStatus}
|
||||
onChange={(value: string) => (param.value = value as V[K])}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export function SubscriptionIdParamDropdown<
|
||||
V extends FormValues,
|
||||
K extends Extract<keyof V, string>
|
||||
|
@ -183,7 +251,7 @@ export function SubscriptionIdParamDropdown<
|
|||
resolve();
|
||||
}, 1000);
|
||||
});
|
||||
});
|
||||
}, []);
|
||||
|
||||
const options = subscriptions.map((sub) => {
|
||||
return { value: sub.id, label: sub.displayName };
|
||||
|
@ -197,9 +265,7 @@ export function SubscriptionIdParamDropdown<
|
|||
options={options}
|
||||
placeholder={param.placeholder}
|
||||
value={value}
|
||||
onChange={(newValue: string) => {
|
||||
param.value = newValue as V[K];
|
||||
}}
|
||||
onChange={(newValue: string) => (param.value = newValue as V[K])}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import {
|
|||
getEnvironment,
|
||||
} from "@batch/ui-common/lib/environment";
|
||||
import { FormValues } from "@batch/ui-common/lib/form";
|
||||
import { StorageAccountService } from "@batch/ui-service";
|
||||
import {
|
||||
FormLayout,
|
||||
FormLayoutProvider,
|
||||
|
@ -23,6 +24,7 @@ import { MockBrowserEnvironment } from "./mock-browser-environment";
|
|||
export enum BrowserDependencyName {
|
||||
ParameterTypeResolver = "parameterTypeResolver",
|
||||
FormLayoutProvider = "formLayoutProvider",
|
||||
StorageAccountService = "storageAccount",
|
||||
}
|
||||
|
||||
export interface BrowserEnvironment
|
||||
|
@ -42,6 +44,7 @@ export interface BrowserEnvironmentConfig extends EnvironmentConfig {
|
|||
export interface BrowserDependencyFactories extends DependencyFactories {
|
||||
[BrowserDependencyName.ParameterTypeResolver]: () => ParameterTypeResolver;
|
||||
[BrowserDependencyName.FormLayoutProvider]: () => FormLayoutProvider;
|
||||
[BrowserDependencyName.StorageAccountService]: () => StorageAccountService;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -5,6 +5,7 @@ import {
|
|||
mockDependencyFactories,
|
||||
mockEnvironmentConfig,
|
||||
} from "@batch/ui-common/lib/environment";
|
||||
import { FakeStorageAccountService } from "@batch/ui-service";
|
||||
import { initializeIcons } from "@fluentui/react/lib/Icons";
|
||||
import { BrowserEnvironmentConfig } from ".";
|
||||
import {
|
||||
|
@ -17,12 +18,9 @@ import { MockBrowserEnvironment } from "./mock-browser-environment";
|
|||
let _fluentIconsInitialized = false;
|
||||
|
||||
export const mockBrowserDepFactories: Partial<BrowserDependencyFactories> = {
|
||||
parameterTypeResolver: () => {
|
||||
return new DefaultParameterTypeResolver();
|
||||
},
|
||||
formLayoutProvider: () => {
|
||||
return new DefaultFormLayoutProvider();
|
||||
},
|
||||
parameterTypeResolver: () => new DefaultParameterTypeResolver(),
|
||||
formLayoutProvider: () => new DefaultFormLayoutProvider(),
|
||||
storageAccount: () => new FakeStorageAccountService(),
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
export interface ArmResourceListResponse<T> {
|
||||
value: T[];
|
||||
nextLink?: string;
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
export const Endpoints = {
|
||||
arm: `https://management.azure.com`,
|
||||
};
|
||||
|
||||
export const ApiVersion = {
|
||||
arm: `2022-05-01`,
|
||||
batch: {
|
||||
arm: `2022-06-01`,
|
||||
data: `2022-06-01`,
|
||||
},
|
||||
storage: {
|
||||
arm: `2022-05-01`,
|
||||
data: `2022-05-01`,
|
||||
},
|
||||
};
|
|
@ -1,3 +1,5 @@
|
|||
export * from "./http-service";
|
||||
export * from "./view";
|
||||
export * from "./certificate";
|
||||
export * from "./storage";
|
||||
export * from "./subscription";
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
import {
|
||||
initMockEnvironment,
|
||||
getMockEnvironment,
|
||||
} from "@batch/ui-common/lib/environment";
|
||||
import { MockHttpClient, MockHttpResponse } from "@batch/ui-common/lib/http";
|
||||
import { StorageAccountServiceImpl } from "..";
|
||||
import { ApiVersion, Endpoints } from "../../constants";
|
||||
|
||||
describe("StorageAccountService", () => {
|
||||
let httpClient: MockHttpClient;
|
||||
|
||||
beforeEach(() => {
|
||||
initMockEnvironment();
|
||||
httpClient = getMockEnvironment().getHttpClient();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
const assertions = httpClient.remainingAssertions();
|
||||
if (assertions.length > 0) {
|
||||
throw new Error(
|
||||
`HTTP client has untested assertions (${assertions.join(", ")})`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test("list()", async () => {
|
||||
const service = new StorageAccountServiceImpl();
|
||||
|
||||
httpClient.addExpected(
|
||||
new MockHttpResponse(
|
||||
`${Endpoints.arm}/subscriptions//fake/sub1/providers/Microsoft.Storage/storageAccounts?api-version=${ApiVersion.storage.arm}`,
|
||||
200,
|
||||
JSON.stringify({
|
||||
value: [
|
||||
{ id: "1", name: "One" },
|
||||
{ id: "2", name: "Two" },
|
||||
{ id: "3", name: "Three" },
|
||||
],
|
||||
})
|
||||
)
|
||||
);
|
||||
const accounts = await service.list("/fake/sub1");
|
||||
|
||||
expect(accounts.length).toEqual(3);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,47 @@
|
|||
import { StorageAccount } from "./storage-account-models";
|
||||
import { StorageAccountService } from "./storage-account-service";
|
||||
|
||||
const subscriptionAccounts: { [key: string]: StorageAccount[] } = {
|
||||
"/fake/sub1": [
|
||||
{ id: "/fake/storageA", name: "Storage A" },
|
||||
{ id: "/fake/storageB", name: "Storage B" },
|
||||
{ id: "/fake/storageC", name: "Storage C" },
|
||||
],
|
||||
"/fake/sub2": [
|
||||
{ id: "/fake/storageD", name: "Storage D" },
|
||||
{ id: "/fake/storageE", name: "Storage E" },
|
||||
],
|
||||
"/fake/sub3": [
|
||||
{ id: "/fake/storageF", name: "Storage F" },
|
||||
{ id: "/fake/storageG", name: "Storage G" },
|
||||
{ id: "/fake/storageH", name: "Storage H" },
|
||||
{ id: "/fake/storageI", name: "Storage I" },
|
||||
],
|
||||
};
|
||||
|
||||
export class FakeStorageAccountService implements StorageAccountService {
|
||||
public async list(subscriptionId: string): Promise<StorageAccount[]> {
|
||||
if (subscriptionId in subscriptionAccounts) {
|
||||
return subscriptionAccounts[subscriptionId];
|
||||
} else if (subscriptionId === "/fake/badsub") {
|
||||
// Simulates a network error.
|
||||
throw new Error("No storage accounts in subscription.");
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
public async get(): Promise<StorageAccount | null> {
|
||||
return null;
|
||||
}
|
||||
|
||||
public async create(): Promise<void> {
|
||||
return;
|
||||
}
|
||||
public async remove(): Promise<void> {
|
||||
return;
|
||||
}
|
||||
public async update(): Promise<void> {
|
||||
return;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
export * from "./storage-account-service";
|
||||
export * from "./storage-account-models";
|
||||
export * from "./fake-storage-account-service";
|
|
@ -0,0 +1,4 @@
|
|||
export interface StorageAccount {
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
import { ApiVersion, Endpoints } from "../constants";
|
||||
import { AbstractHttpService } from "../http-service";
|
||||
import { ArmResourceListResponse } from "../arm";
|
||||
import { StorageAccount } from "./storage-account-models";
|
||||
|
||||
export interface StorageAccountService {
|
||||
list(subscriptionId: string): Promise<StorageAccount[]>;
|
||||
get(id: string): Promise<StorageAccount | null>;
|
||||
create(account: StorageAccount): Promise<void>;
|
||||
remove(account: StorageAccount): Promise<void>;
|
||||
update(account: StorageAccount): Promise<void>;
|
||||
}
|
||||
|
||||
export class StorageAccountServiceImpl
|
||||
extends AbstractHttpService
|
||||
implements StorageAccountService
|
||||
{
|
||||
public async list(subscriptionId: string): Promise<StorageAccount[]> {
|
||||
const response = await this.httpClient.get(
|
||||
`${Endpoints.arm}/subscriptions/${subscriptionId}/providers/Microsoft.Storage/storageAccounts?api-version=${ApiVersion.storage.arm}`,
|
||||
{}
|
||||
);
|
||||
const json =
|
||||
(await response.json()) as ArmResourceListResponse<StorageAccount>;
|
||||
return json.value;
|
||||
}
|
||||
|
||||
public async get(): Promise<StorageAccount | null> {
|
||||
return null;
|
||||
}
|
||||
|
||||
public async create(): Promise<void> {
|
||||
return;
|
||||
}
|
||||
public async remove(): Promise<void> {
|
||||
return;
|
||||
}
|
||||
public async update(): Promise<void> {
|
||||
return;
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
export * from "./subscription-models";
|
|
@ -0,0 +1,7 @@
|
|||
export interface Subscription {
|
||||
id: string;
|
||||
subscriptionId: string;
|
||||
tenantId: string;
|
||||
displayName: string;
|
||||
state: string;
|
||||
}
|
|
@ -14,6 +14,7 @@ import {
|
|||
DefaultParameterTypeResolver,
|
||||
} from "@batch/ui-react/lib/components/form";
|
||||
import { StandardLocalizer } from "@batch/ui-common/lib/localization";
|
||||
import { FakeStorageAccountService } from "@batch/ui-service";
|
||||
|
||||
// Defined by webpack
|
||||
declare const ENV: {
|
||||
|
@ -30,6 +31,8 @@ export function init(rootEl: HTMLElement): void {
|
|||
[DependencyName.Logger]: () => new ConsoleLogger(),
|
||||
[DependencyName.Localizer]: () => new StandardLocalizer(),
|
||||
[DependencyName.HttpClient]: () => new MockHttpClient(),
|
||||
[BrowserDependencyName.StorageAccountService]: () =>
|
||||
new FakeStorageAccountService(),
|
||||
[BrowserDependencyName.ParameterTypeResolver]: () =>
|
||||
new DefaultParameterTypeResolver(),
|
||||
[BrowserDependencyName.FormLayoutProvider]: () =>
|
||||
|
|
Загрузка…
Ссылка в новой задаче