mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-12-21 09:51:11 +00:00
Migrate Add Database Panel to React (#597)
Co-authored-by: Steve Faulkner <southpolesteve@gmail.com>
This commit is contained in:
@@ -213,6 +213,8 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
||||
this.isFreeTierAccount() && !this.props.explorer.isFirstResourceCreated()
|
||||
}
|
||||
isDatabase={true}
|
||||
isAutoscaleSelected={this.isNewDatabaseAutoscale}
|
||||
throughput={this.newDatabaseThroughput}
|
||||
isSharded={this.state.isSharded}
|
||||
setThroughputValue={(throughput: number) => (this.newDatabaseThroughput = throughput)}
|
||||
setIsAutoscale={(isAutoscale: boolean) => (this.isNewDatabaseAutoscale = isAutoscale)}
|
||||
@@ -442,6 +444,8 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
||||
this.isFreeTierAccount() && !this.props.explorer.isFirstResourceCreated()
|
||||
}
|
||||
isDatabase={false}
|
||||
isAutoscaleSelected={this.isCollectionAutoscale}
|
||||
throughput={this.collectionThroughput}
|
||||
isSharded={this.state.isSharded}
|
||||
setThroughputValue={(throughput: number) => (this.collectionThroughput = throughput)}
|
||||
setIsAutoscale={(isAutoscale: boolean) => (this.isCollectionAutoscale = isAutoscale)}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<div data-bind="visible: visible, event: { keydown: onPaneKeyDown }">
|
||||
<div data-bind="visible: visible, event: { keydown: onPaneKeyDown }">
|
||||
<div class="contextual-pane-out" data-bind="click: cancel, clickBubble: false"></div>
|
||||
<div class="contextual-pane" data-bind="attr: { id: id }">
|
||||
<!-- Add database form -- Start -->
|
||||
@@ -126,31 +126,31 @@
|
||||
<div data-bind="visible: databaseCreateNewShared">
|
||||
<throughput-input-autopilot-v3
|
||||
params="{
|
||||
step: 100,
|
||||
value: throughput,
|
||||
testId: 'sharedThroughputValue',
|
||||
minimum: minThroughputRU,
|
||||
maximum: maxThroughputRU,
|
||||
isEnabled: databaseCreateNewShared,
|
||||
label: throughputRangeText,
|
||||
ariaLabel: throughputRangeText,
|
||||
costsVisible: costsVisible,
|
||||
requestUnitsUsageCost: requestUnitsUsageCost,
|
||||
spendAckChecked: throughputSpendAck,
|
||||
spendAckId: 'throughputSpendAckDatabase',
|
||||
spendAckText: throughputSpendAckText,
|
||||
spendAckVisible: throughputSpendAckVisible,
|
||||
showAsMandatory: true,
|
||||
infoBubbleText: ruToolTipText,
|
||||
throughputAutoPilotRadioId: 'newDatabase-databaseThroughput-autoPilotRadio',
|
||||
throughputProvisionedRadioId: 'newDatabase-databaseThroughput-manualRadio',
|
||||
throughputModeRadioName: 'throughputModeRadioName',
|
||||
isAutoPilotSelected: isAutoPilotSelected,
|
||||
maxAutoPilotThroughputSet: maxAutoPilotThroughputSet,
|
||||
autoPilotUsageCost: autoPilotUsageCost,
|
||||
canExceedMaximumValue: canExceedMaximumValue,
|
||||
freeTierExceedThroughputTooltip: freeTierExceedThroughputTooltip
|
||||
}"
|
||||
step: 100,
|
||||
value: throughput,
|
||||
testId: 'sharedThroughputValue',
|
||||
minimum: minThroughputRU,
|
||||
maximum: maxThroughputRU,
|
||||
isEnabled: databaseCreateNewShared,
|
||||
label: throughputRangeText,
|
||||
ariaLabel: throughputRangeText,
|
||||
costsVisible: costsVisible,
|
||||
requestUnitsUsageCost: requestUnitsUsageCost,
|
||||
spendAckChecked: throughputSpendAck,
|
||||
spendAckId: 'throughputSpendAckDatabase',
|
||||
spendAckText: throughputSpendAckText,
|
||||
spendAckVisible: throughputSpendAckVisible,
|
||||
showAsMandatory: true,
|
||||
infoBubbleText: ruToolTipText,
|
||||
throughputAutoPilotRadioId: 'newDatabase-databaseThroughput-autoPilotRadio',
|
||||
throughputProvisionedRadioId: 'newDatabase-databaseThroughput-manualRadio',
|
||||
throughputModeRadioName: 'throughputModeRadioName',
|
||||
isAutoPilotSelected: isAutoPilotSelected,
|
||||
maxAutoPilotThroughputSet: maxAutoPilotThroughputSet,
|
||||
autoPilotUsageCost: autoPilotUsageCost,
|
||||
canExceedMaximumValue: canExceedMaximumValue,
|
||||
freeTierExceedThroughputTooltip: freeTierExceedThroughputTooltip
|
||||
}"
|
||||
>
|
||||
</throughput-input-autopilot-v3>
|
||||
<p data-bind="visible: canRequestSupport">
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import { shallow } from "enzyme";
|
||||
import React from "react";
|
||||
import Explorer from "../../Explorer";
|
||||
import { AddDatabasePanel } from "./AddDatabasePanel";
|
||||
|
||||
const props = {
|
||||
explorer: new Explorer(),
|
||||
closePanel: (): void => undefined,
|
||||
openNotificationConsole: (): void => undefined,
|
||||
};
|
||||
|
||||
describe("AddDatabasePane Pane", () => {
|
||||
it("should render Default properly", () => {
|
||||
const wrapper = shallow(<AddDatabasePanel {...props} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
342
src/Explorer/Panes/AddDatabasePanel/AddDatabasePanel.tsx
Normal file
342
src/Explorer/Panes/AddDatabasePanel/AddDatabasePanel.tsx
Normal file
@@ -0,0 +1,342 @@
|
||||
import { Checkbox, Text, TextField } from "@fluentui/react";
|
||||
import React, { FunctionComponent, useEffect, useState } from "react";
|
||||
import * as Constants from "../../../Common/Constants";
|
||||
import { createDatabase } from "../../../Common/dataAccess/createDatabase";
|
||||
import { getErrorMessage, getErrorStack } from "../../../Common/ErrorHandlingUtils";
|
||||
import { InfoTooltip } from "../../../Common/Tooltip/InfoTooltip";
|
||||
import { configContext, Platform } from "../../../ConfigContext";
|
||||
import * as DataModels from "../../../Contracts/DataModels";
|
||||
import { SubscriptionType } from "../../../Contracts/SubscriptionType";
|
||||
import * as SharedConstants from "../../../Shared/Constants";
|
||||
import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
|
||||
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
|
||||
import { userContext } from "../../../UserContext";
|
||||
import * as AutoPilotUtils from "../../../Utils/AutoPilotUtils";
|
||||
import * as PricingUtils from "../../../Utils/PricingUtils";
|
||||
import { ThroughputInput } from "../../Controls/ThroughputInput/ThroughputInput";
|
||||
import Explorer from "../../Explorer";
|
||||
import { PanelInfoErrorComponent } from "../PanelInfoErrorComponent";
|
||||
import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneForm";
|
||||
|
||||
export interface AddDatabasePaneProps {
|
||||
explorer: Explorer;
|
||||
closePanel: () => void;
|
||||
openNotificationConsole: () => void;
|
||||
}
|
||||
|
||||
export const AddDatabasePanel: FunctionComponent<AddDatabasePaneProps> = ({
|
||||
explorer: container,
|
||||
closePanel,
|
||||
openNotificationConsole,
|
||||
}: AddDatabasePaneProps) => {
|
||||
const { subscriptionType } = userContext;
|
||||
const getSharedThroughputDefault = !(subscriptionType === SubscriptionType.EA || container.isServerlessEnabled());
|
||||
const _isAutoPilotSelectedAndWhatTier = (): DataModels.AutoPilotCreationSettings => {
|
||||
if (isAutoPilotSelected && maxAutoPilotThroughputSet) {
|
||||
return {
|
||||
maxThroughput: maxAutoPilotThroughputSet * 1,
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
const isCassandraAccount: boolean = userContext.apiType === "Cassandra";
|
||||
const databaseLabel: string = isCassandraAccount ? "keyspace" : "database";
|
||||
const collectionsLabel: string = isCassandraAccount ? "tables" : "collections";
|
||||
const databaseIdLabel: string = isCassandraAccount ? "Keyspace id" : "Database id";
|
||||
const databaseIdPlaceHolder: string = isCassandraAccount ? "Type a new keyspace id" : "Type a new database id";
|
||||
|
||||
const [databaseId, setDatabaseId] = useState<string>("");
|
||||
const databaseIdTooltipText = `A ${
|
||||
isCassandraAccount ? "keyspace" : "database"
|
||||
} is a logical container of one or more ${isCassandraAccount ? "tables" : "collections"}`;
|
||||
|
||||
const databaseLevelThroughputTooltipText = `Provisioned throughput at the ${databaseLabel} level will be shared across all ${collectionsLabel} within the ${databaseLabel}.`;
|
||||
const [databaseCreateNewShared, setDatabaseCreateNewShared] = useState<boolean>(getSharedThroughputDefault);
|
||||
const [formErrorsDetails, setFormErrorsDetails] = useState<string>();
|
||||
const [formErrors, setFormErrors] = useState<string>("");
|
||||
|
||||
const [isAutoPilotSelected, setIsAutoPilotSelected] = useState<boolean>(container.isAutoscaleDefaultEnabled());
|
||||
|
||||
const throughputDefaults = container.collectionCreationDefaults.throughput;
|
||||
const [throughput, setThroughput] = useState<number>(
|
||||
isAutoPilotSelected ? AutoPilotUtils.minAutoPilotThroughput : throughputDefaults.shared
|
||||
);
|
||||
|
||||
const [throughputSpendAck, setThroughputSpendAck] = useState<boolean>(false);
|
||||
|
||||
const canRequestSupport = () => {
|
||||
if (
|
||||
configContext.platform !== Platform.Emulator &&
|
||||
!userContext.isTryCosmosDBSubscription &&
|
||||
configContext.platform !== Platform.Portal
|
||||
) {
|
||||
const offerThroughput: number = throughput;
|
||||
return offerThroughput <= 100000;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
const isFreeTierAccount: boolean = userContext.databaseAccount?.properties?.enableFreeTier;
|
||||
const upsellMessage: string = PricingUtils.getUpsellMessage(
|
||||
userContext.portalEnv,
|
||||
isFreeTierAccount,
|
||||
container.isFirstResourceCreated(),
|
||||
false
|
||||
);
|
||||
|
||||
const upsellAnchorUrl: string = isFreeTierAccount ? Constants.Urls.freeTierInformation : Constants.Urls.cosmosPricing;
|
||||
|
||||
const upsellAnchorText: string = isFreeTierAccount ? "Learn more" : "More details";
|
||||
const maxAutoPilotThroughputSet = AutoPilotUtils.minAutoPilotThroughput;
|
||||
|
||||
const canConfigureThroughput = !container.isServerlessEnabled();
|
||||
const showUpsellMessage = () => {
|
||||
if (container.isServerlessEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isFreeTierAccount) {
|
||||
return databaseCreateNewShared;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
const [isExecuting, setIsExecuting] = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
setDatabaseCreateNewShared(getSharedThroughputDefault);
|
||||
}, [subscriptionType]);
|
||||
|
||||
const addDatabasePaneMessage = {
|
||||
database: {
|
||||
id: databaseId,
|
||||
shared: databaseCreateNewShared,
|
||||
},
|
||||
subscriptionType: SubscriptionType[subscriptionType],
|
||||
subscriptionQuotaId: userContext.quotaId,
|
||||
defaultsCheck: {
|
||||
flight: userContext.addCollectionFlight,
|
||||
},
|
||||
dataExplorerArea: Constants.Areas.ContextualPane,
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const addDatabasePaneOpenMessage = {
|
||||
subscriptionType: SubscriptionType[subscriptionType],
|
||||
subscriptionQuotaId: userContext.quotaId,
|
||||
defaultsCheck: {
|
||||
throughput: throughput,
|
||||
flight: userContext.addCollectionFlight,
|
||||
},
|
||||
dataExplorerArea: Constants.Areas.ContextualPane,
|
||||
};
|
||||
TelemetryProcessor.trace(Action.CreateDatabase, ActionModifiers.Open, addDatabasePaneOpenMessage);
|
||||
}, []);
|
||||
|
||||
const onSubmit = () => {
|
||||
if (!_isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const offerThroughput: number = _computeOfferThroughput();
|
||||
|
||||
const addDatabasePaneStartMessage = {
|
||||
...addDatabasePaneMessage,
|
||||
offerThroughput,
|
||||
};
|
||||
const startKey: number = TelemetryProcessor.traceStart(Action.CreateDatabase, addDatabasePaneStartMessage);
|
||||
setFormErrors("");
|
||||
setIsExecuting(true);
|
||||
|
||||
const createDatabaseParams: DataModels.CreateDatabaseParams = {
|
||||
databaseId: addDatabasePaneStartMessage.database.id,
|
||||
databaseLevelThroughput: addDatabasePaneStartMessage.database.shared,
|
||||
};
|
||||
if (isAutoPilotSelected) {
|
||||
createDatabaseParams.autoPilotMaxThroughput = addDatabasePaneStartMessage.offerThroughput;
|
||||
} else {
|
||||
createDatabaseParams.offerThroughput = addDatabasePaneStartMessage.offerThroughput;
|
||||
}
|
||||
|
||||
createDatabase(createDatabaseParams).then(
|
||||
() => {
|
||||
_onCreateDatabaseSuccess(offerThroughput, startKey);
|
||||
},
|
||||
(error: string) => {
|
||||
_onCreateDatabaseFailure(error, offerThroughput, startKey);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const _onCreateDatabaseSuccess = (offerThroughput: number, startKey: number): void => {
|
||||
setIsExecuting(false);
|
||||
closePanel();
|
||||
container.refreshAllDatabases();
|
||||
const addDatabasePaneSuccessMessage = {
|
||||
...addDatabasePaneMessage,
|
||||
offerThroughput,
|
||||
};
|
||||
TelemetryProcessor.traceSuccess(Action.CreateDatabase, addDatabasePaneSuccessMessage, startKey);
|
||||
};
|
||||
|
||||
const _onCreateDatabaseFailure = (error: string, offerThroughput: number, startKey: number): void => {
|
||||
setIsExecuting(false);
|
||||
const errorMessage = getErrorMessage(error);
|
||||
setFormErrors(errorMessage);
|
||||
setFormErrorsDetails(errorMessage);
|
||||
const addDatabasePaneFailedMessage = {
|
||||
...addDatabasePaneMessage,
|
||||
offerThroughput,
|
||||
error: errorMessage,
|
||||
errorStack: getErrorStack(error),
|
||||
};
|
||||
TelemetryProcessor.traceFailure(Action.CreateDatabase, addDatabasePaneFailedMessage, startKey);
|
||||
};
|
||||
|
||||
const _getThroughput = (): number => {
|
||||
return isNaN(throughput) ? 0 : Number(throughput);
|
||||
};
|
||||
|
||||
const _computeOfferThroughput = (): number => {
|
||||
if (!canConfigureThroughput) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return _getThroughput();
|
||||
};
|
||||
|
||||
const _isValid = (): boolean => {
|
||||
// TODO add feature flag that disables validation for customers with custom accounts
|
||||
if (isAutoPilotSelected) {
|
||||
const autoPilot = _isAutoPilotSelectedAndWhatTier();
|
||||
if (
|
||||
!autoPilot ||
|
||||
!autoPilot.maxThroughput ||
|
||||
!AutoPilotUtils.isValidAutoPilotThroughput(autoPilot.maxThroughput)
|
||||
) {
|
||||
setFormErrors(
|
||||
`Please enter a value greater than ${AutoPilotUtils.minAutoPilotThroughput} for autopilot throughput`
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
const throughput = _getThroughput();
|
||||
|
||||
if (throughput > SharedConstants.CollectionCreation.DefaultCollectionRUs100K && !throughputSpendAck) {
|
||||
setFormErrors(`Please acknowledge the estimated daily spend.`);
|
||||
return false;
|
||||
}
|
||||
|
||||
const autoscaleThroughput = maxAutoPilotThroughputSet * 1;
|
||||
|
||||
if (
|
||||
isAutoPilotSelected &&
|
||||
autoscaleThroughput > SharedConstants.CollectionCreation.DefaultCollectionRUs100K &&
|
||||
!throughputSpendAck
|
||||
) {
|
||||
setFormErrors(`Please acknowledge the estimated monthly spend.`);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
const handleonChangeDBId = React.useCallback(
|
||||
(event: React.FormEvent<HTMLInputElement | HTMLTextAreaElement>, newValue?: string) => {
|
||||
setDatabaseId(newValue || "");
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const props: RightPaneFormProps = {
|
||||
expandConsole: container.expandConsole,
|
||||
formError: formErrors,
|
||||
formErrorDetail: formErrorsDetails,
|
||||
isExecuting,
|
||||
submitButtonText: "OK",
|
||||
onSubmit,
|
||||
};
|
||||
|
||||
return (
|
||||
<RightPaneForm {...props}>
|
||||
<div className="paneContentContainer" role="dialog" aria-labelledby="databaseTitle">
|
||||
{showUpsellMessage && formErrors === "" && (
|
||||
<PanelInfoErrorComponent
|
||||
message={upsellMessage}
|
||||
messageType="info"
|
||||
showErrorDetails={false}
|
||||
openNotificationConsole={openNotificationConsole}
|
||||
link={upsellAnchorUrl}
|
||||
linkText={upsellAnchorText}
|
||||
/>
|
||||
)}
|
||||
<div className="paneMainContent">
|
||||
<div>
|
||||
<p>
|
||||
<span className="mandatoryStar">*</span>
|
||||
<Text variant="small">{databaseIdLabel}</Text>
|
||||
<InfoTooltip>{databaseIdTooltipText}</InfoTooltip>
|
||||
</p>
|
||||
|
||||
<TextField
|
||||
id="database-id"
|
||||
type="text"
|
||||
aria-required="true"
|
||||
autoComplete="off"
|
||||
pattern="[^/?#\\]*[^/?# \\]"
|
||||
title="May not end with space nor contain characters '\' '/' '#' '?'"
|
||||
size={40}
|
||||
aria-label={databaseIdLabel}
|
||||
placeholder={databaseIdPlaceHolder}
|
||||
value={databaseId}
|
||||
onChange={handleonChangeDBId}
|
||||
autoFocus
|
||||
/>
|
||||
|
||||
<div
|
||||
className="databaseProvision"
|
||||
aria-label="New database provision support"
|
||||
style={{ display: "block ruby" }}
|
||||
>
|
||||
<Checkbox
|
||||
title="Provision shared throughput"
|
||||
styles={{
|
||||
checkbox: { width: 12, height: 12 },
|
||||
label: { padding: 0, alignItems: "center" },
|
||||
}}
|
||||
label="Provision throughput"
|
||||
checked={databaseCreateNewShared}
|
||||
onChange={() => setDatabaseCreateNewShared(!databaseCreateNewShared)}
|
||||
/>{" "}
|
||||
<InfoTooltip>{databaseLevelThroughputTooltipText}</InfoTooltip>
|
||||
</div>
|
||||
{databaseCreateNewShared && (
|
||||
<div>
|
||||
<ThroughputInput
|
||||
showFreeTierExceedThroughputTooltip={isFreeTierAccount && !container?.isFirstResourceCreated()}
|
||||
isDatabase={true}
|
||||
isSharded={databaseCreateNewShared}
|
||||
isAutoscaleSelected={isAutoPilotSelected}
|
||||
throughput={throughput}
|
||||
setThroughputValue={(throughput: number) => setThroughput(throughput)}
|
||||
setIsAutoscale={(isAutoscale: boolean) => setIsAutoPilotSelected(isAutoscale)}
|
||||
onCostAcknowledgeChange={(isAcknowledged: boolean) => setThroughputSpendAck(isAcknowledged)}
|
||||
/>
|
||||
|
||||
{canRequestSupport() && (
|
||||
<p>
|
||||
<a href="https://aka.ms/cosmosdbfeedback?subject=Cosmos%20DB%20More%20Throughput%20Request">
|
||||
Contact support{" "}
|
||||
</a>
|
||||
for more than <span>{throughputDefaults.unlimitedmax?.toLocaleString()} </span> RU/s.
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</RightPaneForm>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,104 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`AddDatabasePane Pane should render Default properly 1`] = `
|
||||
<RightPaneForm
|
||||
expandConsole={[Function]}
|
||||
formError=""
|
||||
isExecuting={false}
|
||||
onSubmit={[Function]}
|
||||
submitButtonText="OK"
|
||||
>
|
||||
<div
|
||||
aria-labelledby="databaseTitle"
|
||||
className="paneContentContainer"
|
||||
role="dialog"
|
||||
>
|
||||
<PanelInfoErrorComponent
|
||||
link="https://aka.ms/azure-cosmos-db-pricing"
|
||||
linkText="More details"
|
||||
message="Start at $24/mo per database, multiple containers included"
|
||||
messageType="info"
|
||||
openNotificationConsole={[Function]}
|
||||
showErrorDetails={false}
|
||||
/>
|
||||
<div
|
||||
className="paneMainContent"
|
||||
>
|
||||
<div>
|
||||
<p>
|
||||
<span
|
||||
className="mandatoryStar"
|
||||
>
|
||||
*
|
||||
</span>
|
||||
<Text
|
||||
variant="small"
|
||||
>
|
||||
Database id
|
||||
</Text>
|
||||
<InfoTooltip>
|
||||
A database is a logical container of one or more collections
|
||||
</InfoTooltip>
|
||||
</p>
|
||||
<StyledTextFieldBase
|
||||
aria-label="Database id"
|
||||
aria-required="true"
|
||||
autoComplete="off"
|
||||
autoFocus={true}
|
||||
id="database-id"
|
||||
onChange={[Function]}
|
||||
pattern="[^/?#\\\\\\\\]*[^/?# \\\\\\\\]"
|
||||
placeholder="Type a new database id"
|
||||
size={40}
|
||||
title="May not end with space nor contain characters '\\\\' '/' '#' '?'"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<div
|
||||
aria-label="New database provision support"
|
||||
className="databaseProvision"
|
||||
style={
|
||||
Object {
|
||||
"display": "block ruby",
|
||||
}
|
||||
}
|
||||
>
|
||||
<StyledCheckboxBase
|
||||
checked={true}
|
||||
label="Provision throughput"
|
||||
onChange={[Function]}
|
||||
styles={
|
||||
Object {
|
||||
"checkbox": Object {
|
||||
"height": 12,
|
||||
"width": 12,
|
||||
},
|
||||
"label": Object {
|
||||
"alignItems": "center",
|
||||
"padding": 0,
|
||||
},
|
||||
}
|
||||
}
|
||||
title="Provision shared throughput"
|
||||
/>
|
||||
|
||||
<InfoTooltip>
|
||||
Provisioned throughput at the database level will be shared across all collections within the database.
|
||||
</InfoTooltip>
|
||||
</div>
|
||||
<div>
|
||||
<ThroughputInput
|
||||
isAutoscaleSelected={false}
|
||||
isDatabase={true}
|
||||
isSharded={true}
|
||||
onCostAcknowledgeChange={[Function]}
|
||||
setIsAutoscale={[Function]}
|
||||
setThroughputValue={[Function]}
|
||||
throughput={400}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</RightPaneForm>
|
||||
`;
|
||||
@@ -17,7 +17,6 @@ export class AddDatabasePaneComponent {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class AddCollectionPaneComponent {
|
||||
constructor() {
|
||||
return {
|
||||
|
||||
@@ -9,12 +9,6 @@ export const PanelFooterComponent: React.FunctionComponent<PanelFooterProps> = (
|
||||
buttonLabel,
|
||||
}: PanelFooterProps): JSX.Element => (
|
||||
<div className="panelFooter">
|
||||
<PrimaryButton
|
||||
type="submit"
|
||||
id="sidePanelOkButton"
|
||||
text={buttonLabel}
|
||||
ariaLabel={buttonLabel}
|
||||
data-testid="submit"
|
||||
/>
|
||||
<PrimaryButton type="submit" id="sidePanelOkButton" text={buttonLabel} ariaLabel={buttonLabel} />
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -22,19 +22,19 @@ export const PanelInfoErrorComponent: React.FunctionComponent<PanelInfoErrorProp
|
||||
}: PanelInfoErrorProps): JSX.Element => {
|
||||
let icon: JSX.Element;
|
||||
if (messageType === "error") {
|
||||
icon = <Icon iconName="StatusErrorFull" className="panelErrorIcon" data-testid="errorIcon" />;
|
||||
icon = <Icon iconName="StatusErrorFull" className="panelErrorIcon" aria-label="error" />;
|
||||
} else if (messageType === "warning") {
|
||||
icon = <Icon iconName="WarningSolid" className="panelWarningIcon" data-testid="warningIcon" />;
|
||||
icon = <Icon iconName="WarningSolid" className="panelWarningIcon" aria-label="warning" />;
|
||||
} else if (messageType === "info") {
|
||||
icon = <Icon iconName="InfoSolid" className="panelLargeInfoIcon" data-testid="InfoIcon" />;
|
||||
icon = <Icon iconName="InfoSolid" className="panelLargeInfoIcon" aria-label="Infomation" />;
|
||||
}
|
||||
|
||||
return (
|
||||
formError && (
|
||||
<Stack className="panelInfoErrorContainer" horizontal verticalAlign="start">
|
||||
<Stack className="panelInfoErrorContainer" horizontal verticalAlign="center">
|
||||
{icon}
|
||||
<span className="panelWarningErrorDetailsLinkContainer">
|
||||
<Text className="panelWarningErrorMessage" variant="small" data-testid="panelmessage">
|
||||
<Text className="panelWarningErrorMessage" variant="small" aria-label="message">
|
||||
{message}
|
||||
{link && linkText && (
|
||||
<Link target="_blank" href={link}>
|
||||
|
||||
@@ -3,48 +3,38 @@ import { mount, ReactWrapper } from "enzyme";
|
||||
import React from "react";
|
||||
import { RightPaneForm } from "./RightPaneForm";
|
||||
|
||||
const onClose = jest.fn();
|
||||
const onSubmit = jest.fn();
|
||||
const expandConsole = jest.fn();
|
||||
|
||||
const props = {
|
||||
closePanel: (): void => undefined,
|
||||
expandConsole,
|
||||
formError: "",
|
||||
formErrorDetail: "",
|
||||
id: "loadQueryPane",
|
||||
isExecuting: false,
|
||||
title: "Load Query Pane",
|
||||
submitButtonText: "Load",
|
||||
onClose,
|
||||
onSubmit,
|
||||
};
|
||||
|
||||
describe("Load Query Pane", () => {
|
||||
describe("Right Pane Form", () => {
|
||||
let wrapper: ReactWrapper;
|
||||
|
||||
it("should render Default properly", () => {
|
||||
wrapper = mount(<RightPaneForm {...props} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
it("should call close method click cancel icon", () => {
|
||||
render(<RightPaneForm {...props} />);
|
||||
fireEvent.click(screen.getByTestId("closePaneBtn"));
|
||||
expect(onClose).toHaveBeenCalled();
|
||||
});
|
||||
it("should call submit method enter in form", () => {
|
||||
render(<RightPaneForm {...props} />);
|
||||
fireEvent.click(screen.getByTestId("submit"));
|
||||
fireEvent.click(screen.getByLabelText("Load"));
|
||||
expect(onSubmit).toHaveBeenCalled();
|
||||
});
|
||||
it("should call submit method click on submit button", () => {
|
||||
render(<RightPaneForm {...props} />);
|
||||
fireEvent.click(screen.getByTestId("submit"));
|
||||
fireEvent.click(screen.getByLabelText("Load"));
|
||||
expect(onSubmit).toHaveBeenCalled();
|
||||
});
|
||||
it("should render error in header", () => {
|
||||
render(<RightPaneForm {...props} formError="file already Exist" />);
|
||||
expect(screen.getByTestId("errorIcon")).toBeDefined();
|
||||
expect(screen.getByTestId("panelmessage").innerHTML).toEqual("file already Exist");
|
||||
expect(screen.getByLabelText("error")).toBeDefined();
|
||||
expect(screen.getByLabelText("message").innerHTML).toEqual("file already Exist");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import { IconButton } from "@fluentui/react";
|
||||
import React, { FunctionComponent, ReactNode } from "react";
|
||||
import { KeyCodes } from "../../../Common/Constants";
|
||||
import { PanelFooterComponent } from "../PanelFooterComponent";
|
||||
import { PanelInfoErrorComponent, PanelInfoErrorProps } from "../PanelInfoErrorComponent";
|
||||
import { PanelLoadingScreen } from "../PanelLoadingScreen";
|
||||
@@ -9,12 +7,9 @@ export interface RightPaneFormProps {
|
||||
expandConsole: () => void;
|
||||
formError: string;
|
||||
formErrorDetail: string;
|
||||
id: string;
|
||||
isExecuting: boolean;
|
||||
onClose: () => void;
|
||||
onSubmit: () => void;
|
||||
submitButtonText: string;
|
||||
title: string;
|
||||
isSubmitButtonHidden?: boolean;
|
||||
children?: ReactNode;
|
||||
}
|
||||
@@ -23,51 +18,16 @@ export const RightPaneForm: FunctionComponent<RightPaneFormProps> = ({
|
||||
expandConsole,
|
||||
formError,
|
||||
formErrorDetail,
|
||||
id,
|
||||
isExecuting,
|
||||
onClose,
|
||||
onSubmit,
|
||||
submitButtonText,
|
||||
title,
|
||||
isSubmitButtonHidden = false,
|
||||
children,
|
||||
}: RightPaneFormProps) => {
|
||||
const getPanelHeight = (): number => {
|
||||
const notificationConsoleElement: HTMLElement = document.getElementById("explorerNotificationConsole");
|
||||
return window.innerHeight - $(notificationConsoleElement).height();
|
||||
};
|
||||
|
||||
const panelHeight: number = getPanelHeight();
|
||||
|
||||
const handleOnSubmit = (event: React.FormEvent<HTMLFormElement>) => {
|
||||
event.preventDefault();
|
||||
onSubmit();
|
||||
};
|
||||
const renderPanelHeader = (): JSX.Element => {
|
||||
return (
|
||||
<div className="firstdivbg headerline">
|
||||
<span id="databaseTitle" role="heading" aria-level={2}>
|
||||
{title}
|
||||
</span>
|
||||
<IconButton
|
||||
ariaLabel="Close pane"
|
||||
title="Close pane"
|
||||
data-testid="closePaneBtn"
|
||||
onClick={onClose}
|
||||
tabIndex={0}
|
||||
className="closePaneBtn"
|
||||
iconProps={{ iconName: "Cancel" }}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const onKeyDown = (event: React.KeyboardEvent<HTMLDivElement>): void => {
|
||||
if (event.keyCode === KeyCodes.Escape) {
|
||||
onClose();
|
||||
event.stopPropagation();
|
||||
}
|
||||
};
|
||||
|
||||
const panelInfoErrorProps: PanelInfoErrorProps = {
|
||||
messageType: "error",
|
||||
@@ -78,19 +38,13 @@ export const RightPaneForm: FunctionComponent<RightPaneFormProps> = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<div tabIndex={-1} onKeyDown={onKeyDown}>
|
||||
<div className="contextual-pane-out" onClick={onClose}></div>
|
||||
<div className="contextual-pane" id={id} style={{ height: panelHeight }} onKeyDown={onKeyDown}>
|
||||
<div className="panelContentWrapper">
|
||||
{renderPanelHeader()}
|
||||
<PanelInfoErrorComponent {...panelInfoErrorProps} />
|
||||
<form className="panelFormWrapper" onSubmit={handleOnSubmit}>
|
||||
{children}
|
||||
{!isSubmitButtonHidden && <PanelFooterComponent buttonLabel={submitButtonText} />}
|
||||
</form>
|
||||
</div>
|
||||
{isExecuting && <PanelLoadingScreen />}
|
||||
</div>
|
||||
</div>
|
||||
<>
|
||||
<PanelInfoErrorComponent {...panelInfoErrorProps} />
|
||||
<form className="panelFormWrapper" onSubmit={handleOnSubmit}>
|
||||
{children}
|
||||
{!isSubmitButtonHidden && <PanelFooterComponent buttonLabel={submitButtonText} />}
|
||||
</form>
|
||||
{isExecuting && <PanelLoadingScreen />}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,16 +1,13 @@
|
||||
import { Checkbox, ChoiceGroup, IChoiceGroupOption, SpinButton } from "@fluentui/react";
|
||||
import React, { FunctionComponent, MouseEvent, useState } from "react";
|
||||
import * as Constants from "../../../Common/Constants";
|
||||
import { Tooltip } from "../../../Common/Tooltip/Tooltip";
|
||||
import { InfoTooltip } from "../../../Common/Tooltip/InfoTooltip";
|
||||
import { configContext } from "../../../ConfigContext";
|
||||
import { LocalStorageUtility, StorageKey } from "../../../Shared/StorageUtility";
|
||||
import * as StringUtility from "../../../Shared/StringUtility";
|
||||
import { userContext } from "../../../UserContext";
|
||||
import { logConsoleInfo } from "../../../Utils/NotificationConsoleUtils";
|
||||
import {
|
||||
GenericRightPaneComponent,
|
||||
GenericRightPaneProps,
|
||||
} from "../GenericRightPaneComponent/GenericRightPaneComponent";
|
||||
import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneForm";
|
||||
|
||||
export interface SettingsPaneProps {
|
||||
expandConsole: () => void;
|
||||
@@ -105,15 +102,12 @@ export const SettingsPane: FunctionComponent<SettingsPaneProps> = ({
|
||||
setGraphAutoVizDisabled(option.key);
|
||||
};
|
||||
|
||||
const genericPaneProps: GenericRightPaneProps = {
|
||||
const genericPaneProps: RightPaneFormProps = {
|
||||
expandConsole,
|
||||
formError: formErrors,
|
||||
formErrorDetail: "",
|
||||
id: "settingspane",
|
||||
isExecuting,
|
||||
title: "Setting",
|
||||
submitButtonText: "Apply",
|
||||
onClose: () => closePanel(),
|
||||
onSubmit: () => handlerOnSubmit(undefined),
|
||||
};
|
||||
const pageOptionList: IChoiceGroupOption[] = [
|
||||
@@ -130,17 +124,17 @@ export const SettingsPane: FunctionComponent<SettingsPaneProps> = ({
|
||||
setPageOption(option.key);
|
||||
};
|
||||
return (
|
||||
<GenericRightPaneComponent {...genericPaneProps}>
|
||||
<RightPaneForm {...genericPaneProps}>
|
||||
<div className="paneMainContent">
|
||||
{shouldShowQueryPageOptions && (
|
||||
<div className="settingsSection">
|
||||
<div className="settingsSectionPart pageOptionsPart">
|
||||
<div className="settingsSectionLabel">
|
||||
Page options
|
||||
<Tooltip>
|
||||
<InfoTooltip>
|
||||
Choose Custom to specify a fixed amount of query results to show, or choose Unlimited to show as many
|
||||
query results per page.
|
||||
</Tooltip>
|
||||
</InfoTooltip>
|
||||
</div>
|
||||
<ChoiceGroup selectedKey={pageOption} options={pageOptionList} onChange={handleOnPageOptionChange} />
|
||||
</div>
|
||||
@@ -149,7 +143,7 @@ export const SettingsPane: FunctionComponent<SettingsPaneProps> = ({
|
||||
<div className="tabcontent">
|
||||
<div className="settingsSectionLabel">
|
||||
Query results per page
|
||||
<Tooltip>Enter the number of query results that should be shown per page.</Tooltip>
|
||||
<InfoTooltip>Enter the number of query results that should be shown per page.</InfoTooltip>
|
||||
</div>
|
||||
|
||||
<SpinButton
|
||||
@@ -176,10 +170,10 @@ export const SettingsPane: FunctionComponent<SettingsPaneProps> = ({
|
||||
<div className="settingsSectionPart">
|
||||
<div className="settingsSectionLabel">
|
||||
Enable cross-partition query
|
||||
<Tooltip>
|
||||
<InfoTooltip>
|
||||
Send more than one request while executing a query. More than one request is necessary if the query is
|
||||
not scoped to single partition key value.
|
||||
</Tooltip>
|
||||
</InfoTooltip>
|
||||
</div>
|
||||
|
||||
<Checkbox
|
||||
@@ -199,11 +193,11 @@ export const SettingsPane: FunctionComponent<SettingsPaneProps> = ({
|
||||
<div className="settingsSectionPart">
|
||||
<div className="settingsSectionLabel">
|
||||
Max degree of parallelism
|
||||
<Tooltip>
|
||||
<InfoTooltip>
|
||||
Gets or sets the number of concurrent operations run client side during parallel query execution. A
|
||||
positive property value limits the number of concurrent operations to the set value. If it is set to
|
||||
less than 0, the system automatically decides the number of concurrent operations to run.
|
||||
</Tooltip>
|
||||
</InfoTooltip>
|
||||
</div>
|
||||
|
||||
<SpinButton
|
||||
@@ -227,10 +221,10 @@ export const SettingsPane: FunctionComponent<SettingsPaneProps> = ({
|
||||
<div className="settingsSectionPart">
|
||||
<div className="settingsSectionLabel">
|
||||
Display Gremlin query results as:
|
||||
<Tooltip>
|
||||
<InfoTooltip>
|
||||
Select Graph to automatically visualize the query results as a Graph or JSON to display the results as
|
||||
JSON.
|
||||
</Tooltip>
|
||||
</InfoTooltip>
|
||||
</div>
|
||||
|
||||
<ChoiceGroup
|
||||
@@ -249,6 +243,6 @@ export const SettingsPane: FunctionComponent<SettingsPaneProps> = ({
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</GenericRightPaneComponent>
|
||||
</RightPaneForm>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Settings Pane should render Default properly 1`] = `
|
||||
<GenericRightPaneComponent
|
||||
<RightPaneForm
|
||||
expandConsole={[Function]}
|
||||
formError=""
|
||||
formErrorDetail=""
|
||||
id="settingspane"
|
||||
isExecuting={false}
|
||||
onClose={[Function]}
|
||||
onSubmit={[Function]}
|
||||
submitButtonText="Apply"
|
||||
title="Setting"
|
||||
>
|
||||
<div
|
||||
className="paneMainContent"
|
||||
@@ -25,9 +22,9 @@ exports[`Settings Pane should render Default properly 1`] = `
|
||||
className="settingsSectionLabel"
|
||||
>
|
||||
Page options
|
||||
<Tooltip>
|
||||
<InfoTooltip>
|
||||
Choose Custom to specify a fixed amount of query results to show, or choose Unlimited to show as many query results per page.
|
||||
</Tooltip>
|
||||
</InfoTooltip>
|
||||
</div>
|
||||
<StyledChoiceGroup
|
||||
onChange={[Function]}
|
||||
@@ -56,9 +53,9 @@ exports[`Settings Pane should render Default properly 1`] = `
|
||||
className="settingsSectionLabel"
|
||||
>
|
||||
Query results per page
|
||||
<Tooltip>
|
||||
<InfoTooltip>
|
||||
Enter the number of query results that should be shown per page.
|
||||
</Tooltip>
|
||||
</InfoTooltip>
|
||||
</div>
|
||||
<StyledSpinButton
|
||||
ariaLabel="Custom query items per page"
|
||||
@@ -85,9 +82,9 @@ exports[`Settings Pane should render Default properly 1`] = `
|
||||
className="settingsSectionLabel"
|
||||
>
|
||||
Enable cross-partition query
|
||||
<Tooltip>
|
||||
<InfoTooltip>
|
||||
Send more than one request while executing a query. More than one request is necessary if the query is not scoped to single partition key value.
|
||||
</Tooltip>
|
||||
</InfoTooltip>
|
||||
</div>
|
||||
<StyledCheckboxBase
|
||||
ariaLabel="Enable cross partition query"
|
||||
@@ -114,9 +111,9 @@ exports[`Settings Pane should render Default properly 1`] = `
|
||||
className="settingsSectionLabel"
|
||||
>
|
||||
Max degree of parallelism
|
||||
<Tooltip>
|
||||
<InfoTooltip>
|
||||
Gets or sets the number of concurrent operations run client side during parallel query execution. A positive property value limits the number of concurrent operations to the set value. If it is set to less than 0, the system automatically decides the number of concurrent operations to run.
|
||||
</Tooltip>
|
||||
</InfoTooltip>
|
||||
</div>
|
||||
<StyledSpinButton
|
||||
ariaLabel="Max degree of parallelism"
|
||||
@@ -148,20 +145,17 @@ exports[`Settings Pane should render Default properly 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</GenericRightPaneComponent>
|
||||
</RightPaneForm>
|
||||
`;
|
||||
|
||||
exports[`Settings Pane should render Gremlin properly 1`] = `
|
||||
<GenericRightPaneComponent
|
||||
<RightPaneForm
|
||||
expandConsole={[Function]}
|
||||
formError=""
|
||||
formErrorDetail=""
|
||||
id="settingspane"
|
||||
isExecuting={false}
|
||||
onClose={[Function]}
|
||||
onSubmit={[Function]}
|
||||
submitButtonText="Apply"
|
||||
title="Setting"
|
||||
>
|
||||
<div
|
||||
className="paneMainContent"
|
||||
@@ -176,9 +170,9 @@ exports[`Settings Pane should render Gremlin properly 1`] = `
|
||||
className="settingsSectionLabel"
|
||||
>
|
||||
Display Gremlin query results as:
|
||||
<Tooltip>
|
||||
<InfoTooltip>
|
||||
Select Graph to automatically visualize the query results as a Graph or JSON to display the results as JSON.
|
||||
</Tooltip>
|
||||
</InfoTooltip>
|
||||
</div>
|
||||
<StyledChoiceGroup
|
||||
aria-label="Graph Auto-visualization"
|
||||
@@ -214,5 +208,5 @@ exports[`Settings Pane should render Gremlin properly 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</GenericRightPaneComponent>
|
||||
</RightPaneForm>
|
||||
`;
|
||||
|
||||
@@ -15,9 +15,6 @@ export const UploadFilePane: FunctionComponent<UploadFilePanelProps> = ({
|
||||
closePanel,
|
||||
uploadFile,
|
||||
}: UploadFilePanelProps) => {
|
||||
const title = "Upload file to notebook server";
|
||||
const submitButtonLabel = "Upload";
|
||||
const selectFileInputLabel = "Select file to upload";
|
||||
const extensions: string = undefined; //ex. ".ipynb"
|
||||
const errorMessage = "Could not upload file";
|
||||
const inProgressMessage = "Uploading file to notebook server";
|
||||
@@ -39,11 +36,8 @@ export const UploadFilePane: FunctionComponent<UploadFilePanelProps> = ({
|
||||
}
|
||||
|
||||
const file: File = files.item(0);
|
||||
// const id: string = logConsoleProgress(
|
||||
// `${inProgressMessage}: ${file.name}`
|
||||
// );
|
||||
|
||||
logConsoleProgress(`${inProgressMessage}: ${file.name}`);
|
||||
const clearMessage = logConsoleProgress(`${inProgressMessage}: ${file.name}`);
|
||||
|
||||
setIsExecuting(true);
|
||||
|
||||
@@ -61,7 +55,7 @@ export const UploadFilePane: FunctionComponent<UploadFilePanelProps> = ({
|
||||
)
|
||||
.finally(() => {
|
||||
setIsExecuting(false);
|
||||
// clearInProgressMessageWithId(id);
|
||||
clearMessage();
|
||||
});
|
||||
};
|
||||
|
||||
@@ -92,18 +86,15 @@ export const UploadFilePane: FunctionComponent<UploadFilePanelProps> = ({
|
||||
expandConsole,
|
||||
formError: formErrors,
|
||||
formErrorDetail: formErrorsDetails,
|
||||
id: "uploadFilePane",
|
||||
isExecuting: isExecuting,
|
||||
title,
|
||||
submitButtonText: submitButtonLabel,
|
||||
onClose: closePanel,
|
||||
submitButtonText: "Upload",
|
||||
onSubmit: submit,
|
||||
};
|
||||
|
||||
return (
|
||||
<RightPaneForm {...genericPaneProps}>
|
||||
<div className="paneMainContent">
|
||||
<Upload label={selectFileInputLabel} accept={extensions} onUpload={updateSelectedFiles} />
|
||||
<Upload label="Select file to upload" accept={extensions} onUpload={updateSelectedFiles} />
|
||||
</div>
|
||||
</RightPaneForm>
|
||||
);
|
||||
|
||||
@@ -2,7 +2,6 @@ import { DetailsList, DetailsListLayoutMode, IColumn, SelectionMode } from "@flu
|
||||
import React, { ChangeEvent, FunctionComponent, useState } from "react";
|
||||
import { Upload } from "../../../Common/Upload/Upload";
|
||||
import { UploadDetailsRecord } from "../../../Contracts/ViewModels";
|
||||
import { userContext } from "../../../UserContext";
|
||||
import { logConsoleError } from "../../../Utils/NotificationConsoleUtils";
|
||||
import Explorer from "../../Explorer";
|
||||
import { getErrorMessage } from "../../Tables/Utilities";
|
||||
@@ -10,23 +9,9 @@ import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneFor
|
||||
|
||||
export interface UploadItemsPaneProps {
|
||||
explorer: Explorer;
|
||||
closePanel: () => void;
|
||||
}
|
||||
|
||||
const getTitle = (): string => {
|
||||
if (userContext.apiType === "Cassandra" || userContext.apiType === "Tables") {
|
||||
return "Upload Tables";
|
||||
} else if (userContext.apiType === "Gremlin") {
|
||||
return "Upload Graph";
|
||||
} else {
|
||||
return "Upload Items";
|
||||
}
|
||||
};
|
||||
|
||||
export const UploadItemsPane: FunctionComponent<UploadItemsPaneProps> = ({
|
||||
explorer,
|
||||
closePanel,
|
||||
}: UploadItemsPaneProps) => {
|
||||
export const UploadItemsPane: FunctionComponent<UploadItemsPaneProps> = ({ explorer }: UploadItemsPaneProps) => {
|
||||
const [files, setFiles] = useState<FileList>();
|
||||
const [uploadFileData, setUploadFileData] = useState<UploadDetailsRecord[]>([]);
|
||||
const [formError, setFormError] = useState<string>("");
|
||||
@@ -71,11 +56,8 @@ export const UploadItemsPane: FunctionComponent<UploadItemsPaneProps> = ({
|
||||
expandConsole: () => explorer.expandConsole(),
|
||||
formError,
|
||||
formErrorDetail,
|
||||
id: "uploaditemspane",
|
||||
isExecuting: isExecuting,
|
||||
title: getTitle(),
|
||||
submitButtonText: "Upload",
|
||||
onClose: closePanel,
|
||||
onSubmit,
|
||||
};
|
||||
|
||||
|
||||
@@ -5,11 +5,8 @@ exports[`Upload Items Pane should render Default properly 1`] = `
|
||||
expandConsole={[Function]}
|
||||
formError=""
|
||||
formErrorDetail=""
|
||||
id="uploaditemspane"
|
||||
onClose={[Function]}
|
||||
onSubmit={[Function]}
|
||||
submitButtonText="Upload"
|
||||
title="Upload Items"
|
||||
>
|
||||
<div
|
||||
className="paneMainContent"
|
||||
|
||||
@@ -1288,20 +1288,20 @@ exports[`Delete Database Confirmation Pane submit() Should call delete database
|
||||
<Stack
|
||||
className="panelInfoErrorContainer"
|
||||
horizontal={true}
|
||||
verticalAlign="start"
|
||||
verticalAlign="center"
|
||||
>
|
||||
<div
|
||||
className="ms-Stack panelInfoErrorContainer css-202"
|
||||
>
|
||||
<StyledIconBase
|
||||
aria-label="warning"
|
||||
className="panelWarningIcon"
|
||||
data-testid="warningIcon"
|
||||
iconName="WarningSolid"
|
||||
key=".0:$.0"
|
||||
>
|
||||
<IconBase
|
||||
aria-label="warning"
|
||||
className="panelWarningIcon"
|
||||
data-testid="warningIcon"
|
||||
iconName="WarningSolid"
|
||||
styles={[Function]}
|
||||
theme={
|
||||
@@ -1579,10 +1579,10 @@ exports[`Delete Database Confirmation Pane submit() Should call delete database
|
||||
}
|
||||
>
|
||||
<i
|
||||
aria-hidden={true}
|
||||
aria-label="warning"
|
||||
className="panelWarningIcon root-204"
|
||||
data-icon-name="WarningSolid"
|
||||
data-testid="warningIcon"
|
||||
role="img"
|
||||
>
|
||||
|
||||
</i>
|
||||
@@ -1593,13 +1593,13 @@ exports[`Delete Database Confirmation Pane submit() Should call delete database
|
||||
key=".0:$.1"
|
||||
>
|
||||
<Text
|
||||
aria-label="message"
|
||||
className="panelWarningErrorMessage"
|
||||
data-testid="panelmessage"
|
||||
variant="small"
|
||||
>
|
||||
<span
|
||||
aria-label="message"
|
||||
className="panelWarningErrorMessage css-205"
|
||||
data-testid="panelmessage"
|
||||
>
|
||||
Warning! The action you are about to take cannot be undone. Continuing will permanently delete this resource and all of its children resources.
|
||||
</span>
|
||||
@@ -2303,14 +2303,12 @@ exports[`Delete Database Confirmation Pane submit() Should call delete database
|
||||
>
|
||||
<CustomizedPrimaryButton
|
||||
ariaLabel="OK"
|
||||
data-testid="submit"
|
||||
id="sidePanelOkButton"
|
||||
text="OK"
|
||||
type="submit"
|
||||
>
|
||||
<PrimaryButton
|
||||
ariaLabel="OK"
|
||||
data-testid="submit"
|
||||
id="sidePanelOkButton"
|
||||
text="OK"
|
||||
theme={
|
||||
@@ -2590,7 +2588,6 @@ exports[`Delete Database Confirmation Pane submit() Should call delete database
|
||||
>
|
||||
<CustomizedDefaultButton
|
||||
ariaLabel="OK"
|
||||
data-testid="submit"
|
||||
id="sidePanelOkButton"
|
||||
onRenderDescription={[Function]}
|
||||
primary={true}
|
||||
@@ -2872,7 +2869,6 @@ exports[`Delete Database Confirmation Pane submit() Should call delete database
|
||||
>
|
||||
<DefaultButton
|
||||
ariaLabel="OK"
|
||||
data-testid="submit"
|
||||
id="sidePanelOkButton"
|
||||
onRenderDescription={[Function]}
|
||||
primary={true}
|
||||
@@ -3155,7 +3151,6 @@ exports[`Delete Database Confirmation Pane submit() Should call delete database
|
||||
<BaseButton
|
||||
ariaLabel="OK"
|
||||
baseClassName="ms-Button"
|
||||
data-testid="submit"
|
||||
id="sidePanelOkButton"
|
||||
onRenderDescription={[Function]}
|
||||
primary={true}
|
||||
@@ -4012,7 +4007,6 @@ exports[`Delete Database Confirmation Pane submit() Should call delete database
|
||||
aria-label="OK"
|
||||
className="ms-Button ms-Button--primary root-218"
|
||||
data-is-focusable={true}
|
||||
data-testid="submit"
|
||||
id="sidePanelOkButton"
|
||||
onClick={[Function]}
|
||||
onKeyDown={[Function]}
|
||||
|
||||
Reference in New Issue
Block a user