Remove Explorer.isEmulator (#256)
This commit is contained in:
parent
5191ae3f3a
commit
14cdf19efb
|
@ -104,8 +104,7 @@ describe("SettingsComponent", () => {
|
|||
expect(settingsComponentInstance.shouldShowKeyspaceSharedThroughputMessage()).toEqual(false);
|
||||
|
||||
const newContainer = new Explorer({
|
||||
notificationsClient: undefined,
|
||||
isEmulator: false
|
||||
notificationsClient: undefined
|
||||
});
|
||||
newContainer.isPreferredApiCassandra = ko.computed(() => true);
|
||||
|
||||
|
@ -148,8 +147,7 @@ describe("SettingsComponent", () => {
|
|||
expect(settingsComponentInstance.hasConflictResolution()).toEqual(undefined);
|
||||
|
||||
const newContainer = new Explorer({
|
||||
notificationsClient: undefined,
|
||||
isEmulator: false
|
||||
notificationsClient: undefined
|
||||
});
|
||||
newContainer.databaseAccount = ko.observable({
|
||||
id: undefined,
|
||||
|
|
|
@ -13,8 +13,7 @@ import ko from "knockout";
|
|||
|
||||
describe("ScaleComponent", () => {
|
||||
const nonNationalCloudContainer = new Explorer({
|
||||
notificationsClient: undefined,
|
||||
isEmulator: false
|
||||
notificationsClient: undefined
|
||||
});
|
||||
nonNationalCloudContainer.getPlatformType = () => PlatformType.Portal;
|
||||
nonNationalCloudContainer.isRunningOnNationalCloud = () => false;
|
||||
|
@ -89,8 +88,7 @@ describe("ScaleComponent", () => {
|
|||
|
||||
it("autoScale enabled", () => {
|
||||
const newContainer = new Explorer({
|
||||
notificationsClient: undefined,
|
||||
isEmulator: false
|
||||
notificationsClient: undefined
|
||||
});
|
||||
|
||||
newContainer.databaseAccount({
|
||||
|
|
|
@ -19,6 +19,7 @@ import {
|
|||
import { getMaxRUs, getMinRUs, hasDatabaseSharedThroughput } from "../SettingsUtils";
|
||||
import * as AutoPilotUtils from "../../../../Utils/AutoPilotUtils";
|
||||
import { Text, TextField, Stack, Label, MessageBar, MessageBarType } from "office-ui-fabric-react";
|
||||
import { configContext, Platform } from "../../../../ConfigContext";
|
||||
|
||||
export interface ScaleComponentProps {
|
||||
collection: ViewModels.Collection;
|
||||
|
@ -43,7 +44,7 @@ export class ScaleComponent extends React.Component<ScaleComponentProps> {
|
|||
private isEmulator: boolean;
|
||||
constructor(props: ScaleComponentProps) {
|
||||
super(props);
|
||||
this.isEmulator = this.props.container.isEmulator;
|
||||
this.isEmulator = configContext.platform === Platform.Emulator;
|
||||
}
|
||||
|
||||
public isAutoScaleEnabled = (): boolean => {
|
||||
|
|
|
@ -106,8 +106,7 @@ describe("SubSettingsComponent", () => {
|
|||
|
||||
it("partitionKey not visible", () => {
|
||||
const newContainer = new Explorer({
|
||||
notificationsClient: undefined,
|
||||
isEmulator: false
|
||||
notificationsClient: undefined
|
||||
});
|
||||
|
||||
newContainer.isPreferredApiCassandra = ko.computed(() => true);
|
||||
|
|
|
@ -4,8 +4,7 @@ import Explorer from "../../Explorer";
|
|||
import ko from "knockout";
|
||||
|
||||
export const container = new Explorer({
|
||||
notificationsClient: undefined,
|
||||
isEmulator: false
|
||||
notificationsClient: undefined
|
||||
});
|
||||
|
||||
export const collection = ({
|
||||
|
|
|
@ -982,7 +982,6 @@ exports[`SettingsComponent renders 1`] = `
|
|||
"isAuthWithResourceToken": [Function],
|
||||
"isCodeOfConductEnabled": [Function],
|
||||
"isCopyNotebookPaneEnabled": [Function],
|
||||
"isEmulator": false,
|
||||
"isEnableMongoCapabilityPresent": [Function],
|
||||
"isFixedCollectionWithSharedThroughputSupported": [Function],
|
||||
"isGalleryPublishEnabled": [Function],
|
||||
|
@ -2296,7 +2295,6 @@ exports[`SettingsComponent renders 1`] = `
|
|||
"isAuthWithResourceToken": [Function],
|
||||
"isCodeOfConductEnabled": [Function],
|
||||
"isCopyNotebookPaneEnabled": [Function],
|
||||
"isEmulator": false,
|
||||
"isEnableMongoCapabilityPresent": [Function],
|
||||
"isFixedCollectionWithSharedThroughputSupported": [Function],
|
||||
"isGalleryPublishEnabled": [Function],
|
||||
|
@ -3623,7 +3621,6 @@ exports[`SettingsComponent renders 1`] = `
|
|||
"isAuthWithResourceToken": [Function],
|
||||
"isCodeOfConductEnabled": [Function],
|
||||
"isCopyNotebookPaneEnabled": [Function],
|
||||
"isEmulator": false,
|
||||
"isEnableMongoCapabilityPresent": [Function],
|
||||
"isFixedCollectionWithSharedThroughputSupported": [Function],
|
||||
"isGalleryPublishEnabled": [Function],
|
||||
|
@ -4937,7 +4934,6 @@ exports[`SettingsComponent renders 1`] = `
|
|||
"isAuthWithResourceToken": [Function],
|
||||
"isCodeOfConductEnabled": [Function],
|
||||
"isCopyNotebookPaneEnabled": [Function],
|
||||
"isEmulator": false,
|
||||
"isEnableMongoCapabilityPresent": [Function],
|
||||
"isFixedCollectionWithSharedThroughputSupported": [Function],
|
||||
"isGalleryPublishEnabled": [Function],
|
||||
|
|
|
@ -100,7 +100,6 @@ enum ShareAccessToggleState {
|
|||
|
||||
interface ExplorerOptions {
|
||||
notificationsClient: NotificationsClientBase;
|
||||
isEmulator: boolean;
|
||||
}
|
||||
interface AdHocAccessData {
|
||||
readWriteUrl: string;
|
||||
|
@ -135,7 +134,6 @@ export default class Explorer {
|
|||
public isFixedCollectionWithSharedThroughputSupported: ko.Computed<boolean>;
|
||||
public isEnableMongoCapabilityPresent: ko.Computed<boolean>;
|
||||
public isServerlessEnabled: ko.Computed<boolean>;
|
||||
public isEmulator: boolean;
|
||||
public isAccountReady: ko.Observable<boolean>;
|
||||
public canSaveQueries: ko.Computed<boolean>;
|
||||
public features: ko.Observable<any>;
|
||||
|
@ -378,7 +376,6 @@ export default class Explorer {
|
|||
});
|
||||
this.memoryUsageInfo = ko.observable<DataModels.MemoryUsageInfo>();
|
||||
this.notificationsClient = options.notificationsClient;
|
||||
this.isEmulator = options.isEmulator;
|
||||
|
||||
this.features = ko.observable();
|
||||
this.serverId = ko.observable<string>();
|
||||
|
|
|
@ -194,7 +194,7 @@ export class CommandBarComponentButtonFactory {
|
|||
buttons.push(fullScreenButton);
|
||||
}
|
||||
|
||||
if (!container.hasOwnProperty("isEmulator") || !container.isEmulator) {
|
||||
if (configContext.platform !== Platform.Emulator) {
|
||||
const label = "Feedback";
|
||||
const feedbackButtonOptions: CommandButtonComponentProps = {
|
||||
iconSrc: FeedbackIcon,
|
||||
|
|
|
@ -40,7 +40,7 @@ describe("Add Collection Pane", () => {
|
|||
};
|
||||
|
||||
beforeEach(() => {
|
||||
explorer = new Explorer({ notificationsClient: null, isEmulator: false });
|
||||
explorer = new Explorer({ notificationsClient: null });
|
||||
explorer.hasAutoPilotV2FeatureFlag = ko.computed<boolean>(() => true);
|
||||
});
|
||||
|
||||
|
|
|
@ -327,7 +327,7 @@ export default class AddCollectionPane extends ContextualPaneBase {
|
|||
|
||||
this.canRequestSupport = ko.pureComputed(() => {
|
||||
if (
|
||||
!this.container.isEmulator &&
|
||||
configContext.platform !== Platform.Emulator &&
|
||||
!this.container.isTryCosmosDBSubscription() &&
|
||||
this.container.getPlatformType() !== PlatformType.Portal
|
||||
) {
|
||||
|
@ -339,7 +339,7 @@ export default class AddCollectionPane extends ContextualPaneBase {
|
|||
});
|
||||
|
||||
this.costsVisible = ko.pureComputed(() => {
|
||||
return !this.container.isEmulator;
|
||||
return configContext.platform !== Platform.Emulator;
|
||||
});
|
||||
|
||||
this.maxCollectionsReached = ko.computed<boolean>(() => {
|
||||
|
|
|
@ -41,8 +41,7 @@ describe("Add Database Pane", () => {
|
|||
|
||||
beforeEach(() => {
|
||||
explorer = new Explorer({
|
||||
notificationsClient: null,
|
||||
isEmulator: false
|
||||
notificationsClient: null
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstan
|
|||
import { ContextualPaneBase } from "./ContextualPaneBase";
|
||||
import { createDatabase } from "../../Common/dataAccess/createDatabase";
|
||||
import { PlatformType } from "../../PlatformType";
|
||||
import { configContext, Platform } from "../../ConfigContext";
|
||||
|
||||
export default class AddDatabasePane extends ContextualPaneBase {
|
||||
public defaultExperience: ko.Computed<string>;
|
||||
|
@ -180,7 +181,7 @@ export default class AddDatabasePane extends ContextualPaneBase {
|
|||
|
||||
this.canRequestSupport = ko.pureComputed(() => {
|
||||
if (
|
||||
!this.container.isEmulator &&
|
||||
configContext.platform !== Platform.Emulator &&
|
||||
!this.container.isTryCosmosDBSubscription() &&
|
||||
this.container.getPlatformType() !== PlatformType.Portal
|
||||
) {
|
||||
|
@ -203,7 +204,7 @@ export default class AddDatabasePane extends ContextualPaneBase {
|
|||
});
|
||||
|
||||
this.costsVisible = ko.pureComputed(() => {
|
||||
return !this.container.isEmulator;
|
||||
return configContext.platform !== Platform.Emulator;
|
||||
});
|
||||
|
||||
this.throughputSpendAckVisible = ko.pureComputed<boolean>(() => {
|
||||
|
|
|
@ -12,6 +12,7 @@ import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstan
|
|||
import { CassandraAPIDataClient } from "../Tables/TableDataClient";
|
||||
import { ContextualPaneBase } from "./ContextualPaneBase";
|
||||
import { HashMap } from "../../Common/HashMap";
|
||||
import { configContext, Platform } from "../../ConfigContext";
|
||||
|
||||
export default class CassandraAddCollectionPane extends ContextualPaneBase {
|
||||
public createTableQuery: ko.Observable<string>;
|
||||
|
@ -231,11 +232,11 @@ export default class CassandraAddCollectionPane extends ContextualPaneBase {
|
|||
});
|
||||
|
||||
this.costsVisible = ko.pureComputed(() => {
|
||||
return !this.container.isEmulator;
|
||||
return configContext.platform !== Platform.Emulator;
|
||||
});
|
||||
|
||||
this.canRequestSupport = ko.pureComputed(() => {
|
||||
if (!this.container.isEmulator && !this.container.isTryCosmosDBSubscription()) {
|
||||
if (configContext.platform !== Platform.Emulator && !this.container.isTryCosmosDBSubscription()) {
|
||||
const offerThroughput: number = this.throughput();
|
||||
return offerThroughput <= 100000;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ describe("Delete Collection Confirmation Pane", () => {
|
|||
let explorer: Explorer;
|
||||
|
||||
beforeEach(() => {
|
||||
explorer = new Explorer({ notificationsClient: null, isEmulator: false });
|
||||
explorer = new Explorer({ notificationsClient: null });
|
||||
});
|
||||
|
||||
it("should be true if 1 database and 1 collection", () => {
|
||||
|
@ -56,7 +56,7 @@ describe("Delete Collection Confirmation Pane", () => {
|
|||
|
||||
describe("shouldRecordFeedback()", () => {
|
||||
it("should return true if last collection and database does not have shared throughput else false", () => {
|
||||
let fakeExplorer = new Explorer({ notificationsClient: null, isEmulator: false });
|
||||
let fakeExplorer = new Explorer({ notificationsClient: null });
|
||||
fakeExplorer.isNotificationConsoleExpanded = ko.observable<boolean>(false);
|
||||
fakeExplorer.refreshAllDatabases = () => Q.resolve();
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ describe("Delete Database Confirmation Pane", () => {
|
|||
});
|
||||
|
||||
beforeEach(() => {
|
||||
explorer = new Explorer({ notificationsClient: null, isEmulator: false });
|
||||
explorer = new Explorer({ notificationsClient: null });
|
||||
});
|
||||
|
||||
it("should be true if only 1 database", () => {
|
||||
|
|
|
@ -7,7 +7,7 @@ describe("Settings Pane", () => {
|
|||
let explorer: Explorer;
|
||||
|
||||
beforeEach(() => {
|
||||
explorer = new Explorer({ notificationsClient: null, isEmulator: false });
|
||||
explorer = new Explorer({ notificationsClient: null });
|
||||
});
|
||||
|
||||
it("should be true for SQL API", () => {
|
||||
|
|
|
@ -20,6 +20,7 @@ import { updateOffer } from "../../Common/dataAccess/updateOffer";
|
|||
import { CommandButtonComponentProps } from "../Controls/CommandButton/CommandButtonComponent";
|
||||
import { userContext } from "../../UserContext";
|
||||
import { updateOfferThroughputBeyondLimit } from "../../Common/dataAccess/updateOfferThroughputBeyondLimit";
|
||||
import { configContext, Platform } from "../../ConfigContext";
|
||||
|
||||
const updateThroughputBeyondLimitWarningMessage: string = `
|
||||
You are about to request an increase in throughput beyond the pre-allocated capacity.
|
||||
|
@ -196,7 +197,7 @@ export default class DatabaseSettingsTab extends TabsBase implements ViewModels.
|
|||
});
|
||||
|
||||
this.costsVisible = ko.computed(() => {
|
||||
return !this.container.isEmulator;
|
||||
return configContext.platform !== Platform.Emulator;
|
||||
});
|
||||
|
||||
this.shouldDisplayPortalUsePrompt = ko.pureComputed<boolean>(
|
||||
|
@ -207,7 +208,7 @@ export default class DatabaseSettingsTab extends TabsBase implements ViewModels.
|
|||
);
|
||||
this.canRequestSupport = ko.pureComputed(() => {
|
||||
if (
|
||||
!!this.container.isEmulator ||
|
||||
configContext.platform === Platform.Emulator ||
|
||||
this.container.getPlatformType() === PlatformType.Hosted ||
|
||||
this.canThroughputExceedMaximumValue()
|
||||
) {
|
||||
|
|
|
@ -28,13 +28,11 @@ describe("Documents tab", () => {
|
|||
|
||||
describe("showPartitionKey", () => {
|
||||
const explorer = new Explorer({
|
||||
notificationsClient: null,
|
||||
isEmulator: false
|
||||
notificationsClient: null
|
||||
});
|
||||
|
||||
const mongoExplorer = new Explorer({
|
||||
notificationsClient: null,
|
||||
isEmulator: false
|
||||
notificationsClient: null
|
||||
});
|
||||
mongoExplorer.defaultExperience(Constants.DefaultAccountExperience.MongoDB);
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ describe("Query Tab", () => {
|
|||
let explorer: Explorer;
|
||||
|
||||
beforeEach(() => {
|
||||
explorer = new Explorer({ notificationsClient: null, isEmulator: false });
|
||||
explorer = new Explorer({ notificationsClient: null });
|
||||
});
|
||||
|
||||
it("should be true for accounts using SQL API", () => {
|
||||
|
@ -69,7 +69,7 @@ describe("Query Tab", () => {
|
|||
let explorer: Explorer;
|
||||
|
||||
beforeEach(() => {
|
||||
explorer = new Explorer({ notificationsClient: null, isEmulator: false });
|
||||
explorer = new Explorer({ notificationsClient: null });
|
||||
});
|
||||
|
||||
it("should be visible when using a supported API", () => {
|
||||
|
|
|
@ -79,7 +79,7 @@ describe("Settings tab", () => {
|
|||
};
|
||||
|
||||
beforeEach(() => {
|
||||
explorer = new Explorer({ notificationsClient: null, isEmulator: false });
|
||||
explorer = new Explorer({ notificationsClient: null });
|
||||
explorer.hasAutoPilotV2FeatureFlag = ko.computed<boolean>(() => true);
|
||||
});
|
||||
|
||||
|
@ -178,7 +178,7 @@ describe("Settings tab", () => {
|
|||
let explorer: Explorer;
|
||||
|
||||
beforeEach(() => {
|
||||
explorer = new Explorer({ notificationsClient: null, isEmulator: false });
|
||||
explorer = new Explorer({ notificationsClient: null });
|
||||
explorer.hasAutoPilotV2FeatureFlag = ko.computed<boolean>(() => true);
|
||||
});
|
||||
|
||||
|
@ -256,7 +256,7 @@ describe("Settings tab", () => {
|
|||
let explorer: Explorer;
|
||||
|
||||
beforeEach(() => {
|
||||
explorer = new Explorer({ notificationsClient: null, isEmulator: false });
|
||||
explorer = new Explorer({ notificationsClient: null });
|
||||
explorer.hasAutoPilotV2FeatureFlag = ko.computed<boolean>(() => true);
|
||||
});
|
||||
|
||||
|
@ -338,8 +338,7 @@ describe("Settings tab", () => {
|
|||
|
||||
function getCollection(defaultApi: string, partitionKeyOption: PartitionKeyOption) {
|
||||
const explorer = new Explorer({
|
||||
notificationsClient: null,
|
||||
isEmulator: false
|
||||
notificationsClient: null
|
||||
});
|
||||
explorer.defaultExperience(defaultApi);
|
||||
explorer.hasAutoPilotV2FeatureFlag = ko.computed<boolean>(() => true);
|
||||
|
@ -471,8 +470,7 @@ describe("Settings tab", () => {
|
|||
describe("AutoPilot", () => {
|
||||
function getCollection(autoPilotTier: DataModels.AutopilotTier) {
|
||||
const explorer = new Explorer({
|
||||
notificationsClient: null,
|
||||
isEmulator: false
|
||||
notificationsClient: null
|
||||
});
|
||||
explorer.hasAutoPilotV2FeatureFlag = ko.computed<boolean>(() => true);
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ import { updateCollection } from "../../Common/dataAccess/updateCollection";
|
|||
import { CommandButtonComponentProps } from "../Controls/CommandButton/CommandButtonComponent";
|
||||
import { userContext } from "../../UserContext";
|
||||
import { updateOfferThroughputBeyondLimit } from "../../Common/dataAccess/updateOfferThroughputBeyondLimit";
|
||||
import { configContext, Platform } from "../../ConfigContext";
|
||||
|
||||
const ttlWarning: string = `
|
||||
The system will automatically delete items based on the TTL value (in seconds) you provide, without needing a delete operation explicitly issued by a client application.
|
||||
|
@ -454,7 +455,7 @@ export default class SettingsTab extends TabsBase implements ViewModels.WaitsFor
|
|||
});
|
||||
|
||||
this.rupmVisible = ko.computed(() => {
|
||||
if (this.container.isEmulator) {
|
||||
if (configContext.platform === Platform.Emulator) {
|
||||
return false;
|
||||
}
|
||||
if (this.container.isFeatureEnabled(Constants.Features.enableRupm)) {
|
||||
|
@ -484,7 +485,7 @@ export default class SettingsTab extends TabsBase implements ViewModels.WaitsFor
|
|||
});
|
||||
|
||||
this.costsVisible = ko.computed(() => {
|
||||
return !this.container.isEmulator;
|
||||
return configContext.platform !== Platform.Emulator;
|
||||
});
|
||||
|
||||
this.isTryCosmosDBSubscription = ko.computed<boolean>(() => {
|
||||
|
@ -500,7 +501,7 @@ export default class SettingsTab extends TabsBase implements ViewModels.WaitsFor
|
|||
});
|
||||
|
||||
this.canRequestSupport = ko.pureComputed(() => {
|
||||
if (this.container.isEmulator) {
|
||||
if (configContext.platform === Platform.Emulator) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -711,7 +712,7 @@ export default class SettingsTab extends TabsBase implements ViewModels.WaitsFor
|
|||
}
|
||||
|
||||
const isThroughputGreaterThanMaxRus = this.throughput() > this.maxRUs();
|
||||
const isEmulator = this.container.isEmulator;
|
||||
const isEmulator = configContext.platform === Platform.Emulator;
|
||||
if (isThroughputGreaterThanMaxRus && isEmulator) {
|
||||
return false;
|
||||
}
|
||||
|
@ -881,7 +882,8 @@ export default class SettingsTab extends TabsBase implements ViewModels.WaitsFor
|
|||
this.maxRUs() <= SharedConstants.CollectionCreation.DefaultCollectionRUs1Million &&
|
||||
this.throughput() > SharedConstants.CollectionCreation.DefaultCollectionRUs1Million;
|
||||
|
||||
const throughputExceedsMaxValue: boolean = !this.container.isEmulator && this.throughput() > this.maxRUs();
|
||||
const throughputExceedsMaxValue: boolean =
|
||||
configContext.platform !== Platform.Emulator && this.throughput() > this.maxRUs();
|
||||
|
||||
const ttlOptionDirty: boolean = this.timeToLive.editableIsDirty();
|
||||
const ttlOrIndexingPolicyFieldsDirty: boolean =
|
||||
|
|
|
@ -16,7 +16,7 @@ describe("Tabs manager tests", () => {
|
|||
let documentsTab: DocumentsTab;
|
||||
|
||||
beforeAll(() => {
|
||||
explorer = new Explorer({ notificationsClient: undefined, isEmulator: false });
|
||||
explorer = new Explorer({ notificationsClient: undefined });
|
||||
explorer.databaseAccount = ko.observable<DataModels.DatabaseAccount>({
|
||||
id: "test",
|
||||
name: "test",
|
||||
|
|
|
@ -7,8 +7,7 @@ import { NotificationsClient } from "./NotificationsClient";
|
|||
export default class EmulatorExplorerFactory {
|
||||
public static createExplorer(): Explorer {
|
||||
const explorer: Explorer = new Explorer({
|
||||
notificationsClient: new NotificationsClient(),
|
||||
isEmulator: true
|
||||
notificationsClient: new NotificationsClient()
|
||||
});
|
||||
explorer.databaseAccount({
|
||||
name: "",
|
||||
|
|
|
@ -4,8 +4,7 @@ import { NotificationsClient } from "./NotificationsClient";
|
|||
export default class HostedExplorerFactory {
|
||||
public createExplorer(): Explorer {
|
||||
const explorer = new Explorer({
|
||||
notificationsClient: new NotificationsClient(),
|
||||
isEmulator: false
|
||||
notificationsClient: new NotificationsClient()
|
||||
});
|
||||
|
||||
return explorer;
|
||||
|
|
|
@ -4,8 +4,7 @@ import { NotificationsClient } from "./NotificationsClient";
|
|||
export default class PortalExplorerFactory {
|
||||
public createExplorer(): Explorer {
|
||||
var explorer = new Explorer({
|
||||
notificationsClient: new NotificationsClient(),
|
||||
isEmulator: false
|
||||
notificationsClient: new NotificationsClient()
|
||||
});
|
||||
|
||||
return explorer;
|
||||
|
|
|
@ -10,8 +10,7 @@ describe("TabRouteHandler", () => {
|
|||
|
||||
beforeAll(() => {
|
||||
(<any>window).dataExplorer = new Explorer({
|
||||
notificationsClient: null,
|
||||
isEmulator: false
|
||||
notificationsClient: null
|
||||
}); // create a mock to avoid null refs
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue