diff --git a/package.json b/package.json index b7b761f16..ee3b0594e 100644 --- a/package.json +++ b/package.json @@ -67,8 +67,7 @@ "react-app-rewired": "^2.1.6", "rimraf": "^2.7.1", "ts-jest": "^24.3.0", - "tslint": "^5.20.1", - "tslint-etc": "^1.11.1", + "eslint": "^6.8.0", "typemoq": "^2.1.0", "webpack": "4.42.0", "webpack-cli": "^3.3.11", @@ -81,7 +80,7 @@ "build:typedefs": "generate-modules ./Modules.json ./src/Components/SampleEditor/Modules.ts", "test": "react-app-rewired test --scripts-version @bentley/react-scripts", "eject": "react-app-rewired eject --scripts-version @bentley/react-scripts", - "lint": "tslint -p . 1>&2", + "lint": "eslint ./src/**/*.{ts,tsx} 1>&2", "test-build": "tsc 1>&2 --noEmit false --jsx preserve --outDir ./lib", "test-build:watch": "tsc 1>&2 --noEmit false --jsx preserve --outDir ./lib -w", "test-certa": "certa -r chrome", @@ -90,7 +89,37 @@ }, "homepage": "./", "eslintConfig": { - "extends": "react-app" + "extends": "./node_modules/@bentley/build-tools/.eslintrc.js", + "ignorePatterns": [ + "*.d.ts" + ], + "rules": { + "deprecation/deprecation": "off" + }, + "overrides": [ + { + "files": [ + "*.tsx" + ], + "rules": { + "@typescript-eslint/naming-convention": [ + "warn", + { + "selector": "function", + "format": [ + "camelCase", + "PascalCase" + ] + } + ] + } + } + ], + "settings": { + "react": { + "version": "detect" + } + } }, "browserslist": [ "electron 6.0.0", @@ -103,4 +132,4 @@ "not dead", "not <0.2%" ] -} +} \ No newline at end of file diff --git a/src/Components/ErrorBoundary/ErrorDisplay.tsx b/src/Components/ErrorBoundary/ErrorDisplay.tsx index 038587278..fed4d5bb6 100644 --- a/src/Components/ErrorBoundary/ErrorDisplay.tsx +++ b/src/Components/ErrorBoundary/ErrorDisplay.tsx @@ -11,9 +11,9 @@ export function DisplayError(props: { error?: Error, errorInfo?: React.ErrorInfo

A runtime error has occurred.

{props.error &&

{props.error.name}: {props.error.message}

} - {props.error && props.error.stack && {props.error.stack.split("\n").map((line) => {line}
)}
} + {props.error && props.error.stack && {props.error.stack.split("\n").map((line, i) => {line}
)}
} {props.errorInfo &&

The above error occurred in the following component stack:

} - {props.errorInfo && {props.errorInfo.componentStack.split("\n").map((line) => {line}
)}
} + {props.errorInfo && {props.errorInfo.componentStack.split("\n").map((line, i) => {line}
)}
}
); diff --git a/src/Components/GenericReloadableComponent/GenericReloadableComponent.tsx b/src/Components/GenericReloadableComponent/GenericReloadableComponent.tsx index 6e13a7fb9..2d6e1073e 100644 --- a/src/Components/GenericReloadableComponent/GenericReloadableComponent.tsx +++ b/src/Components/GenericReloadableComponent/GenericReloadableComponent.tsx @@ -39,13 +39,22 @@ export class ReloadableConnection extends React.PureComponent { - this.setState({ imodel }, () => { if (this.props.onIModelReady) this.props.onIModelReady(imodel); }); + this.setState({ imodel }); } } diff --git a/src/Components/IModelSelector/IModelSelector.tsx b/src/Components/IModelSelector/IModelSelector.tsx index 3c58e0a57..1b1570fda 100644 --- a/src/Components/IModelSelector/IModelSelector.tsx +++ b/src/Components/IModelSelector/IModelSelector.tsx @@ -28,7 +28,7 @@ export class IModelSelector extends React.Component { public static defaultIModel = SampleIModels.MetroStation; private _handleSelection = async (event: React.ChangeEvent) => { - const index = Number.parseInt(event.target.selectedOptions[0].value, undefined); + const index = Number.parseInt(event.target.selectedOptions[0].value, 10); const iModelName = this.props.iModelNames[index]; this.props.onIModelChange(iModelName); diff --git a/src/Components/SampleEditor/Modules.ts b/src/Components/SampleEditor/Modules.ts index 1d54aee18..95a932b12 100644 --- a/src/Components/SampleEditor/Modules.ts +++ b/src/Components/SampleEditor/Modules.ts @@ -4,155 +4,155 @@ *--------------------------------------------------------------------------------------------*/ import { ExternalModule, InternalModule, ModuleBase } from "@bentley/monaco-editor"; export const modules: ModuleBase[] = [ - ({ - name: "react", - import: import("react"), - } as InternalModule), - ({ - name: "react-dom", - import: import("react-dom"), - } as InternalModule), - ({ - name: "@bentley/bentleyjs-core", - import: import("@bentley/bentleyjs-core"), - } as InternalModule), - ({ - name: "@bentley/context-registry-client", - import: import("@bentley/context-registry-client"), - } as InternalModule), - ({ - name: "@bentley/frontend-authorization-client", - import: import("@bentley/frontend-authorization-client"), - } as InternalModule), - ({ - name: "@bentley/geometry-core", - import: import("@bentley/geometry-core"), - } as InternalModule), - ({ - name: "@bentley/imodelhub-client", - import: import("@bentley/imodelhub-client"), - } as InternalModule), - ({ - name: "@bentley/imodeljs-common", - import: import("@bentley/imodeljs-common"), - } as InternalModule), - ({ - name: "@bentley/imodeljs-frontend", - import: import("@bentley/imodeljs-frontend"), - } as InternalModule), - ({ - name: "@bentley/imodeljs-i18n", - import: import("@bentley/imodeljs-i18n"), - } as InternalModule), - ({ - name: "@bentley/imodeljs-quantity", - import: import("@bentley/imodeljs-quantity"), - } as InternalModule), - ({ - name: "@bentley/itwin-client", - import: import("@bentley/itwin-client"), - } as InternalModule), - ({ - name: "@bentley/ui-abstract", - import: import("@bentley/ui-abstract"), - } as InternalModule), - ({ - name: "@bentley/ui-components", - import: import("@bentley/ui-components"), - } as InternalModule), - ({ - name: "@bentley/ui-core", - import: import("@bentley/ui-core"), - } as InternalModule), - ({ - name: "@bentley/presentation-frontend", - import: import("@bentley/presentation-frontend"), - } as InternalModule), - ({ - name: "@bentley/presentation-common", - import: import("@bentley/presentation-common"), - } as InternalModule), - ({ - name: "@bentley/presentation-components", - import: import("@bentley/presentation-components"), - } as InternalModule), - ({ - name: "@bentley/product-settings-client", - import: import("@bentley/product-settings-client"), - } as InternalModule), - ({ - name: "@bentley/orbitgt-core", - import: import("@bentley/orbitgt-core"), - } as InternalModule), - ({ - name: "@bentley/webgl-compatibility", - import: import("@bentley/webgl-compatibility"), - } as InternalModule), - ({ - name: "api/viewSetup", - import: import("../../api/viewSetup"), - typedef: import("!!raw-loader!../../api/viewSetup.d.ts"), - } as InternalModule), - ({ - name: "api/showcasetooladmin", - import: import("../../api/showcasetooladmin"), - typedef: import("!!raw-loader!../../api/showcasetooladmin.d.ts"), - } as InternalModule), - ({ - name: "common/CommonComponentTools/ComponentContainer", - import: import("../../common/CommonComponentTools/ComponentContainer"), - typedef: import("!!raw-loader!../../common/CommonComponentTools/ComponentContainer.d.ts"), - } as InternalModule), - ({ - name: "common/DataProvider/SampleDataProvider", - import: import("../../common/DataProvider/SampleDataProvider"), - typedef: import("!!raw-loader!../../common/DataProvider/SampleDataProvider.d.ts"), - } as InternalModule), - ({ - name: "common/PointSelector/PointGenerators", - import: import("../../common/PointSelector/PointGenerators"), - typedef: import("!!raw-loader!../../common/PointSelector/PointGenerators.d.ts"), - } as InternalModule), - ({ - name: "common/PointSelector/PointSelector", - import: import("../../common/PointSelector/PointSelector"), - typedef: import("!!raw-loader!../../common/PointSelector/PointSelector.d.ts"), - } as InternalModule), - ({ - name: "Components/Viewport/ReloadableViewport", - import: import("../Viewport/ReloadableViewport"), - typedef: import("!!raw-loader!../Viewport/ReloadableViewport.d.ts"), - } as InternalModule), - ({ - name: "Components/ControlPane/ControlPane", - import: import("../ControlPane/ControlPane"), - typedef: import("!!raw-loader!../ControlPane/ControlPane.d.ts"), - } as InternalModule), - ({ - name: "common/SampleApp", - import: import("../../common/SampleApp"), - typedef: import("!!raw-loader!../../common/SampleApp.d.ts"), - } as InternalModule), - ({ - name: "common/CommonComponentTools/index.scss", - import: import("!!raw-loader!common/CommonComponentTools/index.scss"), - } as InternalModule), - ({ - name: "common/DataProvider/Trees.scss", - import: import("!!raw-loader!common/DataProvider/Trees.scss"), - } as InternalModule), - ({ - name: "common/samples-common.scss", - import: import("!!raw-loader!common/samples-common.scss"), - } as InternalModule), - ({ - name: "@bentley/icons-generic-webfont/dist/bentley-icons-generic-webfont.css", - import: import("!!raw-loader!@bentley/icons-generic-webfont/dist/bentley-icons-generic-webfont.css"), - } as InternalModule), - ({ - name: "react", - } as ExternalModule), - ({ - name: "react-dom", - } as ExternalModule), + ({ + name: "react", + import: import("react"), + } as InternalModule), + ({ + name: "react-dom", + import: import("react-dom"), + } as InternalModule), + ({ + name: "@bentley/bentleyjs-core", + import: import("@bentley/bentleyjs-core"), + } as InternalModule), + ({ + name: "@bentley/context-registry-client", + import: import("@bentley/context-registry-client"), + } as InternalModule), + ({ + name: "@bentley/frontend-authorization-client", + import: import("@bentley/frontend-authorization-client"), + } as InternalModule), + ({ + name: "@bentley/geometry-core", + import: import("@bentley/geometry-core"), + } as InternalModule), + ({ + name: "@bentley/imodelhub-client", + import: import("@bentley/imodelhub-client"), + } as InternalModule), + ({ + name: "@bentley/imodeljs-common", + import: import("@bentley/imodeljs-common"), + } as InternalModule), + ({ + name: "@bentley/imodeljs-frontend", + import: import("@bentley/imodeljs-frontend"), + } as InternalModule), + ({ + name: "@bentley/imodeljs-i18n", + import: import("@bentley/imodeljs-i18n"), + } as InternalModule), + ({ + name: "@bentley/imodeljs-quantity", + import: import("@bentley/imodeljs-quantity"), + } as InternalModule), + ({ + name: "@bentley/itwin-client", + import: import("@bentley/itwin-client"), + } as InternalModule), + ({ + name: "@bentley/ui-abstract", + import: import("@bentley/ui-abstract"), + } as InternalModule), + ({ + name: "@bentley/ui-components", + import: import("@bentley/ui-components"), + } as InternalModule), + ({ + name: "@bentley/ui-core", + import: import("@bentley/ui-core"), + } as InternalModule), + ({ + name: "@bentley/presentation-frontend", + import: import("@bentley/presentation-frontend"), + } as InternalModule), + ({ + name: "@bentley/presentation-common", + import: import("@bentley/presentation-common"), + } as InternalModule), + ({ + name: "@bentley/presentation-components", + import: import("@bentley/presentation-components"), + } as InternalModule), + ({ + name: "@bentley/product-settings-client", + import: import("@bentley/product-settings-client"), + } as InternalModule), + ({ + name: "@bentley/orbitgt-core", + import: import("@bentley/orbitgt-core"), + } as InternalModule), + ({ + name: "@bentley/webgl-compatibility", + import: import("@bentley/webgl-compatibility"), + } as InternalModule), + ({ + name: "api/viewSetup", + import: import("../../api/viewSetup"), + typedef: import("!!raw-loader!../../api/viewSetup.d.ts"), + } as InternalModule), + ({ + name: "api/showcasetooladmin", + import: import("../../api/showcasetooladmin"), + typedef: import("!!raw-loader!../../api/showcasetooladmin.d.ts"), + } as InternalModule), + ({ + name: "common/CommonComponentTools/ComponentContainer", + import: import("../../common/CommonComponentTools/ComponentContainer"), + typedef: import("!!raw-loader!../../common/CommonComponentTools/ComponentContainer.d.ts"), + } as InternalModule), + ({ + name: "common/DataProvider/SampleDataProvider", + import: import("../../common/DataProvider/SampleDataProvider"), + typedef: import("!!raw-loader!../../common/DataProvider/SampleDataProvider.d.ts"), + } as InternalModule), + ({ + name: "common/PointSelector/PointGenerators", + import: import("../../common/PointSelector/PointGenerators"), + typedef: import("!!raw-loader!../../common/PointSelector/PointGenerators.d.ts"), + } as InternalModule), + ({ + name: "common/PointSelector/PointSelector", + import: import("../../common/PointSelector/PointSelector"), + typedef: import("!!raw-loader!../../common/PointSelector/PointSelector.d.ts"), + } as InternalModule), + ({ + name: "Components/Viewport/ReloadableViewport", + import: import("../Viewport/ReloadableViewport"), + typedef: import("!!raw-loader!../Viewport/ReloadableViewport.d.ts"), + } as InternalModule), + ({ + name: "Components/ControlPane/ControlPane", + import: import("../ControlPane/ControlPane"), + typedef: import("!!raw-loader!../ControlPane/ControlPane.d.ts"), + } as InternalModule), + ({ + name: "common/SampleApp", + import: import("../../common/SampleApp"), + typedef: import("!!raw-loader!../../common/SampleApp.d.ts"), + } as InternalModule), + ({ + name: "common/CommonComponentTools/index.scss", + import: import("!!raw-loader!common/CommonComponentTools/index.scss"), + } as InternalModule), + ({ + name: "common/DataProvider/Trees.scss", + import: import("!!raw-loader!common/DataProvider/Trees.scss"), + } as InternalModule), + ({ + name: "common/samples-common.scss", + import: import("!!raw-loader!common/samples-common.scss"), + } as InternalModule), + ({ + name: "@bentley/icons-generic-webfont/dist/bentley-icons-generic-webfont.css", + import: import("!!raw-loader!@bentley/icons-generic-webfont/dist/bentley-icons-generic-webfont.css"), + } as InternalModule), + ({ + name: "react", + } as ExternalModule), + ({ + name: "react-dom", + } as ExternalModule), ]; diff --git a/src/Components/SampleEditor/SampleEditor.tsx b/src/Components/SampleEditor/SampleEditor.tsx index ea8259cad..814532fb3 100644 --- a/src/Components/SampleEditor/SampleEditor.tsx +++ b/src/Components/SampleEditor/SampleEditor.tsx @@ -8,8 +8,8 @@ import { featureFlags, FeatureToggleClient } from "../../FeatureToggleClient"; import { modules } from "./Modules"; import "@bentley/monaco-editor/lib/editor/icons/codicon.css"; import "./SampleEditor.scss"; -// tslint:disable-next-line: variable-name -const MonacoEditor = React.lazy(() => import("@bentley/monaco-editor")); +// eslint-disable-next-line @typescript-eslint/naming-convention +const MonacoEditor = React.lazy(async () => import("@bentley/monaco-editor")); export interface SampleEditorProps { files?: any[]; @@ -42,7 +42,7 @@ export default class SampleEditor extends React.Component) => { - const target = (event.target as HTMLElement).closest(".sample-editor-pane-nav-item") as HTMLElement | null; + const target = (event.target as HTMLElement).closest(".sample-editor-pane-nav-item") as HTMLElement; if (target && target.title && target.title.toLowerCase() !== this.state.active) { this.setState({ active: target.title.toLowerCase() }); } else { diff --git a/src/Components/SampleGallery/SampleGallery.tsx b/src/Components/SampleGallery/SampleGallery.tsx index 0c945e5c0..11e7c12f0 100644 --- a/src/Components/SampleGallery/SampleGallery.tsx +++ b/src/Components/SampleGallery/SampleGallery.tsx @@ -31,7 +31,7 @@ export class SampleGallery extends React.Component diff --git a/src/Components/SampleShowcase/SampleShowcase.tsx b/src/Components/SampleShowcase/SampleShowcase.tsx index b550e5503..db95d48ac 100644 --- a/src/Components/SampleShowcase/SampleShowcase.tsx +++ b/src/Components/SampleShowcase/SampleShowcase.tsx @@ -95,13 +95,45 @@ export class SampleShowcase extends React.Component<{}, ShowcaseState> { return { group, sample, imodel }; } + private updateURLParams() { + const params = new URLSearchParams(); + params.append("group", this.state.activeSampleGroup); + params.append("sample", this.state.activeSampleName); + + if (this.state.iModelName) { + params.append("imodel", this.state.iModelName); + } + + // Detect if editor was enabled in URL params as a semi-backdoor, this + // bypasses the ld feature flag + const editorEnabled = new URLSearchParams(window.location.search).get("editor"); + if (editorEnabled) params.append("editor", editorEnabled); + + window.history.replaceState(null, "", `?${params.toString()}`); + + // Send to parent if within an iframe. + if (window.self !== window.top) { + window.parent.postMessage(`?${params.toString()}`, "*"); + } + } + public componentDidMount() { - // tslint:disable-next-line no-floating-promises this._onActiveSampleChange(this.state.activeSampleGroup, this.state.activeSampleName); document.documentElement.setAttribute("data-theme", "dark"); } + public componentDidUpdate(_prevProps: {}, prevState: ShowcaseState) { + if (prevState.activeSampleGroup !== this.state.activeSampleGroup || + prevState.activeSampleName !== this.state.activeSampleName || + prevState.iModelName !== this.state.iModelName) { + this.updateURLParams(); + } + + if (prevState.iModelName !== this.state.iModelName) + this._onActiveSampleChange(this.state.activeSampleGroup, this.state.activeSampleName); + } + private getSampleByName(groupName: string, sampleName: string): SampleSpec | undefined { const group = sampleManifest.find((v) => v.groupName === groupName); @@ -145,28 +177,7 @@ export class SampleShowcase extends React.Component<{}, ShowcaseState> { sampleUI = await newSampleSpec.setup(iModelName, iModelSelector); } - this.setState({ activeSampleGroup: groupName, activeSampleName: sampleName, sampleUI, iModelName }, () => { - const params = new URLSearchParams(); - params.append("group", groupName); - params.append("sample", sampleName); - - if (iModelName) { - params.append("imodel", iModelName); - } - - // Detect if editor was enabled in URL params as a semi-backdoor, this - // bypasses the ld feature flag - const editorEnabled = new URLSearchParams(window.location.search).get("editor"); - if (editorEnabled) params.append("editor", editorEnabled); - - window.history.replaceState(null, "", "?" + params.toString()); - - // Send to parent if within an iframe. - if (window.self !== window.top) { - window.parent.postMessage("?" + params.toString(), "*"); - } - - }); + this.setState({ activeSampleGroup: groupName, activeSampleName: sampleName, sampleUI, iModelName }); } private _onGalleryChanged = (groupName: string, sampleName: string) => { @@ -189,12 +200,11 @@ export class SampleShowcase extends React.Component<{}, ShowcaseState> { if (undefined !== oldSample && oldSample.teardown) oldSample.teardown(); - // tslint:disable-next-line no-floating-promises this.setupNewSample(groupName, sampleName); } private _onIModelChange = (iModelName: string) => { - this.setState({ iModelName }, () => this._onActiveSampleChange(this.state.activeSampleGroup, this.state.activeSampleName)); + this.setState({ iModelName }); } private _onEditorButtonClick = () => { diff --git a/src/Components/Startup/Startup.tsx b/src/Components/Startup/Startup.tsx index fdfbcaefe..b38a123e8 100644 --- a/src/Components/Startup/Startup.tsx +++ b/src/Components/Startup/Startup.tsx @@ -37,7 +37,7 @@ export class StartupComponent extends React.Component ({ user: { ...prev.user, isLoading: false } }), () => { - this.openIModel(); // tslint:disable-line no-floating-promises - }); + this.setState((prev) => ({ user: { ...prev.user, isLoading: false, isAuthorized: true } })); } public componentWillUnmount() { @@ -56,14 +54,25 @@ export class StartupComponent extends React.Component { this.setState((prev) => ({ user: { ...prev.user, isLoading: true } })); await SampleBaseApp.oidcClient.signIn(new FrontendRequestContext()); } private _onUserStateChanged = () => { - this.setState((prev) => ({ user: { ...prev.user, isLoading: false, isAuthorized: SampleBaseApp.oidcClient.isAuthorized } }), - () => { if (this.state.user.isAuthorized) { this.openIModel(); } }); // tslint:disable-line no-floating-promises + this.setState((prev) => ({ user: { ...prev.user, isLoading: false, isAuthorized: SampleBaseApp.oidcClient.isAuthorized } })); } private async getIModelInfo(): Promise<{ projectId: string, imodelId: string }> { @@ -100,10 +109,7 @@ export class StartupComponent extends React.Component { - if (imodel) - this.props.onIModelReady(imodel); - }); + this.setState({ imodel }); } /** The component's render method */ @@ -114,7 +120,7 @@ export class StartupComponent extends React.Component); } else if (!this.state.imodel) { // if we don't have an imodel yet - render a spinner while we are waiting diff --git a/src/Components/Viewport/ReloadableViewport.tsx b/src/Components/Viewport/ReloadableViewport.tsx index 55ef5291e..e45ed1cad 100644 --- a/src/Components/Viewport/ReloadableViewport.tsx +++ b/src/Components/Viewport/ReloadableViewport.tsx @@ -45,14 +45,20 @@ export class ReloadableViewport extends React.PureComponent { const viewState = (this.props.getCustomViewState) ? await this.props.getCustomViewState(imodel) : await ViewSetup.getDefaultView(imodel); - this.setState({ imodel, viewState }, () => { if (this.props.onIModelReady) this.props.onIModelReady(imodel); }); + this.setState({ imodel, viewState }); } } diff --git a/src/Components/Viewport/ViewportAndNavigation.tsx b/src/Components/Viewport/ViewportAndNavigation.tsx index 9148987e5..bb4e636f7 100644 --- a/src/Components/Viewport/ViewportAndNavigation.tsx +++ b/src/Components/Viewport/ViewportAndNavigation.tsx @@ -13,7 +13,7 @@ import { viewWithUnifiedSelection } from "@bentley/presentation-components"; import "./Toolbar.scss"; // create a HOC viewport component that supports unified selection -// tslint:disable-next-line:variable-name +// eslint-disable-next-line @typescript-eslint/naming-convention const SimpleViewport = viewWithUnifiedSelection(ViewportComponent); /** React props for [[ViewportAndNavigationComponents]] component */ diff --git a/src/Components/Widgets/SmallStatusBar.tsx b/src/Components/Widgets/SmallStatusBar.tsx index 25673b34c..72bba4635 100644 --- a/src/Components/Widgets/SmallStatusBar.tsx +++ b/src/Components/Widgets/SmallStatusBar.tsx @@ -14,15 +14,15 @@ export class SmallStatusBarWidgetControl extends StatusBarWidgetControl { private _statusBarItems: StatusBarItem[] | undefined; private get statusBarItems(): StatusBarItem[] { - // tslint:disable-next-line: variable-name + // eslint-disable-next-line @typescript-eslint/naming-convention const ToolAssistance = withStatusFieldProps(ToolAssistanceField); - // tslint:disable-next-line: variable-name + // eslint-disable-next-line @typescript-eslint/naming-convention const MessageCenter = withMessageCenterFieldProps(MessageCenterField); - // tslint:disable-next-line: variable-name + // eslint-disable-next-line @typescript-eslint/naming-convention const SnapMode = withMessageCenterFieldProps(SnapModeField); - // tslint:disable-next-line: variable-name + // eslint-disable-next-line @typescript-eslint/naming-convention const ActivityCenter = withStatusFieldProps(ActivityCenterField); - // tslint:disable-next-line: variable-name + // eslint-disable-next-line @typescript-eslint/naming-convention const FooterMode = withStatusFieldProps(FooterModeField); if (!this._statusBarItems) { diff --git a/src/Components/frontstages/StartupComponentFrontstage.tsx b/src/Components/frontstages/StartupComponentFrontstage.tsx index f392f9f45..161e4ca50 100644 --- a/src/Components/frontstages/StartupComponentFrontstage.tsx +++ b/src/Components/frontstages/StartupComponentFrontstage.tsx @@ -16,13 +16,15 @@ import { import { StageUsage } from "@bentley/ui-abstract"; import { SmallStatusBarWidgetControl } from "../Widgets/SmallStatusBar"; +/* eslint-disable react/jsx-key */ + /** * Startup Component Stage for AppUi samples */ export class StartupComponentFrontstage extends FrontstageProvider { /** Define the Frontstage properties */ - public get frontstage(): React.ReactElement { + public get frontstage(): React.ReactElement { return ( } />, + } />, ]} /> } @@ -51,7 +53,7 @@ export class StartupComponentFrontstage extends FrontstageProvider { viewNavigationTools={ } />, + } />, ]} /> } diff --git a/src/Components/frontstages/ViewportFrontstage.tsx b/src/Components/frontstages/ViewportFrontstage.tsx index 3f6a4ae58..7029c7173 100644 --- a/src/Components/frontstages/ViewportFrontstage.tsx +++ b/src/Components/frontstages/ViewportFrontstage.tsx @@ -3,12 +3,15 @@ * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ import * as React from "react"; -import { BasicNavigationWidget, BasicToolWidget, ContentGroup, ContentGroupProps, ContentLayoutDef, ContentLayoutProps, +import { + BasicNavigationWidget, BasicToolWidget, ContentGroup, ContentGroupProps, ContentLayoutDef, ContentLayoutProps, CoreTools, Frontstage, FrontstageProps, FrontstageProvider, IModelViewportControl, UiFramework, Widget, Zone, } from "@bentley/ui-framework"; import { StageUsage } from "@bentley/ui-abstract"; import { SmallStatusBarWidgetControl } from "../Widgets/SmallStatusBar"; +/* eslint-disable react/jsx-key */ + // A content layout sets the number and arrangement of content views in a frontstage const sampleContentLayout: ContentLayoutProps = { id: "SampleContentLayout", @@ -22,7 +25,7 @@ const sampleViewportGroupProps: ContentGroupProps = { { classId: IModelViewportControl, id: "sampleIModelView", - applicationData: { viewState: UiFramework.getDefaultViewState, iModelConnection: UiFramework.getIModelConnection }, // Options passed to the ContentControl component + applicationData: { viewState: UiFramework.getDefaultViewState.bind(UiFramework), iModelConnection: UiFramework.getIModelConnection.bind(UiFramework) }, // Options passed to the ContentControl component }, ], }; diff --git a/src/FeatureToggleClient.ts b/src/FeatureToggleClient.ts index ef2c1c2dc..f6b4b6d59 100644 --- a/src/FeatureToggleClient.ts +++ b/src/FeatureToggleClient.ts @@ -16,7 +16,7 @@ export const featureFlags = { export class FeatureToggleClient { private static readonly _ldClientSideIds: { [deploymentEnv: string]: string } = { - DEPLOYED: "5beb1872d4851c306086a4fc", + DEPLOYED: "5beb1872d4851c306086a4fc", // eslint-disable-line @typescript-eslint/naming-convention }; private static _ldClient?: LDClient; @@ -38,7 +38,7 @@ export class FeatureToggleClient { private static evaluateFeature(featureKey: string, defaultValue?: LDFlagValue): LDFlagValue { assert(!!FeatureToggleClient._ldClient, "FeatureToggleClient.initialize hasn't been called yet."); - return FeatureToggleClient._ldClient!.variation(featureKey, defaultValue); + return FeatureToggleClient._ldClient.variation(featureKey, defaultValue); } } diff --git a/src/NoSignInIAuthClient.ts b/src/NoSignInIAuthClient.ts index 17a30c13d..77663f1c8 100644 --- a/src/NoSignInIAuthClient.ts +++ b/src/NoSignInIAuthClient.ts @@ -48,7 +48,9 @@ export class NoSignInIAuthClient implements FrontendAuthorizationClient { const body = await response.json(); const tokenJson = { ...await body, + // eslint-disable-next-line @typescript-eslint/naming-convention _userInfo: { id: "MockId" }, + // eslint-disable-next-line @typescript-eslint/naming-convention _tokenString: body._jwt, }; this._accessToken = AccessToken.fromJson(tokenJson); diff --git a/src/SampleBaseApp.ts b/src/SampleBaseApp.ts index 9a9b301e4..dc4f58161 100644 --- a/src/SampleBaseApp.ts +++ b/src/SampleBaseApp.ts @@ -6,7 +6,7 @@ import { ClientRequestContext, Config, Id64String } from "@bentley/bentleyjs-cor import { /* BrowserAuthorizationCallbackHandler */ BrowserAuthorizationClient /* BrowserAuthorizationClientConfiguration */ } from "@bentley/frontend-authorization-client"; import { UrlDiscoveryClient } from "@bentley/itwin-client"; import { FrontendRequestContext, IModelApp, IModelAppOptions, IModelConnection, TileAdmin } from "@bentley/imodeljs-frontend"; -import { BentleyCloudRpcManager, BentleyCloudRpcParams, IModelReadRpcInterface, IModelTileRpcInterface } from "@bentley/imodeljs-common"; +import { BentleyCloudRpcManager, IModelReadRpcInterface, IModelTileRpcInterface } from "@bentley/imodeljs-common"; import { MarkupApp } from "@bentley/imodeljs-markup"; import { PresentationRpcInterface } from "@bentley/presentation-common"; import { Presentation } from "@bentley/presentation-frontend"; @@ -73,12 +73,10 @@ export class SampleBaseApp { const rpcInterfaces = [IModelReadRpcInterface, IModelTileRpcInterface, PresentationRpcInterface]; // initialize RPC for web apps - let rpcParams: BentleyCloudRpcParams; - const urlClient = new UrlDiscoveryClient(); const requestContext = new FrontendRequestContext(); const orchestratorUrl = await urlClient.discoverUrl(requestContext, "iModelJsOrchestrator.K8S", undefined); - rpcParams = { info: { title: "general-purpose-imodeljs-backend", version: "v2.0" }, uriPrefix: orchestratorUrl }; + const rpcParams = { info: { title: "general-purpose-imodeljs-backend", version: "v2.0" }, uriPrefix: orchestratorUrl }; BentleyCloudRpcManager.initializeClient(rpcParams, rpcInterfaces); } diff --git a/src/api/Notifications/NotificationManager.tsx b/src/api/Notifications/NotificationManager.tsx index 649596e3e..47415b881 100644 --- a/src/api/Notifications/NotificationManager.tsx +++ b/src/api/Notifications/NotificationManager.tsx @@ -40,16 +40,16 @@ export class ShowcaseNotificationManager extends AppNotificationManager { const height = 20; const width = 20; location.style.position = "absolute"; - location.style.top = (pt.y - height / 2) + "px"; - location.style.left = (pt.x - width / 2) + "px"; - location.style.width = width + "px"; - location.style.height = height + "px"; + location.style.top = `${pt.y - height / 2}px`; + location.style.left = `${pt.x - width / 2}px`; + location.style.width = `${width}px`; + location.style.height = `${height}px`; el.appendChild(location); this._el = el; this._tooltipDiv = location; this._toolTip = new ToolTip(location, { trigger: "manual", html: true, placement: (options && options.placement) ? options.placement as any : "right-start", title: message }); - this._toolTip!.show(); + this._toolTip.show(); } } diff --git a/src/api/viewSetup.ts b/src/api/viewSetup.ts index 3ae0f8d4d..7f061a5ae 100644 --- a/src/api/viewSetup.ts +++ b/src/api/viewSetup.ts @@ -6,7 +6,7 @@ import { Id64, Id64String } from "@bentley/bentleyjs-core"; import { BackgroundMapProps, ColorDef } from "@bentley/imodeljs-common"; import { AuthorizedFrontendRequestContext, DrawingViewState, Environment, IModelApp, IModelConnection, - SpatialViewState, ViewState, ViewState3d, + SpatialViewState, ViewState, } from "@bentley/imodeljs-frontend"; import { SettingsMapResult, SettingsStatus } from "@bentley/product-settings-client"; @@ -22,12 +22,12 @@ export class ViewSetup { // Return first spatial view definition (if any) const spatialViews: IModelConnection.ViewSpec[] = await imodel.views.getViewList({ from: SpatialViewState.classFullName }); if (spatialViews.length > 0) - return spatialViews[0].id!; + return spatialViews[0].id; // Return first drawing view definition (if any) const drawingViews: IModelConnection.ViewSpec[] = await imodel.views.getViewList({ from: DrawingViewState.classFullName }); if (drawingViews.length > 0) - return drawingViews[0].id!; + return drawingViews[0].id; throw new Error("No valid view definitions in imodel"); } @@ -60,7 +60,7 @@ export class ViewSetup { viewState.viewFlags.grid = false; if (viewState.is3d()) { - const viewState3d = viewState as ViewState3d; + const viewState3d = viewState; const displayStyle = viewState3d.getDisplayStyle3d(); displayStyle.changeBackgroundMapProps({ useDepthBuffer: true }); diff --git a/src/common/CommonComponentTools/ComponentContainer.tsx b/src/common/CommonComponentTools/ComponentContainer.tsx index f1182f801..7459c4f60 100644 --- a/src/common/CommonComponentTools/ComponentContainer.tsx +++ b/src/common/CommonComponentTools/ComponentContainer.tsx @@ -31,7 +31,6 @@ export interface ComponentExampleProps { } // This formats a single component, along with its corresponding title and description, and adds them to the DOM -// tslint:disable-next-line:variable-name export const ComponentExample: React.FC = (props: ComponentExampleProps) => { const { title, description, content } = props; return ( diff --git a/src/common/PointSelector/PointSelector.tsx b/src/common/PointSelector/PointSelector.tsx index d8cbb73c0..337e8c8a6 100644 --- a/src/common/PointSelector/PointSelector.tsx +++ b/src/common/PointSelector/PointSelector.tsx @@ -60,19 +60,21 @@ export class PointSelector extends React.Component this.notifyChange()); + this.setState({ pointGenerator }); } private _onChangePointCount = (event: React.ChangeEvent) => { - this.setState({ pointCount: Number(event.target.value) }, () => this.notifyChange()); + this.setState({ pointCount: Number(event.target.value) }); } public componentDidMount() { this.notifyChange(); } - public componentDidUpdate(prevProps: PointSelectorProps) { - if (undefined !== this.props.range && this.props.range !== prevProps.range) { + public componentDidUpdate(prevProps: PointSelectorProps, prevState: PointSelectorState) { + if (undefined !== this.props.range && (this.props.range !== prevProps.range || + prevState.pointCount !== this.state.pointCount || + prevState.pointGenerator !== this.state.pointGenerator)) { this.notifyChange(); } } diff --git a/src/frontend-samples/app-ui-samples/toolbar-button-provider-sample/ToolbarButtonUi.tsx b/src/frontend-samples/app-ui-samples/toolbar-button-provider-sample/ToolbarButtonUi.tsx index 7464ba180..1252cef1e 100644 --- a/src/frontend-samples/app-ui-samples/toolbar-button-provider-sample/ToolbarButtonUi.tsx +++ b/src/frontend-samples/app-ui-samples/toolbar-button-provider-sample/ToolbarButtonUi.tsx @@ -12,7 +12,7 @@ export class ToolbarButtonProvider implements UiItemsProvider { */ public provideToolbarButtonItems(_stageId: string, stageUsage: string, toolbarUsage: ToolbarUsage, toolbarOrientation: ToolbarOrientation): CommonToolbarItem[] { if (stageUsage === StageUsage.General && toolbarUsage === ToolbarUsage.ContentManipulation && toolbarOrientation === ToolbarOrientation.Horizontal) { - const simpleActionSpec = ToolbarItemUtilities.createActionButton("Open message box", 1000, "icon-lightbulb", "Added Tool", this.startTool); + const simpleActionSpec = ToolbarItemUtilities.createActionButton("Open message box", 1000, "icon-lightbulb", "Added Tool", () => this.startTool()); return [simpleActionSpec]; } return []; diff --git a/src/frontend-samples/app-ui-samples/toolbar-button-provider-sample/sampleSpec.tsx b/src/frontend-samples/app-ui-samples/toolbar-button-provider-sample/sampleSpec.tsx index e8a051277..9522d59a5 100644 --- a/src/frontend-samples/app-ui-samples/toolbar-button-provider-sample/sampleSpec.tsx +++ b/src/frontend-samples/app-ui-samples/toolbar-button-provider-sample/sampleSpec.tsx @@ -17,7 +17,7 @@ export function getToolbarButtonSample(): SampleSpec { { name: "ToolbarButtonUi.tsx", import: import("!!raw-loader!./ToolbarButtonUi") }, ], customModelList: [SampleIModels.MetroStation, SampleIModels.RetailBuilding, SampleIModels.BayTown, SampleIModels.House, SampleIModels.Stadium], - setup: ToolbarButtonSample.setup, - teardown: ToolbarButtonSample.teardown, + setup: ToolbarButtonSample.setup.bind(ToolbarButtonSample), + teardown: ToolbarButtonSample.teardown.bind(ToolbarButtonSample), }); } diff --git a/src/frontend-samples/app-ui-samples/viewport-frontstage-sample/sampleSpec.tsx b/src/frontend-samples/app-ui-samples/viewport-frontstage-sample/sampleSpec.tsx index 669c1f0d0..fdd3157d5 100644 --- a/src/frontend-samples/app-ui-samples/viewport-frontstage-sample/sampleSpec.tsx +++ b/src/frontend-samples/app-ui-samples/viewport-frontstage-sample/sampleSpec.tsx @@ -17,7 +17,7 @@ export function getViewportFrontstageSample(): SampleSpec { { name: "ViewportFrontstageUi.tsx", import: import("!!raw-loader!../../../Components/frontstages/ViewportFrontstage") }, ], customModelList: [SampleIModels.MetroStation, SampleIModels.RetailBuilding, SampleIModels.BayTown, SampleIModels.House, SampleIModels.Stadium], - setup: ViewportFrontstageSample.setup, - teardown: ViewportFrontstageSample.teardown, + setup: ViewportFrontstageSample.setup.bind(ViewportFrontstageSample), + teardown: ViewportFrontstageSample.teardown.bind(ViewportFrontstageSample), }); } diff --git a/src/frontend-samples/component-gallery/badge-sample/sampleSpec.ts b/src/frontend-samples/component-gallery/badge-sample/sampleSpec.ts index 958a0f97b..9a41cf2a8 100644 --- a/src/frontend-samples/component-gallery/badge-sample/sampleSpec.ts +++ b/src/frontend-samples/component-gallery/badge-sample/sampleSpec.ts @@ -15,6 +15,6 @@ export function getBadgeSpec(): SampleSpec { files: [ { name: "Badge.tsx", import: import("!!raw-loader!./Badge"), entry: true }, ], - setup: BadgeList.setup, + setup: BadgeList.setup.bind(BadgeList), }); } diff --git a/src/frontend-samples/component-gallery/button-sample/sampleSpec.ts b/src/frontend-samples/component-gallery/button-sample/sampleSpec.ts index fb9ecba44..71a4a2328 100644 --- a/src/frontend-samples/component-gallery/button-sample/sampleSpec.ts +++ b/src/frontend-samples/component-gallery/button-sample/sampleSpec.ts @@ -15,6 +15,6 @@ export function getButtonSpec(): SampleSpec { files: [ { name: "Button.tsx", import: import("!!raw-loader!./Button"), entry: true }, ], - setup: ButtonList.setup, + setup: ButtonList.setup.bind(ButtonList), }); } diff --git a/src/frontend-samples/component-gallery/checklistbox-sample/sampleSpec.ts b/src/frontend-samples/component-gallery/checklistbox-sample/sampleSpec.ts index 2464cefaf..9df554c04 100644 --- a/src/frontend-samples/component-gallery/checklistbox-sample/sampleSpec.ts +++ b/src/frontend-samples/component-gallery/checklistbox-sample/sampleSpec.ts @@ -15,6 +15,6 @@ export function getCheckListBoxSpec(): SampleSpec { files: [ { name: "CheckListBox.tsx", import: import("!!raw-loader!./CheckListBox"), entry: true }, ], - setup: CheckListBoxList.setup, + setup: CheckListBoxList.setup.bind(CheckListBoxList), }); } diff --git a/src/frontend-samples/component-gallery/expandable-list-sample/ExpandableList.tsx b/src/frontend-samples/component-gallery/expandable-list-sample/ExpandableList.tsx index 3060f2feb..e13bf45a3 100644 --- a/src/frontend-samples/component-gallery/expandable-list-sample/ExpandableList.tsx +++ b/src/frontend-samples/component-gallery/expandable-list-sample/ExpandableList.tsx @@ -26,16 +26,16 @@ export default class ExpandableListList extends React.Component<{}> implements S { }}> Hello World! - + ), createComponentExample("ExpandableList w/ singleExpandOnly", "ExpandableList with singleExpandOnly prop", { }}> Hello World 1 - + { }}> Hello World 2 - + ), ]; } diff --git a/src/frontend-samples/component-gallery/expandable-list-sample/SampleExpandableBlock.tsx b/src/frontend-samples/component-gallery/expandable-list-sample/SampleExpandableBlock.tsx index 81c683073..e2907c521 100644 --- a/src/frontend-samples/component-gallery/expandable-list-sample/SampleExpandableBlock.tsx +++ b/src/frontend-samples/component-gallery/expandable-list-sample/SampleExpandableBlock.tsx @@ -6,18 +6,18 @@ import * as React from "react"; import { ExpandableBlock, ExpandableBlockProps } from "@bentley/ui-core"; /** Sample component using ExpandableBlock with an expanded state */ -// tslint:disable-next-line:variable-name +// eslint-disable-next-line @typescript-eslint/naming-convention export const SampleExpandableBlock: React.FC = (props: ExpandableBlockProps) => { const [expanded, setExpanded] = React.useState(true); // Inverts the expandable block's current state - const _handleClick = (event: React.MouseEvent): void => { + const handleClick = (event: React.MouseEvent): void => { setExpanded(!expanded); props.onClick && props.onClick(event); }; return ( - + ); }; diff --git a/src/frontend-samples/component-gallery/expandable-list-sample/sampleSpec.ts b/src/frontend-samples/component-gallery/expandable-list-sample/sampleSpec.ts index bcc651d3c..b9bd0dd97 100644 --- a/src/frontend-samples/component-gallery/expandable-list-sample/sampleSpec.ts +++ b/src/frontend-samples/component-gallery/expandable-list-sample/sampleSpec.ts @@ -16,6 +16,6 @@ export function getExpandableListSpec(): SampleSpec { { name: "ExpandableList.tsx", import: import("!!raw-loader!./ExpandableList"), entry: true }, { name: "SampleExpandableBlock.tsx", import: import("!!raw-loader!./SampleExpandableBlock") }, ], - setup: ExpandableListList.setup, + setup: ExpandableListList.setup.bind(ExpandableListList), }); } diff --git a/src/frontend-samples/component-gallery/inputs-sample/SampleImageCheckBox.tsx b/src/frontend-samples/component-gallery/inputs-sample/SampleImageCheckBox.tsx index 039a36c05..192a0016a 100644 --- a/src/frontend-samples/component-gallery/inputs-sample/SampleImageCheckBox.tsx +++ b/src/frontend-samples/component-gallery/inputs-sample/SampleImageCheckBox.tsx @@ -6,17 +6,17 @@ import * as React from "react"; import { ImageCheckBox, ImageCheckBoxProps } from "@bentley/ui-core"; /** Sample component using ImageCheckBox with a checked state */ -// tslint:disable-next-line:variable-name +// eslint-disable-next-line @typescript-eslint/naming-convention export const SampleImageCheckBox: React.FC = (props: ImageCheckBoxProps) => { const [checked, setChecked] = React.useState(false); // Inverts the current state of the image check box - const _handleClick = (targetChecked: boolean): any => { + const handleClick = (targetChecked: boolean): any => { setChecked(targetChecked); props.onClick && props.onClick(targetChecked); }; return ( - + ); }; diff --git a/src/frontend-samples/component-gallery/inputs-sample/sampleSpec.ts b/src/frontend-samples/component-gallery/inputs-sample/sampleSpec.ts index d72529882..b3e6674aa 100644 --- a/src/frontend-samples/component-gallery/inputs-sample/sampleSpec.ts +++ b/src/frontend-samples/component-gallery/inputs-sample/sampleSpec.ts @@ -16,6 +16,6 @@ export function getInputsSpec(): SampleSpec { { name: "Inputs.tsx", import: import("!!raw-loader!./Inputs"), entry: true }, { name: "SampleImageCheckBox.tsx", import: import("!!raw-loader!./SampleImageCheckBox") }, ], - setup: InputsList.setup, + setup: InputsList.setup.bind(InputsList), }); } diff --git a/src/frontend-samples/component-gallery/loading-sample/sampleSpec.ts b/src/frontend-samples/component-gallery/loading-sample/sampleSpec.ts index 75db97fbe..eb8cdde86 100644 --- a/src/frontend-samples/component-gallery/loading-sample/sampleSpec.ts +++ b/src/frontend-samples/component-gallery/loading-sample/sampleSpec.ts @@ -15,6 +15,6 @@ export function getLoadingSpec(): SampleSpec { files: [ { name: "Loading.tsx", import: import("!!raw-loader!./Loading"), entry: true }, ], - setup: LoadingList.setup, + setup: LoadingList.setup.bind(LoadingList), }); } diff --git a/src/frontend-samples/component-gallery/search-box-sample/SearchBox.tsx b/src/frontend-samples/component-gallery/search-box-sample/SearchBox.tsx index 9d8bb15b0..6dfa79dfa 100644 --- a/src/frontend-samples/component-gallery/search-box-sample/SearchBox.tsx +++ b/src/frontend-samples/component-gallery/search-box-sample/SearchBox.tsx @@ -22,7 +22,7 @@ export default class SearchBoxList extends React.Component<{}> implements Sample public static getSearchBoxData(): ComponentExampleProps[] { return [ createComponentExample("SearchBox", undefined, - // tslint:disable-next-line: no-console + // eslint-disable-next-line no-console console.log(`Search text: ${value}`)} />), ]; } diff --git a/src/frontend-samples/component-gallery/search-box-sample/sampleSpec.ts b/src/frontend-samples/component-gallery/search-box-sample/sampleSpec.ts index 21ca0fdb3..3dad4bb93 100644 --- a/src/frontend-samples/component-gallery/search-box-sample/sampleSpec.ts +++ b/src/frontend-samples/component-gallery/search-box-sample/sampleSpec.ts @@ -15,6 +15,6 @@ export function getSearchBoxSpec(): SampleSpec { files: [ { name: "SearchBox.tsx", import: import("!!raw-loader!./SearchBox"), entry: true }, ], - setup: SearchBoxList.setup, + setup: SearchBoxList.setup.bind(SearchBoxList), }); } diff --git a/src/frontend-samples/component-gallery/slider-sample/sampleSpec.ts b/src/frontend-samples/component-gallery/slider-sample/sampleSpec.ts index 1bb3f9513..3fcbb0b92 100644 --- a/src/frontend-samples/component-gallery/slider-sample/sampleSpec.ts +++ b/src/frontend-samples/component-gallery/slider-sample/sampleSpec.ts @@ -15,6 +15,6 @@ export function getSliderSpec(): SampleSpec { files: [ { name: "Slider.tsx", import: import("!!raw-loader!./Slider"), entry: true }, ], - setup: SliderList.setup, + setup: SliderList.setup.bind(SliderList), }); } diff --git a/src/frontend-samples/component-gallery/split-button-sample/sampleSpec.ts b/src/frontend-samples/component-gallery/split-button-sample/sampleSpec.ts index 5e877eab2..0ef04804c 100644 --- a/src/frontend-samples/component-gallery/split-button-sample/sampleSpec.ts +++ b/src/frontend-samples/component-gallery/split-button-sample/sampleSpec.ts @@ -15,6 +15,6 @@ export function getSplitButtonSpec(): SampleSpec { files: [ { name: "SplitButton.tsx", import: import("!!raw-loader!./SplitButton"), entry: true }, ], - setup: SplitButtonList.setup, + setup: SplitButtonList.setup.bind(SplitButtonList), }); } diff --git a/src/frontend-samples/component-gallery/tabs-sample/sampleSpec.ts b/src/frontend-samples/component-gallery/tabs-sample/sampleSpec.ts index 18d5c6894..6a9a96566 100644 --- a/src/frontend-samples/component-gallery/tabs-sample/sampleSpec.ts +++ b/src/frontend-samples/component-gallery/tabs-sample/sampleSpec.ts @@ -15,6 +15,6 @@ export function getTabsSpec(): SampleSpec { files: [ { name: "Tabs.tsx", import: import("!!raw-loader!./Tabs"), entry: true }, ], - setup: TabsList.setup, + setup: TabsList.setup.bind(TabsList), }); } diff --git a/src/frontend-samples/component-gallery/text-sample/sampleSpec.ts b/src/frontend-samples/component-gallery/text-sample/sampleSpec.ts index 626df78c3..9a7de0886 100644 --- a/src/frontend-samples/component-gallery/text-sample/sampleSpec.ts +++ b/src/frontend-samples/component-gallery/text-sample/sampleSpec.ts @@ -15,6 +15,6 @@ export function getTextSpec(): SampleSpec { files: [ { name: "Text.tsx", import: import("!!raw-loader!./Text"), entry: true }, ], - setup: TextList.setup, + setup: TextList.setup.bind(TextList), }); } diff --git a/src/frontend-samples/component-gallery/tiles-sample/Tiles.tsx b/src/frontend-samples/component-gallery/tiles-sample/Tiles.tsx index f04e9f009..f05fd9a0c 100644 --- a/src/frontend-samples/component-gallery/tiles-sample/Tiles.tsx +++ b/src/frontend-samples/component-gallery/tiles-sample/Tiles.tsx @@ -23,13 +23,13 @@ export default class TilesList extends React.Component<{}> implements SampleApp return [ createComponentExample("Normal Tile", undefined, - Link 1 {/* eslint-disable-line jsx-a11y/anchor-is-valid */} - Link 2 {/* eslint-disable-line jsx-a11y/anchor-is-valid */} + Link 1 + Link 2 ), createComponentExample("Featured Tile", undefined, - Link 1 {/* eslint-disable-line jsx-a11y/anchor-is-valid */} - Link 2 {/* eslint-disable-line jsx-a11y/anchor-is-valid */} + Link 1 + Link 2 ), createComponentExample("Minimal Tile", undefined, ), createComponentExample("Featured Minimal Tile", undefined, ), diff --git a/src/frontend-samples/component-gallery/tiles-sample/sampleSpec.ts b/src/frontend-samples/component-gallery/tiles-sample/sampleSpec.ts index 5bf3c2ad6..5a3ecdf99 100644 --- a/src/frontend-samples/component-gallery/tiles-sample/sampleSpec.ts +++ b/src/frontend-samples/component-gallery/tiles-sample/sampleSpec.ts @@ -15,6 +15,6 @@ export function getTilesSpec(): SampleSpec { files: [ { name: "Tiles.tsx", import: import("!!raw-loader!./Tiles"), entry: true }, ], - setup: TilesList.setup, + setup: TilesList.setup.bind(TilesList), }); } diff --git a/src/frontend-samples/component-gallery/toggle-sample/sampleSpec.ts b/src/frontend-samples/component-gallery/toggle-sample/sampleSpec.ts index 2eb407f09..bac54ca29 100644 --- a/src/frontend-samples/component-gallery/toggle-sample/sampleSpec.ts +++ b/src/frontend-samples/component-gallery/toggle-sample/sampleSpec.ts @@ -15,6 +15,6 @@ export function getToggleSpec(): SampleSpec { files: [ { name: "Toggle.tsx", import: import("!!raw-loader!./Toggle"), entry: true }, ], - setup: ToggleList.setup, + setup: ToggleList.setup.bind(ToggleList), }); } diff --git a/src/frontend-samples/emphasize-elements-sample/sampleSpec.ts b/src/frontend-samples/emphasize-elements-sample/sampleSpec.ts index 7afddb16c..4af7cfff1 100644 --- a/src/frontend-samples/emphasize-elements-sample/sampleSpec.ts +++ b/src/frontend-samples/emphasize-elements-sample/sampleSpec.ts @@ -17,7 +17,7 @@ export function getEmphasizeElementsSpec(): SampleSpec { ], customModelList: [SampleIModels.RetailBuilding, SampleIModels.MetroStation, SampleIModels.BayTown, SampleIModels.House, SampleIModels.Stadium], - setup: EmphasizeElementsApp.setup, - teardown: EmphasizeElementsApp.teardown, + setup: EmphasizeElementsApp.setup.bind(EmphasizeElementsApp), + teardown: EmphasizeElementsApp.teardown.bind(EmphasizeElementsApp), }); } diff --git a/src/frontend-samples/heatmap-decorator-sample/HeatmapDecoratorUI.tsx b/src/frontend-samples/heatmap-decorator-sample/HeatmapDecoratorUI.tsx index 680c63a36..ec4e4d9f5 100644 --- a/src/frontend-samples/heatmap-decorator-sample/HeatmapDecoratorUI.tsx +++ b/src/frontend-samples/heatmap-decorator-sample/HeatmapDecoratorUI.tsx @@ -45,26 +45,41 @@ export default class HeatmapDecoratorUI extends React.Component { - this.setState({ points }, () => { + public componentDidUpdate(_prevProps: {}, prevState: HeatmapDecoratorUIState) { + if (prevState.imodel !== this.state.imodel) + if (this.state.showDecorator) { + HeatmapDecoratorApp.setupDecorator(this.state.points, this.state.range, this.state.spreadFactor, this.state.height); + HeatmapDecoratorApp.enableDecorations(); + } + + if (prevState.points !== this.state.points) { if (HeatmapDecoratorApp.decorator) HeatmapDecoratorApp.decorator.setPoints(this.state.points); - }); - } + } - private _onChangeSpreadFactor = (event: React.ChangeEvent) => { - this.setState({ spreadFactor: Number(event.target.value) }, () => { + if (prevState.spreadFactor !== this.state.spreadFactor) { if (HeatmapDecoratorApp.decorator) HeatmapDecoratorApp.decorator.setSpreadFactor(this.state.spreadFactor); - }); + } + + if (prevState.showDecorator !== this.state.showDecorator) { + if (this.state.showDecorator) + HeatmapDecoratorApp.enableDecorations(); + else + HeatmapDecoratorApp.disableDecorations(); + } + } + + private _onPointsChanged = (points: Point3d[]) => { + this.setState({ points }); + } + + private _onChangeSpreadFactor = (event: React.ChangeEvent) => { + this.setState({ spreadFactor: Number(event.target.value) }); } private _onChangeShowHeatmap = (checked: boolean) => { - if (checked) { - this.setState({ showDecorator: true }, () => HeatmapDecoratorApp.enableDecorations()); - } else { - this.setState({ showDecorator: false }, () => HeatmapDecoratorApp.disableDecorations()); - } + this.setState({ showDecorator: checked }); } /** This callback will be executed by ReloadableViewport to initialize the viewstate */ @@ -100,12 +115,7 @@ export default class HeatmapDecoratorUI extends React.Component { - if (this.state.showDecorator) { - HeatmapDecoratorApp.setupDecorator(this.state.points, this.state.range, this.state.spreadFactor, this.state.height); - HeatmapDecoratorApp.enableDecorations(); - } - }); + this.setState({ imodel, vp, range, height }); }); } diff --git a/src/frontend-samples/heatmap-decorator-sample/sampleSpec.ts b/src/frontend-samples/heatmap-decorator-sample/sampleSpec.ts index dec71521f..1058ee816 100644 --- a/src/frontend-samples/heatmap-decorator-sample/sampleSpec.ts +++ b/src/frontend-samples/heatmap-decorator-sample/sampleSpec.ts @@ -15,7 +15,7 @@ export function getHeatmapDecoratorSpec(): SampleSpec { { name: "HeatmapDecoratorUI.tsx", import: import("!!raw-loader!./HeatmapDecoratorUI") }, { name: "HeatmapDecorator.tsx", import: import("!!raw-loader!./HeatmapDecorator") }, ], - setup: HeatmapDecoratorApp.setup, - teardown: HeatmapDecoratorApp.teardown, + setup: HeatmapDecoratorApp.setup.bind(HeatmapDecoratorApp), + teardown: HeatmapDecoratorApp.teardown.bind(HeatmapDecoratorApp), }); } diff --git a/src/frontend-samples/marker-pin-sample/MarkerPinDecorator.ts b/src/frontend-samples/marker-pin-sample/MarkerPinDecorator.ts index 5fea04b7c..2b6964cf1 100644 --- a/src/frontend-samples/marker-pin-sample/MarkerPinDecorator.ts +++ b/src/frontend-samples/marker-pin-sample/MarkerPinDecorator.ts @@ -178,7 +178,7 @@ class SampleMarkerSet extends MarkerSet { let index = 1; for (const point of points) { - this.markers.add(new SamplePinMarker(point, "Marker " + index++, image, this)); + this.markers.add(new SamplePinMarker(point, `Marker ${index++}`, image, this)); } } diff --git a/src/frontend-samples/marker-pin-sample/MarkerPinUI.tsx b/src/frontend-samples/marker-pin-sample/MarkerPinUI.tsx index 4bb437a88..1e79fbefb 100644 --- a/src/frontend-samples/marker-pin-sample/MarkerPinUI.tsx +++ b/src/frontend-samples/marker-pin-sample/MarkerPinUI.tsx @@ -32,7 +32,7 @@ interface MarkerPinsUIState { } export default class MarkerPinsUI extends React.Component<{ - iModelName: string, iModelSelector: React.ReactNode; + iModelName: string; iModelSelector: React.ReactNode; }, MarkerPinsUIState> { /** Creates a Sample instance */ @@ -47,6 +47,26 @@ export default class MarkerPinsUI extends React.Component<{ }; } + public componentDidUpdate(_prevProps: {}, prevState: MarkerPinsUIState) { + if (prevState.imodel !== this.state.imodel) + if (this.state.showDecorator) { + MarkerPinApp.setupDecorator(this.state.points); + MarkerPinApp.enableDecorations(); + } + + if (prevState.points !== this.state.points) { + if (MarkerPinApp.decoratorIsSetup()) + MarkerPinApp.setMarkerPoints(this.state.points); + } + + if (prevState.showDecorator !== this.state.showDecorator) { + if (this.state.showDecorator) + MarkerPinApp.enableDecorations(); + else + MarkerPinApp.disableDecorations(); + } + } + /** This callback will be executed when the user interacts with the PointSelector * UI component. It is also called once when the component initializes. */ @@ -55,25 +75,22 @@ export default class MarkerPinsUI extends React.Component<{ for (const point of points) point.z = this.state.height; - this.setState({ points }, () => { - if (MarkerPinApp.decoratorIsSetup()) - MarkerPinApp.setMarkerPoints(points); - }); + this.setState({ points }); } /** Called when the user changes the showMarkers toggle. */ private _onChangeShowMarkers = (checked: boolean) => { if (checked) { - this.setState({ showDecorator: true }, () => MarkerPinApp.enableDecorations()); + this.setState({ showDecorator: true }); } else { - this.setState({ showDecorator: false }, () => MarkerPinApp.disableDecorations()); + this.setState({ showDecorator: false }); } } /** A static array of pin images. */ private static getManualPinSelections(): ManualPinSelection[] { - return ( - [{ image: "Google_Maps_pin.svg", name: "Google Pin" }, + return ([ + { image: "Google_Maps_pin.svg", name: "Google Pin" }, { image: "pin_celery.svg", name: "Celery Pin" }, { image: "pin_poloblue.svg", name: "Polo blue Pin" }]); } @@ -127,12 +144,7 @@ export default class MarkerPinsUI extends React.Component<{ // Grab the max Z for the view contents. We'll use this as the plane for the auto-generated markers. */ const height = range3d.zHigh; - this.setState({ imodel, range, height }, () => { - if (this.state.showDecorator) { - MarkerPinApp.setupDecorator(this.state.points); - MarkerPinApp.enableDecorations(); - } - }); + this.setState({ imodel, range, height }); }); } @@ -169,7 +181,7 @@ export default class MarkerPinsUI extends React.Component<{ return ( <> - + ); } } diff --git a/src/frontend-samples/marker-pin-sample/sampleSpec.ts b/src/frontend-samples/marker-pin-sample/sampleSpec.ts index a51f384ee..79357c16e 100644 --- a/src/frontend-samples/marker-pin-sample/sampleSpec.ts +++ b/src/frontend-samples/marker-pin-sample/sampleSpec.ts @@ -17,7 +17,7 @@ export function getMarkerPinSpec(): SampleSpec { { name: "PlaceMarkerTool.ts", import: import("!!raw-loader!./PlaceMarkerTool") }, { name: "PopupMenu.tsx", import: import("!!raw-loader!./PopupMenu") }, ], - setup: MarkerPinApp.setup, - teardown: MarkerPinApp.teardown, + setup: MarkerPinApp.setup.bind(MarkerPinApp), + teardown: MarkerPinApp.teardown.bind(MarkerPinApp), }); } diff --git a/src/frontend-samples/multi-viewport-sample/MultiViewportUI.tsx b/src/frontend-samples/multi-viewport-sample/MultiViewportUI.tsx index 4e2b16cc1..62cc7b100 100644 --- a/src/frontend-samples/multi-viewport-sample/MultiViewportUI.tsx +++ b/src/frontend-samples/multi-viewport-sample/MultiViewportUI.tsx @@ -31,7 +31,7 @@ export default class MultiViewportUI extends React.Component { if (args.previous) - args.previous!.vpDiv.classList.remove("active-viewport"); + args.previous.vpDiv.classList.remove("active-viewport"); if (args.current) args.current.vpDiv.classList.add("active-viewport"); } @@ -43,7 +43,8 @@ export default class MultiViewportUI extends React.Component { - this.setState({ viewports: [...this.state.viewports, viewport] }); + const viewports = this.state.viewports; + this.setState({ viewports: [...viewports, viewport] }); } // Handles when the app teardown is called which signals when the views are all closed. diff --git a/src/frontend-samples/multi-viewport-sample/sampleSpec.tsx b/src/frontend-samples/multi-viewport-sample/sampleSpec.tsx index be348e4ad..5c65c00a1 100644 --- a/src/frontend-samples/multi-viewport-sample/sampleSpec.tsx +++ b/src/frontend-samples/multi-viewport-sample/sampleSpec.tsx @@ -15,7 +15,7 @@ export function getMultiViewportSpec(): SampleSpec { { name: "MultiViewportUI.tsx", import: import("!!raw-loader!./MultiViewportUI") }, { name: "multi-view-sample.scss", import: import("!!raw-loader!./multi-view-sample.scss") }, ], - setup: MultiViewportApp.setup, - teardown: MultiViewportApp.teardown, + setup: MultiViewportApp.setup.bind(MultiViewportApp), + teardown: MultiViewportApp.teardown.bind(MultiViewportApp), }); } diff --git a/src/frontend-samples/reality-data-sample/RealityDataUI.tsx b/src/frontend-samples/reality-data-sample/RealityDataUI.tsx index 7583de52f..570d22c54 100644 --- a/src/frontend-samples/reality-data-sample/RealityDataUI.tsx +++ b/src/frontend-samples/reality-data-sample/RealityDataUI.tsx @@ -24,11 +24,19 @@ export default class RealityDataUI extends React.Component<{ iModelName: string, }; } + public componentDidUpdate(_prevProps: {}, prevState: RealityDataState) { + if (prevState.showRealityData !== this.state.showRealityData) { + const vp = IModelApp.viewManager.selectedView; + if (vp) + RealityDataApp.toggleRealityModel(this.state.showRealityData, vp, this.state.imodel!); + } + } + // Create the react components for the toggle private createToggle(label: string, info: string) { const show: boolean = this.state.showRealityData; - const element = this._onChangeToggle(checked)} />; + const element = this._onChangeToggle(checked)} />; return (
<> @@ -41,18 +49,7 @@ export default class RealityDataUI extends React.Component<{ iModelName: string, // Handle changes to the toggle. private _onChangeToggle = async (checked: boolean) => { - if (this.state.imodel) { - const vp = IModelApp.viewManager.selectedView; - if (undefined === vp) { - return false; - } - - this.setState({ showRealityData: checked }, async () => { - await RealityDataApp.toggleRealityModel(checked, vp, this.state.imodel!); - }); - } - - return false; + this.setState({ showRealityData: checked }); } /** @@ -63,8 +60,7 @@ export default class RealityDataUI extends React.Component<{ iModelName: string, this.setState({ imodel }); IModelApp.viewManager.onViewOpen.addOnce((_vp: ScreenViewport) => { - // tslint:disable-next-line no-floating-promises - this.setState({ imodel, showRealityData: true }, () => { RealityDataApp.toggleRealityModel(true, _vp, imodel); }); + this.setState({ imodel, showRealityData: true }); }); } diff --git a/src/frontend-samples/reality-data-sample/sampleSpec.tsx b/src/frontend-samples/reality-data-sample/sampleSpec.tsx index 98b690620..24b9c0420 100644 --- a/src/frontend-samples/reality-data-sample/sampleSpec.tsx +++ b/src/frontend-samples/reality-data-sample/sampleSpec.tsx @@ -16,6 +16,6 @@ export function getRealityDataSpec(): SampleSpec { { name: "RealityDataUI.tsx", import: import("!!raw-loader!./RealityDataUI") }, ], customModelList: [SampleIModels.ExtonCampus], - setup: RealityDataApp.setup, + setup: RealityDataApp.setup.bind(RealityDataApp), }); } diff --git a/src/frontend-samples/shadow-study-sample/ShadowStudyUI.tsx b/src/frontend-samples/shadow-study-sample/ShadowStudyUI.tsx index 7d982592a..cd381a2e4 100644 --- a/src/frontend-samples/shadow-study-sample/ShadowStudyUI.tsx +++ b/src/frontend-samples/shadow-study-sample/ShadowStudyUI.tsx @@ -103,11 +103,11 @@ export default class ShadowStudyUI extends React.Component<{ iModelName: string, const minute = this.state.date.getMinutes(); let minString: string; if (minute < 10) - minString = "0" + String(minute); + minString = `0${String(minute)}`; else minString = String(minute); const hour = this.state.date.getHours(); - return String(hour) + ":" + minString; + return `${String(hour)}:${minString}`; } // Initialize the data view when a new iModel is loaded @@ -140,7 +140,7 @@ export default class ShadowStudyUI extends React.Component<{ iModelName: string,
Date
-
{String(this.state.date.getMonth() + 1) + "/" + this.state.date.getDate() + "/" + this.state.date.getFullYear()}
+
{`${String(this.state.date.getMonth() + 1)}/${this.state.date.getDate()}/${this.state.date.getFullYear()}`}
diff --git a/src/frontend-samples/shadow-study-sample/sampleSpec.ts b/src/frontend-samples/shadow-study-sample/sampleSpec.ts index f6b138484..65b6747e0 100644 --- a/src/frontend-samples/shadow-study-sample/sampleSpec.ts +++ b/src/frontend-samples/shadow-study-sample/sampleSpec.ts @@ -15,6 +15,6 @@ export function getShadowStudySpec(): SampleSpec { { name: "ShadowStudyUI.tsx", import: import("!!raw-loader!./ShadowStudyUI") }, ], - setup: ShadowStudyApp.setup, + setup: ShadowStudyApp.setup.bind(ShadowStudyApp), }); } diff --git a/src/frontend-samples/thematic-display-sample/sampleSpec.ts b/src/frontend-samples/thematic-display-sample/sampleSpec.ts index efc557e26..8fdece0a3 100644 --- a/src/frontend-samples/thematic-display-sample/sampleSpec.ts +++ b/src/frontend-samples/thematic-display-sample/sampleSpec.ts @@ -16,7 +16,7 @@ export function getThematicDisplaySpec(): SampleSpec { { name: "ThematicDisplayUI.tsx", import: import("!!raw-loader!./ThematicDisplayUI") }, ], customModelList: [SampleIModels.RetailBuilding, SampleIModels.MetroStation, SampleIModels.BayTown, SampleIModels.House, SampleIModels.Stadium], - setup: ThematicDisplaySampleApp.setup, - teardown: ThematicDisplaySampleApp.teardown, + setup: ThematicDisplaySampleApp.setup.bind(ThematicDisplaySampleApp), + teardown: ThematicDisplaySampleApp.teardown.bind(ThematicDisplaySampleApp), }); } diff --git a/src/frontend-samples/tooltip-customize-sample/TooltipCustomizeApp.tsx b/src/frontend-samples/tooltip-customize-sample/TooltipCustomizeApp.tsx index 430f81301..cbafd0656 100644 --- a/src/frontend-samples/tooltip-customize-sample/TooltipCustomizeApp.tsx +++ b/src/frontend-samples/tooltip-customize-sample/TooltipCustomizeApp.tsx @@ -10,6 +10,7 @@ import { ElemProperty, TooltipCustomizeSettings, TooltipCustomizeUI } from "./To import { HitDetail, imageElementFromUrl } from "@bentley/imodeljs-frontend"; import SampleApp from "common/SampleApp"; + // SampleToolAdmin would typically extend ToolAdmin // See Notes on use of ProxyToolAdmin at the bottom of this file. // Do this: "class YourToolAdmin extends ToolAdmin" @@ -28,7 +29,7 @@ export class SampleToolAdmin extends ProxyToolAdmin { if (!this.settings.showImage && !this.settings.showCustomText && !this.settings.showElementProperty && !this.settings.showDefaultToolTip) return ""; - const tip = document.createElement("div") as HTMLDivElement; + const tip = document.createElement("div"); let needHR = false; if (this.settings.showImage) { const img = await imageElementFromUrl(".\\iModeljs-logo.png"); @@ -39,7 +40,7 @@ export class SampleToolAdmin extends ProxyToolAdmin { if (this.settings.showCustomText) { if (needHR) tip.appendChild(document.createElement("hr")); - const customText = document.createElement("span") as HTMLSpanElement; + const customText = document.createElement("span"); customText.innerHTML = this.settings.customText; tip.appendChild(customText); needHR = true; @@ -50,7 +51,7 @@ export class SampleToolAdmin extends ProxyToolAdmin { tip.appendChild(document.createElement("hr")); const propertyName = this.settings.elemProperty as string; - let msg = "" + propertyName + ": "; + let msg = `${propertyName}: `; if (hit.isElementHit) { const query = `SELECT ${propertyName} AS val FROM BisCore.SpatialElement @@ -68,16 +69,16 @@ export class SampleToolAdmin extends ProxyToolAdmin { break; case ElemProperty.Origin: msg += "
    "; - msg += "
  • x: " + row.val.x + "
  • "; - msg += "
  • y: " + row.val.y + "
  • "; - msg += "
  • z: " + row.val.z + "
  • "; + msg += `
  • x: ${row.val.x}
  • `; + msg += `
  • y: ${row.val.y}
  • `; + msg += `
  • z: ${row.val.z}
  • `; msg += "
"; break; } } } - const htmlTip = document.createElement("span") as HTMLSpanElement; + const htmlTip = document.createElement("span"); htmlTip.innerHTML = msg; tip.appendChild(htmlTip); needHR = true; @@ -88,7 +89,7 @@ export class SampleToolAdmin extends ProxyToolAdmin { tip.appendChild(document.createElement("hr")); let defaultTip = await super.getToolTip(hit); if (typeof defaultTip === "string") { - const htmlTip = document.createElement("span") as HTMLSpanElement; + const htmlTip = document.createElement("span"); htmlTip.innerHTML = defaultTip; defaultTip = htmlTip; } diff --git a/src/frontend-samples/tooltip-customize-sample/TooltipCustomizeUI.tsx b/src/frontend-samples/tooltip-customize-sample/TooltipCustomizeUI.tsx index 6de8b4b88..e9d877ffd 100644 --- a/src/frontend-samples/tooltip-customize-sample/TooltipCustomizeUI.tsx +++ b/src/frontend-samples/tooltip-customize-sample/TooltipCustomizeUI.tsx @@ -32,59 +32,42 @@ export class TooltipCustomizeUI extends React.Component<{ iModelName: string, iM /** Creates a Sample instance */ constructor(props?: any, context?: any) { super(props, context); - // Use "IModelApp.toolAdmin as YourToolAdmin" see Notes at bottom of this file. + // Use "IModelApp.toolAdmin as YourToolAdmin" see Notes at bottom of TooltipCustomizeApp.tsx. const toolAdmin = ShowcaseToolAdmin.get().getProxyToolAdmin() as SampleToolAdmin; this.state = { ...toolAdmin.settings }; } + public componentDidUpdate(_prevProps: {}, prevState: TooltipCustomizeSettings) { + // Use "IModelApp.toolAdmin as YourToolAdmin" see Notes at bottom of TooltipCustomizeApp.tsx. + const toolAdmin = ShowcaseToolAdmin.get().getProxyToolAdmin() as SampleToolAdmin; + if (prevState !== this.state) + toolAdmin.settings = this.state; + } + private _onChangeShowImage = (checked: boolean) => { - this.setState({ showImage: checked }, () => { - // Use "IModelApp.toolAdmin as YourToolAdmin" see Notes at bottom of this file. - const toolAdmin = ShowcaseToolAdmin.get().getProxyToolAdmin() as SampleToolAdmin; - toolAdmin.settings.showImage = checked; - }); + this.setState({ showImage: checked }); } private _onChangeShowCustomText = (checked: boolean) => { - this.setState({ showCustomText: checked }, () => { - // Use "IModelApp.toolAdmin as YourToolAdmin" see Notes at bottom of this file. - const toolAdmin = ShowcaseToolAdmin.get().getProxyToolAdmin() as SampleToolAdmin; - toolAdmin.settings.showCustomText = checked; - }); + this.setState({ showCustomText: checked }); } private _onChangeShowElementProperty = (checked: boolean) => { - this.setState({ showElementProperty: checked }, () => { - // Use "IModelApp.toolAdmin as YourToolAdmin" see Notes at bottom of this file. - const toolAdmin = ShowcaseToolAdmin.get().getProxyToolAdmin() as SampleToolAdmin; - toolAdmin.settings.showElementProperty = checked; - }); + this.setState({ showElementProperty: checked }); } private _onChangeShowDefaultToolTip = (checked: boolean) => { - this.setState({ showDefaultToolTip: checked }, () => { - // Use "IModelApp.toolAdmin as YourToolAdmin" see Notes at bottom of this file. - const toolAdmin = ShowcaseToolAdmin.get().getProxyToolAdmin() as SampleToolAdmin; - toolAdmin.settings.showDefaultToolTip = checked; - }); + this.setState({ showDefaultToolTip: checked }); } private _onChangeCustomText = (event: React.ChangeEvent) => { const value: string = event.target.value; - this.setState({ customText: value }, () => { - // Use "IModelApp.toolAdmin as YourToolAdmin" see Notes at bottom of this file. - const toolAdmin = ShowcaseToolAdmin.get().getProxyToolAdmin() as SampleToolAdmin; - toolAdmin.settings.customText = value; - }); + this.setState({ customText: value }); } private _onChangeElementProperty = (event: React.ChangeEvent) => { const value = event.target.value as ElemProperty; - this.setState({ elemProperty: value }, () => { - // Use "IModelApp.toolAdmin as YourToolAdmin" see Notes at bottom of this file. - const toolAdmin = ShowcaseToolAdmin.get().getProxyToolAdmin() as SampleToolAdmin; - toolAdmin.settings.elemProperty = value; - }); + this.setState({ elemProperty: value }); } /** Components for rendering the sample's instructions and controls */ diff --git a/src/frontend-samples/tooltip-customize-sample/sampleSpec.ts b/src/frontend-samples/tooltip-customize-sample/sampleSpec.ts index 32d2997fc..c233a611a 100644 --- a/src/frontend-samples/tooltip-customize-sample/sampleSpec.ts +++ b/src/frontend-samples/tooltip-customize-sample/sampleSpec.ts @@ -14,7 +14,7 @@ export function getTooltipCustomizeSpec(): SampleSpec { { name: "TooltipCustomizeApp.tsx", import: import("!!raw-loader!./TooltipCustomizeApp"), entry: true }, { name: "TooltipCustomizeUI.tsx", import: import("!!raw-loader!./TooltipCustomizeUI") }, ], - setup: TooltipCustomizeApp.setup, - teardown: TooltipCustomizeApp.teardown, + setup: TooltipCustomizeApp.setup.bind(TooltipCustomizeApp), + teardown: TooltipCustomizeApp.teardown.bind(TooltipCustomizeApp), }); } diff --git a/src/frontend-samples/tree-samples/basic-tree/sampleSpec.ts b/src/frontend-samples/tree-samples/basic-tree/sampleSpec.ts index 8cf08c94c..677033b34 100644 --- a/src/frontend-samples/tree-samples/basic-tree/sampleSpec.ts +++ b/src/frontend-samples/tree-samples/basic-tree/sampleSpec.ts @@ -15,6 +15,6 @@ export function getBasicTreeSpec(): SampleSpec { files: [ { name: "BasicTreeApp.tsx", import: import("!!raw-loader!./BasicTreeApp"), entry: true }, ], - setup: BasicTreeApp.setup, + setup: BasicTreeApp.setup.bind(BasicTreeApp), }); } diff --git a/src/frontend-samples/tree-samples/custom-checkboxes-tree/sampleSpec.ts b/src/frontend-samples/tree-samples/custom-checkboxes-tree/sampleSpec.ts index 2bd76f876..4ca4f9c44 100644 --- a/src/frontend-samples/tree-samples/custom-checkboxes-tree/sampleSpec.ts +++ b/src/frontend-samples/tree-samples/custom-checkboxes-tree/sampleSpec.ts @@ -15,6 +15,6 @@ export function getCustomCheckboxesTreeSpec(): SampleSpec { files: [ { name: "CustomCheckboxesTreeApp.tsx", import: import("!!raw-loader!./CustomCheckboxesTreeApp"), entry: true }, ], - setup: CustomCheckboxesTreeApp.setup, + setup: CustomCheckboxesTreeApp.setup.bind(CustomCheckboxesTreeApp), }); } diff --git a/src/frontend-samples/tree-samples/custom-event-handler-tree/sampleSpec.ts b/src/frontend-samples/tree-samples/custom-event-handler-tree/sampleSpec.ts index 9c69e2083..0591af95f 100644 --- a/src/frontend-samples/tree-samples/custom-event-handler-tree/sampleSpec.ts +++ b/src/frontend-samples/tree-samples/custom-event-handler-tree/sampleSpec.ts @@ -15,6 +15,6 @@ export function getCustomEventHandlerTreeSpec(): SampleSpec { files: [ { name: "CustomEventHandlerTreeApp.tsx", import: import("!!raw-loader!./CustomEventHandlerTreeApp"), entry: true }, ], - setup: CustomEventHandlerTreeApp.setup, + setup: CustomEventHandlerTreeApp.setup.bind(CustomEventHandlerTreeApp), }); } diff --git a/src/frontend-samples/tree-samples/custom-node-loading-tree/CustomNodeLoadingTreeApp.tsx b/src/frontend-samples/tree-samples/custom-node-loading-tree/CustomNodeLoadingTreeApp.tsx index 28f019204..5a367f3a7 100644 --- a/src/frontend-samples/tree-samples/custom-node-loading-tree/CustomNodeLoadingTreeApp.tsx +++ b/src/frontend-samples/tree-samples/custom-node-loading-tree/CustomNodeLoadingTreeApp.tsx @@ -29,7 +29,7 @@ export interface CustomNodeLoadingTreeProps { } const PAGING_SIZE = 20; -const RULESET_TREE_HIERARCHY: Ruleset = require("../TreeHierarchy.json"); // tslint:disable-line: no-var-requires +const RULESET_TREE_HIERARCHY: Ruleset = require("../TreeHierarchy.json"); // eslint-disable-line @typescript-eslint/no-var-requires /** * This component demonstrates how to use `ControlledTree` with custom nodes loading to load nodes from * multiple data providers. Default node loaders `TreeNodeLoader` and `PagedTreeNodeLoader` works with diff --git a/src/frontend-samples/tree-samples/custom-node-loading-tree/sampleSpec.ts b/src/frontend-samples/tree-samples/custom-node-loading-tree/sampleSpec.ts index bd68a59fc..5f6578cef 100644 --- a/src/frontend-samples/tree-samples/custom-node-loading-tree/sampleSpec.ts +++ b/src/frontend-samples/tree-samples/custom-node-loading-tree/sampleSpec.ts @@ -13,6 +13,6 @@ export function getCustomNodeLoadingTreeSpec(): SampleSpec { files: [ { name: "CustomNodeLoadingTreeApp.tsx", import: import("!!raw-loader!./CustomNodeLoadingTreeApp"), entry: true }, ], - setup: CustomNodeLoadingTreeApp.setup, + setup: CustomNodeLoadingTreeApp.setup.bind(CustomNodeLoadingTreeApp), }); } diff --git a/src/frontend-samples/tree-samples/custom-table-node-tree/sampleSpec.ts b/src/frontend-samples/tree-samples/custom-table-node-tree/sampleSpec.ts index 1b6b8cad6..48b80d96b 100644 --- a/src/frontend-samples/tree-samples/custom-table-node-tree/sampleSpec.ts +++ b/src/frontend-samples/tree-samples/custom-table-node-tree/sampleSpec.ts @@ -16,6 +16,6 @@ export function getCustomTableNodeTreeSpec(): SampleSpec { { name: "CustomTableNodeTreeApp.tsx", import: import("!!raw-loader!./CustomTableNodeTreeApp"), entry: true }, { name: "TableNodeTree.scss", import: import("!!raw-loader!./TableNodeTree.scss") }, ], - setup: TableNodeTreeApp.setup, + setup: TableNodeTreeApp.setup.bind(TableNodeTreeApp), }); } diff --git a/src/frontend-samples/tree-samples/custom-webfont-icons-tree/CustomWebfontIconsTreeApp.tsx b/src/frontend-samples/tree-samples/custom-webfont-icons-tree/CustomWebfontIconsTreeApp.tsx index 9130b29bb..9778c93e6 100644 --- a/src/frontend-samples/tree-samples/custom-webfont-icons-tree/CustomWebfontIconsTreeApp.tsx +++ b/src/frontend-samples/tree-samples/custom-webfont-icons-tree/CustomWebfontIconsTreeApp.tsx @@ -11,7 +11,7 @@ import "@fortawesome/fontawesome-free/css/all.css"; import SampleApp from "common/SampleApp"; import { CustomWebfontIconsTreeUI } from "./CustomWebfontIconsTreeUI"; const PAGING_SIZE = 20; -const RULESET_TREE_WITH_ICONS: Ruleset = require("./TreeWithIcons.json"); // tslint:disable-line: no-var-requires +const RULESET_TREE_WITH_ICONS: Ruleset = require("./TreeWithIcons.json"); // eslint-disable-line @typescript-eslint/no-var-requires export interface CustomWebfontIconsTreeProps { imodel: IModelConnection; diff --git a/src/frontend-samples/tree-samples/custom-webfont-icons-tree/sampleSpec.tsx b/src/frontend-samples/tree-samples/custom-webfont-icons-tree/sampleSpec.tsx index c71423153..35020b375 100644 --- a/src/frontend-samples/tree-samples/custom-webfont-icons-tree/sampleSpec.tsx +++ b/src/frontend-samples/tree-samples/custom-webfont-icons-tree/sampleSpec.tsx @@ -13,6 +13,6 @@ export function getCustomWebfontIconsTreeSpec(): SampleSpec { files: [ { name: "CustomWebfontIconsTreeApp.tsx", import: import("!!raw-loader!./CustomWebfontIconsTreeApp"), entry: true }, ], - setup: CustomWebfontIconsTreeApp.setup, + setup: CustomWebfontIconsTreeApp.setup.bind(CustomWebfontIconsTreeApp), }); } diff --git a/src/frontend-samples/tree-samples/presentation-tree/PresentationTreeApp.tsx b/src/frontend-samples/tree-samples/presentation-tree/PresentationTreeApp.tsx index 1e14e0124..f32010d58 100644 --- a/src/frontend-samples/tree-samples/presentation-tree/PresentationTreeApp.tsx +++ b/src/frontend-samples/tree-samples/presentation-tree/PresentationTreeApp.tsx @@ -10,7 +10,7 @@ import { Ruleset } from "@bentley/presentation-common"; import SampleApp from "common/SampleApp"; import { PresentationTreeUI } from "./PresentationTreeUI"; const PAGING_SIZE = 20; -const RULESET_TREE_HIERARCHY: Ruleset = require("../TreeHierarchy.json"); // tslint:disable-line: no-var-requires +const RULESET_TREE_HIERARCHY: Ruleset = require("../TreeHierarchy.json"); // eslint-disable-line @typescript-eslint/no-var-requires export interface PresentationTreeProps { imodel: IModelConnection; diff --git a/src/frontend-samples/tree-samples/presentation-tree/sampleSpec.ts b/src/frontend-samples/tree-samples/presentation-tree/sampleSpec.ts index ef391de86..078ddd550 100644 --- a/src/frontend-samples/tree-samples/presentation-tree/sampleSpec.ts +++ b/src/frontend-samples/tree-samples/presentation-tree/sampleSpec.ts @@ -13,6 +13,6 @@ export function getPresentationTreeSpec(): SampleSpec { files: [ { name: "PresentationTreeApp.tsx", import: import("!!raw-loader!./PresentationTreeApp"), entry: true }, ], - setup: PresentationTreeApp.setup, + setup: PresentationTreeApp.setup.bind(PresentationTreeApp), }); } diff --git a/src/frontend-samples/tree-samples/unified-selection-tree/UnifiedSelectionTreeApp.tsx b/src/frontend-samples/tree-samples/unified-selection-tree/UnifiedSelectionTreeApp.tsx index bfe8e7b1c..2804fe461 100644 --- a/src/frontend-samples/tree-samples/unified-selection-tree/UnifiedSelectionTreeApp.tsx +++ b/src/frontend-samples/tree-samples/unified-selection-tree/UnifiedSelectionTreeApp.tsx @@ -10,7 +10,7 @@ import { Ruleset } from "@bentley/presentation-common"; import SampleApp from "common/SampleApp"; import { UnifiedSelectionTreeUI } from "./UnifiedSelectionTreeUI"; const PAGING_SIZE = 20; -const RULESET_TREE_HIERARCHY: Ruleset = require("../TreeHierarchy.json"); // tslint:disable-line: no-var-requires +const RULESET_TREE_HIERARCHY: Ruleset = require("../TreeHierarchy.json"); // eslint-disable-line @typescript-eslint/no-var-requires export default class UnifiedSelectionTreeApp extends React.Component<{}> implements SampleApp { public static async setup(iModelName: string, iModelSelector: React.ReactNode) { @@ -31,6 +31,7 @@ export interface UnifiedSelectionTreeProps { * is used. It extends default `TreeEventHandler` and additionally adds/removes keys to/from Unified Selection * when nodes are selected/deselected and changes tree selection to match Unified Selection. */ +// eslint-disable-next-line @typescript-eslint/naming-convention export function UnifiedSelectionTree(props: UnifiedSelectionTreeProps) { // create tree node loader to load nodes using presentation rules. It loads nodes to tree model // in pages using supplied iModel and presentation ruleset. diff --git a/src/frontend-samples/tree-samples/unified-selection-tree/sampleSpec.ts b/src/frontend-samples/tree-samples/unified-selection-tree/sampleSpec.ts index c92f6d9e4..3785fb937 100644 --- a/src/frontend-samples/tree-samples/unified-selection-tree/sampleSpec.ts +++ b/src/frontend-samples/tree-samples/unified-selection-tree/sampleSpec.ts @@ -13,6 +13,6 @@ export function getUnifiedSelectionTreeSpec(): SampleSpec { files: [ { name: "UnifiedSelectionTreeApp.tsx", import: import("!!raw-loader!./UnifiedSelectionTreeApp"), entry: true }, ], - setup: UnifiedSelectionTreeApp.setup, + setup: UnifiedSelectionTreeApp.setup.bind(UnifiedSelectionTreeApp), }); } diff --git a/src/frontend-samples/view-attributes-sample/ViewAttributesUI.tsx b/src/frontend-samples/view-attributes-sample/ViewAttributesUI.tsx index e47a286f6..47a6fcbee 100644 --- a/src/frontend-samples/view-attributes-sample/ViewAttributesUI.tsx +++ b/src/frontend-samples/view-attributes-sample/ViewAttributesUI.tsx @@ -48,7 +48,8 @@ export default class ViewAttributesUI extends React.Component<{ iModelName: stri if (undefined === this.state.vp) return; - this.setState({ attrValues: ViewAttributesApp.getAttrValues(this.state.vp) }); + const attrValues = ViewAttributesApp.getAttrValues(this.state.vp); + this.setState({ attrValues }); } // This common function is used to create the react components for each row of the UI. diff --git a/src/frontend-samples/view-attributes-sample/sampleSpec.ts b/src/frontend-samples/view-attributes-sample/sampleSpec.ts index 316c7797b..87174910d 100644 --- a/src/frontend-samples/view-attributes-sample/sampleSpec.ts +++ b/src/frontend-samples/view-attributes-sample/sampleSpec.ts @@ -14,6 +14,6 @@ export function getViewAttributesSpec(): SampleSpec { { name: "ViewAttributesApp.tsx", import: import("!!raw-loader!./ViewAttributesApp"), entry: true }, { name: "ViewAttributesUI.tsx", import: import("!!raw-loader!./ViewAttributesUI") }, ], - setup: ViewAttributesApp.setup, + setup: ViewAttributesApp.setup.bind(ViewAttributesApp), }); } diff --git a/src/frontend-samples/view-clip-sample/ViewClipApp.tsx b/src/frontend-samples/view-clip-sample/ViewClipApp.tsx index 1cf96bfea..04a30a537 100644 --- a/src/frontend-samples/view-clip-sample/ViewClipApp.tsx +++ b/src/frontend-samples/view-clip-sample/ViewClipApp.tsx @@ -73,17 +73,15 @@ export default class ViewClipApp implements SampleApp { public static setClipPlane(vp: ScreenViewport, clipPlane: string, imodel: IModelConnection) { let rotationType: EditManipulator.RotationType; switch (clipPlane) { + default: case "0": rotationType = EditManipulator.RotationType.Top; break; case "1": rotationType = EditManipulator.RotationType.Front; break; case "2": rotationType = EditManipulator.RotationType.Left; break; - case "None": { - this.clearClips(vp); - return true; - } default: rotationType = EditManipulator.RotationType.Top; break; + case "None": return true; } // Get the center point of the displayed extents as a starting point for the clip plane - const point: Point3d = imodel!.displayedExtents.center; + const point: Point3d = imodel.displayedExtents.center; const normal: Vector3d | undefined = this.getPlaneInwardNormal(rotationType, vp); const plane: Plane3dByOriginAndUnitNormal | undefined = Plane3dByOriginAndUnitNormal.create(point, normal!); if (undefined === plane) diff --git a/src/frontend-samples/view-clip-sample/ViewClipUI.tsx b/src/frontend-samples/view-clip-sample/ViewClipUI.tsx index 261697cf8..3975c4ba1 100644 --- a/src/frontend-samples/view-clip-sample/ViewClipUI.tsx +++ b/src/frontend-samples/view-clip-sample/ViewClipUI.tsx @@ -35,17 +35,38 @@ export class ViewClipUI extends React.Component) => { - this.setState({ showClipBlock: false, clipPlane: event.target.value }); + public componentDidUpdate(_prevProps: ViewClipUIProps, prevState: ViewClipUIState) { + if (!this.state.imodel) + return; + const vp = IModelApp.viewManager.selectedView; if (undefined === vp) { - return false; + return; } - if (this.state.imodel) { - return ViewClipApp.setClipPlane(vp, event.target.value, this.state.imodel); + + if (prevState.showClipBlock !== this.state.showClipBlock || + prevState.clipPlane !== this.state.clipPlane) { + + if (this.state.clipPlane === "None" && !this.state.showClipBlock) { + ViewClipApp.clearClips(vp); + return; + } + + if (this.state.showClipBlock) { + // Clear any other clips before adding the clip range + ViewClipApp.clearClips(vp); + if (!vp.view.getViewClip()) + ViewClipApp.addExtentsClipRange(vp); + return; + } + + ViewClipApp.setClipPlane(vp, this.state.clipPlane, this.state.imodel); } - return false; + } + + /* Handler for plane select */ + private _onPlaneSelectChange = (event: React.ChangeEvent) => { + this.setState({ showClipBlock: false, clipPlane: event.target.value }); } /* Method for flipping (negating) the current clip plane. */ @@ -76,19 +97,6 @@ export class ViewClipUI extends React.Component { this.setState({ showClipBlock: showClipRange, clipPlane: "None" }); - const vp = IModelApp.viewManager.selectedView; - if (undefined === vp) { - return false; - } - // Clear any other clips before adding the clip range - ViewClipApp.clearClips(vp); - if (showClipRange) { - if (!vp.view.getViewClip()) - ViewClipApp.addExtentsClipRange(vp); - } else { - ViewClipApp.clearClips(vp); - } - return true; } public getIsoView = async (imodel: IModelConnection): Promise => { @@ -108,11 +116,8 @@ export class ViewClipUI extends React.Component { - this.setState({ imodel }); - IModelApp.viewManager.onViewOpen.addOnce((_vp: ScreenViewport) => { - // tslint:disable-next-line no-floating-promises - this.setState({ imodel, showClipBlock: true }, () => { this._onToggleRangeClip(true); }); + this.setState({ imodel, showClipBlock: true }); }); } diff --git a/src/frontend-samples/view-clip-sample/sampleSpec.ts b/src/frontend-samples/view-clip-sample/sampleSpec.ts index d6db9e619..9b0be97e3 100644 --- a/src/frontend-samples/view-clip-sample/sampleSpec.ts +++ b/src/frontend-samples/view-clip-sample/sampleSpec.ts @@ -16,6 +16,6 @@ export function getViewClipSpec(): SampleSpec { { name: "ViewClipUI.tsx", import: import("!!raw-loader!./ViewClipUI") }, ], customModelList: [SampleIModels.RetailBuilding, SampleIModels.MetroStation, SampleIModels.BayTown, SampleIModels.House, SampleIModels.Stadium], - setup: ViewClipApp.setup, + setup: ViewClipApp.setup.bind(ViewClipApp), }); } diff --git a/src/frontend-samples/viewer-only-2d-sample/ViewerOnly2dUI.tsx b/src/frontend-samples/viewer-only-2d-sample/ViewerOnly2dUI.tsx index 8408b230e..cb3e95295 100644 --- a/src/frontend-samples/viewer-only-2d-sample/ViewerOnly2dUI.tsx +++ b/src/frontend-samples/viewer-only-2d-sample/ViewerOnly2dUI.tsx @@ -55,7 +55,7 @@ export default class ViewerOnly2dUI extends React.Component { - drawingViews.push(); + drawingViews.push(); }); return drawingViews; } @@ -63,14 +63,14 @@ export default class ViewerOnly2dUI extends React.Component { - sheetViews.push(); + sheetViews.push(); }); return sheetViews; } /** When a model is selected in above list, get its view and switch to it. */ private _handleSelection = async (event: React.ChangeEvent) => { - const index = Number.parseInt(event.target.selectedOptions[0].value, undefined); + const index = Number.parseInt(event.target.selectedOptions[0].value, 10); const modelList = event.target.selectedOptions[0].value.includes("sheet") ? this.state.sheets : this.state.drawings; if (this.state.imodel) { await ViewerOnly2dApp.changeViewportView(this.state.imodel, modelList[index]); diff --git a/src/frontend-samples/viewer-only-2d-sample/sampleSpec.ts b/src/frontend-samples/viewer-only-2d-sample/sampleSpec.ts index 4f0277ebb..8fec4dc1b 100644 --- a/src/frontend-samples/viewer-only-2d-sample/sampleSpec.ts +++ b/src/frontend-samples/viewer-only-2d-sample/sampleSpec.ts @@ -17,6 +17,6 @@ export function getViewerOnly2dSpec(): SampleSpec { { name: "ViewCreator2d.tsx", import: import("!!raw-loader!./ViewCreator2d") }, ], customModelList: [SampleIModels.House, SampleIModels.MetroStation], - setup: ViewerOnly2dApp.setup, + setup: ViewerOnly2dApp.setup.bind(ViewerOnly2dApp), }); } diff --git a/src/frontend-samples/viewport-only-sample/sampleSpec.tsx b/src/frontend-samples/viewport-only-sample/sampleSpec.tsx index dcde6fc43..569aabdcd 100644 --- a/src/frontend-samples/viewport-only-sample/sampleSpec.tsx +++ b/src/frontend-samples/viewport-only-sample/sampleSpec.tsx @@ -14,6 +14,6 @@ export function getViewportOnlySpec(): SampleSpec { { name: "ViewportOnlyApp.tsx", import: import("!!raw-loader!./ViewportOnlyApp"), entry: true }, { name: "ViewportOnlyUI.tsx", import: import("!!raw-loader!./ViewportOnlyUI") }, ], - setup: ViewportOnlyApp.setup, + setup: ViewportOnlyApp.setup.bind(ViewportOnlyApp), }); } diff --git a/src/frontend-samples/zoom-to-elements-sample/ZoomToElementsUI.tsx b/src/frontend-samples/zoom-to-elements-sample/ZoomToElementsUI.tsx index bf7478288..4b3b5a9c9 100644 --- a/src/frontend-samples/zoom-to-elements-sample/ZoomToElementsUI.tsx +++ b/src/frontend-samples/zoom-to-elements-sample/ZoomToElementsUI.tsx @@ -111,7 +111,7 @@ export default class ZoomToElementsUI extends React.Component { return ( ); } @@ -149,7 +149,7 @@ export default class ZoomToElementsUI extends React.Component
- +
); diff --git a/src/frontend-samples/zoom-to-elements-sample/sampleSpec.ts b/src/frontend-samples/zoom-to-elements-sample/sampleSpec.ts index 67e896935..65738a2aa 100644 --- a/src/frontend-samples/zoom-to-elements-sample/sampleSpec.ts +++ b/src/frontend-samples/zoom-to-elements-sample/sampleSpec.ts @@ -17,6 +17,6 @@ export function getZoomToElementsSpec(): SampleSpec { { name: "index.scss", import: import("!!raw-loader!./index.scss") }, ], customModelList: [SampleIModels.BayTown, SampleIModels.RetailBuilding, SampleIModels.MetroStation, SampleIModels.House, SampleIModels.Stadium], - setup: ZoomToElementsApp.setup, + setup: ZoomToElementsApp.setup.bind(ZoomToElementsApp), }); } diff --git a/src/index.tsx b/src/index.tsx index 4086a8979..b6a753a6a 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -19,7 +19,7 @@ import { SampleBaseApp } from "./SampleBaseApp"; , document.getElementById("root"), ); -})(); // tslint:disable-line:no-floating-promises +})(); // If you want your app to work offline and load faster, you can change // unregister() to register() below. Note this comes with some pitfalls. diff --git a/src/raw-loader.d.ts b/src/raw-loader.d.ts index 13267bf8b..f8d673aa6 100644 --- a/src/raw-loader.d.ts +++ b/src/raw-loader.d.ts @@ -2,7 +2,7 @@ * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ -declare module '!!raw-loader!*' { +declare module "!!raw-loader!*" { const contents: string export = contents -} \ No newline at end of file +} diff --git a/src/serviceWorker.ts b/src/serviceWorker.ts index e65467b3d..a826cdf07 100644 --- a/src/serviceWorker.ts +++ b/src/serviceWorker.ts @@ -14,25 +14,23 @@ // To learn more about the benefits of this model and instructions on how to // opt-in, read https://bit.ly/CRA-PWA -// tslint:disable - const isLocalhost = Boolean( - window.location.hostname === 'localhost' || + window.location.hostname === "localhost" || // [::1] is the IPv6 localhost address. - window.location.hostname === '[::1]' || + window.location.hostname === "[::1]" || // 127.0.0.0/8 are considered localhost for IPv4. window.location.hostname.match( /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ ) ); -type Config = { +interface Config { onSuccess?: (registration: ServiceWorkerRegistration) => void; onUpdate?: (registration: ServiceWorkerRegistration) => void; -}; +} export function register(config?: Config) { - if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { + if (process.env.NODE_ENV === "production" && "serviceWorker" in navigator) { // The URL constructor is available in all browsers that support SW. const publicUrl = new URL( process.env.PUBLIC_URL!, @@ -45,7 +43,7 @@ export function register(config?: Config) { return; } - window.addEventListener('load', () => { + window.addEventListener("load", () => { const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; if (isLocalhost) { @@ -55,9 +53,10 @@ export function register(config?: Config) { // Add some additional logging to localhost, pointing developers to the // service worker/PWA documentation. navigator.serviceWorker.ready.then(() => { + // eslint-disable-next-line no-console console.log( - 'This web app is being served cache-first by a service ' + - 'worker. To learn more, visit https://bit.ly/CRA-PWA' + "This web app is being served cache-first by a service " + + "worker. To learn more, visit https://bit.ly/CRA-PWA" ); }); } else { @@ -71,21 +70,22 @@ export function register(config?: Config) { function registerValidSW(swUrl: string, config?: Config) { navigator.serviceWorker .register(swUrl) - .then(registration => { + .then((registration) => { registration.onupdatefound = () => { const installingWorker = registration.installing; if (installingWorker == null) { return; } installingWorker.onstatechange = () => { - if (installingWorker.state === 'installed') { + if (installingWorker.state === "installed") { if (navigator.serviceWorker.controller) { // At this point, the updated precached content has been fetched, // but the previous service worker will still serve the older // content until all client tabs are closed. + // eslint-disable-next-line no-console console.log( - 'New content is available and will be used when all ' + - 'tabs for this page are closed. See https://bit.ly/CRA-PWA.' + "New content is available and will be used when all " + + "tabs for this page are closed. See https://bit.ly/CRA-PWA." ); // Execute callback @@ -96,7 +96,8 @@ function registerValidSW(swUrl: string, config?: Config) { // At this point, everything has been precached. // It's the perfect time to display a // "Content is cached for offline use." message. - console.log('Content is cached for offline use.'); + // eslint-disable-next-line no-console + console.log("Content is cached for offline use."); // Execute callback if (config && config.onSuccess) { @@ -107,25 +108,27 @@ function registerValidSW(swUrl: string, config?: Config) { }; }; }) - .catch(error => { - console.error('Error during service worker registration:', error); + .catch((error) => { + // eslint-disable-next-line no-console + console.error("Error during service worker registration:", error); }); } function checkValidServiceWorker(swUrl: string, config?: Config) { // Check if the service worker can be found. If it can't reload the page. fetch(swUrl, { - headers: { 'Service-Worker': 'script' } + // eslint-disable-next-line @typescript-eslint/naming-convention + headers: { "Service-Worker": "script" }, }) - .then(response => { + .then((response) => { // Ensure service worker exists, and that we really are getting a JS file. - const contentType = response.headers.get('content-type'); + const contentType = response.headers.get("content-type"); if ( response.status === 404 || - (contentType != null && contentType.indexOf('javascript') === -1) + (contentType != null && contentType.indexOf("javascript") === -1) ) { // No service worker found. Probably a different app. Reload the page. - navigator.serviceWorker.ready.then(registration => { + navigator.serviceWorker.ready.then((registration) => { registration.unregister().then(() => { window.location.reload(); }); @@ -136,19 +139,21 @@ function checkValidServiceWorker(swUrl: string, config?: Config) { } }) .catch(() => { + // eslint-disable-next-line no-console console.log( - 'No internet connection found. App is running in offline mode.' + "No internet connection found. App is running in offline mode." ); }); } export function unregister() { - if ('serviceWorker' in navigator) { + if ("serviceWorker" in navigator) { navigator.serviceWorker.ready - .then(registration => { + .then((registration) => { registration.unregister(); }) - .catch(error => { + .catch((error) => { + // eslint-disable-next-line no-console console.error(error.message); }); } diff --git a/src/test/frontend-sample-showcase.test.tsx b/src/test/frontend-sample-showcase.test.tsx index 813b187e8..a4d7bf3ff 100644 --- a/src/test/frontend-sample-showcase.test.tsx +++ b/src/test/frontend-sample-showcase.test.tsx @@ -3,10 +3,8 @@ * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ /* eslint-disable @typescript-eslint/no-unused-expressions */ -/* tslint:disable:no-console */ import { expect } from "chai"; import RealityDataApp from "frontend-samples/reality-data-sample/RealityDataApp"; -// tslint:disable-next-line:no-direct-imports import * as TypeMoq from "typemoq"; import { Range3d } from "@bentley/geometry-core"; import { ContextRealityModelProps } from "@bentley/imodeljs-common"; @@ -26,12 +24,12 @@ describe("View Clipping Sample", () => { imodelMock.setup((_) => _.displayedExtents).returns(() => new Range3d(1, 1, 1, 1, 1, 1)); }); - after(() => TestApp.shutdown()); + after(async () => TestApp.shutdown()); it("Adds a view clip plane to the viewport", () => { const vp: ScreenViewport = TestUtilities.getScreenViewport(); if (vp) { - ViewClipApp.setClipPlane(vp, "0", imodelMock.object as IModelConnection); + ViewClipApp.setClipPlane(vp, "0", imodelMock.object); expect(vp.view.getViewClip()).to.not.be.undefined; ViewClipApp.clearClips(vp); } else { @@ -59,7 +57,7 @@ describe("Thematic display", () => { imodelMock.setup((_) => _.displayedExtents).returns(() => new Range3d(1, 1, 1, 1, 1, 1)); }); - after(() => TestApp.shutdown()); + after(async () => TestApp.shutdown()); it("Turns thematic display on/off", () => { const vp: ScreenViewport = TestUtilities.getScreenViewport(); @@ -79,7 +77,7 @@ describe("Shadow Study", () => { imodelMock.setup((_) => _.displayedExtents).returns(() => new Range3d(1, 1, 1, 1, 1, 1)); }); - after(() => TestApp.shutdown()); + after(async () => TestApp.shutdown()); it("Sets sun time", () => { const time: number = 123; @@ -116,7 +114,7 @@ describe("Emphasize Elements", () => { imodelMock.setup((_) => _.displayedExtents).returns(() => new Range3d(1, 1, 1, 1, 1, 1)); }); - after(() => TestApp.shutdown()); + after(async () => TestApp.shutdown()); it("Emphasizes some elements", () => { IModelApp.viewManager.setSelectedView(TestUtilities.getScreenViewport()); @@ -150,7 +148,7 @@ describe("Reality Data", () => { imodelMock.setup((_) => _.displayedExtents).returns(() => new Range3d(1, 1, 1, 1, 1, 1)); }); - after(() => TestApp.shutdown()); + after(async () => TestApp.shutdown()); it("Removes reality data models", () => { IModelApp.viewManager.setSelectedView(TestUtilities.getScreenViewport()); @@ -171,8 +169,7 @@ describe("Reality Data", () => { models = 0; // Toggle off all reality models - // tslint:disable-next-line: no-floating-promises - RealityDataApp.toggleRealityModel(false, vp, imodelMock.object as IModelConnection); + RealityDataApp.toggleRealityModel(false, vp, imodelMock.object); style = vp.displayStyle.clone(); style.forEachRealityModel( () => models++, diff --git a/src/test/utils/testUtilities.ts b/src/test/utils/testUtilities.ts index 089185659..34c9c84c9 100644 --- a/src/test/utils/testUtilities.ts +++ b/src/test/utils/testUtilities.ts @@ -13,8 +13,8 @@ import { BlankConnection, IModelConnection, ScreenViewport, SpatialViewState } f function createViewDiv() { const div = document.createElement("div"); assert(null !== div); - div!.style.width = div!.style.height = "1000px"; - document.body.appendChild(div!); + div.style.width = div.style.height = "1000px"; + document.body.appendChild(div); return div; }