mirror of
https://github.com/getredash/redash.git
synced 2025-12-19 17:37:19 -05:00
Compare commits
10 Commits
master
...
ts-migrate
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
521ca6afa4 | ||
|
|
1ba94d30a1 | ||
|
|
e4d2c82338 | ||
|
|
95621a93bc | ||
|
|
2f1ed63bd5 | ||
|
|
f23f1d1924 | ||
|
|
c426379bef | ||
|
|
501ca0bef8 | ||
|
|
4c385f85f1 | ||
|
|
698d87ed48 |
@@ -51,7 +51,7 @@ module.exports = {
|
||||
"no-useless-constructor": "off",
|
||||
"@typescript-eslint/no-useless-constructor": "error",
|
||||
// Many API fields and generated types use camelcase
|
||||
"@typescript-eslint/camelcase": "off",
|
||||
"@typescript-eslint/camelcase": "off","@typescript-eslint/no-empty-function": "off",
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
import { configure } from "enzyme";
|
||||
import Adapter from "enzyme-adapter-react-16";
|
||||
|
||||
configure({ adapter: new Adapter() });
|
||||
5
client/app/__tests__/enzyme_setup.ts
Normal file
5
client/app/__tests__/enzyme_setup.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { configure } from "enzyme";
|
||||
// @ts-expect-error ts-migrate(7016) FIXME: Could not find a declaration file for module 'enzy... Remove this comment to see the full error message
|
||||
import Adapter from "enzyme-adapter-react-16";
|
||||
|
||||
configure({ adapter: new Adapter() });
|
||||
@@ -3,7 +3,7 @@ import AceEditor from "react-ace";
|
||||
|
||||
import "./AceEditorInput.less";
|
||||
|
||||
function AceEditorInput(props, ref) {
|
||||
function AceEditorInput(props: any, ref: any) {
|
||||
return (
|
||||
<div className="ace-editor-input" data-test={props["data-test"]}>
|
||||
<AceEditor
|
||||
@@ -7,6 +7,7 @@ import CreateDashboardDialog from "@/components/dashboards/CreateDashboardDialog
|
||||
import { useCurrentRoute } from "@/components/ApplicationArea/Router";
|
||||
import { Auth, currentUser } from "@/services/auth";
|
||||
import settingsMenu from "@/services/settingsMenu";
|
||||
// @ts-expect-error ts-migrate(2307) FIXME: Cannot find module '@/assets/images/redash_icon_sm... Remove this comment to see the full error message
|
||||
import logoUrl from "@/assets/images/redash_icon_small.png";
|
||||
|
||||
import DesktopOutlinedIcon from "@ant-design/icons/DesktopOutlined";
|
||||
@@ -19,7 +20,10 @@ import SettingOutlinedIcon from "@ant-design/icons/SettingOutlined";
|
||||
import VersionInfo from "./VersionInfo";
|
||||
import "./DesktopNavbar.less";
|
||||
|
||||
function NavbarSection({ children, ...props }) {
|
||||
function NavbarSection({
|
||||
children,
|
||||
...props
|
||||
}: any) {
|
||||
return (
|
||||
<Menu selectable={false} mode="vertical" theme="dark" {...props}>
|
||||
{children}
|
||||
@@ -34,6 +38,7 @@ function useNavbarActiveState() {
|
||||
() => ({
|
||||
dashboards: includes(
|
||||
["Dashboards.List", "Dashboards.Favorites", "Dashboards.ViewOrEdit", "Dashboards.LegacyViewOrEdit"],
|
||||
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||
currentRoute.id
|
||||
),
|
||||
queries: includes(
|
||||
@@ -46,11 +51,15 @@ function useNavbarActiveState() {
|
||||
"Queries.New",
|
||||
"Queries.Edit",
|
||||
],
|
||||
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||
currentRoute.id
|
||||
),
|
||||
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||
dataSources: includes(["DataSources.List"], currentRoute.id),
|
||||
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||
alerts: includes(["Alerts.List", "Alerts.New", "Alerts.View", "Alerts.Edit"], currentRoute.id),
|
||||
}),
|
||||
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||
[currentRoute.id]
|
||||
);
|
||||
}
|
||||
@@ -76,6 +85,7 @@ export default function DesktopNavbar() {
|
||||
|
||||
<NavbarSection>
|
||||
{currentUser.hasPermission("list_dashboards") && (
|
||||
// @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call.
|
||||
<Menu.Item key="dashboards" className={activeState.dashboards ? "navbar-active-item" : null}>
|
||||
<Link href="dashboards">
|
||||
<DesktopOutlinedIcon />
|
||||
@@ -84,6 +94,7 @@ export default function DesktopNavbar() {
|
||||
</Menu.Item>
|
||||
)}
|
||||
{currentUser.hasPermission("view_query") && (
|
||||
// @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call.
|
||||
<Menu.Item key="queries" className={activeState.queries ? "navbar-active-item" : null}>
|
||||
<Link href="queries">
|
||||
<CodeOutlinedIcon />
|
||||
@@ -92,6 +103,7 @@ export default function DesktopNavbar() {
|
||||
</Menu.Item>
|
||||
)}
|
||||
{currentUser.hasPermission("list_alerts") && (
|
||||
// @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call.
|
||||
<Menu.Item key="alerts" className={activeState.alerts ? "navbar-active-item" : null}>
|
||||
<Link href="alerts">
|
||||
<AlertOutlinedIcon />
|
||||
@@ -122,6 +134,7 @@ export default function DesktopNavbar() {
|
||||
)}
|
||||
{canCreateDashboard && (
|
||||
<Menu.Item key="new-dashboard">
|
||||
{/* @ts-expect-error ts-migrate(2554) FIXME: Expected 1 arguments, but got 0. */}
|
||||
<a data-test="CreateDashboardMenuItem" onMouseUp={() => CreateDashboardDialog.showModal()}>
|
||||
New Dashboard
|
||||
</a>
|
||||
@@ -140,13 +153,16 @@ export default function DesktopNavbar() {
|
||||
|
||||
<NavbarSection>
|
||||
<Menu.Item key="help">
|
||||
{/* @ts-expect-error ts-migrate(2746) FIXME: This JSX tag's 'children' prop expects a single ch... Remove this comment to see the full error message */}
|
||||
<HelpTrigger showTooltip={false} type="HOME">
|
||||
<QuestionCircleOutlinedIcon />
|
||||
<span className="desktop-navbar-label">Help</span>
|
||||
</HelpTrigger>
|
||||
</Menu.Item>
|
||||
{firstSettingsTab && (
|
||||
// @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call.
|
||||
<Menu.Item key="settings" className={activeState.dataSources ? "navbar-active-item" : null}>
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'path' does not exist on type 'number | (... Remove this comment to see the full error message */}
|
||||
<Link href={firstSettingsTab.path} data-test="SettingsLink">
|
||||
<SettingOutlinedIcon />
|
||||
<span className="desktop-navbar-label">Settings</span>
|
||||
@@ -161,6 +177,7 @@ export default function DesktopNavbar() {
|
||||
popupClassName="desktop-navbar-submenu"
|
||||
title={
|
||||
<span data-test="ProfileDropdown" className="desktop-navbar-profile-menu-title">
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'profile_image_url' does not exist on typ... Remove this comment to see the full error message */}
|
||||
<img className="profile__image_thumb" src={currentUser.profile_image_url} alt={currentUser.name} />
|
||||
</span>
|
||||
}>
|
||||
@@ -1,6 +1,5 @@
|
||||
import { first } from "lodash";
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import Button from "antd/lib/button";
|
||||
import MenuOutlinedIcon from "@ant-design/icons/MenuOutlined";
|
||||
import Dropdown from "antd/lib/dropdown";
|
||||
@@ -8,11 +7,18 @@ import Menu from "antd/lib/menu";
|
||||
import Link from "@/components/Link";
|
||||
import { Auth, currentUser } from "@/services/auth";
|
||||
import settingsMenu from "@/services/settingsMenu";
|
||||
// @ts-expect-error ts-migrate(2307) FIXME: Cannot find module '@/assets/images/redash_icon_sm... Remove this comment to see the full error message
|
||||
import logoUrl from "@/assets/images/redash_icon_small.png";
|
||||
|
||||
import "./MobileNavbar.less";
|
||||
|
||||
export default function MobileNavbar({ getPopupContainer }) {
|
||||
type OwnProps = {
|
||||
getPopupContainer?: (...args: any[]) => any;
|
||||
};
|
||||
|
||||
type Props = OwnProps & typeof MobileNavbar.defaultProps;
|
||||
|
||||
export default function MobileNavbar({ getPopupContainer }: Props) {
|
||||
const firstSettingsTab = first(settingsMenu.getAvailableItems());
|
||||
|
||||
return (
|
||||
@@ -50,6 +56,7 @@ export default function MobileNavbar({ getPopupContainer }) {
|
||||
<Menu.Divider />
|
||||
{firstSettingsTab && (
|
||||
<Menu.Item key="settings">
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'path' does not exist on type 'number | (... Remove this comment to see the full error message */}
|
||||
<Link href={firstSettingsTab.path}>Settings</Link>
|
||||
</Menu.Item>
|
||||
)}
|
||||
@@ -79,10 +86,6 @@ export default function MobileNavbar({ getPopupContainer }) {
|
||||
);
|
||||
}
|
||||
|
||||
MobileNavbar.propTypes = {
|
||||
getPopupContainer: PropTypes.func,
|
||||
};
|
||||
|
||||
MobileNavbar.defaultProps = {
|
||||
getPopupContainer: null,
|
||||
};
|
||||
@@ -1,15 +1,19 @@
|
||||
import React from "react";
|
||||
import Link from "@/components/Link";
|
||||
import { clientConfig, currentUser } from "@/services/auth";
|
||||
// @ts-expect-error ts-migrate(7042) FIXME: Module '@/version.json' was resolved to '/Users/el... Remove this comment to see the full error message
|
||||
import frontendVersion from "@/version.json";
|
||||
|
||||
export default function VersionInfo() {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div>
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'version' does not exist on type '{}'. */}
|
||||
Version: {clientConfig.version}
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'version' does not exist on type '{}'. */}
|
||||
{frontendVersion !== clientConfig.version && ` (${frontendVersion.substring(0, 8)})`}
|
||||
</div>
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'newVersionAvailable' does not exist on t... Remove this comment to see the full error message */}
|
||||
{clientConfig.newVersionAvailable && currentUser.hasPermission("super_admin") && (
|
||||
<div className="m-t-10">
|
||||
{/* eslint-disable react/jsx-no-target-blank */}
|
||||
@@ -1,27 +1,36 @@
|
||||
import React, { useRef, useCallback } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import DynamicComponent from "@/components/DynamicComponent";
|
||||
import DesktopNavbar from "./DesktopNavbar";
|
||||
import MobileNavbar from "./MobileNavbar";
|
||||
|
||||
import "./index.less";
|
||||
|
||||
export default function ApplicationLayout({ children }) {
|
||||
type OwnProps = {
|
||||
children?: React.ReactNode;
|
||||
};
|
||||
|
||||
type Props = OwnProps & typeof ApplicationLayout.defaultProps;
|
||||
|
||||
export default function ApplicationLayout({ children }: Props) {
|
||||
const mobileNavbarContainerRef = useRef();
|
||||
|
||||
const getMobileNavbarPopupContainer = useCallback(() => mobileNavbarContainerRef.current, []);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
{/* @ts-expect-error ts-migrate(2746) FIXME: This JSX tag's 'children' prop expects a single ch... Remove this comment to see the full error message */}
|
||||
<DynamicComponent name="ApplicationWrapper">
|
||||
<div className="application-layout-side-menu">
|
||||
<DynamicComponent name="ApplicationDesktopNavbar">
|
||||
{/* @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call. */}
|
||||
<DesktopNavbar />
|
||||
</DynamicComponent>
|
||||
</div>
|
||||
<div className="application-layout-content">
|
||||
{/* @ts-expect-error ts-migrate(2322) FIXME: Type 'MutableRefObject<undefined>' is not assignab... Remove this comment to see the full error message */}
|
||||
<nav className="application-layout-top-menu" ref={mobileNavbarContainerRef}>
|
||||
<DynamicComponent name="ApplicationMobileNavbar" getPopupContainer={getMobileNavbarPopupContainer}>
|
||||
{/* @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call. */}
|
||||
<MobileNavbar getPopupContainer={getMobileNavbarPopupContainer} />
|
||||
</DynamicComponent>
|
||||
</nav>
|
||||
@@ -32,10 +41,6 @@ export default function ApplicationLayout({ children }) {
|
||||
);
|
||||
}
|
||||
|
||||
ApplicationLayout.propTypes = {
|
||||
children: PropTypes.node,
|
||||
};
|
||||
|
||||
ApplicationLayout.defaultProps = {
|
||||
children: null,
|
||||
};
|
||||
@@ -10,7 +10,9 @@ const ErrorMessages = {
|
||||
|
||||
function mockAxiosError(status = 500, response = {}) {
|
||||
const error = new Error(`Failed with code ${status}.`);
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isAxiosError' does not exist on type 'Er... Remove this comment to see the full error message
|
||||
error.isAxiosError = true;
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'response' does not exist on type 'Error'... Remove this comment to see the full error message
|
||||
error.response = { status, ...response };
|
||||
return error;
|
||||
}
|
||||
@@ -22,7 +24,7 @@ describe("Error Message", () => {
|
||||
spyError.mockReset();
|
||||
});
|
||||
|
||||
function expectErrorMessageToBe(error, errorMessage) {
|
||||
function expectErrorMessageToBe(error: any, errorMessage: any) {
|
||||
const component = mount(<ErrorMessage error={error} />);
|
||||
|
||||
expect(component.find(".error-state__details h4").text()).toBe(errorMessage);
|
||||
@@ -1,12 +1,11 @@
|
||||
import { get, isObject } from "lodash";
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import "./ErrorMessage.less";
|
||||
import DynamicComponent from "@/components/DynamicComponent";
|
||||
import { ErrorMessageDetails } from "@/components/ApplicationArea/ErrorMessageDetails";
|
||||
|
||||
function getErrorMessageByStatus(status, defaultMessage) {
|
||||
function getErrorMessageByStatus(status: any, defaultMessage: any) {
|
||||
switch (status) {
|
||||
case 404:
|
||||
return "It seems like the page you're looking for cannot be found.";
|
||||
@@ -18,22 +17,31 @@ function getErrorMessageByStatus(status, defaultMessage) {
|
||||
}
|
||||
}
|
||||
|
||||
function getErrorMessage(error) {
|
||||
function getErrorMessage(error: any) {
|
||||
const message = "It seems like we encountered an error. Try refreshing this page or contact your administrator.";
|
||||
if (isObject(error)) {
|
||||
// HTTP errors
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isAxiosError' does not exist on type 'ob... Remove this comment to see the full error message
|
||||
if (error.isAxiosError && isObject(error.response)) {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'response' does not exist on type 'object... Remove this comment to see the full error message
|
||||
return getErrorMessageByStatus(error.response.status, get(error, "response.data.message", message));
|
||||
}
|
||||
// Router errors
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'status' does not exist on type 'object'.
|
||||
if (error.status) {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'status' does not exist on type 'object'.
|
||||
return getErrorMessageByStatus(error.status, message);
|
||||
}
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
export default function ErrorMessage({ error, message }) {
|
||||
type Props = {
|
||||
error: any;
|
||||
message?: string;
|
||||
};
|
||||
|
||||
export default function ErrorMessage({ error, message }: Props) {
|
||||
if (!error) {
|
||||
return null;
|
||||
}
|
||||
@@ -62,8 +70,3 @@ export default function ErrorMessage({ error, message }) {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
ErrorMessage.propTypes = {
|
||||
error: PropTypes.object.isRequired,
|
||||
message: PropTypes.string,
|
||||
};
|
||||
@@ -1,11 +0,0 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
export function ErrorMessageDetails(props) {
|
||||
return <h4>{props.message}</h4>;
|
||||
}
|
||||
|
||||
ErrorMessageDetails.propTypes = {
|
||||
error: PropTypes.instanceOf(Error).isRequired,
|
||||
message: PropTypes.string.isRequired,
|
||||
};
|
||||
@@ -0,0 +1,10 @@
|
||||
import React from "react";
|
||||
|
||||
type Props = {
|
||||
error: any; // TODO: PropTypes.instanceOf(Error)
|
||||
message: string;
|
||||
};
|
||||
|
||||
export function ErrorMessageDetails(props: Props) {
|
||||
return <h4>{props.message}</h4>;
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
import { isFunction, startsWith, trimStart, trimEnd } from "lodash";
|
||||
import React, { useState, useEffect, useRef, useContext } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import UniversalRouter from "universal-router";
|
||||
import ErrorBoundary from "@redash/viz/lib/components/ErrorBoundary";
|
||||
import location from "@/services/location";
|
||||
@@ -20,7 +19,7 @@ export function useCurrentRoute() {
|
||||
return useContext(CurrentRouteContext);
|
||||
}
|
||||
|
||||
export function stripBase(href) {
|
||||
export function stripBase(href: any) {
|
||||
// Resolve provided link and '' (root) relative to document's base.
|
||||
// If provided href is not related to current document (does not
|
||||
// start with resolved root) - return false. Otherwise
|
||||
@@ -36,7 +35,20 @@ export function stripBase(href) {
|
||||
return false;
|
||||
}
|
||||
|
||||
export default function Router({ routes, onRouteChange }) {
|
||||
type OwnProps = {
|
||||
routes?: {
|
||||
path: string;
|
||||
render?: (...args: any[]) => any;
|
||||
resolve?: {
|
||||
[key: string]: any;
|
||||
};
|
||||
}[];
|
||||
onRouteChange?: (...args: any[]) => any;
|
||||
};
|
||||
|
||||
type Props = OwnProps & typeof Router.defaultProps;
|
||||
|
||||
export default function Router({ routes, onRouteChange }: Props) {
|
||||
const [currentRoute, setCurrentRoute] = useState(null);
|
||||
|
||||
const currentPathRef = useRef(null);
|
||||
@@ -47,15 +59,17 @@ export default function Router({ routes, onRouteChange }) {
|
||||
|
||||
const router = new UniversalRouter(routes, {
|
||||
resolveRoute({ route }, routeParams) {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'render' does not exist on type 'Route<Co... Remove this comment to see the full error message
|
||||
if (isFunction(route.render)) {
|
||||
return { ...route, routeParams };
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
function resolve(action) {
|
||||
function resolve(action: any) {
|
||||
if (!isAbandoned) {
|
||||
if (errorHandlerRef.current) {
|
||||
// @ts-expect-error ts-migrate(2532) FIXME: Object is possibly 'undefined'.
|
||||
errorHandlerRef.current.reset();
|
||||
}
|
||||
|
||||
@@ -70,6 +84,7 @@ export default function Router({ routes, onRouteChange }) {
|
||||
if (pathname === currentPathRef.current) {
|
||||
return;
|
||||
}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'null'.
|
||||
currentPathRef.current = pathname;
|
||||
|
||||
// Don't reload controller if URL was replaced
|
||||
@@ -87,7 +102,8 @@ export default function Router({ routes, onRouteChange }) {
|
||||
.catch(error => {
|
||||
if (!isAbandoned && currentPathRef.current === pathname) {
|
||||
setCurrentRoute({
|
||||
render: currentRoute => <ErrorMessage {...currentRoute.routeParams} />,
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type '{ render: (currentRoute: any) =>... Remove this comment to see the full error message
|
||||
render: (currentRoute: any) => <ErrorMessage {...currentRoute.routeParams} />,
|
||||
routeParams: { error },
|
||||
});
|
||||
}
|
||||
@@ -97,7 +113,7 @@ export default function Router({ routes, onRouteChange }) {
|
||||
|
||||
resolve("PUSH");
|
||||
|
||||
const unlisten = location.listen((unused, action) => resolve(action));
|
||||
const unlisten = location.listen((unused: any, action: any) => resolve(action));
|
||||
|
||||
return () => {
|
||||
isAbandoned = true;
|
||||
@@ -116,29 +132,15 @@ export default function Router({ routes, onRouteChange }) {
|
||||
|
||||
return (
|
||||
<CurrentRouteContext.Provider value={currentRoute}>
|
||||
<ErrorBoundary ref={errorHandlerRef} renderError={error => <ErrorMessage error={error} />}>
|
||||
{/* @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call. */}
|
||||
<ErrorBoundary ref={errorHandlerRef} renderError={(error: any) => <ErrorMessage error={error} />}>
|
||||
{/* @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'. */}
|
||||
{currentRoute.render(currentRoute)}
|
||||
</ErrorBoundary>
|
||||
</CurrentRouteContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
Router.propTypes = {
|
||||
routes: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
path: PropTypes.string.isRequired,
|
||||
render: PropTypes.func, // (routeParams: PropTypes.object; currentRoute; location) => PropTypes.node
|
||||
// Additional props to be injected into route component.
|
||||
// Object keys are props names. Object values will become prop values:
|
||||
// - if value is a function - it will be called without arguments, and result will be used; otherwise value will be used;
|
||||
// - after previous step, if value is a promise - router will wait for it to resolve; resolved value then will be used;
|
||||
// otherwise value will be used directly.
|
||||
resolve: PropTypes.objectOf(PropTypes.any),
|
||||
})
|
||||
),
|
||||
onRouteChange: PropTypes.func,
|
||||
};
|
||||
|
||||
Router.defaultProps = {
|
||||
routes: [],
|
||||
onRouteChange: () => {},
|
||||
@@ -1,7 +1,7 @@
|
||||
import { isString } from "lodash";
|
||||
import navigateTo from "./navigateTo";
|
||||
|
||||
export default function handleNavigationIntent(event) {
|
||||
export default function handleNavigationIntent(event: any) {
|
||||
let element = event.target;
|
||||
while (element) {
|
||||
if (element.tagName === "A") {
|
||||
@@ -9,13 +9,15 @@ export default function ApplicationArea() {
|
||||
const [unhandledError, setUnhandledError] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||
if (currentRoute && currentRoute.title) {
|
||||
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||
document.title = currentRoute.title;
|
||||
}
|
||||
}, [currentRoute]);
|
||||
|
||||
useEffect(() => {
|
||||
function globalErrorHandler(event) {
|
||||
function globalErrorHandler(event: any) {
|
||||
event.preventDefault();
|
||||
setUnhandledError(event.error);
|
||||
}
|
||||
@@ -33,5 +35,6 @@ export default function ApplicationArea() {
|
||||
return <ErrorMessage error={unhandledError} />;
|
||||
}
|
||||
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'RouteItem[]' is not assignable to type '{ pa... Remove this comment to see the full error message
|
||||
return <Router routes={routes.items} onRouteChange={setCurrentRoute} />;
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import { stripBase } from "./Router";
|
||||
|
||||
// When `replace` is set to `true` - it will just replace current URL
|
||||
// without reloading current page (router will skip this location change)
|
||||
export default function navigateTo(href, replace = false) {
|
||||
export default function navigateTo(href: any, replace = false) {
|
||||
// Allow calling chain to roll up, and then navigate
|
||||
setTimeout(() => {
|
||||
const isExternal = stripBase(href) === false;
|
||||
@@ -1,8 +1,14 @@
|
||||
import React, { useEffect, useState, useContext } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { ErrorBoundaryContext } from "@redash/viz/lib/components/ErrorBoundary";
|
||||
import { Auth, clientConfig } from "@/services/auth";
|
||||
|
||||
type OwnProps = {
|
||||
apiKey: string;
|
||||
renderChildren?: (...args: any[]) => any;
|
||||
};
|
||||
|
||||
type Props = OwnProps & typeof ApiKeySessionWrapper.defaultProps;
|
||||
|
||||
// This wrapper modifies `route.render` function and instead of passing `currentRoute` passes an object
|
||||
// that contains:
|
||||
// - `currentRoute.routeParams`
|
||||
@@ -10,7 +16,8 @@ import { Auth, clientConfig } from "@/services/auth";
|
||||
// - `onError` field which is a `handleError` method of nearest error boundary
|
||||
// - `apiKey` field
|
||||
|
||||
function ApiKeySessionWrapper({ apiKey, currentRoute, renderChildren }) {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'currentRoute' does not exist on type 'Pr... Remove this comment to see the full error message
|
||||
function ApiKeySessionWrapper({ apiKey, currentRoute, renderChildren }: Props) {
|
||||
const [isAuthenticated, setIsAuthenticated] = useState(false);
|
||||
const { handleError } = useContext(ErrorBoundaryContext);
|
||||
|
||||
@@ -33,6 +40,7 @@ function ApiKeySessionWrapper({ apiKey, currentRoute, renderChildren }) {
|
||||
};
|
||||
}, [apiKey]);
|
||||
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'disablePublicUrls' does not exist on typ... Remove this comment to see the full error message
|
||||
if (!isAuthenticated || clientConfig.disablePublicUrls) {
|
||||
return null;
|
||||
}
|
||||
@@ -44,20 +52,18 @@ function ApiKeySessionWrapper({ apiKey, currentRoute, renderChildren }) {
|
||||
);
|
||||
}
|
||||
|
||||
ApiKeySessionWrapper.propTypes = {
|
||||
apiKey: PropTypes.string.isRequired,
|
||||
renderChildren: PropTypes.func,
|
||||
};
|
||||
|
||||
ApiKeySessionWrapper.defaultProps = {
|
||||
renderChildren: () => null,
|
||||
};
|
||||
|
||||
export default function routeWithApiKeySession({ render, getApiKey, ...rest }) {
|
||||
export default function routeWithApiKeySession({
|
||||
render,
|
||||
getApiKey,
|
||||
...rest
|
||||
}: any) {
|
||||
return {
|
||||
...rest,
|
||||
render: currentRoute => (
|
||||
<ApiKeySessionWrapper apiKey={getApiKey(currentRoute)} currentRoute={currentRoute} renderChildren={render} />
|
||||
),
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '{ apiKey: any; currentRoute: any; renderChil... Remove this comment to see the full error message
|
||||
render: (currentRoute: any) => <ApiKeySessionWrapper apiKey={getApiKey(currentRoute)} currentRoute={currentRoute} renderChildren={render} />,
|
||||
};
|
||||
}
|
||||
@@ -60,8 +60,9 @@ export function UserSessionWrapper<P>({ bodyClass, currentRoute, render }: UserS
|
||||
|
||||
return (
|
||||
<ApplicationLayout>
|
||||
{/* @ts-expect-error ts-migrate(2322) FIXME: Type 'Element' is not assignable to type 'null | u... Remove this comment to see the full error message */}
|
||||
<React.Fragment key={currentRoute.key}>
|
||||
{/* @ts-expect-error FIXME */}
|
||||
{/* @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call. */}
|
||||
<ErrorBoundary renderError={(error: Error) => <ErrorMessage error={error} />}>
|
||||
<ErrorBoundaryContext.Consumer>
|
||||
{({ handleError } /* : { handleError: UserSessionWrapperRenderChildrenProps<P>["onError"] } FIXME bring back type */) =>
|
||||
|
||||
@@ -13,16 +13,18 @@ const Text = Typography.Text;
|
||||
function BeaconConsent() {
|
||||
const [hide, setHide] = useState(false);
|
||||
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'showBeaconConsentMessage' does not exist... Remove this comment to see the full error message
|
||||
if (!clientConfig.showBeaconConsentMessage || hide) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const hideConsentCard = () => {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'showBeaconConsentMessage' does not exist... Remove this comment to see the full error message
|
||||
clientConfig.showBeaconConsentMessage = false;
|
||||
setHide(true);
|
||||
};
|
||||
|
||||
const confirmConsent = confirm => {
|
||||
const confirmConsent = (confirm: any) => {
|
||||
let message = "🙏 Thank you.";
|
||||
|
||||
if (!confirm) {
|
||||
@@ -39,11 +41,13 @@ function BeaconConsent() {
|
||||
|
||||
return (
|
||||
<DynamicComponent name="BeaconConsent">
|
||||
{/* @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call. */}
|
||||
<div className="m-t-10 tiled">
|
||||
<Card
|
||||
title={
|
||||
<>
|
||||
Would you be ok with sharing anonymous usage data with the Redash team?{" "}
|
||||
{/* @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'never'. */}
|
||||
<HelpTrigger type="USAGE_DATA_SHARING" />
|
||||
</>
|
||||
}
|
||||
@@ -1,7 +1,15 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
function BigMessage({ message, icon, children, className }) {
|
||||
type OwnProps = {
|
||||
message?: string;
|
||||
icon: string;
|
||||
children?: React.ReactNode;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
type Props = OwnProps & typeof BigMessage.defaultProps;
|
||||
|
||||
function BigMessage({ message, icon, children, className }: Props) {
|
||||
return (
|
||||
<div className={"p-15 text-center " + className}>
|
||||
<h3 className="m-t-0 m-b-0">
|
||||
@@ -14,13 +22,6 @@ function BigMessage({ message, icon, children, className }) {
|
||||
);
|
||||
}
|
||||
|
||||
BigMessage.propTypes = {
|
||||
message: PropTypes.string,
|
||||
icon: PropTypes.string.isRequired,
|
||||
children: PropTypes.node,
|
||||
className: PropTypes.string,
|
||||
};
|
||||
|
||||
BigMessage.defaultProps = {
|
||||
message: "",
|
||||
children: null,
|
||||
@@ -1,24 +1,30 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import Button from "antd/lib/button";
|
||||
import Tooltip from "antd/lib/tooltip";
|
||||
import CopyOutlinedIcon from "@ant-design/icons/CopyOutlined";
|
||||
import "./CodeBlock.less";
|
||||
|
||||
export default class CodeBlock extends React.Component {
|
||||
static propTypes = {
|
||||
copyable: PropTypes.bool,
|
||||
children: PropTypes.node,
|
||||
};
|
||||
type OwnProps = {
|
||||
copyable?: boolean;
|
||||
};
|
||||
|
||||
type State = any;
|
||||
|
||||
type Props = OwnProps & typeof CodeBlock.defaultProps;
|
||||
|
||||
export default class CodeBlock extends React.Component<Props, State> {
|
||||
static defaultProps = {
|
||||
copyable: false,
|
||||
children: null,
|
||||
};
|
||||
|
||||
copyFeatureEnabled: any;
|
||||
ref: any;
|
||||
resetCopyState: any;
|
||||
|
||||
state = { copied: null };
|
||||
|
||||
constructor(props) {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.ref = React.createRef();
|
||||
this.copyFeatureEnabled = props.copyable && document.queryCommandSupported("copy");
|
||||
@@ -33,6 +39,7 @@ export default class CodeBlock extends React.Component {
|
||||
|
||||
copy = () => {
|
||||
// select text
|
||||
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||
window.getSelection().selectAllChildren(this.ref.current);
|
||||
|
||||
// copy
|
||||
@@ -49,6 +56,7 @@ export default class CodeBlock extends React.Component {
|
||||
}
|
||||
|
||||
// reset selection
|
||||
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||
window.getSelection().removeAllRanges();
|
||||
|
||||
// reset tooltip
|
||||
@@ -1,12 +1,20 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import cx from "classnames";
|
||||
import AntCollapse from "antd/lib/collapse";
|
||||
|
||||
export default function Collapse({ collapsed, children, className, ...props }) {
|
||||
type OwnProps = {
|
||||
collapsed?: boolean;
|
||||
children?: React.ReactNode;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
type Props = OwnProps & typeof Collapse.defaultProps;
|
||||
|
||||
export default function Collapse({ collapsed, children, className, ...props }: Props) {
|
||||
return (
|
||||
<AntCollapse
|
||||
{...props}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string | null' is not assignable to type 'st... Remove this comment to see the full error message
|
||||
activeKey={collapsed ? null : "content"}
|
||||
className={cx(className, "ant-collapse-headerless")}>
|
||||
<AntCollapse.Panel key="content" header="">
|
||||
@@ -16,12 +24,6 @@ export default function Collapse({ collapsed, children, className, ...props }) {
|
||||
);
|
||||
}
|
||||
|
||||
Collapse.propTypes = {
|
||||
collapsed: PropTypes.bool,
|
||||
children: PropTypes.node,
|
||||
className: PropTypes.string,
|
||||
};
|
||||
|
||||
Collapse.defaultProps = {
|
||||
collapsed: true,
|
||||
children: null,
|
||||
@@ -1,11 +1,11 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { isEmpty, toUpper, includes, get } from "lodash";
|
||||
import Button from "antd/lib/button";
|
||||
import List from "antd/lib/list";
|
||||
import Modal from "antd/lib/modal";
|
||||
import Input from "antd/lib/input";
|
||||
import Steps from "antd/lib/steps";
|
||||
// @ts-expect-error ts-migrate(6133) FIXME: 'DialogPropType' is declared but its value is neve... Remove this comment to see the full error message
|
||||
import { wrap as wrapDialog, DialogPropType } from "@/components/DialogWrapper";
|
||||
import Link from "@/components/Link";
|
||||
import { PreviewCard } from "@/components/PreviewCard";
|
||||
@@ -23,15 +23,21 @@ const StepEnum = {
|
||||
DONE: 2,
|
||||
};
|
||||
|
||||
class CreateSourceDialog extends React.Component {
|
||||
static propTypes = {
|
||||
dialog: DialogPropType.isRequired,
|
||||
types: PropTypes.arrayOf(PropTypes.object),
|
||||
sourceType: PropTypes.string.isRequired,
|
||||
imageFolder: PropTypes.string.isRequired,
|
||||
helpTriggerPrefix: PropTypes.string,
|
||||
onCreate: PropTypes.func.isRequired,
|
||||
};
|
||||
type OwnProps = {
|
||||
// @ts-expect-error ts-migrate(2749) FIXME: 'DialogPropType' refers to a value, but is being u... Remove this comment to see the full error message
|
||||
dialog: DialogPropType;
|
||||
types?: any[];
|
||||
sourceType: string;
|
||||
imageFolder: string;
|
||||
helpTriggerPrefix?: string;
|
||||
onCreate: (...args: any[]) => any;
|
||||
};
|
||||
|
||||
type State = any;
|
||||
|
||||
type Props = OwnProps & typeof CreateSourceDialog.defaultProps;
|
||||
|
||||
class CreateSourceDialog extends React.Component<Props, State> {
|
||||
|
||||
static defaultProps = {
|
||||
types: [],
|
||||
@@ -45,7 +51,7 @@ class CreateSourceDialog extends React.Component {
|
||||
currentStep: StepEnum.SELECT_TYPE,
|
||||
};
|
||||
|
||||
selectType = selectedType => {
|
||||
selectType = (selectedType: any) => {
|
||||
this.setState({ selectedType, currentStep: StepEnum.CONFIGURE_IT });
|
||||
};
|
||||
|
||||
@@ -55,17 +61,19 @@ class CreateSourceDialog extends React.Component {
|
||||
}
|
||||
};
|
||||
|
||||
createSource = (values, successCallback, errorCallback) => {
|
||||
createSource = (values: any, successCallback: any, errorCallback: any) => {
|
||||
const { selectedType, savingSource } = this.state;
|
||||
if (!savingSource) {
|
||||
this.setState({ savingSource: true, currentStep: StepEnum.DONE });
|
||||
this.props
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'onCreate' does not exist on type 'never'... Remove this comment to see the full error message
|
||||
.onCreate(selectedType, values)
|
||||
.then(data => {
|
||||
.then((data: any) => {
|
||||
successCallback("Saved.");
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dialog' does not exist on type 'never'.
|
||||
this.props.dialog.close({ success: true, data });
|
||||
})
|
||||
.catch(error => {
|
||||
.catch((error: any) => {
|
||||
this.setState({ savingSource: false, currentStep: StepEnum.CONFIGURE_IT });
|
||||
errorCallback(get(error, "response.data.message", "Failed saving."));
|
||||
});
|
||||
@@ -75,8 +83,9 @@ class CreateSourceDialog extends React.Component {
|
||||
renderTypeSelector() {
|
||||
const { types } = this.props;
|
||||
const { searchText } = this.state;
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'filter' does not exist on type 'never'.
|
||||
const filteredTypes = types.filter(
|
||||
type => isEmpty(searchText) || includes(type.name.toLowerCase(), searchText.toLowerCase())
|
||||
(type: any) => isEmpty(searchText) || includes(type.name.toLowerCase(), searchText.toLowerCase())
|
||||
);
|
||||
return (
|
||||
<div className="m-t-10">
|
||||
@@ -100,22 +109,30 @@ class CreateSourceDialog extends React.Component {
|
||||
renderForm() {
|
||||
const { imageFolder, helpTriggerPrefix } = this.props;
|
||||
const { selectedType } = this.state;
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'null' is not assignable to param... Remove this comment to see the full error message
|
||||
const fields = helper.getFields(selectedType);
|
||||
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||
const helpTriggerType = `${helpTriggerPrefix}${toUpper(selectedType.type)}`;
|
||||
return (
|
||||
<div>
|
||||
<div className="d-flex justify-content-center align-items-center">
|
||||
{/* @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'. */}
|
||||
<img className="p-5" src={`${imageFolder}/${selectedType.type}.png`} alt={selectedType.name} width="48" />
|
||||
{/* @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'. */}
|
||||
<h4 className="m-0">{selectedType.name}</h4>
|
||||
</div>
|
||||
<div className="text-right">
|
||||
{/* @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message */}
|
||||
{HELP_TRIGGER_TYPES[helpTriggerType] && (
|
||||
// @ts-expect-error ts-migrate(2746) FIXME: This JSX tag's 'children' prop expects a single ch... Remove this comment to see the full error message
|
||||
<HelpTrigger className="f-13" type={helpTriggerType}>
|
||||
Setup Instructions <i className="fa fa-question-circle" />
|
||||
</HelpTrigger>
|
||||
)}
|
||||
</div>
|
||||
{/* @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'never'. */}
|
||||
<DynamicForm id="sourceForm" fields={fields} onSubmit={this.createSource} feedbackIcons hideSubmitButton />
|
||||
{/* @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'. */}
|
||||
{selectedType.type === "databricks" && (
|
||||
<small>
|
||||
By using the Databricks Data Source you agree to the Databricks JDBC/ODBC{" "}
|
||||
@@ -129,7 +146,7 @@ class CreateSourceDialog extends React.Component {
|
||||
);
|
||||
}
|
||||
|
||||
renderItem(item) {
|
||||
renderItem(item: any) {
|
||||
const { imageFolder } = this.props;
|
||||
return (
|
||||
<List.Item className="p-l-10 p-r-10 clickable" onClick={() => this.selectType(item)}>
|
||||
@@ -139,6 +156,7 @@ class CreateSourceDialog extends React.Component {
|
||||
roundedImage={false}
|
||||
data-test="PreviewItem"
|
||||
data-test-type={item.type}>
|
||||
{/* @ts-expect-error ts-migrate(2322) FIXME: Type 'Element' is not assignable to type 'null | u... Remove this comment to see the full error message */}
|
||||
<i className="fa fa-angle-double-right" />
|
||||
</PreviewCard>
|
||||
</List.Item>
|
||||
@@ -150,11 +168,13 @@ class CreateSourceDialog extends React.Component {
|
||||
const { dialog, sourceType } = this.props;
|
||||
return (
|
||||
<Modal
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'props' does not exist on type 'never'.
|
||||
{...dialog.props}
|
||||
title={`Create a New ${sourceType}`}
|
||||
footer={
|
||||
currentStep === StepEnum.SELECT_TYPE
|
||||
? [
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dismiss' does not exist on type 'never'.
|
||||
<Button key="cancel" onClick={() => dialog.dismiss()} data-test="CreateSourceCancelButton">
|
||||
Cancel
|
||||
</Button>,
|
||||
@@ -1,43 +0,0 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import DatePicker from "antd/lib/date-picker";
|
||||
import { clientConfig } from "@/services/auth";
|
||||
import { Moment } from "@/components/proptypes";
|
||||
|
||||
const DateInput = React.forwardRef(({ defaultValue, value, onSelect, className, ...props }, ref) => {
|
||||
const format = clientConfig.dateFormat || "YYYY-MM-DD";
|
||||
const additionalAttributes = {};
|
||||
if (defaultValue && defaultValue.isValid()) {
|
||||
additionalAttributes.defaultValue = defaultValue;
|
||||
}
|
||||
if (value === null || (value && value.isValid())) {
|
||||
additionalAttributes.value = value;
|
||||
}
|
||||
return (
|
||||
<DatePicker
|
||||
ref={ref}
|
||||
className={className}
|
||||
{...additionalAttributes}
|
||||
format={format}
|
||||
placeholder="Select Date"
|
||||
onChange={onSelect}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
DateInput.propTypes = {
|
||||
defaultValue: Moment,
|
||||
value: Moment,
|
||||
onSelect: PropTypes.func,
|
||||
className: PropTypes.string,
|
||||
};
|
||||
|
||||
DateInput.defaultProps = {
|
||||
defaultValue: null,
|
||||
value: undefined,
|
||||
onSelect: () => {},
|
||||
className: "",
|
||||
};
|
||||
|
||||
export default DateInput;
|
||||
48
client/app/components/DateInput.tsx
Normal file
48
client/app/components/DateInput.tsx
Normal file
@@ -0,0 +1,48 @@
|
||||
import React from "react";
|
||||
import DatePicker from "antd/lib/date-picker";
|
||||
import { clientConfig } from "@/services/auth";
|
||||
// @ts-expect-error ts-migrate(6133) FIXME: 'Moment' is declared but its value is never read.
|
||||
import { Moment } from "@/components/proptypes";
|
||||
|
||||
type Props = {
|
||||
// @ts-expect-error ts-migrate(2749) FIXME: 'Moment' refers to a value, but is being used as a... Remove this comment to see the full error message
|
||||
defaultValue?: Moment;
|
||||
// @ts-expect-error ts-migrate(2749) FIXME: 'Moment' refers to a value, but is being used as a... Remove this comment to see the full error message
|
||||
value?: Moment;
|
||||
onSelect?: (...args: any[]) => any;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
const DateInput = React.forwardRef<any, Props>(({ defaultValue, value, onSelect, className, ...props }, ref) => {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dateFormat' does not exist on type '{}'.
|
||||
const format = clientConfig.dateFormat || "YYYY-MM-DD";
|
||||
const additionalAttributes = {};
|
||||
if (defaultValue && defaultValue.isValid()) {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'defaultValue' does not exist on type '{}... Remove this comment to see the full error message
|
||||
additionalAttributes.defaultValue = defaultValue;
|
||||
}
|
||||
if (value === null || (value && value.isValid())) {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'value' does not exist on type '{}'.
|
||||
additionalAttributes.value = value;
|
||||
}
|
||||
return (
|
||||
<DatePicker
|
||||
ref={ref}
|
||||
className={className}
|
||||
{...additionalAttributes}
|
||||
format={format}
|
||||
placeholder="Select Date"
|
||||
onChange={onSelect}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
DateInput.defaultProps = {
|
||||
defaultValue: null,
|
||||
value: undefined,
|
||||
onSelect: () => {},
|
||||
className: "",
|
||||
};
|
||||
|
||||
export default DateInput;
|
||||
@@ -1,45 +0,0 @@
|
||||
import { isArray } from "lodash";
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import DatePicker from "antd/lib/date-picker";
|
||||
import { clientConfig } from "@/services/auth";
|
||||
import { Moment } from "@/components/proptypes";
|
||||
|
||||
const { RangePicker } = DatePicker;
|
||||
|
||||
const DateRangeInput = React.forwardRef(({ defaultValue, value, onSelect, className, ...props }, ref) => {
|
||||
const format = clientConfig.dateFormat || "YYYY-MM-DD";
|
||||
const additionalAttributes = {};
|
||||
if (isArray(defaultValue) && defaultValue[0].isValid() && defaultValue[1].isValid()) {
|
||||
additionalAttributes.defaultValue = defaultValue;
|
||||
}
|
||||
if (value === null || (isArray(value) && value[0].isValid() && value[1].isValid())) {
|
||||
additionalAttributes.value = value;
|
||||
}
|
||||
return (
|
||||
<RangePicker
|
||||
ref={ref}
|
||||
className={className}
|
||||
{...additionalAttributes}
|
||||
format={format}
|
||||
onChange={onSelect}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
DateRangeInput.propTypes = {
|
||||
defaultValue: PropTypes.arrayOf(Moment),
|
||||
value: PropTypes.arrayOf(Moment),
|
||||
onSelect: PropTypes.func,
|
||||
className: PropTypes.string,
|
||||
};
|
||||
|
||||
DateRangeInput.defaultProps = {
|
||||
defaultValue: null,
|
||||
value: undefined,
|
||||
onSelect: () => {},
|
||||
className: "",
|
||||
};
|
||||
|
||||
export default DateRangeInput;
|
||||
51
client/app/components/DateRangeInput.tsx
Normal file
51
client/app/components/DateRangeInput.tsx
Normal file
@@ -0,0 +1,51 @@
|
||||
import { isArray } from "lodash";
|
||||
import React from "react";
|
||||
import DatePicker from "antd/lib/date-picker";
|
||||
import { clientConfig } from "@/services/auth";
|
||||
// @ts-expect-error ts-migrate(6133) FIXME: 'Moment' is declared but its value is never read.
|
||||
import { Moment } from "@/components/proptypes";
|
||||
|
||||
const { RangePicker } = DatePicker;
|
||||
|
||||
type Props = {
|
||||
// @ts-expect-error ts-migrate(2749) FIXME: 'Moment' refers to a value, but is being used as a... Remove this comment to see the full error message
|
||||
defaultValue?: Moment[];
|
||||
// @ts-expect-error ts-migrate(2749) FIXME: 'Moment' refers to a value, but is being used as a... Remove this comment to see the full error message
|
||||
value?: Moment[];
|
||||
onSelect?: (...args: any[]) => any;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
const DateRangeInput = React.forwardRef<any, Props>(({ defaultValue, value, onSelect, className, ...props }, ref) => {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dateFormat' does not exist on type '{}'.
|
||||
const format = clientConfig.dateFormat || "YYYY-MM-DD";
|
||||
const additionalAttributes = {};
|
||||
if (isArray(defaultValue) && defaultValue[0].isValid() && defaultValue[1].isValid()) {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'defaultValue' does not exist on type '{}... Remove this comment to see the full error message
|
||||
additionalAttributes.defaultValue = defaultValue;
|
||||
}
|
||||
if (value === null || (isArray(value) && value[0].isValid() && value[1].isValid())) {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'value' does not exist on type '{}'.
|
||||
additionalAttributes.value = value;
|
||||
}
|
||||
return (
|
||||
<RangePicker
|
||||
ref={ref}
|
||||
className={className}
|
||||
{...additionalAttributes}
|
||||
format={format}
|
||||
onChange={onSelect}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
DateRangeInput.defaultProps = {
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'null' is not assignable to type 'any[] | und... Remove this comment to see the full error message
|
||||
defaultValue: null,
|
||||
value: undefined,
|
||||
onSelect: () => {},
|
||||
className: "",
|
||||
};
|
||||
|
||||
export default DateRangeInput;
|
||||
@@ -1,46 +0,0 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import DatePicker from "antd/lib/date-picker";
|
||||
import { clientConfig } from "@/services/auth";
|
||||
import { Moment } from "@/components/proptypes";
|
||||
|
||||
const DateTimeInput = React.forwardRef(({ defaultValue, value, withSeconds, onSelect, className, ...props }, ref) => {
|
||||
const format = (clientConfig.dateFormat || "YYYY-MM-DD") + (withSeconds ? " HH:mm:ss" : " HH:mm");
|
||||
const additionalAttributes = {};
|
||||
if (defaultValue && defaultValue.isValid()) {
|
||||
additionalAttributes.defaultValue = defaultValue;
|
||||
}
|
||||
if (value === null || (value && value.isValid())) {
|
||||
additionalAttributes.value = value;
|
||||
}
|
||||
return (
|
||||
<DatePicker
|
||||
ref={ref}
|
||||
className={className}
|
||||
showTime
|
||||
{...additionalAttributes}
|
||||
format={format}
|
||||
placeholder="Select Date and Time"
|
||||
onChange={onSelect}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
DateTimeInput.propTypes = {
|
||||
defaultValue: Moment,
|
||||
value: Moment,
|
||||
withSeconds: PropTypes.bool,
|
||||
onSelect: PropTypes.func,
|
||||
className: PropTypes.string,
|
||||
};
|
||||
|
||||
DateTimeInput.defaultProps = {
|
||||
defaultValue: null,
|
||||
value: undefined,
|
||||
withSeconds: false,
|
||||
onSelect: () => {},
|
||||
className: "",
|
||||
};
|
||||
|
||||
export default DateTimeInput;
|
||||
51
client/app/components/DateTimeInput.tsx
Normal file
51
client/app/components/DateTimeInput.tsx
Normal file
@@ -0,0 +1,51 @@
|
||||
import React from "react";
|
||||
import DatePicker from "antd/lib/date-picker";
|
||||
import { clientConfig } from "@/services/auth";
|
||||
// @ts-expect-error ts-migrate(6133) FIXME: 'Moment' is declared but its value is never read.
|
||||
import { Moment } from "@/components/proptypes";
|
||||
|
||||
type Props = {
|
||||
// @ts-expect-error ts-migrate(2749) FIXME: 'Moment' refers to a value, but is being used as a... Remove this comment to see the full error message
|
||||
defaultValue?: Moment;
|
||||
// @ts-expect-error ts-migrate(2749) FIXME: 'Moment' refers to a value, but is being used as a... Remove this comment to see the full error message
|
||||
value?: Moment;
|
||||
withSeconds?: boolean;
|
||||
onSelect?: (...args: any[]) => any;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
const DateTimeInput = React.forwardRef<any, Props>(({ defaultValue, value, withSeconds, onSelect, className, ...props }, ref) => {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dateFormat' does not exist on type '{}'.
|
||||
const format = (clientConfig.dateFormat || "YYYY-MM-DD") + (withSeconds ? " HH:mm:ss" : " HH:mm");
|
||||
const additionalAttributes = {};
|
||||
if (defaultValue && defaultValue.isValid()) {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'defaultValue' does not exist on type '{}... Remove this comment to see the full error message
|
||||
additionalAttributes.defaultValue = defaultValue;
|
||||
}
|
||||
if (value === null || (value && value.isValid())) {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'value' does not exist on type '{}'.
|
||||
additionalAttributes.value = value;
|
||||
}
|
||||
return (
|
||||
<DatePicker
|
||||
ref={ref}
|
||||
className={className}
|
||||
showTime
|
||||
{...additionalAttributes}
|
||||
format={format}
|
||||
placeholder="Select Date and Time"
|
||||
onChange={onSelect}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
DateTimeInput.defaultProps = {
|
||||
defaultValue: null,
|
||||
value: undefined,
|
||||
withSeconds: false,
|
||||
onSelect: () => {},
|
||||
className: "",
|
||||
};
|
||||
|
||||
export default DateTimeInput;
|
||||
@@ -1,20 +1,33 @@
|
||||
import { isArray } from "lodash";
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import DatePicker from "antd/lib/date-picker";
|
||||
import { clientConfig } from "@/services/auth";
|
||||
// @ts-expect-error ts-migrate(6133) FIXME: 'Moment' is declared but its value is never read.
|
||||
import { Moment } from "@/components/proptypes";
|
||||
|
||||
const { RangePicker } = DatePicker;
|
||||
|
||||
const DateTimeRangeInput = React.forwardRef(
|
||||
type Props = {
|
||||
// @ts-expect-error ts-migrate(2749) FIXME: 'Moment' refers to a value, but is being used as a... Remove this comment to see the full error message
|
||||
defaultValue?: Moment[];
|
||||
// @ts-expect-error ts-migrate(2749) FIXME: 'Moment' refers to a value, but is being used as a... Remove this comment to see the full error message
|
||||
value?: Moment[];
|
||||
withSeconds?: boolean;
|
||||
onSelect?: (...args: any[]) => any;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
const DateTimeRangeInput = React.forwardRef<any, Props>(
|
||||
({ defaultValue, value, withSeconds, onSelect, className, ...props }, ref) => {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dateFormat' does not exist on type '{}'.
|
||||
const format = (clientConfig.dateFormat || "YYYY-MM-DD") + (withSeconds ? " HH:mm:ss" : " HH:mm");
|
||||
const additionalAttributes = {};
|
||||
if (isArray(defaultValue) && defaultValue[0].isValid() && defaultValue[1].isValid()) {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'defaultValue' does not exist on type '{}... Remove this comment to see the full error message
|
||||
additionalAttributes.defaultValue = defaultValue;
|
||||
}
|
||||
if (value === null || (isArray(value) && value[0].isValid() && value[1].isValid())) {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'value' does not exist on type '{}'.
|
||||
additionalAttributes.value = value;
|
||||
}
|
||||
return (
|
||||
@@ -31,15 +44,8 @@ const DateTimeRangeInput = React.forwardRef(
|
||||
}
|
||||
);
|
||||
|
||||
DateTimeRangeInput.propTypes = {
|
||||
defaultValue: PropTypes.arrayOf(Moment),
|
||||
value: PropTypes.arrayOf(Moment),
|
||||
withSeconds: PropTypes.bool,
|
||||
onSelect: PropTypes.func,
|
||||
className: PropTypes.string,
|
||||
};
|
||||
|
||||
DateTimeRangeInput.defaultProps = {
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'null' is not assignable to type 'any[] | und... Remove this comment to see the full error message
|
||||
defaultValue: null,
|
||||
value: undefined,
|
||||
withSeconds: false,
|
||||
@@ -3,6 +3,17 @@ import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import ReactDOM from "react-dom";
|
||||
|
||||
type DialogPropType = {
|
||||
props: {
|
||||
visible?: boolean;
|
||||
onOk?: (...args: any[]) => any;
|
||||
onCancel?: (...args: any[]) => any;
|
||||
afterClose?: (...args: any[]) => any;
|
||||
};
|
||||
close: (...args: any[]) => any;
|
||||
dismiss: (...args: any[]) => any;
|
||||
};
|
||||
|
||||
/**
|
||||
Wrapper for dialogs based on Ant's <Modal> component.
|
||||
|
||||
@@ -75,7 +86,7 @@ import ReactDOM from "react-dom";
|
||||
);
|
||||
}
|
||||
|
||||
4. wrap your component and export it:
|
||||
4. wrap your component and it:
|
||||
|
||||
export default wrapDialog(YourComponent).
|
||||
|
||||
@@ -96,18 +107,20 @@ import ReactDOM from "react-dom";
|
||||
}
|
||||
*/
|
||||
|
||||
export const DialogPropType = PropTypes.shape({
|
||||
props: PropTypes.shape({
|
||||
visible: PropTypes.bool,
|
||||
onOk: PropTypes.func,
|
||||
onCancel: PropTypes.func,
|
||||
afterClose: PropTypes.func,
|
||||
}).isRequired,
|
||||
close: PropTypes.func.isRequired,
|
||||
dismiss: PropTypes.func.isRequired,
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'Requireable<InferProps<{ props: Validator<In... Remove this comment to see the full error message
|
||||
export const DialogPropType: PropTypes.Requireable<DialogPropType> = PropTypes.shape({
|
||||
props: PropTypes.shape({
|
||||
visible: PropTypes.bool,
|
||||
onOk: PropTypes.func,
|
||||
onCancel: PropTypes.func,
|
||||
afterClose: PropTypes.func,
|
||||
}).isRequired,
|
||||
close: PropTypes.func.isRequired,
|
||||
dismiss: PropTypes.func.isRequired,
|
||||
});
|
||||
|
||||
function openDialog(DialogComponent, props) {
|
||||
|
||||
function openDialog(DialogComponent: any, props: any) {
|
||||
const dialog = {
|
||||
props: {
|
||||
visible: true,
|
||||
@@ -121,7 +134,7 @@ function openDialog(DialogComponent, props) {
|
||||
dismiss: () => {},
|
||||
};
|
||||
|
||||
let pendingCloseTask = null;
|
||||
let pendingCloseTask: any = null;
|
||||
|
||||
const handlers = {
|
||||
onClose: () => {},
|
||||
@@ -143,7 +156,7 @@ function openDialog(DialogComponent, props) {
|
||||
}, 10);
|
||||
}
|
||||
|
||||
function processDialogClose(result, setAdditionalDialogProps) {
|
||||
function processDialogClose(result: any, setAdditionalDialogProps: any) {
|
||||
dialog.props.okButtonProps = { disabled: true };
|
||||
dialog.props.cancelButtonProps = { disabled: true };
|
||||
setAdditionalDialogProps();
|
||||
@@ -160,9 +173,11 @@ function openDialog(DialogComponent, props) {
|
||||
});
|
||||
}
|
||||
|
||||
function closeDialog(result) {
|
||||
function closeDialog(result: any) {
|
||||
if (!pendingCloseTask) {
|
||||
// @ts-expect-error ts-migrate(2554) FIXME: Expected 0 arguments, but got 1.
|
||||
pendingCloseTask = processDialogClose(handlers.onClose(result), () => {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'loading' does not exist on type '{}'.
|
||||
dialog.props.okButtonProps.loading = true;
|
||||
}).finally(() => {
|
||||
pendingCloseTask = null;
|
||||
@@ -171,9 +186,11 @@ function openDialog(DialogComponent, props) {
|
||||
return pendingCloseTask;
|
||||
}
|
||||
|
||||
function dismissDialog(result) {
|
||||
function dismissDialog(result: any) {
|
||||
if (!pendingCloseTask) {
|
||||
// @ts-expect-error ts-migrate(2554) FIXME: Expected 0 arguments, but got 1.
|
||||
pendingCloseTask = processDialogClose(handlers.onDismiss(result), () => {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'loading' does not exist on type '{}'.
|
||||
dialog.props.cancelButtonProps.loading = true;
|
||||
}).finally(() => {
|
||||
pendingCloseTask = null;
|
||||
@@ -182,26 +199,30 @@ function openDialog(DialogComponent, props) {
|
||||
return pendingCloseTask;
|
||||
}
|
||||
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '(result: any) => any' is not assignable to t... Remove this comment to see the full error message
|
||||
dialog.props.onOk = closeDialog;
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '(result: any) => any' is not assignable to t... Remove this comment to see the full error message
|
||||
dialog.props.onCancel = dismissDialog;
|
||||
dialog.props.afterClose = destroyDialog;
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '(result: any) => any' is not assignable to t... Remove this comment to see the full error message
|
||||
dialog.close = closeDialog;
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '(result: any) => any' is not assignable to t... Remove this comment to see the full error message
|
||||
dialog.dismiss = dismissDialog;
|
||||
|
||||
const result = {
|
||||
close: closeDialog,
|
||||
dismiss: dismissDialog,
|
||||
update: newProps => {
|
||||
update: (newProps: any) => {
|
||||
props = { ...props, ...newProps };
|
||||
render();
|
||||
},
|
||||
onClose: handler => {
|
||||
onClose: (handler: any) => {
|
||||
if (isFunction(handler)) {
|
||||
handlers.onClose = handler;
|
||||
}
|
||||
return result;
|
||||
},
|
||||
onDismiss: handler => {
|
||||
onDismiss: (handler: any) => {
|
||||
if (isFunction(handler)) {
|
||||
handlers.onDismiss = handler;
|
||||
}
|
||||
@@ -214,14 +235,9 @@ function openDialog(DialogComponent, props) {
|
||||
return result;
|
||||
}
|
||||
|
||||
export function wrap(DialogComponent) {
|
||||
export function wrap(DialogComponent: any) {
|
||||
return {
|
||||
Component: DialogComponent,
|
||||
showModal: props => openDialog(DialogComponent, props),
|
||||
showModal: (props: any) => openDialog(DialogComponent, props),
|
||||
};
|
||||
}
|
||||
|
||||
export default {
|
||||
DialogPropType,
|
||||
wrap,
|
||||
};
|
||||
@@ -1,32 +1,35 @@
|
||||
import { isFunction, isString, isUndefined } from "lodash";
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
const componentsRegistry = new Map();
|
||||
const activeInstances = new Set();
|
||||
|
||||
export function registerComponent(name, component) {
|
||||
export function registerComponent(name: any, component: any) {
|
||||
if (isString(name) && name !== "") {
|
||||
componentsRegistry.set(name, isFunction(component) ? component : null);
|
||||
// Refresh active DynamicComponent instances which use this component
|
||||
activeInstances.forEach(dynamicComponent => {
|
||||
// @ts-expect-error ts-migrate(2571) FIXME: Object is of type 'unknown'.
|
||||
if (dynamicComponent.props.name === name) {
|
||||
// @ts-expect-error ts-migrate(2571) FIXME: Object is of type 'unknown'.
|
||||
dynamicComponent.forceUpdate();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function unregisterComponent(name) {
|
||||
export function unregisterComponent(name: any) {
|
||||
registerComponent(name, null);
|
||||
}
|
||||
|
||||
export default class DynamicComponent extends React.Component {
|
||||
static propTypes = {
|
||||
name: PropTypes.string.isRequired,
|
||||
fallback: PropTypes.node,
|
||||
children: PropTypes.node,
|
||||
};
|
||||
type OwnProps = {
|
||||
name: string;
|
||||
fallback?: React.ReactNode;
|
||||
};
|
||||
|
||||
type Props = OwnProps & typeof DynamicComponent.defaultProps;
|
||||
|
||||
export default class DynamicComponent extends React.Component<Props> {
|
||||
|
||||
static defaultProps = {
|
||||
children: null,
|
||||
@@ -1,21 +1,25 @@
|
||||
import { trim } from "lodash";
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import cx from "classnames";
|
||||
import Input from "antd/lib/input";
|
||||
|
||||
export default class EditInPlace extends React.Component {
|
||||
static propTypes = {
|
||||
ignoreBlanks: PropTypes.bool,
|
||||
isEditable: PropTypes.bool,
|
||||
placeholder: PropTypes.string,
|
||||
value: PropTypes.string,
|
||||
onDone: PropTypes.func.isRequired,
|
||||
onStopEditing: PropTypes.func,
|
||||
multiline: PropTypes.bool,
|
||||
editorProps: PropTypes.object,
|
||||
defaultEditing: PropTypes.bool,
|
||||
};
|
||||
type OwnProps = {
|
||||
ignoreBlanks?: boolean;
|
||||
isEditable?: boolean;
|
||||
placeholder?: string;
|
||||
value?: string;
|
||||
onDone: (...args: any[]) => any;
|
||||
onStopEditing?: (...args: any[]) => any;
|
||||
multiline?: boolean;
|
||||
editorProps?: any;
|
||||
defaultEditing?: boolean;
|
||||
};
|
||||
|
||||
type State = any;
|
||||
|
||||
type Props = OwnProps & typeof EditInPlace.defaultProps;
|
||||
|
||||
export default class EditInPlace extends React.Component<Props, State> {
|
||||
|
||||
static defaultProps = {
|
||||
ignoreBlanks: false,
|
||||
@@ -28,14 +32,14 @@ export default class EditInPlace extends React.Component {
|
||||
defaultEditing: false,
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
editing: props.defaultEditing,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidUpdate(_, prevState) {
|
||||
componentDidUpdate(_: Props, prevState: State) {
|
||||
if (!this.state.editing && prevState.editing) {
|
||||
this.props.onStopEditing();
|
||||
}
|
||||
@@ -47,7 +51,7 @@ export default class EditInPlace extends React.Component {
|
||||
}
|
||||
};
|
||||
|
||||
stopEditing = currentValue => {
|
||||
stopEditing = (currentValue: any) => {
|
||||
const newValue = trim(currentValue);
|
||||
const ignorableBlank = this.props.ignoreBlanks && newValue === "";
|
||||
if (!ignorableBlank && newValue !== this.props.value) {
|
||||
@@ -56,7 +60,7 @@ export default class EditInPlace extends React.Component {
|
||||
this.setState({ editing: false });
|
||||
};
|
||||
|
||||
handleKeyDown = event => {
|
||||
handleKeyDown = (event: any) => {
|
||||
if (event.keyCode === 13 && !event.shiftKey) {
|
||||
event.preventDefault();
|
||||
this.stopEditing(event.target.value);
|
||||
@@ -86,7 +90,7 @@ export default class EditInPlace extends React.Component {
|
||||
return (
|
||||
<InputComponent
|
||||
defaultValue={value}
|
||||
onBlur={e => this.stopEditing(e.target.value)}
|
||||
onBlur={(e: any) => this.stopEditing(e.target.value)}
|
||||
onKeyDown={this.handleKeyDown}
|
||||
autoFocus
|
||||
{...editorProps}
|
||||
@@ -96,6 +100,7 @@ export default class EditInPlace extends React.Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'className' does not exist on type 'Reado... Remove this comment to see the full error message
|
||||
<span className={cx("edit-in-place", { active: this.state.editing }, this.props.className)}>
|
||||
{this.state.editing ? this.renderEdit() : this.renderNormal()}
|
||||
</span>
|
||||
@@ -1,6 +1,5 @@
|
||||
import { includes, words, capitalize, clone, isNull } from "lodash";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import Checkbox from "antd/lib/checkbox";
|
||||
import Modal from "antd/lib/modal";
|
||||
import Form from "antd/lib/form";
|
||||
@@ -8,6 +7,7 @@ import Button from "antd/lib/button";
|
||||
import Select from "antd/lib/select";
|
||||
import Input from "antd/lib/input";
|
||||
import Divider from "antd/lib/divider";
|
||||
// @ts-expect-error ts-migrate(6133) FIXME: 'DialogPropType' is declared but its value is neve... Remove this comment to see the full error message
|
||||
import { wrap as wrapDialog, DialogPropType } from "@/components/DialogWrapper";
|
||||
import QuerySelector from "@/components/QuerySelector";
|
||||
import { Query } from "@/services/query";
|
||||
@@ -15,20 +15,28 @@ import { Query } from "@/services/query";
|
||||
const { Option } = Select;
|
||||
const formItemProps = { labelCol: { span: 6 }, wrapperCol: { span: 16 } };
|
||||
|
||||
function getDefaultTitle(text) {
|
||||
function getDefaultTitle(text: any) {
|
||||
return capitalize(words(text).join(" ")); // humanize
|
||||
}
|
||||
|
||||
function isTypeDateRange(type) {
|
||||
function isTypeDateRange(type: any) {
|
||||
return /-range/.test(type);
|
||||
}
|
||||
|
||||
function joinExampleList(multiValuesOptions) {
|
||||
function joinExampleList(multiValuesOptions: any) {
|
||||
const { prefix, suffix } = multiValuesOptions;
|
||||
return ["value1", "value2", "value3"].map(value => `${prefix}${value}${suffix}`).join(",");
|
||||
}
|
||||
|
||||
function NameInput({ name, type, onChange, existingNames, setValidation }) {
|
||||
type NameInputProps = {
|
||||
name: string;
|
||||
onChange: (...args: any[]) => any;
|
||||
existingNames: string[];
|
||||
setValidation: (...args: any[]) => any;
|
||||
type: string;
|
||||
};
|
||||
|
||||
function NameInput({ name, type, onChange, existingNames, setValidation }: NameInputProps) {
|
||||
let helpText = "";
|
||||
let validateStatus = "";
|
||||
|
||||
@@ -41,6 +49,7 @@ function NameInput({ name, type, onChange, existingNames, setValidation }) {
|
||||
validateStatus = "error";
|
||||
} else {
|
||||
if (isTypeDateRange(type)) {
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'Element' is not assignable to type 'string'.
|
||||
helpText = (
|
||||
<React.Fragment>
|
||||
Appears in query as{" "}
|
||||
@@ -52,21 +61,23 @@ function NameInput({ name, type, onChange, existingNames, setValidation }) {
|
||||
}
|
||||
|
||||
return (
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type '"" | "err... Remove this comment to see the full error message
|
||||
<Form.Item required label="Keyword" help={helpText} validateStatus={validateStatus} {...formItemProps}>
|
||||
<Input onChange={e => onChange(e.target.value)} autoFocus />
|
||||
</Form.Item>
|
||||
);
|
||||
}
|
||||
|
||||
NameInput.propTypes = {
|
||||
name: PropTypes.string.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
existingNames: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||
setValidation: PropTypes.func.isRequired,
|
||||
type: PropTypes.string.isRequired,
|
||||
type OwnEditParameterSettingsDialogProps = {
|
||||
parameter: any;
|
||||
// @ts-expect-error ts-migrate(2749) FIXME: 'DialogPropType' refers to a value, but is being u... Remove this comment to see the full error message
|
||||
dialog: DialogPropType;
|
||||
existingParams?: string[];
|
||||
};
|
||||
|
||||
function EditParameterSettingsDialog(props) {
|
||||
type EditParameterSettingsDialogProps = OwnEditParameterSettingsDialogProps & typeof EditParameterSettingsDialog.defaultProps;
|
||||
|
||||
function EditParameterSettingsDialog(props: EditParameterSettingsDialogProps) {
|
||||
const [param, setParam] = useState(clone(props.parameter));
|
||||
const [isNameValid, setIsNameValid] = useState(true);
|
||||
const [initialQuery, setInitialQuery] = useState();
|
||||
@@ -77,6 +88,7 @@ function EditParameterSettingsDialog(props) {
|
||||
useEffect(() => {
|
||||
const queryId = props.parameter.queryId;
|
||||
if (queryId) {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'get' does not exist on type 'typeof Quer... Remove this comment to see the full error message
|
||||
Query.get({ id: queryId }).then(setInitialQuery);
|
||||
}
|
||||
}, [props.parameter.queryId]);
|
||||
@@ -157,6 +169,7 @@ function EditParameterSettingsDialog(props) {
|
||||
</Option>
|
||||
<Option value="enum">Dropdown List</Option>
|
||||
<Option value="query">Query Based Dropdown List</Option>
|
||||
{/* @ts-expect-error ts-migrate(2741) FIXME: Property 'value' is missing in type '{ children: E... Remove this comment to see the full error message */}
|
||||
<Option disabled key="dv1">
|
||||
<Divider className="select-option-divider" />
|
||||
</Option>
|
||||
@@ -167,6 +180,7 @@ function EditParameterSettingsDialog(props) {
|
||||
Date and Time
|
||||
</Option>
|
||||
<Option value="datetime-with-seconds">Date and Time (with seconds)</Option>
|
||||
{/* @ts-expect-error ts-migrate(2741) FIXME: Property 'value' is missing in type '{ children: E... Remove this comment to see the full error message */}
|
||||
<Option disabled key="dv2">
|
||||
<Divider className="select-option-divider" />
|
||||
</Option>
|
||||
@@ -189,8 +203,11 @@ function EditParameterSettingsDialog(props) {
|
||||
{param.type === "query" && (
|
||||
<Form.Item label="Query" help="Select query to load dropdown values from" {...formItemProps}>
|
||||
<QuerySelector
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'undefined' is not assignable to type 'never'... Remove this comment to see the full error message
|
||||
selectedQuery={initialQuery}
|
||||
onChange={q => setParam({ ...param, queryId: q && q.id })}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '(q: any) => void' is not assignable to type ... Remove this comment to see the full error message
|
||||
onChange={(q: any) => setParam({ ...param, queryId: q && q.id })}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'never'.
|
||||
type="select"
|
||||
/>
|
||||
</Form.Item>
|
||||
@@ -251,12 +268,6 @@ function EditParameterSettingsDialog(props) {
|
||||
);
|
||||
}
|
||||
|
||||
EditParameterSettingsDialog.propTypes = {
|
||||
parameter: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
|
||||
dialog: DialogPropType.isRequired,
|
||||
existingParams: PropTypes.arrayOf(PropTypes.string),
|
||||
};
|
||||
|
||||
EditParameterSettingsDialog.defaultProps = {
|
||||
existingParams: [],
|
||||
};
|
||||
@@ -1,5 +1,4 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import Dropdown from "antd/lib/dropdown";
|
||||
import Menu from "antd/lib/menu";
|
||||
import Button from "antd/lib/button";
|
||||
@@ -13,7 +12,20 @@ import EllipsisOutlinedIcon from "@ant-design/icons/EllipsisOutlined";
|
||||
|
||||
import QueryResultsLink from "./QueryResultsLink";
|
||||
|
||||
export default function QueryControlDropdown(props) {
|
||||
type OwnProps = {
|
||||
query: any;
|
||||
queryResult?: any;
|
||||
queryExecuting: boolean;
|
||||
showEmbedDialog: (...args: any[]) => any;
|
||||
embed?: boolean;
|
||||
apiKey?: string;
|
||||
selectedTab?: string | number;
|
||||
openAddToDashboardForm: (...args: any[]) => any;
|
||||
};
|
||||
|
||||
type Props = OwnProps & typeof QueryControlDropdown.defaultProps;
|
||||
|
||||
export default function QueryControlDropdown(props: Props) {
|
||||
const menu = (
|
||||
<Menu>
|
||||
{!props.query.isNew() && (!props.query.is_draft || !props.query.is_archived) && (
|
||||
@@ -23,6 +35,7 @@ export default function QueryControlDropdown(props) {
|
||||
</a>
|
||||
</Menu.Item>
|
||||
)}
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'disablePublicUrls' does not exist on typ... Remove this comment to see the full error message */}
|
||||
{!clientConfig.disablePublicUrls && !props.query.isNew() && (
|
||||
<Menu.Item>
|
||||
<a onClick={() => props.showEmbedDialog(props.query, props.selectedTab)} data-test="ShowEmbedDialogButton">
|
||||
@@ -75,17 +88,6 @@ export default function QueryControlDropdown(props) {
|
||||
);
|
||||
}
|
||||
|
||||
QueryControlDropdown.propTypes = {
|
||||
query: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
|
||||
queryResult: PropTypes.object, // eslint-disable-line react/forbid-prop-types
|
||||
queryExecuting: PropTypes.bool.isRequired,
|
||||
showEmbedDialog: PropTypes.func.isRequired,
|
||||
embed: PropTypes.bool,
|
||||
apiKey: PropTypes.string,
|
||||
selectedTab: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
openAddToDashboardForm: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
QueryControlDropdown.defaultProps = {
|
||||
queryResult: {},
|
||||
embed: false,
|
||||
@@ -1,8 +1,19 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import Link from "@/components/Link";
|
||||
|
||||
export default function QueryResultsLink(props) {
|
||||
type OwnProps = {
|
||||
query: any;
|
||||
queryResult?: any;
|
||||
fileType?: string;
|
||||
disabled: boolean;
|
||||
embed?: boolean;
|
||||
apiKey?: string;
|
||||
children: React.ReactNode[] | React.ReactNode;
|
||||
};
|
||||
|
||||
type Props = OwnProps & typeof QueryResultsLink.defaultProps;
|
||||
|
||||
export default function QueryResultsLink(props: Props) {
|
||||
let href = "";
|
||||
|
||||
const { query, queryResult, fileType } = props;
|
||||
@@ -24,16 +35,6 @@ export default function QueryResultsLink(props) {
|
||||
);
|
||||
}
|
||||
|
||||
QueryResultsLink.propTypes = {
|
||||
query: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
|
||||
queryResult: PropTypes.object, // eslint-disable-line react/forbid-prop-types
|
||||
fileType: PropTypes.string,
|
||||
disabled: PropTypes.bool.isRequired,
|
||||
embed: PropTypes.bool,
|
||||
apiKey: PropTypes.string,
|
||||
children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]).isRequired,
|
||||
};
|
||||
|
||||
QueryResultsLink.defaultProps = {
|
||||
queryResult: {},
|
||||
fileType: "csv",
|
||||
@@ -1,9 +1,15 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import Button from "antd/lib/button";
|
||||
import FormOutlinedIcon from "@ant-design/icons/FormOutlined";
|
||||
|
||||
export default function EditVisualizationButton(props) {
|
||||
type OwnProps = {
|
||||
openVisualizationEditor: (...args: any[]) => any;
|
||||
selectedTab?: string | number;
|
||||
};
|
||||
|
||||
type Props = OwnProps & typeof EditVisualizationButton.defaultProps;
|
||||
|
||||
export default function EditVisualizationButton(props: Props) {
|
||||
return (
|
||||
<Button
|
||||
data-test="EditVisualization"
|
||||
@@ -15,11 +21,6 @@ export default function EditVisualizationButton(props) {
|
||||
);
|
||||
}
|
||||
|
||||
EditVisualizationButton.propTypes = {
|
||||
openVisualizationEditor: PropTypes.func.isRequired,
|
||||
selectedTab: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
};
|
||||
|
||||
EditVisualizationButton.defaultProps = {
|
||||
selectedTab: "",
|
||||
};
|
||||
@@ -1,12 +1,21 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import cx from "classnames";
|
||||
import { clientConfig, currentUser } from "@/services/auth";
|
||||
import Tooltip from "antd/lib/tooltip";
|
||||
import Alert from "antd/lib/alert";
|
||||
import HelpTrigger from "@/components/HelpTrigger";
|
||||
|
||||
export default function EmailSettingsWarning({ featureName, className, mode, adminOnly }) {
|
||||
type OwnProps = {
|
||||
featureName: string;
|
||||
className?: string;
|
||||
mode?: "alert" | "icon";
|
||||
adminOnly?: boolean;
|
||||
};
|
||||
|
||||
type Props = OwnProps & typeof EmailSettingsWarning.defaultProps;
|
||||
|
||||
export default function EmailSettingsWarning({ featureName, className, mode, adminOnly }: Props) {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'mailSettingsMissing' does not exist on t... Remove this comment to see the full error message
|
||||
if (!clientConfig.mailSettingsMissing) {
|
||||
return null;
|
||||
}
|
||||
@@ -18,6 +27,7 @@ export default function EmailSettingsWarning({ featureName, className, mode, adm
|
||||
const message = (
|
||||
<span>
|
||||
Your mail server isn't configured correctly, and is needed for {featureName} to work.{" "}
|
||||
{/* @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'never'. */}
|
||||
<HelpTrigger type="MAIL_CONFIG" className="f-inherit" />
|
||||
</span>
|
||||
);
|
||||
@@ -33,13 +43,6 @@ export default function EmailSettingsWarning({ featureName, className, mode, adm
|
||||
return <Alert message={message} type="error" className={className} />;
|
||||
}
|
||||
|
||||
EmailSettingsWarning.propTypes = {
|
||||
featureName: PropTypes.string.isRequired,
|
||||
className: PropTypes.string,
|
||||
mode: PropTypes.oneOf(["alert", "icon"]),
|
||||
adminOnly: PropTypes.bool,
|
||||
};
|
||||
|
||||
EmailSettingsWarning.defaultProps = {
|
||||
className: null,
|
||||
mode: "alert",
|
||||
@@ -1,19 +1,21 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
export default class FavoritesControl extends React.Component {
|
||||
static propTypes = {
|
||||
item: PropTypes.shape({
|
||||
is_favorite: PropTypes.bool.isRequired,
|
||||
}).isRequired,
|
||||
onChange: PropTypes.func,
|
||||
};
|
||||
type OwnProps = {
|
||||
item: {
|
||||
is_favorite: boolean;
|
||||
};
|
||||
onChange?: (...args: any[]) => any;
|
||||
};
|
||||
|
||||
type Props = OwnProps & typeof FavoritesControl.defaultProps;
|
||||
|
||||
export default class FavoritesControl extends React.Component<Props> {
|
||||
|
||||
static defaultProps = {
|
||||
onChange: () => {},
|
||||
};
|
||||
|
||||
toggleItem(event, item, callback) {
|
||||
toggleItem(event: any, item: any, callback: any) {
|
||||
const action = item.is_favorite ? item.unfavorite.bind(item) : item.favorite.bind(item);
|
||||
const savedIsFavorite = item.is_favorite;
|
||||
|
||||
@@ -8,18 +8,28 @@ import { formatColumnValue } from "@/lib/utils";
|
||||
const ALL_VALUES = "###Redash::Filters::SelectAll###";
|
||||
const NONE_VALUES = "###Redash::Filters::Clear###";
|
||||
|
||||
export const FilterType = PropTypes.shape({
|
||||
name: PropTypes.string.isRequired,
|
||||
friendlyName: PropTypes.string.isRequired,
|
||||
multiple: PropTypes.bool,
|
||||
current: PropTypes.oneOfType([PropTypes.any, PropTypes.arrayOf(PropTypes.any)]),
|
||||
values: PropTypes.arrayOf(PropTypes.any).isRequired,
|
||||
type FilterType = {
|
||||
name: string;
|
||||
friendlyName: string;
|
||||
multiple?: boolean;
|
||||
current?: any | any[];
|
||||
values: any[];
|
||||
};
|
||||
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'Requireable<InferProps<{ name: Validator<str... Remove this comment to see the full error message
|
||||
const FilterType: PropTypes.Requireable<FilterType> = PropTypes.shape({
|
||||
name: PropTypes.string.isRequired,
|
||||
friendlyName: PropTypes.string.isRequired,
|
||||
multiple: PropTypes.bool,
|
||||
current: PropTypes.oneOfType([PropTypes.any, PropTypes.arrayOf(PropTypes.any)]),
|
||||
values: PropTypes.arrayOf(PropTypes.any).isRequired,
|
||||
});
|
||||
export { FilterType };
|
||||
|
||||
export const FiltersType = PropTypes.arrayOf(FilterType);
|
||||
|
||||
function createFilterChangeHandler(filters, onChange) {
|
||||
return (filter, values) => {
|
||||
function createFilterChangeHandler(filters: any, onChange: any) {
|
||||
return (filter: any, values: any) => {
|
||||
if (isArray(values)) {
|
||||
values = map(values, value => filter.values[toNumber(value.key)] || value.key);
|
||||
} else {
|
||||
@@ -38,7 +48,7 @@ function createFilterChangeHandler(filters, onChange) {
|
||||
};
|
||||
}
|
||||
|
||||
export function filterData(rows, filters = []) {
|
||||
export function filterData(rows: any, filters = []) {
|
||||
if (!isArray(rows)) {
|
||||
return [];
|
||||
}
|
||||
@@ -49,7 +59,9 @@ export function filterData(rows, filters = []) {
|
||||
// "every" field's value should match "some" of corresponding filter's values
|
||||
result = result.filter(row =>
|
||||
every(filters, filter => {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'name' does not exist on type 'never'.
|
||||
const rowValue = row[filter.name];
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'current' does not exist on type 'never'.
|
||||
const filterValues = isArray(filter.current) ? filter.current : [filter.current];
|
||||
return some(filterValues, filterValue => {
|
||||
if (moment.isMoment(rowValue)) {
|
||||
@@ -66,11 +78,20 @@ export function filterData(rows, filters = []) {
|
||||
return result;
|
||||
}
|
||||
|
||||
function Filters({ filters, onChange }) {
|
||||
type OwnProps = {
|
||||
// @ts-expect-error ts-migrate(2749) FIXME: 'FiltersType' refers to a value, but is being used... Remove this comment to see the full error message
|
||||
filters: FiltersType;
|
||||
onChange?: (...args: any[]) => any;
|
||||
};
|
||||
|
||||
type Props = OwnProps & typeof Filters.defaultProps;
|
||||
|
||||
function Filters({ filters, onChange }: Props) {
|
||||
if (filters.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '(filter: any, values: any) => void' is not a... Remove this comment to see the full error message
|
||||
onChange = createFilterChangeHandler(filters, onChange);
|
||||
|
||||
return (
|
||||
@@ -79,6 +100,7 @@ function Filters({ filters, onChange }) {
|
||||
<div className="row">
|
||||
{map(filters, filter => {
|
||||
const options = map(filter.values, (value, index) => (
|
||||
// @ts-expect-error ts-migrate(2741) FIXME: Property 'value' is missing in type '{ children: a... Remove this comment to see the full error message
|
||||
<Select.Option key={index}>{formatColumnValue(value, get(filter, "column.type"))}</Select.Option>
|
||||
));
|
||||
|
||||
@@ -90,6 +112,7 @@ function Filters({ filters, onChange }) {
|
||||
<label>{filter.friendlyName}</label>
|
||||
{options.length === 0 && <Select className="w-100" disabled value="No values" />}
|
||||
{options.length > 0 && (
|
||||
// @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call.
|
||||
<Select
|
||||
labelInValue
|
||||
className="w-100"
|
||||
@@ -111,10 +134,12 @@ function Filters({ filters, onChange }) {
|
||||
onChange={values => onChange(filter, values)}>
|
||||
{!filter.multiple && options}
|
||||
{filter.multiple && [
|
||||
// @ts-expect-error ts-migrate(2741) FIXME: Property 'value' is missing in type '{ children: (... Remove this comment to see the full error message
|
||||
<Select.Option key={NONE_VALUES} data-test="ClearOption">
|
||||
<i className="fa fa-square-o m-r-5" />
|
||||
Clear
|
||||
</Select.Option>,
|
||||
// @ts-expect-error ts-migrate(2741) FIXME: Property 'value' is missing in type '{ children: (... Remove this comment to see the full error message
|
||||
<Select.Option key={ALL_VALUES} data-test="SelectAllOption">
|
||||
<i className="fa fa-check-square-o m-r-5" />
|
||||
Select All
|
||||
@@ -134,11 +159,6 @@ function Filters({ filters, onChange }) {
|
||||
);
|
||||
}
|
||||
|
||||
Filters.propTypes = {
|
||||
filters: FiltersType.isRequired,
|
||||
onChange: PropTypes.func, // (name, value) => void
|
||||
};
|
||||
|
||||
Filters.defaultProps = {
|
||||
onChange: () => {},
|
||||
};
|
||||
@@ -51,6 +51,16 @@ export const TYPES = mapValues(
|
||||
([url, title]) => [DOMAIN + HELP_PATH + url, title]
|
||||
);
|
||||
|
||||
type OwnProps = {
|
||||
type?: string;
|
||||
href?: string;
|
||||
title?: React.ReactNode;
|
||||
className?: string;
|
||||
showTooltip?: boolean;
|
||||
renderAsLink?: boolean;
|
||||
children?: React.ReactNode;
|
||||
};
|
||||
|
||||
const HelpTriggerPropTypes = {
|
||||
type: PropTypes.string,
|
||||
href: PropTypes.string,
|
||||
@@ -71,7 +81,7 @@ const HelpTriggerDefaultProps = {
|
||||
children: <i className="fa fa-question-circle" />,
|
||||
};
|
||||
|
||||
export function helpTriggerWithTypes(types, allowedDomains = [], drawerClassName = null) {
|
||||
export function helpTriggerWithTypes(types: any, allowedDomains = [], drawerClassName = null) {
|
||||
return class HelpTrigger extends React.Component {
|
||||
static propTypes = {
|
||||
...HelpTriggerPropTypes,
|
||||
@@ -97,14 +107,18 @@ export function helpTriggerWithTypes(types, allowedDomains = [], drawerClassName
|
||||
|
||||
componentWillUnmount() {
|
||||
window.removeEventListener("message", this.onPostMessageReceived);
|
||||
// @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call.
|
||||
clearTimeout(this.iframeLoadingTimeout);
|
||||
}
|
||||
|
||||
loadIframe = url => {
|
||||
loadIframe = (url: any) => {
|
||||
// @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call.
|
||||
clearTimeout(this.iframeLoadingTimeout);
|
||||
this.setState({ loading: true, error: false });
|
||||
|
||||
// @ts-expect-error ts-migrate(2571) FIXME: Object is of type 'unknown'.
|
||||
this.iframeRef.current.src = url;
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'number' is not assignable to type 'null'.
|
||||
this.iframeLoadingTimeout = setTimeout(() => {
|
||||
this.setState({ error: url, loading: false });
|
||||
}, IFRAME_TIMEOUT); // safety
|
||||
@@ -112,10 +126,11 @@ export function helpTriggerWithTypes(types, allowedDomains = [], drawerClassName
|
||||
|
||||
onIframeLoaded = () => {
|
||||
this.setState({ loading: false });
|
||||
// @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call.
|
||||
clearTimeout(this.iframeLoadingTimeout);
|
||||
};
|
||||
|
||||
onPostMessageReceived = event => {
|
||||
onPostMessageReceived = (event: any) => {
|
||||
if (!some(allowedDomains, domain => startsWith(event.origin, domain))) {
|
||||
return;
|
||||
}
|
||||
@@ -129,11 +144,13 @@ export function helpTriggerWithTypes(types, allowedDomains = [], drawerClassName
|
||||
};
|
||||
|
||||
getUrl = () => {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'type' does not exist on type 'Readonly<{... Remove this comment to see the full error message
|
||||
const helpTriggerType = get(types, this.props.type);
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'href' does not exist on type 'Readonly<{... Remove this comment to see the full error message
|
||||
return helpTriggerType ? helpTriggerType[0] : this.props.href;
|
||||
};
|
||||
|
||||
openDrawer = e => {
|
||||
openDrawer = (e: any) => {
|
||||
// keep "open in new tab" behavior
|
||||
if (!e.shiftKey && !e.ctrlKey && !e.metaKey) {
|
||||
e.preventDefault();
|
||||
@@ -143,7 +160,7 @@ export function helpTriggerWithTypes(types, allowedDomains = [], drawerClassName
|
||||
}
|
||||
};
|
||||
|
||||
closeDrawer = event => {
|
||||
closeDrawer = (event: any) => {
|
||||
if (event) {
|
||||
event.preventDefault();
|
||||
}
|
||||
@@ -157,16 +174,20 @@ export function helpTriggerWithTypes(types, allowedDomains = [], drawerClassName
|
||||
return null;
|
||||
}
|
||||
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'type' does not exist on type 'Readonly<{... Remove this comment to see the full error message
|
||||
const tooltip = get(types, `${this.props.type}[1]`, this.props.title);
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'className' does not exist on type 'Reado... Remove this comment to see the full error message
|
||||
const className = cx("help-trigger", this.props.className);
|
||||
const url = this.state.currentUrl;
|
||||
const isAllowedDomain = some(allowedDomains, domain => startsWith(url || targetUrl, domain));
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'renderAsLink' does not exist on type 'Re... Remove this comment to see the full error message
|
||||
const shouldRenderAsLink = this.props.renderAsLink || !isAllowedDomain;
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Tooltip
|
||||
title={
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'showTooltip' does not exist on type 'Rea... Remove this comment to see the full error message
|
||||
this.props.showTooltip ? (
|
||||
<>
|
||||
{tooltip}
|
||||
@@ -211,6 +232,7 @@ export function helpTriggerWithTypes(types, allowedDomains = [], drawerClassName
|
||||
{/* iframe */}
|
||||
{!this.state.error && (
|
||||
<iframe
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'RefObject<unknown>' is not assignable to typ... Remove this comment to see the full error message
|
||||
ref={this.iframeRef}
|
||||
title="Usage Help"
|
||||
src="about:blank"
|
||||
@@ -226,6 +248,7 @@ export function helpTriggerWithTypes(types, allowedDomains = [], drawerClassName
|
||||
|
||||
{/* error message */}
|
||||
{this.state.error && (
|
||||
// @ts-expect-error ts-migrate(2746) FIXME: This JSX tag's 'children' prop expects a single ch... Remove this comment to see the full error message
|
||||
<BigMessage icon="fa-exclamation-circle" className="help-message">
|
||||
Something went wrong.
|
||||
<br />
|
||||
@@ -239,6 +262,7 @@ export function helpTriggerWithTypes(types, allowedDomains = [], drawerClassName
|
||||
</div>
|
||||
|
||||
{/* extra content */}
|
||||
{/* @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call. */}
|
||||
<DynamicComponent name="HelpDrawerExtraContent" onLeave={this.closeDrawer} openPageUrl={this.loadIframe} />
|
||||
</Drawer>
|
||||
</React.Fragment>
|
||||
@@ -247,11 +271,12 @@ export function helpTriggerWithTypes(types, allowedDomains = [], drawerClassName
|
||||
};
|
||||
}
|
||||
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'never'.
|
||||
registerComponent("HelpTrigger", helpTriggerWithTypes(TYPES, [DOMAIN]));
|
||||
|
||||
export default function HelpTrigger(props) {
|
||||
type Props = OwnProps & typeof HelpTriggerDefaultProps;
|
||||
|
||||
export default function HelpTrigger(props: Props) {
|
||||
return <DynamicComponent {...props} name="HelpTrigger" />;
|
||||
}
|
||||
|
||||
HelpTrigger.propTypes = HelpTriggerPropTypes;
|
||||
HelpTrigger.defaultProps = HelpTriggerDefaultProps;
|
||||
@@ -3,8 +3,13 @@ import Input from "antd/lib/input";
|
||||
import CopyOutlinedIcon from "@ant-design/icons/CopyOutlined";
|
||||
import Tooltip from "antd/lib/tooltip";
|
||||
|
||||
export default class InputWithCopy extends React.Component {
|
||||
constructor(props) {
|
||||
type State = any;
|
||||
|
||||
export default class InputWithCopy extends React.Component<{}, State> {
|
||||
copyFeatureSupported: any;
|
||||
ref: any;
|
||||
resetCopyState: any;
|
||||
constructor(props: {}) {
|
||||
super(props);
|
||||
this.state = { copied: null };
|
||||
this.ref = React.createRef();
|
||||
@@ -1,21 +1,21 @@
|
||||
import React from "react";
|
||||
import Button from "antd/lib/button";
|
||||
|
||||
function DefaultLinkComponent(props) {
|
||||
function DefaultLinkComponent(props: any) {
|
||||
return <a {...props} />; // eslint-disable-line jsx-a11y/anchor-has-content
|
||||
}
|
||||
|
||||
function Link(props) {
|
||||
function Link(props: any) {
|
||||
return <Link.Component {...props} />;
|
||||
}
|
||||
|
||||
Link.Component = DefaultLinkComponent;
|
||||
|
||||
function DefaultButtonLinkComponent(props) {
|
||||
function DefaultButtonLinkComponent(props: any) {
|
||||
return <Button role="button" {...props} />;
|
||||
}
|
||||
|
||||
function ButtonLink(props) {
|
||||
function ButtonLink(props: any) {
|
||||
return <ButtonLink.Component {...props} />;
|
||||
}
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import BigMessage from "@/components/BigMessage";
|
||||
import { TagsControl } from "@/components/tags-control/TagsControl";
|
||||
|
||||
export default function NoTaggedObjectsFound({ objectType, tags }) {
|
||||
return (
|
||||
<BigMessage icon="fa-tags">
|
||||
No {objectType} found tagged with
|
||||
<TagsControl className="inline-tags-control" tags={Array.from(tags)} tagSeparator={"+"} />.
|
||||
</BigMessage>
|
||||
);
|
||||
}
|
||||
|
||||
NoTaggedObjectsFound.propTypes = {
|
||||
objectType: PropTypes.string.isRequired,
|
||||
tags: PropTypes.oneOfType([PropTypes.array, PropTypes.objectOf(Set)]).isRequired,
|
||||
};
|
||||
22
client/app/components/NoTaggedObjectsFound.tsx
Normal file
22
client/app/components/NoTaggedObjectsFound.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
import React from "react";
|
||||
import BigMessage from "@/components/BigMessage";
|
||||
import { TagsControl } from "@/components/tags-control/TagsControl";
|
||||
|
||||
type Props = {
|
||||
objectType: string;
|
||||
tags: any[] | {
|
||||
// @ts-expect-error ts-migrate(2314) FIXME: Generic type 'Set<T>' requires 1 type argument(s).
|
||||
[key: string]: Set;
|
||||
};
|
||||
};
|
||||
|
||||
export default function NoTaggedObjectsFound({ objectType, tags }: Props) {
|
||||
return (
|
||||
// @ts-expect-error ts-migrate(2746) FIXME: This JSX tag's 'children' prop expects a single ch... Remove this comment to see the full error message
|
||||
<BigMessage icon="fa-tags">
|
||||
No {objectType} found tagged with
|
||||
{/* @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call. */}
|
||||
<TagsControl className="inline-tags-control" tags={Array.from(tags)} tagSeparator={"+"} />.
|
||||
</BigMessage>
|
||||
);
|
||||
}
|
||||
@@ -1,9 +1,15 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import "./index.less";
|
||||
|
||||
export default function PageHeader({ title, actions }) {
|
||||
type OwnProps = {
|
||||
title?: string;
|
||||
actions?: React.ReactNode;
|
||||
};
|
||||
|
||||
type Props = OwnProps & typeof PageHeader.defaultProps;
|
||||
|
||||
export default function PageHeader({ title, actions }: Props) {
|
||||
return (
|
||||
<div className="page-header-wrapper">
|
||||
<h3>{title}</h3>
|
||||
@@ -12,11 +18,6 @@ export default function PageHeader({ title, actions }) {
|
||||
);
|
||||
}
|
||||
|
||||
PageHeader.propTypes = {
|
||||
title: PropTypes.string,
|
||||
actions: PropTypes.node,
|
||||
};
|
||||
|
||||
PageHeader.defaultProps = {
|
||||
title: "",
|
||||
actions: null,
|
||||
@@ -1,10 +1,20 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import Pagination from "antd/lib/pagination";
|
||||
|
||||
const MIN_ITEMS_PER_PAGE = 5;
|
||||
|
||||
export default function Paginator({ page, showPageSizeSelect, pageSize, onPageSizeChange, totalCount, onChange }) {
|
||||
type OwnProps = {
|
||||
page: number;
|
||||
showPageSizeSelect?: boolean;
|
||||
pageSize: number;
|
||||
totalCount: number;
|
||||
onPageSizeChange?: (...args: any[]) => any;
|
||||
onChange?: (...args: any[]) => any;
|
||||
};
|
||||
|
||||
type Props = OwnProps & typeof Paginator.defaultProps;
|
||||
|
||||
export default function Paginator({ page, showPageSizeSelect, pageSize, onPageSizeChange, totalCount, onChange }: Props) {
|
||||
if (totalCount <= (showPageSizeSelect ? MIN_ITEMS_PER_PAGE : pageSize)) {
|
||||
return null;
|
||||
}
|
||||
@@ -23,15 +33,6 @@ export default function Paginator({ page, showPageSizeSelect, pageSize, onPageSi
|
||||
);
|
||||
}
|
||||
|
||||
Paginator.propTypes = {
|
||||
page: PropTypes.number.isRequired,
|
||||
showPageSizeSelect: PropTypes.bool,
|
||||
pageSize: PropTypes.number.isRequired,
|
||||
totalCount: PropTypes.number.isRequired,
|
||||
onPageSizeChange: PropTypes.func,
|
||||
onChange: PropTypes.func,
|
||||
};
|
||||
|
||||
Paginator.defaultProps = {
|
||||
showPageSizeSelect: false,
|
||||
onChange: () => {},
|
||||
@@ -1,11 +1,15 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import Button from "antd/lib/button";
|
||||
import Badge from "antd/lib/badge";
|
||||
import Tooltip from "antd/lib/tooltip";
|
||||
import KeyboardShortcuts from "@/services/KeyboardShortcuts";
|
||||
|
||||
function ParameterApplyButton({ paramCount, onClick }) {
|
||||
type Props = {
|
||||
onClick: (...args: any[]) => any;
|
||||
paramCount: number;
|
||||
};
|
||||
|
||||
function ParameterApplyButton({ paramCount, onClick }: Props) {
|
||||
// show spinner when count is empty so the fade out is consistent
|
||||
const icon = !paramCount ? "spinner fa-pulse" : "check";
|
||||
|
||||
@@ -24,9 +28,4 @@ function ParameterApplyButton({ paramCount, onClick }) {
|
||||
);
|
||||
}
|
||||
|
||||
ParameterApplyButton.propTypes = {
|
||||
onClick: PropTypes.func.isRequired,
|
||||
paramCount: PropTypes.number.isRequired,
|
||||
};
|
||||
|
||||
export default ParameterApplyButton;
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
import { isString, extend, each, has, map, includes, findIndex, find, fromPairs, clone, isEmpty } from "lodash";
|
||||
import React, { Fragment } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import classNames from "classnames";
|
||||
import Select from "antd/lib/select";
|
||||
import Table from "antd/lib/table";
|
||||
@@ -32,7 +31,7 @@ export const MappingType = {
|
||||
StaticValue: "static-value",
|
||||
};
|
||||
|
||||
export function parameterMappingsToEditableMappings(mappings, parameters, existingParameterNames = []) {
|
||||
export function parameterMappingsToEditableMappings(mappings: any, parameters: any, existingParameterNames = []) {
|
||||
return map(mappings, mapping => {
|
||||
const result = extend({}, mapping);
|
||||
const alreadyExists = includes(existingParameterNames, mapping.mapTo);
|
||||
@@ -57,7 +56,7 @@ export function parameterMappingsToEditableMappings(mappings, parameters, existi
|
||||
});
|
||||
}
|
||||
|
||||
export function editableMappingsToParameterMappings(mappings) {
|
||||
export function editableMappingsToParameterMappings(mappings: any) {
|
||||
return fromPairs(
|
||||
map(
|
||||
// convert to map
|
||||
@@ -92,8 +91,8 @@ export function editableMappingsToParameterMappings(mappings) {
|
||||
);
|
||||
}
|
||||
|
||||
export function synchronizeWidgetTitles(sourceMappings, widgets) {
|
||||
const affectedWidgets = [];
|
||||
export function synchronizeWidgetTitles(sourceMappings: any, widgets: any) {
|
||||
const affectedWidgets: any = [];
|
||||
|
||||
each(sourceMappings, sourceMapping => {
|
||||
if (sourceMapping.type === ParameterMappingType.DashboardLevel) {
|
||||
@@ -119,13 +118,16 @@ export function synchronizeWidgetTitles(sourceMappings, widgets) {
|
||||
return affectedWidgets;
|
||||
}
|
||||
|
||||
export class ParameterMappingInput extends React.Component {
|
||||
static propTypes = {
|
||||
mapping: PropTypes.object, // eslint-disable-line react/forbid-prop-types
|
||||
existingParamNames: PropTypes.arrayOf(PropTypes.string),
|
||||
onChange: PropTypes.func,
|
||||
inputError: PropTypes.string,
|
||||
};
|
||||
type OwnParameterMappingInputProps = {
|
||||
mapping?: any;
|
||||
existingParamNames?: string[];
|
||||
onChange?: (...args: any[]) => any;
|
||||
inputError?: string;
|
||||
};
|
||||
|
||||
type ParameterMappingInputProps = OwnParameterMappingInputProps & typeof ParameterMappingInput.defaultProps;
|
||||
|
||||
export class ParameterMappingInput extends React.Component<ParameterMappingInputProps> {
|
||||
|
||||
static defaultProps = {
|
||||
mapping: {},
|
||||
@@ -140,7 +142,7 @@ export class ParameterMappingInput extends React.Component {
|
||||
className: "form-item",
|
||||
};
|
||||
|
||||
updateSourceType = type => {
|
||||
updateSourceType = (type: any) => {
|
||||
let {
|
||||
mapping: { mapTo },
|
||||
} = this.props;
|
||||
@@ -155,26 +157,34 @@ export class ParameterMappingInput extends React.Component {
|
||||
this.updateParamMapping({ type, mapTo });
|
||||
};
|
||||
|
||||
updateParamMapping = update => {
|
||||
updateParamMapping = (update: any) => {
|
||||
const { onChange, mapping } = this.props;
|
||||
const newMapping = extend({}, mapping, update);
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'value' does not exist on type 'never'.
|
||||
if (newMapping.value !== mapping.value) {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'param' does not exist on type 'never'.
|
||||
newMapping.param = cloneParameter(newMapping.param);
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'param' does not exist on type 'never'.
|
||||
newMapping.param.setValue(newMapping.value);
|
||||
}
|
||||
if (has(update, "type")) {
|
||||
if (update.type === MappingType.StaticValue) {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'value' does not exist on type 'never'.
|
||||
newMapping.value = newMapping.param.value;
|
||||
} else {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'value' does not exist on type 'never'.
|
||||
newMapping.value = null;
|
||||
}
|
||||
}
|
||||
// @ts-expect-error ts-migrate(2349) FIXME: This expression is not callable.
|
||||
onChange(newMapping);
|
||||
};
|
||||
|
||||
renderMappingTypeSelector() {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'existingParamNames' does not exist on ty... Remove this comment to see the full error message
|
||||
const noExisting = isEmpty(this.props.existingParamNames);
|
||||
return (
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'mapping' does not exist on type 'never'.
|
||||
<Radio.Group value={this.props.mapping.type} onChange={e => this.updateSourceType(e.target.value)}>
|
||||
<Radio className="radio" value={MappingType.DashboardAddNew} data-test="NewDashboardParameterOption">
|
||||
New dashboard parameter
|
||||
@@ -208,6 +218,7 @@ export class ParameterMappingInput extends React.Component {
|
||||
const { mapping, existingParamNames } = this.props;
|
||||
const options = map(existingParamNames, paramName => ({ label: paramName, value: paramName }));
|
||||
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'mapTo' does not exist on type 'never'.
|
||||
return <Select value={mapping.mapTo} onChange={mapTo => this.updateParamMapping({ mapTo })} options={options} />;
|
||||
}
|
||||
|
||||
@@ -215,18 +226,25 @@ export class ParameterMappingInput extends React.Component {
|
||||
const { mapping } = this.props;
|
||||
return (
|
||||
<ParameterValueInput
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'any' is not assignable to type 'never'.
|
||||
type={mapping.param.type}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'any' is not assignable to type 'never'.
|
||||
value={mapping.param.normalizedValue}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'any' is not assignable to type 'never'.
|
||||
enumOptions={mapping.param.enumOptions}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'any' is not assignable to type 'never'.
|
||||
queryId={mapping.param.queryId}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'any' is not assignable to type 'never'.
|
||||
parameter={mapping.param}
|
||||
onSelect={value => this.updateParamMapping({ value })}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '(value: any) => void' is not assignable to t... Remove this comment to see the full error message
|
||||
onSelect={(value: any) => this.updateParamMapping({ value })}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
renderInputBlock() {
|
||||
const { mapping } = this.props;
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'type' does not exist on type 'never'.
|
||||
switch (mapping.type) {
|
||||
case MappingType.DashboardAddNew:
|
||||
return ["Key", "Enter a new parameter keyword", this.renderDashboardAddNew()];
|
||||
@@ -262,14 +280,17 @@ export class ParameterMappingInput extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
class MappingEditor extends React.Component {
|
||||
static propTypes = {
|
||||
mapping: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
|
||||
existingParamNames: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
};
|
||||
type MappingEditorProps = {
|
||||
mapping: any;
|
||||
existingParamNames: string[];
|
||||
onChange: (...args: any[]) => any;
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
type MappingEditorState = any;
|
||||
|
||||
class MappingEditor extends React.Component<MappingEditorProps, MappingEditorState> {
|
||||
|
||||
constructor(props: MappingEditorProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
visible: false,
|
||||
@@ -278,12 +299,12 @@ class MappingEditor extends React.Component {
|
||||
};
|
||||
}
|
||||
|
||||
onVisibleChange = visible => {
|
||||
onVisibleChange = (visible: any) => {
|
||||
if (visible) this.show();
|
||||
else this.hide();
|
||||
};
|
||||
|
||||
onChange = mapping => {
|
||||
onChange = (mapping: any) => {
|
||||
let inputError = null;
|
||||
|
||||
if (mapping.type === MappingType.DashboardAddNew) {
|
||||
@@ -319,8 +340,10 @@ class MappingEditor extends React.Component {
|
||||
return (
|
||||
<div className="parameter-mapping-editor" data-test="EditParamMappingPopover">
|
||||
<header>
|
||||
{/* @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'never'. */}
|
||||
Edit Source and Value <HelpTrigger type="VALUE_SOURCE_OPTIONS" />
|
||||
</header>
|
||||
{/* @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call. */}
|
||||
<ParameterMappingInput
|
||||
mapping={mapping}
|
||||
existingParamNames={this.props.existingParamNames}
|
||||
@@ -354,12 +377,17 @@ class MappingEditor extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
class TitleEditor extends React.Component {
|
||||
static propTypes = {
|
||||
existingParams: PropTypes.arrayOf(PropTypes.object),
|
||||
mapping: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
|
||||
onChange: PropTypes.func.isRequired,
|
||||
};
|
||||
type OwnTitleEditorProps = {
|
||||
existingParams?: any[];
|
||||
mapping: any;
|
||||
onChange: (...args: any[]) => any;
|
||||
};
|
||||
|
||||
type TitleEditorState = any;
|
||||
|
||||
type TitleEditorProps = OwnTitleEditorProps & typeof TitleEditor.defaultProps;
|
||||
|
||||
class TitleEditor extends React.Component<TitleEditorProps, TitleEditorState> {
|
||||
|
||||
static defaultProps = {
|
||||
existingParams: [],
|
||||
@@ -370,14 +398,14 @@ class TitleEditor extends React.Component {
|
||||
title: "", // will be set on editing
|
||||
};
|
||||
|
||||
onPopupVisibleChange = showPopup => {
|
||||
onPopupVisibleChange = (showPopup: any) => {
|
||||
this.setState({
|
||||
showPopup,
|
||||
title: showPopup ? this.getMappingTitle() : "",
|
||||
});
|
||||
};
|
||||
|
||||
onEditingTitleChange = event => {
|
||||
onEditingTitleChange = (event: any) => {
|
||||
this.setState({ title: event.target.value });
|
||||
};
|
||||
|
||||
@@ -472,12 +500,15 @@ class TitleEditor extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
export class ParameterMappingListInput extends React.Component {
|
||||
static propTypes = {
|
||||
mappings: PropTypes.arrayOf(PropTypes.object),
|
||||
existingParams: PropTypes.arrayOf(PropTypes.object),
|
||||
onChange: PropTypes.func,
|
||||
};
|
||||
type OwnParameterMappingListInputProps = {
|
||||
mappings?: any[];
|
||||
existingParams?: any[];
|
||||
onChange?: (...args: any[]) => any;
|
||||
};
|
||||
|
||||
type ParameterMappingListInputProps = OwnParameterMappingListInputProps & typeof ParameterMappingListInput.defaultProps;
|
||||
|
||||
export class ParameterMappingListInput extends React.Component<ParameterMappingListInputProps> {
|
||||
|
||||
static defaultProps = {
|
||||
mappings: [],
|
||||
@@ -485,7 +516,8 @@ export class ParameterMappingListInput extends React.Component {
|
||||
onChange: () => {},
|
||||
};
|
||||
|
||||
static getStringValue(value) {
|
||||
// @ts-expect-error ts-migrate(7023) FIXME: 'getStringValue' implicitly has return type 'any' ... Remove this comment to see the full error message
|
||||
static getStringValue(value: any) {
|
||||
// null
|
||||
if (!value) {
|
||||
return "";
|
||||
@@ -505,7 +537,7 @@ export class ParameterMappingListInput extends React.Component {
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
static getDefaultValue(mapping, existingParams) {
|
||||
static getDefaultValue(mapping: any, existingParams: any) {
|
||||
const { type, mapTo, name } = mapping;
|
||||
let { param } = mapping;
|
||||
|
||||
@@ -532,7 +564,10 @@ export class ParameterMappingListInput extends React.Component {
|
||||
return this.getStringValue(value);
|
||||
}
|
||||
|
||||
static getSourceTypeLabel({ type, mapTo }) {
|
||||
static getSourceTypeLabel({
|
||||
type,
|
||||
mapTo
|
||||
}: any) {
|
||||
switch (type) {
|
||||
case MappingType.DashboardAddNew:
|
||||
case MappingType.DashboardMapToExisting:
|
||||
@@ -550,13 +585,15 @@ export class ParameterMappingListInput extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
updateParamMapping(oldMapping, newMapping) {
|
||||
updateParamMapping(oldMapping: any, newMapping: any) {
|
||||
const mappings = [...this.props.mappings];
|
||||
const index = findIndex(mappings, oldMapping);
|
||||
if (index >= 0) {
|
||||
// This should be the only possible case, but need to handle `else` too
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'any' is not assignable to type 'never'.
|
||||
mappings[index] = newMapping;
|
||||
} else {
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'any' is not assignable to parame... Remove this comment to see the full error message
|
||||
mappings.push(newMapping);
|
||||
}
|
||||
this.props.onChange(mappings);
|
||||
@@ -592,6 +629,7 @@ export class ParameterMappingListInput extends React.Component {
|
||||
title="Default Value"
|
||||
dataIndex="mapping"
|
||||
key="value"
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'getDefaultValue' does not exist on type ... Remove this comment to see the full error message
|
||||
render={mapping => this.constructor.getDefaultValue(mapping, this.props.existingParams)}
|
||||
/>
|
||||
<Table.Column
|
||||
@@ -605,6 +643,7 @@ export class ParameterMappingListInput extends React.Component {
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'getSourceTypeLabel' does not exist on ty... Remove this comment to see the full error message */}
|
||||
{this.constructor.getSourceTypeLabel(mapping)}{" "}
|
||||
<MappingEditor
|
||||
mapping={mapping}
|
||||
@@ -1,6 +1,5 @@
|
||||
import { isEqual, isEmpty, map } from "lodash";
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import SelectWithVirtualScroll from "@/components/SelectWithVirtualScroll";
|
||||
import Input from "antd/lib/input";
|
||||
import InputNumber from "antd/lib/input-number";
|
||||
@@ -13,19 +12,24 @@ import "./ParameterValueInput.less";
|
||||
const multipleValuesProps = {
|
||||
maxTagCount: 3,
|
||||
maxTagTextLength: 10,
|
||||
maxTagPlaceholder: num => `+${num.length} more`,
|
||||
maxTagPlaceholder: (num: any) => `+${num.length} more`,
|
||||
};
|
||||
|
||||
class ParameterValueInput extends React.Component {
|
||||
static propTypes = {
|
||||
type: PropTypes.string,
|
||||
value: PropTypes.any, // eslint-disable-line react/forbid-prop-types
|
||||
enumOptions: PropTypes.string,
|
||||
queryId: PropTypes.number,
|
||||
parameter: PropTypes.any, // eslint-disable-line react/forbid-prop-types
|
||||
onSelect: PropTypes.func,
|
||||
className: PropTypes.string,
|
||||
};
|
||||
type OwnProps = {
|
||||
type?: string;
|
||||
value?: any;
|
||||
enumOptions?: string;
|
||||
queryId?: number;
|
||||
parameter?: any;
|
||||
onSelect?: (...args: any[]) => any;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
type State = any;
|
||||
|
||||
type Props = OwnProps & typeof ParameterValueInput.defaultProps;
|
||||
|
||||
class ParameterValueInput extends React.Component<Props, State> {
|
||||
|
||||
static defaultProps = {
|
||||
type: "text",
|
||||
@@ -37,28 +41,34 @@ class ParameterValueInput extends React.Component {
|
||||
className: "",
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'parameter' does not exist on type 'never... Remove this comment to see the full error message
|
||||
value: props.parameter.hasPendingValue ? props.parameter.pendingValue : props.value,
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'parameter' does not exist on type 'never... Remove this comment to see the full error message
|
||||
isDirty: props.parameter.hasPendingValue,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidUpdate = prevProps => {
|
||||
componentDidUpdate = (prevProps: any) => {
|
||||
const { value, parameter } = this.props;
|
||||
// if value prop updated, reset dirty state
|
||||
if (prevProps.value !== value || prevProps.parameter !== parameter) {
|
||||
this.setState({
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'hasPendingValue' does not exist on type ... Remove this comment to see the full error message
|
||||
value: parameter.hasPendingValue ? parameter.pendingValue : value,
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'hasPendingValue' does not exist on type ... Remove this comment to see the full error message
|
||||
isDirty: parameter.hasPendingValue,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
onSelect = value => {
|
||||
onSelect = (value: any) => {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'value' does not exist on type 'never'.
|
||||
const isDirty = !isEqual(value, this.props.value);
|
||||
this.setState({ value, isDirty });
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'onSelect' does not exist on type 'never'... Remove this comment to see the full error message
|
||||
this.props.onSelect(value, isDirty);
|
||||
};
|
||||
|
||||
@@ -68,9 +78,11 @@ class ParameterValueInput extends React.Component {
|
||||
return (
|
||||
<DateParameter
|
||||
type={type}
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'className' does not exist on type 'never... Remove this comment to see the full error message
|
||||
className={this.props.className}
|
||||
value={value}
|
||||
parameter={parameter}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '(value: any) => void' is not assignable to t... Remove this comment to see the full error message
|
||||
onSelect={this.onSelect}
|
||||
/>
|
||||
);
|
||||
@@ -82,9 +94,11 @@ class ParameterValueInput extends React.Component {
|
||||
return (
|
||||
<DateRangeParameter
|
||||
type={type}
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'className' does not exist on type 'never... Remove this comment to see the full error message
|
||||
className={this.props.className}
|
||||
value={value}
|
||||
parameter={parameter}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '(value: any) => void' is not assignable to t... Remove this comment to see the full error message
|
||||
onSelect={this.onSelect}
|
||||
/>
|
||||
);
|
||||
@@ -93,13 +107,17 @@ class ParameterValueInput extends React.Component {
|
||||
renderEnumInput() {
|
||||
const { enumOptions, parameter } = this.props;
|
||||
const { value } = this.state;
|
||||
const enumOptionsArray = enumOptions.split("\n").filter(v => v !== "");
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'split' does not exist on type 'never'.
|
||||
const enumOptionsArray = enumOptions.split("\n").filter((v: any) => v !== "");
|
||||
// Antd Select doesn't handle null in multiple mode
|
||||
const normalize = val => (parameter.multiValuesOptions && val === null ? [] : val);
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'multiValuesOptions' does not exist on ty... Remove this comment to see the full error message
|
||||
const normalize = (val: any) => parameter.multiValuesOptions && val === null ? [] : val;
|
||||
|
||||
return (
|
||||
<SelectWithVirtualScroll
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'className' does not exist on type 'never... Remove this comment to see the full error message
|
||||
className={this.props.className}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '"multiple" | "default"' is not assignable to... Remove this comment to see the full error message
|
||||
mode={parameter.multiValuesOptions ? "multiple" : "default"}
|
||||
optionFilterProp="children"
|
||||
value={normalize(value)}
|
||||
@@ -118,13 +136,19 @@ class ParameterValueInput extends React.Component {
|
||||
const { value } = this.state;
|
||||
return (
|
||||
<QueryBasedParameterInput
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'any' is not assignable to type 'never'.
|
||||
className={this.props.className}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'never'.
|
||||
mode={parameter.multiValuesOptions ? "multiple" : "default"}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'never'.
|
||||
optionFilterProp="children"
|
||||
parameter={parameter}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'any' is not assignable to type 'never'.
|
||||
value={value}
|
||||
queryId={queryId}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '(value: any) => void' is not assignable to t... Remove this comment to see the full error message
|
||||
onSelect={this.onSelect}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'number' is not assignable to type 'never'.
|
||||
style={{ minWidth: 60 }}
|
||||
{...multipleValuesProps}
|
||||
/>
|
||||
@@ -135,7 +159,7 @@ class ParameterValueInput extends React.Component {
|
||||
const { className } = this.props;
|
||||
const { value } = this.state;
|
||||
|
||||
const normalize = val => (isNaN(val) ? undefined : val);
|
||||
const normalize = (val: any) => isNaN(val) ? undefined : val;
|
||||
|
||||
return (
|
||||
<InputNumber className={className} value={normalize(value)} onChange={val => this.onSelect(normalize(val))} />
|
||||
@@ -1,8 +1,8 @@
|
||||
import { size, filter, forEach, extend } from "lodash";
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { SortableContainer, SortableElement, DragHandle } from "@redash/viz/lib/components/sortable";
|
||||
import location from "@/services/location";
|
||||
// @ts-expect-error ts-migrate(6133) FIXME: 'Parameter' is declared but its value is never rea... Remove this comment to see the full error message
|
||||
import { Parameter, createParameter } from "@/services/parameters";
|
||||
import ParameterApplyButton from "@/components/ParameterApplyButton";
|
||||
import ParameterValueInput from "@/components/ParameterValueInput";
|
||||
@@ -11,24 +11,28 @@ import { toHuman } from "@/lib/utils";
|
||||
|
||||
import "./Parameters.less";
|
||||
|
||||
function updateUrl(parameters) {
|
||||
function updateUrl(parameters: any) {
|
||||
const params = extend({}, location.search);
|
||||
parameters.forEach(param => {
|
||||
parameters.forEach((param: any) => {
|
||||
extend(params, param.toUrlParams());
|
||||
});
|
||||
location.setSearch(params, true);
|
||||
}
|
||||
|
||||
export default class Parameters extends React.Component {
|
||||
static propTypes = {
|
||||
parameters: PropTypes.arrayOf(PropTypes.instanceOf(Parameter)),
|
||||
editable: PropTypes.bool,
|
||||
disableUrlUpdate: PropTypes.bool,
|
||||
onValuesChange: PropTypes.func,
|
||||
onPendingValuesChange: PropTypes.func,
|
||||
onParametersEdit: PropTypes.func,
|
||||
};
|
||||
type OwnProps = {
|
||||
parameters?: any[]; // TODO: PropTypes.instanceOf(Parameter)
|
||||
editable?: boolean;
|
||||
disableUrlUpdate?: boolean;
|
||||
onValuesChange?: (...args: any[]) => any;
|
||||
onPendingValuesChange?: (...args: any[]) => any;
|
||||
onParametersEdit?: (...args: any[]) => any;
|
||||
};
|
||||
|
||||
type State = any;
|
||||
|
||||
type Props = OwnProps & typeof Parameters.defaultProps;
|
||||
|
||||
export default class Parameters extends React.Component<Props, State> {
|
||||
static defaultProps = {
|
||||
parameters: [],
|
||||
editable: false,
|
||||
@@ -38,7 +42,9 @@ export default class Parameters extends React.Component {
|
||||
onParametersEdit: () => {},
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
onBeforeSortStart: any;
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
const { parameters } = props;
|
||||
this.state = { parameters };
|
||||
@@ -47,7 +53,7 @@ export default class Parameters extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate = prevProps => {
|
||||
componentDidUpdate = (prevProps: any) => {
|
||||
const { parameters, disableUrlUpdate } = this.props;
|
||||
const parametersChanged = prevProps.parameters !== parameters;
|
||||
const disableUrlUpdateChanged = prevProps.disableUrlUpdate !== disableUrlUpdate;
|
||||
@@ -59,7 +65,7 @@ export default class Parameters extends React.Component {
|
||||
}
|
||||
};
|
||||
|
||||
handleKeyDown = e => {
|
||||
handleKeyDown = (e: any) => {
|
||||
// Cmd/Ctrl/Alt + Enter
|
||||
if (e.keyCode === 13 && (e.ctrlKey || e.metaKey || e.altKey)) {
|
||||
e.stopPropagation();
|
||||
@@ -67,9 +73,11 @@ export default class Parameters extends React.Component {
|
||||
}
|
||||
};
|
||||
|
||||
setPendingValue = (param, value, isDirty) => {
|
||||
setPendingValue = (param: any, value: any, isDirty: any) => {
|
||||
const { onPendingValuesChange } = this.props;
|
||||
this.setState(({ parameters }) => {
|
||||
this.setState(({
|
||||
parameters
|
||||
}: any) => {
|
||||
if (isDirty) {
|
||||
param.setPendingValue(value);
|
||||
} else {
|
||||
@@ -80,10 +88,15 @@ export default class Parameters extends React.Component {
|
||||
});
|
||||
};
|
||||
|
||||
moveParameter = ({ oldIndex, newIndex }) => {
|
||||
moveParameter = ({
|
||||
oldIndex,
|
||||
newIndex
|
||||
}: any) => {
|
||||
const { onParametersEdit } = this.props;
|
||||
if (oldIndex !== newIndex) {
|
||||
this.setState(({ parameters }) => {
|
||||
this.setState(({
|
||||
parameters
|
||||
}: any) => {
|
||||
parameters.splice(newIndex, 0, parameters.splice(oldIndex, 1)[0]);
|
||||
onParametersEdit();
|
||||
return { parameters };
|
||||
@@ -93,8 +106,10 @@ export default class Parameters extends React.Component {
|
||||
|
||||
applyChanges = () => {
|
||||
const { onValuesChange, disableUrlUpdate } = this.props;
|
||||
this.setState(({ parameters }) => {
|
||||
const parametersWithPendingValues = parameters.filter(p => p.hasPendingValue);
|
||||
this.setState(({
|
||||
parameters
|
||||
}: any) => {
|
||||
const parametersWithPendingValues = parameters.filter((p: any) => p.hasPendingValue);
|
||||
forEach(parameters, p => p.applyPendingValue());
|
||||
if (!disableUrlUpdate) {
|
||||
updateUrl(parameters);
|
||||
@@ -104,10 +119,12 @@ export default class Parameters extends React.Component {
|
||||
});
|
||||
};
|
||||
|
||||
showParameterSettings = (parameter, index) => {
|
||||
showParameterSettings = (parameter: any, index: any) => {
|
||||
const { onParametersEdit } = this.props;
|
||||
EditParameterSettingsDialog.showModal({ parameter }).onClose(updated => {
|
||||
this.setState(({ parameters }) => {
|
||||
EditParameterSettingsDialog.showModal({ parameter }).onClose((updated: any) => {
|
||||
this.setState(({
|
||||
parameters
|
||||
}: any) => {
|
||||
const updatedParameter = extend(parameter, updated);
|
||||
parameters[index] = createParameter(updatedParameter, updatedParameter.parentQueryId);
|
||||
onParametersEdit();
|
||||
@@ -116,7 +133,7 @@ export default class Parameters extends React.Component {
|
||||
});
|
||||
};
|
||||
|
||||
renderParameter(param, index) {
|
||||
renderParameter(param: any, index: any) {
|
||||
const { editable } = this.props;
|
||||
return (
|
||||
<div key={param.name} className="di-block" data-test={`ParameterName-${param.name}`}>
|
||||
@@ -133,12 +150,18 @@ export default class Parameters extends React.Component {
|
||||
)}
|
||||
</div>
|
||||
<ParameterValueInput
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'any' is not assignable to type 'never'.
|
||||
type={param.type}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'any' is not assignable to type 'never'.
|
||||
value={param.normalizedValue}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'any' is not assignable to type 'never'.
|
||||
parameter={param}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'any' is not assignable to type 'never'.
|
||||
enumOptions={param.enumOptions}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'any' is not assignable to type 'never'.
|
||||
queryId={param.queryId}
|
||||
onSelect={(value, isDirty) => this.setPendingValue(param, value, isDirty)}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '(value: any, isDirty: any) => void' is not a... Remove this comment to see the full error message
|
||||
onSelect={(value: any, isDirty: any) => this.setPendingValue(param, value, isDirty)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
@@ -149,6 +172,7 @@ export default class Parameters extends React.Component {
|
||||
const { editable } = this.props;
|
||||
const dirtyParamCount = size(filter(parameters, "hasPendingValue"));
|
||||
return (
|
||||
// @ts-expect-error ts-migrate(2746) FIXME: This JSX tag's 'children' prop expects a single ch... Remove this comment to see the full error message
|
||||
<SortableContainer
|
||||
disabled={!editable}
|
||||
axis="xy"
|
||||
@@ -161,7 +185,7 @@ export default class Parameters extends React.Component {
|
||||
className: "parameter-container",
|
||||
onKeyDown: dirtyParamCount ? this.handleKeyDown : null,
|
||||
}}>
|
||||
{parameters.map((param, index) => (
|
||||
{parameters.map((param: any, index: any) => (
|
||||
<SortableElement key={param.name} index={index}>
|
||||
<div className="parameter-block" data-editable={editable || null}>
|
||||
{editable && <DragHandle data-test={`DragHandle-${param.name}`} />}
|
||||
@@ -1,6 +1,5 @@
|
||||
import React, { useState, useEffect, useCallback } from "react";
|
||||
import { axios } from "@/services/axios";
|
||||
import PropTypes from "prop-types";
|
||||
import { each, debounce, get, find } from "lodash";
|
||||
import Button from "antd/lib/button";
|
||||
import List from "antd/lib/list";
|
||||
@@ -8,6 +7,7 @@ import Modal from "antd/lib/modal";
|
||||
import Select from "antd/lib/select";
|
||||
import Tag from "antd/lib/tag";
|
||||
import Tooltip from "antd/lib/tooltip";
|
||||
// @ts-expect-error ts-migrate(6133) FIXME: 'DialogPropType' is declared but its value is neve... Remove this comment to see the full error message
|
||||
import { wrap as wrapDialog, DialogPropType } from "@/components/DialogWrapper";
|
||||
import { toHuman } from "@/lib/utils";
|
||||
import HelpTrigger from "@/components/HelpTrigger";
|
||||
@@ -20,13 +20,13 @@ import "./index.less";
|
||||
const { Option } = Select;
|
||||
const DEBOUNCE_SEARCH_DURATION = 200;
|
||||
|
||||
function useGrantees(url) {
|
||||
function useGrantees(url: any) {
|
||||
const loadGrantees = useCallback(
|
||||
() =>
|
||||
axios.get(url).then(data => {
|
||||
const resultGrantees = [];
|
||||
const resultGrantees: any = [];
|
||||
each(data, (grantees, accessType) => {
|
||||
grantees.forEach(grantee => {
|
||||
grantees.forEach((grantee: any) => {
|
||||
grantee.accessType = toHuman(accessType);
|
||||
resultGrantees.push(grantee);
|
||||
});
|
||||
@@ -40,6 +40,7 @@ function useGrantees(url) {
|
||||
(userId, accessType = "modify") =>
|
||||
axios
|
||||
.post(url, { access_type: accessType, user_id: userId })
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'string' is not assignable to par... Remove this comment to see the full error message
|
||||
.catch(() => notification.error("Could not grant permission to the user")),
|
||||
[url]
|
||||
);
|
||||
@@ -48,6 +49,7 @@ function useGrantees(url) {
|
||||
(userId, accessType = "modify") =>
|
||||
axios
|
||||
.delete(url, { data: { access_type: accessType, user_id: userId } })
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'string' is not assignable to par... Remove this comment to see the full error message
|
||||
.catch(() => notification.error("Could not remove permission from the user")),
|
||||
[url]
|
||||
);
|
||||
@@ -55,37 +57,48 @@ function useGrantees(url) {
|
||||
return { loadGrantees, addPermission, removePermission };
|
||||
}
|
||||
|
||||
const searchUsers = searchTerm =>
|
||||
User.query({ q: searchTerm })
|
||||
.then(({ results }) => results)
|
||||
.catch(() => []);
|
||||
const searchUsers = (searchTerm: any) => User.query({ q: searchTerm })
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'results' does not exist on type 'AxiosRe... Remove this comment to see the full error message
|
||||
.then(({ results }) => results)
|
||||
.catch(() => []);
|
||||
|
||||
function PermissionsEditorDialogHeader({ context }) {
|
||||
type OwnPermissionsEditorDialogHeaderProps = {
|
||||
context?: "query" | "dashboard";
|
||||
};
|
||||
|
||||
type PermissionsEditorDialogHeaderProps = OwnPermissionsEditorDialogHeaderProps & typeof PermissionsEditorDialogHeader.defaultProps;
|
||||
|
||||
function PermissionsEditorDialogHeader({ context }: PermissionsEditorDialogHeaderProps) {
|
||||
return (
|
||||
<>
|
||||
Manage Permissions
|
||||
<div className="modal-header-desc">
|
||||
{`Editing this ${context} is enabled for the users in this list and for admins. `}
|
||||
{/* @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'never'. */}
|
||||
<HelpTrigger type="MANAGE_PERMISSIONS" />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
PermissionsEditorDialogHeader.propTypes = { context: PropTypes.oneOf(["query", "dashboard"]) };
|
||||
PermissionsEditorDialogHeader.defaultProps = { context: "query" };
|
||||
|
||||
function UserSelect({ onSelect, shouldShowUser }) {
|
||||
type OwnUserSelectProps = {
|
||||
onSelect?: (...args: any[]) => any;
|
||||
shouldShowUser?: (...args: any[]) => any;
|
||||
};
|
||||
|
||||
type UserSelectProps = OwnUserSelectProps & typeof UserSelect.defaultProps;
|
||||
|
||||
function UserSelect({ onSelect, shouldShowUser }: UserSelectProps) {
|
||||
const [loadingUsers, setLoadingUsers] = useState(true);
|
||||
const [users, setUsers] = useState([]);
|
||||
const [searchTerm, setSearchTerm] = useState("");
|
||||
|
||||
const debouncedSearchUsers = useCallback(
|
||||
debounce(
|
||||
search =>
|
||||
searchUsers(search)
|
||||
.then(setUsers)
|
||||
.finally(() => setLoadingUsers(false)),
|
||||
(search: any) => searchUsers(search)
|
||||
.then(setUsers)
|
||||
.finally(() => setLoadingUsers(false)),
|
||||
DEBOUNCE_SEARCH_DURATION
|
||||
),
|
||||
[]
|
||||
@@ -109,6 +122,7 @@ function UserSelect({ onSelect, shouldShowUser }) {
|
||||
getPopupContainer={trigger => trigger.parentNode}
|
||||
onSelect={onSelect}>
|
||||
{users.filter(shouldShowUser).map(user => (
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'id' does not exist on type 'never'.
|
||||
<Option key={user.id} value={user.id}>
|
||||
<UserPreviewCard user={user} />
|
||||
</Option>
|
||||
@@ -116,14 +130,19 @@ function UserSelect({ onSelect, shouldShowUser }) {
|
||||
</Select>
|
||||
);
|
||||
}
|
||||
|
||||
UserSelect.propTypes = {
|
||||
onSelect: PropTypes.func,
|
||||
shouldShowUser: PropTypes.func,
|
||||
};
|
||||
UserSelect.defaultProps = { onSelect: () => {}, shouldShowUser: () => true };
|
||||
|
||||
function PermissionsEditorDialog({ dialog, author, context, aclUrl }) {
|
||||
type OwnPermissionsEditorDialogProps = {
|
||||
// @ts-expect-error ts-migrate(2749) FIXME: 'DialogPropType' refers to a value, but is being u... Remove this comment to see the full error message
|
||||
dialog: DialogPropType;
|
||||
author: any;
|
||||
context?: "query" | "dashboard";
|
||||
aclUrl: string;
|
||||
};
|
||||
|
||||
type PermissionsEditorDialogProps = OwnPermissionsEditorDialogProps & typeof PermissionsEditorDialog.defaultProps;
|
||||
|
||||
function PermissionsEditorDialog({ dialog, author, context, aclUrl }: PermissionsEditorDialogProps) {
|
||||
const [loadingGrantees, setLoadingGrantees] = useState(true);
|
||||
const [grantees, setGrantees] = useState([]);
|
||||
const { loadGrantees, addPermission, removePermission } = useGrantees(aclUrl);
|
||||
@@ -131,6 +150,7 @@ function PermissionsEditorDialog({ dialog, author, context, aclUrl }) {
|
||||
setLoadingGrantees(true);
|
||||
loadGrantees()
|
||||
.then(setGrantees)
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'string' is not assignable to par... Remove this comment to see the full error message
|
||||
.catch(() => notification.error("Failed to load grantees list"))
|
||||
.finally(() => setLoadingGrantees(false));
|
||||
}, [loadGrantees]);
|
||||
@@ -151,8 +171,10 @@ function PermissionsEditorDialog({ dialog, author, context, aclUrl }) {
|
||||
title={<PermissionsEditorDialogHeader context={context} />}
|
||||
footer={<Button onClick={dialog.dismiss}>Close</Button>}>
|
||||
<UserSelect
|
||||
onSelect={userId => addPermission(userId).then(loadUsersWithPermissions)}
|
||||
shouldShowUser={user => !userHasPermission(user)}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '(userId: any) => Promise<void>' is not assig... Remove this comment to see the full error message
|
||||
onSelect={(userId: any) => addPermission(userId).then(loadUsersWithPermissions)}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '(user: any) => boolean' is not assignable to... Remove this comment to see the full error message
|
||||
shouldShowUser={(user: any) => !userHasPermission(user)}
|
||||
/>
|
||||
<div className="d-flex align-items-center m-t-5">
|
||||
<h5 className="flex-fill">Users with permissions</h5>
|
||||
@@ -165,6 +187,7 @@ function PermissionsEditorDialog({ dialog, author, context, aclUrl }) {
|
||||
renderItem={user => (
|
||||
<List.Item>
|
||||
<UserPreviewCard key={user.id} user={user}>
|
||||
{/* @ts-expect-error ts-migrate(2322) FIXME: Type 'Element' is not assignable to type 'null | u... Remove this comment to see the full error message */}
|
||||
{user.id === author.id ? (
|
||||
<Tag className="m-0">Author</Tag>
|
||||
) : (
|
||||
@@ -184,13 +207,6 @@ function PermissionsEditorDialog({ dialog, author, context, aclUrl }) {
|
||||
);
|
||||
}
|
||||
|
||||
PermissionsEditorDialog.propTypes = {
|
||||
dialog: DialogPropType.isRequired,
|
||||
author: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
|
||||
context: PropTypes.oneOf(["query", "dashboard"]),
|
||||
aclUrl: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
PermissionsEditorDialog.defaultProps = { context: "query" };
|
||||
|
||||
export default wrapDialog(PermissionsEditorDialog);
|
||||
@@ -1,11 +1,21 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import classNames from "classnames";
|
||||
import Link from "@/components/Link";
|
||||
|
||||
type OwnPreviewCardProps = {
|
||||
imageUrl: string;
|
||||
title: React.ReactNode;
|
||||
body?: React.ReactNode;
|
||||
roundedImage?: boolean;
|
||||
className?: string;
|
||||
children?: React.ReactNode;
|
||||
};
|
||||
|
||||
type PreviewCardProps = OwnPreviewCardProps & typeof PreviewCard.defaultProps;
|
||||
|
||||
// PreviewCard
|
||||
|
||||
export function PreviewCard({ imageUrl, roundedImage, title, body, children, className, ...props }) {
|
||||
export function PreviewCard({ imageUrl, roundedImage, title, body, children, className, ...props }: PreviewCardProps) {
|
||||
return (
|
||||
<div {...props} className={className + " w-100 d-flex align-items-center"}>
|
||||
<img
|
||||
@@ -24,15 +34,6 @@ export function PreviewCard({ imageUrl, roundedImage, title, body, children, cla
|
||||
);
|
||||
}
|
||||
|
||||
PreviewCard.propTypes = {
|
||||
imageUrl: PropTypes.string.isRequired,
|
||||
title: PropTypes.node.isRequired,
|
||||
body: PropTypes.node,
|
||||
roundedImage: PropTypes.bool,
|
||||
className: PropTypes.string,
|
||||
children: PropTypes.node,
|
||||
};
|
||||
|
||||
PreviewCard.defaultProps = {
|
||||
body: null,
|
||||
roundedImage: true,
|
||||
@@ -40,36 +41,52 @@ PreviewCard.defaultProps = {
|
||||
children: null,
|
||||
};
|
||||
|
||||
type OwnUserPreviewCardProps = {
|
||||
user: {
|
||||
profile_image_url: string;
|
||||
name: string;
|
||||
email: string;
|
||||
};
|
||||
withLink?: boolean;
|
||||
children?: React.ReactNode;
|
||||
};
|
||||
|
||||
type UserPreviewCardProps = OwnUserPreviewCardProps & typeof UserPreviewCard.defaultProps;
|
||||
|
||||
// UserPreviewCard
|
||||
|
||||
export function UserPreviewCard({ user, withLink, children, ...props }) {
|
||||
export function UserPreviewCard({ user, withLink, children, ...props }: UserPreviewCardProps) {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'id' does not exist on type '{ profile_im... Remove this comment to see the full error message
|
||||
const title = withLink ? <Link href={"users/" + user.id}>{user.name}</Link> : user.name;
|
||||
return (
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'null | un... Remove this comment to see the full error message
|
||||
<PreviewCard {...props} imageUrl={user.profile_image_url} title={title} body={user.email}>
|
||||
{children}
|
||||
</PreviewCard>
|
||||
);
|
||||
}
|
||||
|
||||
UserPreviewCard.propTypes = {
|
||||
user: PropTypes.shape({
|
||||
profile_image_url: PropTypes.string.isRequired,
|
||||
name: PropTypes.string.isRequired,
|
||||
email: PropTypes.string.isRequired,
|
||||
}).isRequired,
|
||||
withLink: PropTypes.bool,
|
||||
children: PropTypes.node,
|
||||
};
|
||||
|
||||
UserPreviewCard.defaultProps = {
|
||||
withLink: false,
|
||||
children: null,
|
||||
};
|
||||
|
||||
type OwnDataSourcePreviewCardProps = {
|
||||
dataSource: {
|
||||
name: string;
|
||||
type: string;
|
||||
};
|
||||
withLink?: boolean;
|
||||
children?: React.ReactNode;
|
||||
};
|
||||
|
||||
type DataSourcePreviewCardProps = OwnDataSourcePreviewCardProps & typeof DataSourcePreviewCard.defaultProps;
|
||||
|
||||
// DataSourcePreviewCard
|
||||
|
||||
export function DataSourcePreviewCard({ dataSource, withLink, children, ...props }) {
|
||||
export function DataSourcePreviewCard({ dataSource, withLink, children, ...props }: DataSourcePreviewCardProps) {
|
||||
const imageUrl = `static/images/db-logos/${dataSource.type}.png`;
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'id' does not exist on type '{ name: stri... Remove this comment to see the full error message
|
||||
const title = withLink ? <Link href={"data_sources/" + dataSource.id}>{dataSource.name}</Link> : dataSource.name;
|
||||
return (
|
||||
<PreviewCard {...props} imageUrl={imageUrl} title={title}>
|
||||
@@ -78,15 +95,6 @@ export function DataSourcePreviewCard({ dataSource, withLink, children, ...props
|
||||
);
|
||||
}
|
||||
|
||||
DataSourcePreviewCard.propTypes = {
|
||||
dataSource: PropTypes.shape({
|
||||
name: PropTypes.string.isRequired,
|
||||
type: PropTypes.string.isRequired,
|
||||
}).isRequired,
|
||||
withLink: PropTypes.bool,
|
||||
children: PropTypes.node,
|
||||
};
|
||||
|
||||
DataSourcePreviewCard.defaultProps = {
|
||||
withLink: false,
|
||||
children: null,
|
||||
@@ -1,17 +1,21 @@
|
||||
import { find, isArray, get, first, map, intersection, isEqual, isEmpty } from "lodash";
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import SelectWithVirtualScroll from "@/components/SelectWithVirtualScroll";
|
||||
|
||||
export default class QueryBasedParameterInput extends React.Component {
|
||||
static propTypes = {
|
||||
parameter: PropTypes.any, // eslint-disable-line react/forbid-prop-types
|
||||
value: PropTypes.any, // eslint-disable-line react/forbid-prop-types
|
||||
mode: PropTypes.oneOf(["default", "multiple"]),
|
||||
queryId: PropTypes.number,
|
||||
onSelect: PropTypes.func,
|
||||
className: PropTypes.string,
|
||||
};
|
||||
type OwnProps = {
|
||||
parameter?: any;
|
||||
value?: any;
|
||||
mode?: "default" | "multiple";
|
||||
queryId?: number;
|
||||
onSelect?: (...args: any[]) => any;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
type State = any;
|
||||
|
||||
type Props = OwnProps & typeof QueryBasedParameterInput.defaultProps;
|
||||
|
||||
export default class QueryBasedParameterInput extends React.Component<Props, State> {
|
||||
|
||||
static defaultProps = {
|
||||
value: null,
|
||||
@@ -22,7 +26,7 @@ export default class QueryBasedParameterInput extends React.Component {
|
||||
className: "",
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
options: [],
|
||||
@@ -32,20 +36,26 @@ export default class QueryBasedParameterInput extends React.Component {
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'queryId' does not exist on type 'never'.
|
||||
this._loadOptions(this.props.queryId);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
componentDidUpdate(prevProps: Props) {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'queryId' does not exist on type 'never'.
|
||||
if (this.props.queryId !== prevProps.queryId) {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'queryId' does not exist on type 'never'.
|
||||
this._loadOptions(this.props.queryId);
|
||||
}
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'value' does not exist on type 'never'.
|
||||
if (this.props.value !== prevProps.value) {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'value' does not exist on type 'never'.
|
||||
this.setValue(this.props.value);
|
||||
}
|
||||
}
|
||||
|
||||
setValue(value) {
|
||||
setValue(value: any) {
|
||||
const { options } = this.state;
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'mode' does not exist on type 'never'.
|
||||
if (this.props.mode === "multiple") {
|
||||
value = isArray(value) ? value : [value];
|
||||
const optionValues = map(options, option => option.value);
|
||||
@@ -53,22 +63,28 @@ export default class QueryBasedParameterInput extends React.Component {
|
||||
this.setState({ value: validValues });
|
||||
return validValues;
|
||||
}
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'value' does not exist on type 'never'.
|
||||
const found = find(options, option => option.value === this.props.value) !== undefined;
|
||||
value = found ? value : get(first(options), "value");
|
||||
this.setState({ value });
|
||||
return value;
|
||||
}
|
||||
|
||||
async _loadOptions(queryId) {
|
||||
async _loadOptions(queryId: any) {
|
||||
if (queryId && queryId !== this.state.queryId) {
|
||||
this.setState({ loading: true });
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'parameter' does not exist on type 'never... Remove this comment to see the full error message
|
||||
const options = await this.props.parameter.loadDropdownValues();
|
||||
|
||||
// stale queryId check
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'queryId' does not exist on type 'never'.
|
||||
if (this.props.queryId === queryId) {
|
||||
this.setState({ options, loading: false }, () => {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'value' does not exist on type 'never'.
|
||||
const updatedValue = this.setValue(this.props.value);
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'value' does not exist on type 'never'.
|
||||
if (!isEqual(updatedValue, this.props.value)) {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'onSelect' does not exist on type 'never'... Remove this comment to see the full error message
|
||||
this.props.onSelect(updatedValue);
|
||||
}
|
||||
});
|
||||
@@ -77,6 +93,7 @@ export default class QueryBasedParameterInput extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
// @ts-expect-error ts-migrate(2700) FIXME: Rest types may only be created from object types.
|
||||
const { className, mode, onSelect, queryId, value, ...otherProps } = this.props;
|
||||
const { loading, options } = this.state;
|
||||
return (
|
||||
@@ -1,39 +1,44 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { VisualizationType } from "@redash/viz/lib";
|
||||
import Link from "@/components/Link";
|
||||
import VisualizationName from "@/components/visualizations/VisualizationName";
|
||||
|
||||
import "./QueryLink.less";
|
||||
|
||||
function QueryLink({ query, visualization, readOnly }) {
|
||||
type OwnProps = {
|
||||
query: any;
|
||||
visualization?: VisualizationType;
|
||||
readOnly?: boolean;
|
||||
};
|
||||
|
||||
type Props = OwnProps & typeof QueryLink.defaultProps;
|
||||
|
||||
function QueryLink({ query, visualization, readOnly }: Props) {
|
||||
const getUrl = () => {
|
||||
let hash = null;
|
||||
if (visualization) {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'type' does not exist on type 'never'.
|
||||
if (visualization.type === "TABLE") {
|
||||
// link to hard-coded table tab instead of the (hidden) visualization tab
|
||||
hash = "table";
|
||||
} else {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'id' does not exist on type 'never'.
|
||||
hash = visualization.id;
|
||||
}
|
||||
}
|
||||
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'getUrl' does not exist on type 'never'.
|
||||
return query.getUrl(false, hash);
|
||||
};
|
||||
|
||||
return (
|
||||
<Link href={readOnly ? null : getUrl()} className="query-link">
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'name' does not exist on type 'never'. */}
|
||||
<VisualizationName visualization={visualization} /> <span>{query.name}</span>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
QueryLink.propTypes = {
|
||||
query: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
|
||||
visualization: VisualizationType,
|
||||
readOnly: PropTypes.bool,
|
||||
};
|
||||
|
||||
QueryLink.defaultProps = {
|
||||
visualization: null,
|
||||
readOnly: false,
|
||||
@@ -1,6 +1,5 @@
|
||||
import { find } from "lodash";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import cx from "classnames";
|
||||
import Input from "antd/lib/input";
|
||||
import Select from "antd/lib/select";
|
||||
@@ -10,23 +9,38 @@ import { QueryTagsControl } from "@/components/tags-control/TagsControl";
|
||||
import useSearchResults from "@/lib/hooks/useSearchResults";
|
||||
|
||||
const { Option } = Select;
|
||||
function search(term) {
|
||||
function search(term: any) {
|
||||
if (term === null) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
// get recent
|
||||
if (!term) {
|
||||
return Query.recent().then(results => results.filter(item => !item.is_draft)); // filter out draft
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'recent' does not exist on type 'typeof Q... Remove this comment to see the full error message
|
||||
return Query.recent().then((results: any) => results.filter((item: any) => !item.is_draft)); // filter out draft
|
||||
}
|
||||
|
||||
// search by query
|
||||
return Query.query({ q: term }).then(({ results }) => results);
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'query' does not exist on type 'typeof Qu... Remove this comment to see the full error message
|
||||
return Query.query({ q: term }).then(({
|
||||
results
|
||||
}: any) => results);
|
||||
}
|
||||
|
||||
export default function QuerySelector(props) {
|
||||
type OwnProps = {
|
||||
onChange: (...args: any[]) => any;
|
||||
selectedQuery?: any;
|
||||
type?: "select" | "default";
|
||||
className?: string;
|
||||
disabled?: boolean;
|
||||
};
|
||||
|
||||
type Props = OwnProps & typeof QuerySelector.defaultProps;
|
||||
|
||||
export default function QuerySelector(props: Props) {
|
||||
const [searchTerm, setSearchTerm] = useState("");
|
||||
const [selectedQuery, setSelectedQuery] = useState();
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'never[]' is not assignable to type 'null | u... Remove this comment to see the full error message
|
||||
const [doSearch, searchResults, searching] = useSearchResults(search, { initialResults: [] });
|
||||
|
||||
const placeholder = "Search a query by name";
|
||||
@@ -34,57 +48,71 @@ export default function QuerySelector(props) {
|
||||
const spinIcon = <i className={cx("fa fa-spinner fa-pulse hide-in-percy", { hidden: !searching })} />;
|
||||
|
||||
useEffect(() => {
|
||||
// @ts-expect-error ts-migrate(2349) FIXME: This expression is not callable.
|
||||
doSearch(searchTerm);
|
||||
}, [doSearch, searchTerm]);
|
||||
|
||||
// set selected from prop
|
||||
useEffect(() => {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'selectedQuery' does not exist on type 'n... Remove this comment to see the full error message
|
||||
if (props.selectedQuery) {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'selectedQuery' does not exist on type 'n... Remove this comment to see the full error message
|
||||
setSelectedQuery(props.selectedQuery);
|
||||
}
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'selectedQuery' does not exist on type 'n... Remove this comment to see the full error message
|
||||
}, [props.selectedQuery]);
|
||||
|
||||
function selectQuery(queryId) {
|
||||
function selectQuery(queryId: any) {
|
||||
let query = null;
|
||||
if (queryId) {
|
||||
// @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call.
|
||||
query = find(searchResults, { id: queryId });
|
||||
if (!query) {
|
||||
// shouldn't happen
|
||||
// @ts-expect-error ts-migrate(2554) FIXME: Expected 1 arguments, but got 2.
|
||||
notification.error("Something went wrong...", "Couldn't select query");
|
||||
}
|
||||
}
|
||||
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'string | null' is not assignable... Remove this comment to see the full error message
|
||||
setSearchTerm(query ? null : ""); // empty string triggers recent fetch
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'unknown' is not assignable to pa... Remove this comment to see the full error message
|
||||
setSelectedQuery(query);
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'onChange' does not exist on type 'never'... Remove this comment to see the full error message
|
||||
props.onChange(query);
|
||||
}
|
||||
|
||||
function renderResults() {
|
||||
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||
if (!searchResults.length) {
|
||||
return <div className="text-muted">No results matching search term.</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="list-group">
|
||||
{searchResults.map(q => (
|
||||
<a
|
||||
className={cx("query-selector-result", "list-group-item", { inactive: q.is_draft })}
|
||||
key={q.id}
|
||||
onClick={() => selectQuery(q.id)}
|
||||
data-test={`QueryId${q.id}`}>
|
||||
{q.name} <QueryTagsControl isDraft={q.is_draft} tags={q.tags} className="inline-tags-control" />
|
||||
</a>
|
||||
))}
|
||||
{/* @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'. */}
|
||||
{searchResults.map((q: any) => <a
|
||||
className={cx("query-selector-result", "list-group-item", { inactive: q.is_draft })}
|
||||
key={q.id}
|
||||
onClick={() => selectQuery(q.id)}
|
||||
data-test={`QueryId${q.id}`}>
|
||||
{/* @ts-expect-error ts-migrate(2322) FIXME: Type '{ isDraft: any; tags: any; className: string... Remove this comment to see the full error message */}
|
||||
{q.name} <QueryTagsControl isDraft={q.is_draft} tags={q.tags} className="inline-tags-control" />
|
||||
</a>)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'disabled' does not exist on type 'never'... Remove this comment to see the full error message
|
||||
if (props.disabled) {
|
||||
// @ts-expect-error ts-migrate(2532) FIXME: Object is possibly 'undefined'.
|
||||
return <Input value={selectedQuery && selectedQuery.name} placeholder={placeholder} disabled />;
|
||||
}
|
||||
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'type' does not exist on type 'never'.
|
||||
if (props.type === "select") {
|
||||
const suffixIcon = selectedQuery ? clearIcon : null;
|
||||
// @ts-expect-error ts-migrate(2532) FIXME: Object is possibly 'undefined'.
|
||||
const value = selectedQuery ? selectedQuery.name : searchTerm;
|
||||
|
||||
return (
|
||||
@@ -99,10 +127,12 @@ export default function QuerySelector(props) {
|
||||
notFoundContent={null}
|
||||
filterOption={false}
|
||||
defaultActiveFirstOption={false}
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'className' does not exist on type 'never... Remove this comment to see the full error message
|
||||
className={props.className}
|
||||
data-test="QuerySelector">
|
||||
{searchResults &&
|
||||
searchResults.map(q => {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'map' does not exist on type 'true | ((se... Remove this comment to see the full error message
|
||||
searchResults.map((q: any) => {
|
||||
const disabled = q.is_draft;
|
||||
return (
|
||||
<Option
|
||||
@@ -114,6 +144,7 @@ export default function QuerySelector(props) {
|
||||
{q.name}{" "}
|
||||
<QueryTagsControl
|
||||
isDraft={q.is_draft}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '{ isDraft: any; tags: any; className: string... Remove this comment to see the full error message
|
||||
tags={q.tags}
|
||||
className={cx("inline-tags-control", { disabled })}
|
||||
/>
|
||||
@@ -127,6 +158,7 @@ export default function QuerySelector(props) {
|
||||
return (
|
||||
<span data-test="QuerySelector">
|
||||
{selectedQuery ? (
|
||||
// @ts-expect-error ts-migrate(2532) FIXME: Object is possibly 'undefined'.
|
||||
<Input value={selectedQuery.name} suffix={clearIcon} readOnly />
|
||||
) : (
|
||||
<Input
|
||||
@@ -143,14 +175,6 @@ export default function QuerySelector(props) {
|
||||
);
|
||||
}
|
||||
|
||||
QuerySelector.propTypes = {
|
||||
onChange: PropTypes.func.isRequired,
|
||||
selectedQuery: PropTypes.object, // eslint-disable-line react/forbid-prop-types
|
||||
type: PropTypes.oneOf(["select", "default"]),
|
||||
className: PropTypes.string,
|
||||
disabled: PropTypes.bool,
|
||||
};
|
||||
|
||||
QuerySelector.defaultProps = {
|
||||
selectedQuery: null,
|
||||
type: "default",
|
||||
@@ -1,12 +1,20 @@
|
||||
import d3 from "d3";
|
||||
import React, { useRef, useMemo, useCallback, useState, useEffect } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { Resizable as ReactResizable } from "react-resizable";
|
||||
import KeyboardShortcuts from "@/services/KeyboardShortcuts";
|
||||
|
||||
import "./index.less";
|
||||
|
||||
export default function Resizable({ toggleShortcut, direction, sizeAttribute, children }) {
|
||||
type OwnProps = {
|
||||
direction?: "horizontal" | "vertical";
|
||||
sizeAttribute?: string;
|
||||
toggleShortcut?: string;
|
||||
children?: React.ReactElement;
|
||||
};
|
||||
|
||||
type Props = OwnProps & typeof Resizable.defaultProps;
|
||||
|
||||
export default function Resizable({ toggleShortcut, direction, sizeAttribute, children }: Props) {
|
||||
const [size, setSize] = useState(0);
|
||||
const elementRef = useRef();
|
||||
const wasUsingTouchEventsRef = useRef(false);
|
||||
@@ -19,6 +27,7 @@ export default function Resizable({ toggleShortcut, direction, sizeAttribute, ch
|
||||
if (!elementRef.current) {
|
||||
return 0;
|
||||
}
|
||||
// @ts-expect-error ts-migrate(2532) FIXME: Object is possibly 'undefined'.
|
||||
return Math.floor(elementRef.current.getBoundingClientRect()[sizeProp]);
|
||||
}, [sizeProp]);
|
||||
|
||||
@@ -28,10 +37,12 @@ export default function Resizable({ toggleShortcut, direction, sizeAttribute, ch
|
||||
return;
|
||||
}
|
||||
|
||||
// @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call.
|
||||
const element = d3.select(elementRef.current);
|
||||
let targetSize;
|
||||
if (savedSize.current === null) {
|
||||
targetSize = "0px";
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'null'.
|
||||
savedSize.current = `${getElementSize()}px`;
|
||||
} else {
|
||||
targetSize = savedSize.current;
|
||||
@@ -42,10 +53,13 @@ export default function Resizable({ toggleShortcut, direction, sizeAttribute, ch
|
||||
.style(sizeAttribute, savedSize.current || "0px")
|
||||
.transition()
|
||||
.duration(200)
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'string' is not assignable to par... Remove this comment to see the full error message
|
||||
.ease("swing")
|
||||
// @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call.
|
||||
.style(sizeAttribute, targetSize);
|
||||
|
||||
// update state to new element's size
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'string | null' is not assignable... Remove this comment to see the full error message
|
||||
setSize(parseInt(targetSize) || 0);
|
||||
}, [getElementSize, sizeAttribute]);
|
||||
|
||||
@@ -92,8 +106,9 @@ export default function Resizable({ toggleShortcut, direction, sizeAttribute, ch
|
||||
// updated here and in `draggableCore::onMouseDown` handler to ensure that right value will be used
|
||||
setSize(getElementSize());
|
||||
},
|
||||
onResize: (unused, data) => {
|
||||
onResize: (unused: any, data: any) => {
|
||||
// update element directly for better UI responsiveness
|
||||
// @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call.
|
||||
d3.select(elementRef.current).style(sizeAttribute, `${data.size[sizeProp]}px`);
|
||||
setSize(data.size[sizeProp]);
|
||||
wasResizedRef.current = true;
|
||||
@@ -109,7 +124,7 @@ export default function Resizable({ toggleShortcut, direction, sizeAttribute, ch
|
||||
|
||||
const draggableCoreOptions = useMemo(
|
||||
() => ({
|
||||
onMouseDown: e => {
|
||||
onMouseDown: (e: any) => {
|
||||
// In some cases this handler is executed twice during the same resize operation - first time
|
||||
// with `touchstart` event and second time with `mousedown` (probably emulated by browser).
|
||||
// Therefore we set the flag only when we receive `touchstart` because in ths case it's definitely
|
||||
@@ -130,6 +145,7 @@ export default function Resizable({ toggleShortcut, direction, sizeAttribute, ch
|
||||
return null;
|
||||
}
|
||||
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'CElement<any, Component<any, any, any>>' is ... Remove this comment to see the full error message
|
||||
children = React.createElement(children.type, { ...children.props, ref: elementRef });
|
||||
|
||||
return (
|
||||
@@ -148,13 +164,6 @@ export default function Resizable({ toggleShortcut, direction, sizeAttribute, ch
|
||||
);
|
||||
}
|
||||
|
||||
Resizable.propTypes = {
|
||||
direction: PropTypes.oneOf(["horizontal", "vertical"]),
|
||||
sizeAttribute: PropTypes.string,
|
||||
toggleShortcut: PropTypes.string,
|
||||
children: PropTypes.element,
|
||||
};
|
||||
|
||||
Resizable.defaultProps = {
|
||||
direction: "horizontal",
|
||||
sizeAttribute: null, // "width"/"height" - depending on `direction`
|
||||
@@ -1,24 +1,33 @@
|
||||
import { filter, find, isEmpty, size } from "lodash";
|
||||
import React, { useState, useCallback, useEffect } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import classNames from "classnames";
|
||||
import Modal from "antd/lib/modal";
|
||||
import Input from "antd/lib/input";
|
||||
import List from "antd/lib/list";
|
||||
import Button from "antd/lib/button";
|
||||
// @ts-expect-error ts-migrate(6133) FIXME: 'DialogPropType' is declared but its value is neve... Remove this comment to see the full error message
|
||||
import { wrap as wrapDialog, DialogPropType } from "@/components/DialogWrapper";
|
||||
import BigMessage from "@/components/BigMessage";
|
||||
import LoadingState from "@/components/items-list/components/LoadingState";
|
||||
import notification from "@/services/notification";
|
||||
import useSearchResults from "@/lib/hooks/useSearchResults";
|
||||
|
||||
function ItemsList({ items, renderItem, onItemClick }) {
|
||||
type OwnItemsListProps = {
|
||||
items?: any[];
|
||||
renderItem?: (...args: any[]) => any;
|
||||
onItemClick?: (...args: any[]) => any;
|
||||
};
|
||||
|
||||
type ItemsListProps = OwnItemsListProps & typeof ItemsList.defaultProps;
|
||||
|
||||
function ItemsList({ items, renderItem, onItemClick }: ItemsListProps) {
|
||||
const renderListItem = useCallback(
|
||||
item => {
|
||||
const { content, className, isDisabled } = renderItem(item);
|
||||
return (
|
||||
<List.Item
|
||||
className={classNames("p-l-10", "p-r-10", { clickable: !isDisabled, disabled: isDisabled }, className)}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '(() => any) | null' is not assignable to typ... Remove this comment to see the full error message
|
||||
onClick={isDisabled ? null : () => onItemClick(item)}>
|
||||
{content}
|
||||
</List.Item>
|
||||
@@ -30,42 +39,46 @@ function ItemsList({ items, renderItem, onItemClick }) {
|
||||
return <List size="small" dataSource={items} renderItem={renderListItem} />;
|
||||
}
|
||||
|
||||
ItemsList.propTypes = {
|
||||
items: PropTypes.array,
|
||||
renderItem: PropTypes.func,
|
||||
onItemClick: PropTypes.func,
|
||||
};
|
||||
|
||||
ItemsList.defaultProps = {
|
||||
items: [],
|
||||
renderItem: () => {},
|
||||
onItemClick: () => {},
|
||||
};
|
||||
|
||||
function SelectItemsDialog({
|
||||
dialog,
|
||||
dialogTitle,
|
||||
inputPlaceholder,
|
||||
itemKey,
|
||||
renderItem,
|
||||
renderStagedItem,
|
||||
searchItems,
|
||||
selectedItemsTitle,
|
||||
width,
|
||||
showCount,
|
||||
extraFooterContent,
|
||||
}) {
|
||||
type OwnSelectItemsDialogProps = {
|
||||
// @ts-expect-error ts-migrate(2749) FIXME: 'DialogPropType' refers to a value, but is being u... Remove this comment to see the full error message
|
||||
dialog: DialogPropType;
|
||||
dialogTitle?: string;
|
||||
inputPlaceholder?: string;
|
||||
selectedItemsTitle?: string;
|
||||
searchItems: (...args: any[]) => any;
|
||||
itemKey?: (...args: any[]) => any;
|
||||
renderItem?: (...args: any[]) => any;
|
||||
renderStagedItem?: (...args: any[]) => any;
|
||||
width?: string | number;
|
||||
extraFooterContent?: React.ReactNode;
|
||||
showCount?: boolean;
|
||||
};
|
||||
|
||||
type SelectItemsDialogProps = OwnSelectItemsDialogProps & typeof SelectItemsDialog.defaultProps;
|
||||
|
||||
function SelectItemsDialog({ dialog, dialogTitle, inputPlaceholder, itemKey, renderItem, renderStagedItem, searchItems, selectedItemsTitle, width, showCount, extraFooterContent, }: SelectItemsDialogProps) {
|
||||
const [selectedItems, setSelectedItems] = useState([]);
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'never[]' is not assignable to type 'null | u... Remove this comment to see the full error message
|
||||
const [search, items, isLoading] = useSearchResults(searchItems, { initialResults: [] });
|
||||
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||
const hasResults = items.length > 0;
|
||||
|
||||
useEffect(() => {
|
||||
// @ts-expect-error ts-migrate(2349) FIXME: This expression is not callable.
|
||||
search();
|
||||
}, [search]);
|
||||
|
||||
const isItemSelected = useCallback(
|
||||
item => {
|
||||
// @ts-expect-error ts-migrate(2349) FIXME: This expression is not callable.
|
||||
const key = itemKey(item);
|
||||
// @ts-expect-error ts-migrate(2349) FIXME: This expression is not callable.
|
||||
return !!find(selectedItems, i => itemKey(i) === key);
|
||||
},
|
||||
[selectedItems, itemKey]
|
||||
@@ -74,9 +87,12 @@ function SelectItemsDialog({
|
||||
const toggleItem = useCallback(
|
||||
item => {
|
||||
if (isItemSelected(item)) {
|
||||
// @ts-expect-error ts-migrate(2349) FIXME: This expression is not callable.
|
||||
const key = itemKey(item);
|
||||
// @ts-expect-error ts-migrate(2349) FIXME: This expression is not callable.
|
||||
setSelectedItems(filter(selectedItems, i => itemKey(i) !== key));
|
||||
} else {
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'any[]' is not assignable to para... Remove this comment to see the full error message
|
||||
setSelectedItems([...selectedItems, item]);
|
||||
}
|
||||
},
|
||||
@@ -84,8 +100,10 @@ function SelectItemsDialog({
|
||||
);
|
||||
|
||||
const save = useCallback(() => {
|
||||
dialog.close(selectedItems).catch(error => {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'close' does not exist on type 'never'.
|
||||
dialog.close(selectedItems).catch((error: any) => {
|
||||
if (error) {
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'string' is not assignable to par... Remove this comment to see the full error message
|
||||
notification.error("Failed to save some of selected items.");
|
||||
}
|
||||
});
|
||||
@@ -93,6 +111,7 @@ function SelectItemsDialog({
|
||||
|
||||
return (
|
||||
<Modal
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'props' does not exist on type 'never'.
|
||||
{...dialog.props}
|
||||
className="select-items-dialog"
|
||||
width={width}
|
||||
@@ -102,12 +121,15 @@ function SelectItemsDialog({
|
||||
<span className="flex-fill m-r-5" style={{ textAlign: "left", color: "rgba(0, 0, 0, 0.5)" }}>
|
||||
{extraFooterContent}
|
||||
</span>
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'props' does not exist on type 'never'. */}
|
||||
<Button {...dialog.props.cancelButtonProps} onClick={dialog.dismiss}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'props' does not exist on type 'never'.
|
||||
{...dialog.props.okButtonProps}
|
||||
onClick={save}
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'props' does not exist on type 'never'.
|
||||
disabled={selectedItems.length === 0 || dialog.props.okButtonProps.disabled}
|
||||
type="primary">
|
||||
Save
|
||||
@@ -117,6 +139,7 @@ function SelectItemsDialog({
|
||||
}>
|
||||
<div className="d-flex align-items-center m-b-10">
|
||||
<div className="flex-fill">
|
||||
{/* @ts-expect-error ts-migrate(2349) FIXME: This expression is not callable. */}
|
||||
<Input.Search onChange={event => search(event.target.value)} placeholder={inputPlaceholder} autoFocus />
|
||||
</div>
|
||||
{renderStagedItem && (
|
||||
@@ -134,8 +157,11 @@ function SelectItemsDialog({
|
||||
)}
|
||||
{!isLoading && hasResults && (
|
||||
<ItemsList
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'boolean | ((searchTerm: any) => void) | null... Remove this comment to see the full error message
|
||||
items={items}
|
||||
renderItem={item => renderItem(item, { isSelected: isItemSelected(item) })}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '(item: any) => any' is not assignable to typ... Remove this comment to see the full error message
|
||||
renderItem={(item: any) => renderItem(item, { isSelected: isItemSelected(item) })}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '(item: any) => void' is not assignable to ty... Remove this comment to see the full error message
|
||||
onItemClick={toggleItem}
|
||||
/>
|
||||
)}
|
||||
@@ -145,7 +171,9 @@ function SelectItemsDialog({
|
||||
{selectedItems.length > 0 && (
|
||||
<ItemsList
|
||||
items={selectedItems}
|
||||
renderItem={item => renderStagedItem(item, { isSelected: true })}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '(item: any) => any' is not assignable to typ... Remove this comment to see the full error message
|
||||
renderItem={(item: any) => renderStagedItem(item, { isSelected: true })}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '(item: any) => void' is not assignable to ty... Remove this comment to see the full error message
|
||||
onItemClick={toggleItem}
|
||||
/>
|
||||
)}
|
||||
@@ -156,32 +184,11 @@ function SelectItemsDialog({
|
||||
);
|
||||
}
|
||||
|
||||
SelectItemsDialog.propTypes = {
|
||||
dialog: DialogPropType.isRequired,
|
||||
dialogTitle: PropTypes.string,
|
||||
inputPlaceholder: PropTypes.string,
|
||||
selectedItemsTitle: PropTypes.string,
|
||||
searchItems: PropTypes.func.isRequired, // (searchTerm: string): Promise<Items[]> if `searchTerm === ''` load all
|
||||
itemKey: PropTypes.func, // (item) => string|number - return key of item (by default `id`)
|
||||
// left list
|
||||
// (item, { isSelected }) => {
|
||||
// content: node, // item contents
|
||||
// className: string = '', // additional class for item wrapper
|
||||
// isDisabled: bool = false, // is item clickable or disabled
|
||||
// }
|
||||
renderItem: PropTypes.func,
|
||||
// right list; args/results save as for `renderItem`. if not specified - `renderItem` will be used
|
||||
renderStagedItem: PropTypes.func,
|
||||
width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
extraFooterContent: PropTypes.node,
|
||||
showCount: PropTypes.bool,
|
||||
};
|
||||
|
||||
SelectItemsDialog.defaultProps = {
|
||||
dialogTitle: "Add Items",
|
||||
inputPlaceholder: "Search...",
|
||||
selectedItemsTitle: "Selected items",
|
||||
itemKey: item => item.id,
|
||||
itemKey: (item: any) => item.id,
|
||||
renderItem: () => "",
|
||||
renderStagedItem: null, // hidden by default
|
||||
width: "80%",
|
||||
@@ -5,20 +5,24 @@ import Link from "@/components/Link";
|
||||
import location from "@/services/location";
|
||||
import settingsMenu from "@/services/settingsMenu";
|
||||
|
||||
function wrapSettingsTab(id, options, WrappedComponent) {
|
||||
function wrapSettingsTab(id: any, options: any, WrappedComponent: any) {
|
||||
settingsMenu.add(id, options);
|
||||
|
||||
return function SettingsTab(props) {
|
||||
return function SettingsTab(props: any) {
|
||||
const activeItem = settingsMenu.getActiveItem(location.path);
|
||||
return (
|
||||
<div className="settings-screen">
|
||||
<div className="container">
|
||||
<PageHeader title="Settings" />
|
||||
<div className="bg-white tiled">
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'title' does not exist on type 'number | ... Remove this comment to see the full error message */}
|
||||
<Menu selectedKeys={[activeItem && activeItem.title]} selectable={false} mode="horizontal">
|
||||
{settingsMenu.getAvailableItems().map(item => (
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'title' does not exist on type 'number | ... Remove this comment to see the full error message
|
||||
<Menu.Item key={item.title}>
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'path' does not exist on type 'number | (... Remove this comment to see the full error message */}
|
||||
<Link href={item.path} data-test="SettingsScreenItem">
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'title' does not exist on type 'number | ... Remove this comment to see the full error message */}
|
||||
{item.title}
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
@@ -1,19 +1,30 @@
|
||||
import moment from "moment";
|
||||
import { isNil } from "lodash";
|
||||
import React, { useEffect, useMemo, useState } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
// @ts-expect-error ts-migrate(6133) FIXME: 'Moment' is declared but its value is never read.
|
||||
import { Moment } from "@/components/proptypes";
|
||||
import { clientConfig } from "@/services/auth";
|
||||
import Tooltip from "antd/lib/tooltip";
|
||||
|
||||
function toMoment(value) {
|
||||
function toMoment(value: any) {
|
||||
value = !isNil(value) ? moment(value) : null;
|
||||
return value && value.isValid() ? value : null;
|
||||
}
|
||||
|
||||
export default function TimeAgo({ date, placeholder, autoUpdate, variation }) {
|
||||
type OwnProps = {
|
||||
// @ts-expect-error ts-migrate(2749) FIXME: 'Moment' refers to a value, but is being used as a... Remove this comment to see the full error message
|
||||
date?: string | number | any | Moment;
|
||||
placeholder?: string;
|
||||
autoUpdate?: boolean;
|
||||
variation?: "timeAgoInTooltip";
|
||||
};
|
||||
|
||||
type Props = OwnProps & typeof TimeAgo.defaultProps;
|
||||
|
||||
export default function TimeAgo({ date, placeholder, autoUpdate, variation }: Props) {
|
||||
const startDate = toMoment(date);
|
||||
const [value, setValue] = useState(null);
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dateTimeFormat' does not exist on type '... Remove this comment to see the full error message
|
||||
const title = useMemo(() => (startDate ? startDate.format(clientConfig.dateTimeFormat) : null), [startDate]);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -42,13 +53,6 @@ export default function TimeAgo({ date, placeholder, autoUpdate, variation }) {
|
||||
);
|
||||
}
|
||||
|
||||
TimeAgo.propTypes = {
|
||||
date: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.instanceOf(Date), Moment]),
|
||||
placeholder: PropTypes.string,
|
||||
autoUpdate: PropTypes.bool,
|
||||
variation: PropTypes.oneOf(["timeAgoInTooltip"]),
|
||||
};
|
||||
|
||||
TimeAgo.defaultProps = {
|
||||
date: null,
|
||||
placeholder: "",
|
||||
@@ -1,9 +1,16 @@
|
||||
import React, { useMemo, useState, useEffect } from "react";
|
||||
import moment from "moment";
|
||||
import PropTypes from "prop-types";
|
||||
// @ts-expect-error ts-migrate(6133) FIXME: 'Moment' is declared but its value is never read.
|
||||
import { Moment } from "@/components/proptypes";
|
||||
|
||||
export default function Timer({ from }) {
|
||||
type OwnProps = {
|
||||
// @ts-expect-error ts-migrate(2749) FIXME: 'Moment' refers to a value, but is being used as a... Remove this comment to see the full error message
|
||||
from?: string | number | any | Moment;
|
||||
};
|
||||
|
||||
type Props = OwnProps & typeof Timer.defaultProps;
|
||||
|
||||
export default function Timer({ from }: Props) {
|
||||
const startTime = useMemo(() => moment(from).valueOf(), [from]);
|
||||
const [value, setValue] = useState(null);
|
||||
|
||||
@@ -11,6 +18,7 @@ export default function Timer({ from }) {
|
||||
function update() {
|
||||
const diff = moment.now() - startTime;
|
||||
const format = diff > 1000 * 60 * 60 ? "HH:mm:ss" : "mm:ss"; // no HH under an hour
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'string' is not assignable to par... Remove this comment to see the full error message
|
||||
setValue(moment.utc(diff).format(format));
|
||||
}
|
||||
update();
|
||||
@@ -22,10 +30,6 @@ export default function Timer({ from }) {
|
||||
return <span className="rd-timer">{value}</span>;
|
||||
}
|
||||
|
||||
Timer.propTypes = {
|
||||
from: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.instanceOf(Date), Moment]),
|
||||
};
|
||||
|
||||
Timer.defaultProps = {
|
||||
from: null,
|
||||
};
|
||||
@@ -1,12 +1,21 @@
|
||||
import { map } from "lodash";
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import Tag from "antd/lib/tag";
|
||||
import Link from "@/components/Link";
|
||||
|
||||
import "./UserGroups.less";
|
||||
|
||||
export default function UserGroups({ groups, linkGroups, ...props }) {
|
||||
type OwnProps = {
|
||||
groups?: {
|
||||
id: number | string;
|
||||
name?: string;
|
||||
}[];
|
||||
linkGroups?: boolean;
|
||||
};
|
||||
|
||||
type Props = OwnProps & typeof UserGroups.defaultProps;
|
||||
|
||||
export default function UserGroups({ groups, linkGroups, ...props }: Props) {
|
||||
return (
|
||||
<div className="user-groups" {...props}>
|
||||
{map(groups, group => (
|
||||
@@ -16,16 +25,6 @@ export default function UserGroups({ groups, linkGroups, ...props }) {
|
||||
);
|
||||
}
|
||||
|
||||
UserGroups.propTypes = {
|
||||
groups: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
|
||||
name: PropTypes.string,
|
||||
})
|
||||
),
|
||||
linkGroups: PropTypes.bool,
|
||||
};
|
||||
|
||||
UserGroups.defaultProps = {
|
||||
groups: [],
|
||||
linkGroups: true,
|
||||
@@ -1,12 +1,18 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import Menu from "antd/lib/menu";
|
||||
import PageHeader from "@/components/PageHeader";
|
||||
import Link from "@/components/Link";
|
||||
|
||||
import "./layout.less";
|
||||
|
||||
export default function Layout({ activeTab, children }) {
|
||||
type OwnProps = {
|
||||
activeTab?: string;
|
||||
children?: React.ReactNode;
|
||||
};
|
||||
|
||||
type Props = OwnProps & typeof Layout.defaultProps;
|
||||
|
||||
export default function Layout({ activeTab, children }: Props) {
|
||||
return (
|
||||
<div className="admin-page-layout">
|
||||
<div className="container">
|
||||
@@ -30,11 +36,6 @@ export default function Layout({ activeTab, children }) {
|
||||
);
|
||||
}
|
||||
|
||||
Layout.propTypes = {
|
||||
activeTab: PropTypes.string,
|
||||
children: PropTypes.node,
|
||||
};
|
||||
|
||||
Layout.defaultProps = {
|
||||
activeTab: "system_status",
|
||||
children: null,
|
||||
@@ -1,6 +1,5 @@
|
||||
import { map } from "lodash";
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import Badge from "antd/lib/badge";
|
||||
import Card from "antd/lib/card";
|
||||
@@ -8,9 +7,17 @@ import Spin from "antd/lib/spin";
|
||||
import Table from "antd/lib/table";
|
||||
import { Columns } from "@/components/items-list/components/ItemsTable";
|
||||
|
||||
type OwnCounterCardProps = {
|
||||
title: string;
|
||||
value?: number | string;
|
||||
loading: boolean;
|
||||
};
|
||||
|
||||
type CounterCardProps = OwnCounterCardProps & typeof CounterCard.defaultProps;
|
||||
|
||||
// CounterCard
|
||||
|
||||
export function CounterCard({ title, value, loading }) {
|
||||
export function CounterCard({ title, value, loading }: CounterCardProps) {
|
||||
return (
|
||||
<Spin spinning={loading}>
|
||||
<Card>
|
||||
@@ -21,12 +28,6 @@ export function CounterCard({ title, value, loading }) {
|
||||
);
|
||||
}
|
||||
|
||||
CounterCard.propTypes = {
|
||||
title: PropTypes.string.isRequired,
|
||||
value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
||||
loading: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
CounterCard.defaultProps = {
|
||||
value: "",
|
||||
};
|
||||
@@ -39,7 +40,7 @@ const queryJobsColumns = [
|
||||
{ title: "Org ID", dataIndex: "meta.org_id" },
|
||||
{ title: "Data Source ID", dataIndex: "meta.data_source_id" },
|
||||
{ title: "User ID", dataIndex: "meta.user_id" },
|
||||
Columns.custom(scheduled => scheduled.toString(), { title: "Scheduled", dataIndex: "meta.scheduled" }),
|
||||
Columns.custom((scheduled: any) => scheduled.toString(), { title: "Scheduled", dataIndex: "meta.scheduled" }),
|
||||
Columns.timeAgo({ title: "Start Time", dataIndex: "started_at" }),
|
||||
Columns.timeAgo({ title: "Enqueue Time", dataIndex: "enqueued_at" }),
|
||||
];
|
||||
@@ -53,12 +54,11 @@ const otherJobsColumns = [
|
||||
|
||||
const workersColumns = [
|
||||
Columns.custom(
|
||||
value => (
|
||||
<span>
|
||||
<Badge status={{ busy: "processing", idle: "default", started: "success", suspended: "warning" }[value]} />{" "}
|
||||
{value}
|
||||
</span>
|
||||
),
|
||||
(value: any) => <span>
|
||||
{/* @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message */}
|
||||
<Badge status={{ busy: "processing", idle: "default", started: "success", suspended: "warning" }[value]} />{" "}
|
||||
{value}
|
||||
</span>,
|
||||
{ title: "State", dataIndex: "state" }
|
||||
),
|
||||
]
|
||||
@@ -75,12 +75,27 @@ const workersColumns = [
|
||||
|
||||
const queuesColumns = map(["Name", "Started", "Queued"], c => ({ title: c, dataIndex: c.toLowerCase() }));
|
||||
|
||||
const TablePropTypes = {
|
||||
loading: PropTypes.bool.isRequired,
|
||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
type WorkersTableProps = {
|
||||
loading: boolean;
|
||||
items: any[];
|
||||
};
|
||||
|
||||
export function WorkersTable({ loading, items }) {
|
||||
type QueuesTableProps = {
|
||||
loading: boolean;
|
||||
items: any[];
|
||||
};
|
||||
|
||||
type QueryJobsTableProps = {
|
||||
loading: boolean;
|
||||
items: any[];
|
||||
};
|
||||
|
||||
type OtherJobsTableProps = {
|
||||
loading: boolean;
|
||||
items: any[];
|
||||
};
|
||||
|
||||
export function WorkersTable({ loading, items }: WorkersTableProps) {
|
||||
return (
|
||||
<Table
|
||||
loading={loading}
|
||||
@@ -96,9 +111,7 @@ export function WorkersTable({ loading, items }) {
|
||||
);
|
||||
}
|
||||
|
||||
WorkersTable.propTypes = TablePropTypes;
|
||||
|
||||
export function QueuesTable({ loading, items }) {
|
||||
export function QueuesTable({ loading, items }: QueuesTableProps) {
|
||||
return (
|
||||
<Table
|
||||
loading={loading}
|
||||
@@ -114,9 +127,7 @@ export function QueuesTable({ loading, items }) {
|
||||
);
|
||||
}
|
||||
|
||||
QueuesTable.propTypes = TablePropTypes;
|
||||
|
||||
export function QueryJobsTable({ loading, items }) {
|
||||
export function QueryJobsTable({ loading, items }: QueryJobsTableProps) {
|
||||
return (
|
||||
<Table
|
||||
loading={loading}
|
||||
@@ -132,9 +143,7 @@ export function QueryJobsTable({ loading, items }) {
|
||||
);
|
||||
}
|
||||
|
||||
QueryJobsTable.propTypes = TablePropTypes;
|
||||
|
||||
export function OtherJobsTable({ loading, items }) {
|
||||
export function OtherJobsTable({ loading, items }: OtherJobsTableProps) {
|
||||
return (
|
||||
<Table
|
||||
loading={loading}
|
||||
@@ -149,5 +158,3 @@ export function OtherJobsTable({ loading, items }) {
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
OtherJobsTable.propTypes = TablePropTypes;
|
||||
@@ -9,7 +9,9 @@ import TimeAgo from "@/components/TimeAgo";
|
||||
|
||||
import { toHuman, prettySize } from "@/lib/utils";
|
||||
|
||||
export function General({ info }) {
|
||||
export function General({
|
||||
info
|
||||
}: any) {
|
||||
info = toPairs(info);
|
||||
return (
|
||||
<Card title="General" size="small">
|
||||
@@ -19,6 +21,7 @@ export function General({ info }) {
|
||||
size="small"
|
||||
itemLayout="vertical"
|
||||
dataSource={info}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '([name, value]: [any, any]) => Element' is n... Remove this comment to see the full error message
|
||||
renderItem={([name, value]) => (
|
||||
<List.Item extra={<span className="badge">{value}</span>}>{toHuman(name)}</List.Item>
|
||||
)}
|
||||
@@ -28,7 +31,9 @@ export function General({ info }) {
|
||||
);
|
||||
}
|
||||
|
||||
export function DatabaseMetrics({ info }) {
|
||||
export function DatabaseMetrics({
|
||||
info
|
||||
}: any) {
|
||||
return (
|
||||
<Card title="Redash Database" size="small">
|
||||
{info.length === 0 && <div className="text-muted text-center">No data</div>}
|
||||
@@ -37,6 +42,7 @@ export function DatabaseMetrics({ info }) {
|
||||
size="small"
|
||||
itemLayout="vertical"
|
||||
dataSource={info}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '([name, size]: [any, any]) => Element' is no... Remove this comment to see the full error message
|
||||
renderItem={([name, size]) => (
|
||||
<List.Item extra={<span className="badge">{prettySize(size)}</span>}>{name}</List.Item>
|
||||
)}
|
||||
@@ -46,7 +52,9 @@ export function DatabaseMetrics({ info }) {
|
||||
);
|
||||
}
|
||||
|
||||
export function Queues({ info }) {
|
||||
export function Queues({
|
||||
info
|
||||
}: any) {
|
||||
info = toPairs(info);
|
||||
return (
|
||||
<Card title="Queues" size="small">
|
||||
@@ -56,6 +64,7 @@ export function Queues({ info }) {
|
||||
size="small"
|
||||
itemLayout="vertical"
|
||||
dataSource={info}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '([name, queue]: [any, any]) => Element' is n... Remove this comment to see the full error message
|
||||
renderItem={([name, queue]) => (
|
||||
<List.Item extra={<span className="badge">{queue.size}</span>}>{name}</List.Item>
|
||||
)}
|
||||
@@ -65,7 +74,9 @@ export function Queues({ info }) {
|
||||
);
|
||||
}
|
||||
|
||||
export function Manager({ info }) {
|
||||
export function Manager({
|
||||
info
|
||||
}: any) {
|
||||
const items = info
|
||||
? [
|
||||
<List.Item
|
||||
@@ -1,15 +1,23 @@
|
||||
import { map, includes, groupBy, first, find } from "lodash";
|
||||
import React, { useState, useMemo, useCallback } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import Select from "antd/lib/select";
|
||||
import Modal from "antd/lib/modal";
|
||||
// @ts-expect-error ts-migrate(6133) FIXME: 'DialogPropType' is declared but its value is neve... Remove this comment to see the full error message
|
||||
import { wrap as wrapDialog, DialogPropType } from "@/components/DialogWrapper";
|
||||
import { MappingType, ParameterMappingListInput } from "@/components/ParameterMappingInput";
|
||||
import QuerySelector from "@/components/QuerySelector";
|
||||
import notification from "@/services/notification";
|
||||
import { Query } from "@/services/query";
|
||||
|
||||
function VisualizationSelect({ query, visualization, onChange }) {
|
||||
type OwnVisualizationSelectProps = {
|
||||
query?: any;
|
||||
visualization?: any;
|
||||
onChange?: (...args: any[]) => any;
|
||||
};
|
||||
|
||||
type VisualizationSelectProps = OwnVisualizationSelectProps & typeof VisualizationSelect.defaultProps;
|
||||
|
||||
function VisualizationSelect({ query, visualization, onChange }: VisualizationSelectProps) {
|
||||
const visualizationGroups = useMemo(() => {
|
||||
return query ? groupBy(query.visualizations, "type") : {};
|
||||
}, [query]);
|
||||
@@ -50,19 +58,19 @@ function VisualizationSelect({ query, visualization, onChange }) {
|
||||
);
|
||||
}
|
||||
|
||||
VisualizationSelect.propTypes = {
|
||||
query: PropTypes.object,
|
||||
visualization: PropTypes.object,
|
||||
onChange: PropTypes.func,
|
||||
};
|
||||
|
||||
VisualizationSelect.defaultProps = {
|
||||
query: null,
|
||||
visualization: null,
|
||||
onChange: () => {},
|
||||
};
|
||||
|
||||
function AddWidgetDialog({ dialog, dashboard }) {
|
||||
type AddWidgetDialogProps = {
|
||||
// @ts-expect-error ts-migrate(2749) FIXME: 'DialogPropType' refers to a value, but is being u... Remove this comment to see the full error message
|
||||
dialog: DialogPropType;
|
||||
dashboard: any;
|
||||
};
|
||||
|
||||
function AddWidgetDialog({ dialog, dashboard }: AddWidgetDialogProps) {
|
||||
const [selectedQuery, setSelectedQuery] = useState(null);
|
||||
const [selectedVisualization, setSelectedVisualization] = useState(null);
|
||||
const [parameterMappings, setParameterMappings] = useState([]);
|
||||
@@ -75,11 +83,13 @@ function AddWidgetDialog({ dialog, dashboard }) {
|
||||
setParameterMappings([]);
|
||||
|
||||
if (queryId) {
|
||||
Query.get({ id: queryId }).then(query => {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'get' does not exist on type 'typeof Quer... Remove this comment to see the full error message
|
||||
Query.get({ id: queryId }).then((query: any) => {
|
||||
if (query) {
|
||||
const existingParamNames = map(dashboard.getParametersDefs(), param => param.name);
|
||||
setSelectedQuery(query);
|
||||
setParameterMappings(
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type '{ name: any; type: string; mapTo... Remove this comment to see the full error message
|
||||
map(query.getParametersDefs(), param => ({
|
||||
name: param.name,
|
||||
type: includes(existingParamNames, param.name)
|
||||
@@ -92,6 +102,7 @@ function AddWidgetDialog({ dialog, dashboard }) {
|
||||
}))
|
||||
);
|
||||
if (query.visualizations.length > 0) {
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type '((prevState: null) => null) | nu... Remove this comment to see the full error message
|
||||
setSelectedVisualization(first(query.visualizations));
|
||||
}
|
||||
}
|
||||
@@ -103,6 +114,7 @@ function AddWidgetDialog({ dialog, dashboard }) {
|
||||
|
||||
const saveWidget = useCallback(() => {
|
||||
dialog.close({ visualization: selectedVisualization, parameterMappings }).catch(() => {
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'string' is not assignable to par... Remove this comment to see the full error message
|
||||
notification.error("Widget could not be added");
|
||||
});
|
||||
}, [dialog, selectedVisualization, parameterMappings]);
|
||||
@@ -121,12 +133,14 @@ function AddWidgetDialog({ dialog, dashboard }) {
|
||||
okText="Add to Dashboard"
|
||||
width={700}>
|
||||
<div data-test="AddWidgetDialog">
|
||||
<QuerySelector onChange={query => selectQuery(query ? query.id : null)} />
|
||||
{/* @ts-expect-error ts-migrate(2322) FIXME: Type '(query: any) => void' is not assignable to t... Remove this comment to see the full error message */}
|
||||
<QuerySelector onChange={(query: any) => selectQuery(query ? query.id : null)} />
|
||||
|
||||
{selectedQuery && (
|
||||
<VisualizationSelect
|
||||
query={selectedQuery}
|
||||
visualization={selectedVisualization}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'Dispatch<SetStateAction<null>>' is not assig... Remove this comment to see the full error message
|
||||
onChange={setSelectedVisualization}
|
||||
/>
|
||||
)}
|
||||
@@ -140,6 +154,7 @@ function AddWidgetDialog({ dialog, dashboard }) {
|
||||
id="parameter-mappings"
|
||||
mappings={parameterMappings}
|
||||
existingParams={existingParams}
|
||||
// @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call.
|
||||
onChange={setParameterMappings}
|
||||
/>,
|
||||
]}
|
||||
@@ -148,9 +163,4 @@ function AddWidgetDialog({ dialog, dashboard }) {
|
||||
);
|
||||
}
|
||||
|
||||
AddWidgetDialog.propTypes = {
|
||||
dialog: DialogPropType.isRequired,
|
||||
dashboard: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default wrapDialog(AddWidgetDialog);
|
||||
@@ -19,17 +19,17 @@ export default class AutoHeightController {
|
||||
|
||||
onHeightChange = null;
|
||||
|
||||
constructor(handler) {
|
||||
constructor(handler: any) {
|
||||
this.onHeightChange = handler;
|
||||
}
|
||||
|
||||
update(widgets) {
|
||||
update(widgets: any) {
|
||||
const newWidgetIds = widgets
|
||||
.filter(widget => widget.options.position.autoHeight)
|
||||
.map(widget => widget.id.toString());
|
||||
.filter((widget: any) => widget.options.position.autoHeight)
|
||||
.map((widget: any) => widget.id.toString());
|
||||
|
||||
// added
|
||||
newWidgetIds.filter(id => !includes(Object.keys(this.widgets), id)).forEach(this.add);
|
||||
newWidgetIds.filter((id: any) => !includes(Object.keys(this.widgets), id)).forEach(this.add);
|
||||
|
||||
// removed
|
||||
Object.keys(this.widgets)
|
||||
@@ -37,12 +37,13 @@ export default class AutoHeightController {
|
||||
.forEach(this.remove);
|
||||
}
|
||||
|
||||
add = id => {
|
||||
add = (id: any) => {
|
||||
if (this.isEmpty()) {
|
||||
this.start();
|
||||
}
|
||||
|
||||
const selector = WIDGET_SELECTOR.replace("{0}", id);
|
||||
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||
this.widgets[id] = [
|
||||
function getHeight() {
|
||||
const widgetEl = document.querySelector(selector);
|
||||
@@ -66,13 +67,14 @@ export default class AutoHeightController {
|
||||
];
|
||||
};
|
||||
|
||||
remove = id => {
|
||||
remove = (id: any) => {
|
||||
// ignore if not an active autoHeight widget
|
||||
if (!this.exists(id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// not actually deleting from this.widgets to prevent case of unwanted re-adding
|
||||
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||
this.widgets[id.toString()] = false;
|
||||
|
||||
if (this.isEmpty()) {
|
||||
@@ -80,7 +82,8 @@ export default class AutoHeightController {
|
||||
}
|
||||
};
|
||||
|
||||
exists = id => !!this.widgets[id.toString()];
|
||||
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||
exists = (id: any) => !!this.widgets[id.toString()];
|
||||
|
||||
isEmpty = () => !some(this.widgets);
|
||||
|
||||
@@ -88,10 +91,13 @@ export default class AutoHeightController {
|
||||
Object.keys(this.widgets)
|
||||
.filter(this.exists) // reject already removed items
|
||||
.forEach(id => {
|
||||
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||
const [getHeight, prevHeight] = this.widgets[id];
|
||||
const height = getHeight();
|
||||
if (height && height !== prevHeight) {
|
||||
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||
this.widgets[id][1] = height; // save
|
||||
// @ts-expect-error ts-migrate(2721) FIXME: Cannot invoke an object which is possibly 'null'.
|
||||
this.onHeightChange(id, height); // dispatch
|
||||
}
|
||||
});
|
||||
@@ -99,10 +105,12 @@ export default class AutoHeightController {
|
||||
|
||||
start = () => {
|
||||
this.stop();
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'number' is not assignable to type 'null'.
|
||||
this.interval = setInterval(this.checkHeightChanges, INTERVAL);
|
||||
};
|
||||
|
||||
stop = () => {
|
||||
// @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call.
|
||||
clearInterval(this.interval);
|
||||
};
|
||||
|
||||
@@ -114,6 +122,7 @@ export default class AutoHeightController {
|
||||
|
||||
destroy = () => {
|
||||
this.stop();
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'null' is not assignable to type '{}'.
|
||||
this.widgets = null;
|
||||
};
|
||||
}
|
||||
@@ -3,19 +3,25 @@ import React, { useState } from "react";
|
||||
import Modal from "antd/lib/modal";
|
||||
import Input from "antd/lib/input";
|
||||
import DynamicComponent from "@/components/DynamicComponent";
|
||||
// @ts-expect-error ts-migrate(6133) FIXME: 'DialogPropType' is declared but its value is neve... Remove this comment to see the full error message
|
||||
import { wrap as wrapDialog, DialogPropType } from "@/components/DialogWrapper";
|
||||
import navigateTo from "@/components/ApplicationArea/navigateTo";
|
||||
import recordEvent from "@/services/recordEvent";
|
||||
import { policy } from "@/services/policy";
|
||||
import { Dashboard } from "@/services/dashboard";
|
||||
|
||||
function CreateDashboardDialog({ dialog }) {
|
||||
type Props = {
|
||||
// @ts-expect-error ts-migrate(2749) FIXME: 'DialogPropType' refers to a value, but is being u... Remove this comment to see the full error message
|
||||
dialog: DialogPropType;
|
||||
};
|
||||
|
||||
function CreateDashboardDialog({ dialog }: Props) {
|
||||
const [name, setName] = useState("");
|
||||
const [isValid, setIsValid] = useState(false);
|
||||
const [saveInProgress, setSaveInProgress] = useState(false);
|
||||
const isCreateDashboardEnabled = policy.isCreateDashboardEnabled();
|
||||
|
||||
function handleNameChange(event) {
|
||||
function handleNameChange(event: any) {
|
||||
const value = trim(event.target.value);
|
||||
setName(value);
|
||||
setIsValid(value !== "");
|
||||
@@ -25,10 +31,12 @@ function CreateDashboardDialog({ dialog }) {
|
||||
if (name !== "") {
|
||||
setSaveInProgress(true);
|
||||
|
||||
Dashboard.save({ name }).then(data => {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'save' does not exist on type 'typeof Das... Remove this comment to see the full error message
|
||||
Dashboard.save({ name }).then((data: any) => {
|
||||
dialog.close();
|
||||
navigateTo(`${data.url}?edit`);
|
||||
});
|
||||
// @ts-expect-error ts-migrate(2554) FIXME: Expected 4 arguments, but got 2.
|
||||
recordEvent("create", "dashboard");
|
||||
}
|
||||
}
|
||||
@@ -55,6 +63,7 @@ function CreateDashboardDialog({ dialog }) {
|
||||
"data-test": "CreateDashboardDialog",
|
||||
}}>
|
||||
<DynamicComponent name="CreateDashboardDialogExtra" disabled={!isCreateDashboardEnabled}>
|
||||
{/* @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call. */}
|
||||
<Input
|
||||
defaultValue={name}
|
||||
onChange={handleNameChange}
|
||||
@@ -68,8 +77,4 @@ function CreateDashboardDialog({ dialog }) {
|
||||
);
|
||||
}
|
||||
|
||||
CreateDashboardDialog.propTypes = {
|
||||
dialog: DialogPropType.isRequired,
|
||||
};
|
||||
|
||||
export default wrapDialog(CreateDashboardDialog);
|
||||
@@ -4,6 +4,7 @@ import { chain, cloneDeep, find } from "lodash";
|
||||
import cx from "classnames";
|
||||
import { Responsive, WidthProvider } from "react-grid-layout";
|
||||
import { VisualizationWidget, TextboxWidget, RestrictedWidget } from "@/components/dashboards/dashboard-widget";
|
||||
// @ts-expect-error ts-migrate(6133) FIXME: 'FiltersType' is declared but its value is never r... Remove this comment to see the full error message
|
||||
import { FiltersType } from "@/components/Filters";
|
||||
import cfg from "@/config/dashboard-grid-options";
|
||||
import AutoHeightController from "./AutoHeightController";
|
||||
@@ -14,20 +15,36 @@ import "./dashboard-grid.less";
|
||||
|
||||
const ResponsiveGridLayout = WidthProvider(Responsive);
|
||||
|
||||
const WidgetType = PropTypes.shape({
|
||||
id: PropTypes.number.isRequired,
|
||||
options: PropTypes.shape({
|
||||
position: PropTypes.shape({
|
||||
col: PropTypes.number.isRequired,
|
||||
row: PropTypes.number.isRequired,
|
||||
sizeY: PropTypes.number.isRequired,
|
||||
minSizeY: PropTypes.number.isRequired,
|
||||
maxSizeY: PropTypes.number.isRequired,
|
||||
sizeX: PropTypes.number.isRequired,
|
||||
minSizeX: PropTypes.number.isRequired,
|
||||
maxSizeX: PropTypes.number.isRequired,
|
||||
type WidgetType = {
|
||||
id: number;
|
||||
options: {
|
||||
position: {
|
||||
col: number;
|
||||
row: number;
|
||||
sizeY: number;
|
||||
minSizeY: number;
|
||||
maxSizeY: number;
|
||||
sizeX: number;
|
||||
minSizeX: number;
|
||||
maxSizeX: number;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
const WidgetType: PropTypes.Requireable<WidgetType> = PropTypes.shape({
|
||||
id: PropTypes.number.isRequired,
|
||||
options: PropTypes.shape({
|
||||
position: PropTypes.shape({
|
||||
col: PropTypes.number.isRequired,
|
||||
row: PropTypes.number.isRequired,
|
||||
sizeY: PropTypes.number.isRequired,
|
||||
minSizeY: PropTypes.number.isRequired,
|
||||
maxSizeY: PropTypes.number.isRequired,
|
||||
sizeX: PropTypes.number.isRequired,
|
||||
minSizeX: PropTypes.number.isRequired,
|
||||
maxSizeX: PropTypes.number.isRequired,
|
||||
}).isRequired,
|
||||
}).isRequired,
|
||||
}).isRequired,
|
||||
});
|
||||
|
||||
const SINGLE = "single-column";
|
||||
@@ -35,15 +52,25 @@ const MULTI = "multi-column";
|
||||
|
||||
const DashboardWidget = React.memo(
|
||||
function DashboardWidget({
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'widget' does not exist on type '{ childr... Remove this comment to see the full error message
|
||||
widget,
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dashboard' does not exist on type '{ chi... Remove this comment to see the full error message
|
||||
dashboard,
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'onLoadWidget' does not exist on type '{ ... Remove this comment to see the full error message
|
||||
onLoadWidget,
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'onRefreshWidget' does not exist on type ... Remove this comment to see the full error message
|
||||
onRefreshWidget,
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'onRemoveWidget' does not exist on type '... Remove this comment to see the full error message
|
||||
onRemoveWidget,
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'onParameterMappingsChange' does not exis... Remove this comment to see the full error message
|
||||
onParameterMappingsChange,
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'canEdit' does not exist on type '{ child... Remove this comment to see the full error message
|
||||
canEdit,
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isPublic' does not exist on type '{ chil... Remove this comment to see the full error message
|
||||
isPublic,
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isLoading' does not exist on type '{ chi... Remove this comment to see the full error message
|
||||
isLoading,
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'filters' does not exist on type '{ child... Remove this comment to see the full error message
|
||||
filters,
|
||||
}) {
|
||||
const { type } = widget;
|
||||
@@ -68,32 +95,44 @@ const DashboardWidget = React.memo(
|
||||
);
|
||||
}
|
||||
if (type === WidgetTypeEnum.TEXTBOX) {
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '{ widget: any; canEdit: any; isPublic: any; ... Remove this comment to see the full error message
|
||||
return <TextboxWidget widget={widget} canEdit={canEdit} isPublic={isPublic} onDelete={onDelete} />;
|
||||
}
|
||||
return <RestrictedWidget widget={widget} />;
|
||||
},
|
||||
(prevProps, nextProps) =>
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'widget' does not exist on type 'Readonly... Remove this comment to see the full error message
|
||||
prevProps.widget === nextProps.widget &&
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'canEdit' does not exist on type 'Readonl... Remove this comment to see the full error message
|
||||
prevProps.canEdit === nextProps.canEdit &&
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isPublic' does not exist on type 'Readon... Remove this comment to see the full error message
|
||||
prevProps.isPublic === nextProps.isPublic &&
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'isLoading' does not exist on type 'Reado... Remove this comment to see the full error message
|
||||
prevProps.isLoading === nextProps.isLoading &&
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'filters' does not exist on type 'Readonl... Remove this comment to see the full error message
|
||||
prevProps.filters === nextProps.filters
|
||||
);
|
||||
|
||||
class DashboardGrid extends React.Component {
|
||||
static propTypes = {
|
||||
isEditing: PropTypes.bool.isRequired,
|
||||
isPublic: PropTypes.bool,
|
||||
dashboard: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
|
||||
widgets: PropTypes.arrayOf(WidgetType).isRequired,
|
||||
filters: FiltersType,
|
||||
onBreakpointChange: PropTypes.func,
|
||||
onLoadWidget: PropTypes.func,
|
||||
onRefreshWidget: PropTypes.func,
|
||||
onRemoveWidget: PropTypes.func,
|
||||
onLayoutChange: PropTypes.func,
|
||||
onParameterMappingsChange: PropTypes.func,
|
||||
};
|
||||
type OwnProps = {
|
||||
isEditing: boolean;
|
||||
isPublic?: boolean;
|
||||
dashboard: any;
|
||||
widgets: WidgetType[];
|
||||
// @ts-expect-error ts-migrate(2749) FIXME: 'FiltersType' refers to a value, but is being used... Remove this comment to see the full error message
|
||||
filters?: FiltersType;
|
||||
onBreakpointChange?: (...args: any[]) => any;
|
||||
onLoadWidget?: (...args: any[]) => any;
|
||||
onRefreshWidget?: (...args: any[]) => any;
|
||||
onRemoveWidget?: (...args: any[]) => any;
|
||||
onLayoutChange?: (...args: any[]) => any;
|
||||
onParameterMappingsChange?: (...args: any[]) => any;
|
||||
};
|
||||
|
||||
type State = any;
|
||||
|
||||
type Props = OwnProps & typeof DashboardGrid.defaultProps;
|
||||
|
||||
class DashboardGrid extends React.Component<Props, State> {
|
||||
|
||||
static defaultProps = {
|
||||
isPublic: false,
|
||||
@@ -106,7 +145,7 @@ class DashboardGrid extends React.Component {
|
||||
onParameterMappingsChange: () => {},
|
||||
};
|
||||
|
||||
static normalizeFrom(widget) {
|
||||
static normalizeFrom(widget: any) {
|
||||
const {
|
||||
id,
|
||||
options: { position: pos },
|
||||
@@ -129,7 +168,7 @@ class DashboardGrid extends React.Component {
|
||||
|
||||
autoHeightCtrl = null;
|
||||
|
||||
constructor(props) {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
@@ -138,7 +177,9 @@ class DashboardGrid extends React.Component {
|
||||
};
|
||||
|
||||
// init AutoHeightController
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'AutoHeightController' is not assignable to t... Remove this comment to see the full error message
|
||||
this.autoHeightCtrl = new AutoHeightController(this.onWidgetHeightUpdated);
|
||||
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||
this.autoHeightCtrl.update(this.props.widgets);
|
||||
}
|
||||
|
||||
@@ -153,14 +194,16 @@ class DashboardGrid extends React.Component {
|
||||
|
||||
componentDidUpdate() {
|
||||
// update, in case widgets added or removed
|
||||
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||
this.autoHeightCtrl.update(this.props.widgets);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||
this.autoHeightCtrl.destroy();
|
||||
}
|
||||
|
||||
onLayoutChange = (_, layouts) => {
|
||||
onLayoutChange = (_: any, layouts: any) => {
|
||||
// workaround for when dashboard starts at single mode and then multi is empty or carries single col data
|
||||
// fixes test dashboard_spec['shows widgets with full width']
|
||||
// TODO: open react-grid-layout issue
|
||||
@@ -170,6 +213,7 @@ class DashboardGrid extends React.Component {
|
||||
|
||||
// workaround for https://github.com/STRML/react-grid-layout/issues/889
|
||||
// remove next line when fix lands
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '"single-column" | "multi-column"' is not ass... Remove this comment to see the full error message
|
||||
this.mode = document.body.offsetWidth <= cfg.mobileBreakPoint ? SINGLE : MULTI;
|
||||
// end workaround
|
||||
|
||||
@@ -186,14 +230,16 @@ class DashboardGrid extends React.Component {
|
||||
this.props.onLayoutChange(normalized);
|
||||
};
|
||||
|
||||
onBreakpointChange = mode => {
|
||||
onBreakpointChange = (mode: any) => {
|
||||
this.mode = mode;
|
||||
this.props.onBreakpointChange(mode === SINGLE);
|
||||
};
|
||||
|
||||
// height updated by auto-height
|
||||
onWidgetHeightUpdated = (widgetId, newHeight) => {
|
||||
this.setState(({ layouts }) => {
|
||||
onWidgetHeightUpdated = (widgetId: any, newHeight: any) => {
|
||||
this.setState(({
|
||||
layouts
|
||||
}: any) => {
|
||||
const layout = cloneDeep(layouts[MULTI]); // must clone to allow react-grid-layout to compare prev/next state
|
||||
const item = find(layout, { i: widgetId.toString() });
|
||||
if (item) {
|
||||
@@ -206,20 +252,23 @@ class DashboardGrid extends React.Component {
|
||||
};
|
||||
|
||||
// height updated by manual resize
|
||||
onWidgetResize = (layout, oldItem, newItem) => {
|
||||
onWidgetResize = (layout: any, oldItem: any, newItem: any) => {
|
||||
if (oldItem.h !== newItem.h) {
|
||||
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||
this.autoHeightCtrl.remove(Number(newItem.i));
|
||||
}
|
||||
|
||||
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||
this.autoHeightCtrl.resume();
|
||||
};
|
||||
|
||||
normalizeTo = layout => ({
|
||||
normalizeTo = (layout: any) => ({
|
||||
col: layout.x,
|
||||
row: layout.y,
|
||||
sizeX: layout.w,
|
||||
sizeY: layout.h,
|
||||
autoHeight: this.autoHeightCtrl.exists(layout.i),
|
||||
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||
autoHeight: this.autoHeightCtrl.exists(layout.i)
|
||||
});
|
||||
|
||||
render() {
|
||||
@@ -245,6 +294,7 @@ class DashboardGrid extends React.Component {
|
||||
margin={[cfg.margins, cfg.margins]}
|
||||
isDraggable={this.props.isEditing}
|
||||
isResizable={this.props.isEditing}
|
||||
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||
onResizeStart={this.autoHeightCtrl.stop}
|
||||
onResizeStop={this.onWidgetResize}
|
||||
layouts={this.state.layouts}
|
||||
@@ -258,13 +308,16 @@ class DashboardGrid extends React.Component {
|
||||
data-widgetid={widget.id}
|
||||
data-test={`WidgetId${widget.id}`}
|
||||
className={cx("dashboard-widget-wrapper", {
|
||||
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||
"widget-auto-height-enabled": this.autoHeightCtrl.exists(widget.id),
|
||||
})}>
|
||||
<DashboardWidget
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '{ dashboard: any; widget: WidgetType; filter... Remove this comment to see the full error message
|
||||
dashboard={dashboard}
|
||||
widget={widget}
|
||||
filters={filters}
|
||||
isPublic={isPublic}
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'loading' does not exist on type 'WidgetT... Remove this comment to see the full error message
|
||||
isLoading={widget.loading}
|
||||
canEdit={dashboard.canEdit()}
|
||||
onLoadWidget={onLoadWidget}
|
||||
@@ -1,7 +1,7 @@
|
||||
import { isMatch, map, find, sortBy } from "lodash";
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import Modal from "antd/lib/modal";
|
||||
// @ts-expect-error ts-migrate(6133) FIXME: 'DialogPropType' is declared but its value is neve... Remove this comment to see the full error message
|
||||
import { wrap as wrapDialog, DialogPropType } from "@/components/DialogWrapper";
|
||||
import {
|
||||
MappingType,
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
} from "@/components/ParameterMappingInput";
|
||||
import notification from "@/services/notification";
|
||||
|
||||
export function getParamValuesSnapshot(mappings, dashboardParameters) {
|
||||
export function getParamValuesSnapshot(mappings: any, dashboardParameters: any) {
|
||||
return map(
|
||||
sortBy(mappings, m => m.name),
|
||||
m => {
|
||||
@@ -32,24 +32,30 @@ export function getParamValuesSnapshot(mappings, dashboardParameters) {
|
||||
);
|
||||
}
|
||||
|
||||
class EditParameterMappingsDialog extends React.Component {
|
||||
static propTypes = {
|
||||
dashboard: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
|
||||
widget: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
|
||||
dialog: DialogPropType.isRequired,
|
||||
};
|
||||
type Props = {
|
||||
dashboard: any;
|
||||
widget: any;
|
||||
// @ts-expect-error ts-migrate(2749) FIXME: 'DialogPropType' refers to a value, but is being u... Remove this comment to see the full error message
|
||||
dialog: DialogPropType;
|
||||
};
|
||||
|
||||
type State = any;
|
||||
|
||||
class EditParameterMappingsDialog extends React.Component<Props, State> {
|
||||
|
||||
originalParamValuesSnapshot = null;
|
||||
|
||||
constructor(props) {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
const parameterMappings = parameterMappingsToEditableMappings(
|
||||
props.widget.options.parameterMappings,
|
||||
props.widget.query.getParametersDefs(),
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'any[]' is not assignable to para... Remove this comment to see the full error message
|
||||
map(this.props.dashboard.getParametersDefs(), p => p.name)
|
||||
);
|
||||
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '(any[] | undefined)[]' is not assignable to ... Remove this comment to see the full error message
|
||||
this.originalParamValuesSnapshot = getParamValuesSnapshot(
|
||||
parameterMappings,
|
||||
this.props.dashboard.getParametersDefs()
|
||||
@@ -70,6 +76,7 @@ class EditParameterMappingsDialog extends React.Component {
|
||||
widget.options.parameterMappings = newMappings;
|
||||
|
||||
const valuesChanged = !isMatch(
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'null' is not assignable to param... Remove this comment to see the full error message
|
||||
this.originalParamValuesSnapshot,
|
||||
getParamValuesSnapshot(this.state.parameterMappings, this.props.dashboard.getParametersDefs())
|
||||
);
|
||||
@@ -84,6 +91,7 @@ class EditParameterMappingsDialog extends React.Component {
|
||||
this.props.dialog.close(valuesChanged);
|
||||
})
|
||||
.catch(() => {
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'string' is not assignable to par... Remove this comment to see the full error message
|
||||
notification.error("Widget cannot be updated");
|
||||
})
|
||||
.finally(() => {
|
||||
@@ -91,7 +99,7 @@ class EditParameterMappingsDialog extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
updateParamMappings(parameterMappings) {
|
||||
updateParamMappings(parameterMappings: any) {
|
||||
this.setState({ parameterMappings });
|
||||
}
|
||||
|
||||
@@ -108,7 +116,8 @@ class EditParameterMappingsDialog extends React.Component {
|
||||
<ParameterMappingListInput
|
||||
mappings={this.state.parameterMappings}
|
||||
existingParams={this.props.dashboard.getParametersDefs()}
|
||||
onChange={mappings => this.updateParamMappings(mappings)}
|
||||
// @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call.
|
||||
onChange={(mappings: any) => this.updateParamMappings(mappings)}
|
||||
/>
|
||||
)}
|
||||
</Modal>
|
||||
@@ -1,13 +1,24 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import Button from "antd/lib/button";
|
||||
import Modal from "antd/lib/modal";
|
||||
// @ts-expect-error ts-migrate(6133) FIXME: 'DialogPropType' is declared but its value is neve... Remove this comment to see the full error message
|
||||
import { wrap as wrapDialog, DialogPropType } from "@/components/DialogWrapper";
|
||||
// @ts-expect-error ts-migrate(6133) FIXME: 'FiltersType' is declared but its value is never r... Remove this comment to see the full error message
|
||||
import { FiltersType } from "@/components/Filters";
|
||||
import VisualizationRenderer from "@/components/visualizations/VisualizationRenderer";
|
||||
import VisualizationName from "@/components/visualizations/VisualizationName";
|
||||
|
||||
function ExpandedWidgetDialog({ dialog, widget, filters }) {
|
||||
type OwnProps = {
|
||||
// @ts-expect-error ts-migrate(2749) FIXME: 'DialogPropType' refers to a value, but is being u... Remove this comment to see the full error message
|
||||
dialog: DialogPropType;
|
||||
widget: any;
|
||||
// @ts-expect-error ts-migrate(2749) FIXME: 'FiltersType' refers to a value, but is being used... Remove this comment to see the full error message
|
||||
filters?: FiltersType;
|
||||
};
|
||||
|
||||
type Props = OwnProps & typeof ExpandedWidgetDialog.defaultProps;
|
||||
|
||||
function ExpandedWidgetDialog({ dialog, widget, filters }: Props) {
|
||||
return (
|
||||
<Modal
|
||||
{...dialog.props}
|
||||
@@ -28,12 +39,6 @@ function ExpandedWidgetDialog({ dialog, widget, filters }) {
|
||||
);
|
||||
}
|
||||
|
||||
ExpandedWidgetDialog.propTypes = {
|
||||
dialog: DialogPropType.isRequired,
|
||||
widget: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
|
||||
filters: FiltersType,
|
||||
};
|
||||
|
||||
ExpandedWidgetDialog.defaultProps = {
|
||||
filters: [],
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
import { toString } from "lodash";
|
||||
// @ts-expect-error ts-migrate(7016) FIXME: Could not find a declaration file for module 'mark... Remove this comment to see the full error message
|
||||
import { markdown } from "markdown";
|
||||
import React, { useState, useEffect, useCallback } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { useDebouncedCallback } from "use-debounce";
|
||||
import Modal from "antd/lib/modal";
|
||||
import Input from "antd/lib/input";
|
||||
@@ -9,12 +9,22 @@ import Tooltip from "antd/lib/tooltip";
|
||||
import Divider from "antd/lib/divider";
|
||||
import Link from "@/components/Link";
|
||||
import HtmlContent from "@redash/viz/lib/components/HtmlContent";
|
||||
// @ts-expect-error ts-migrate(6133) FIXME: 'DialogPropType' is declared but its value is neve... Remove this comment to see the full error message
|
||||
import { wrap as wrapDialog, DialogPropType } from "@/components/DialogWrapper";
|
||||
import notification from "@/services/notification";
|
||||
|
||||
import "./TextboxDialog.less";
|
||||
|
||||
function TextboxDialog({ dialog, isNew, ...props }) {
|
||||
type OwnProps = {
|
||||
// @ts-expect-error ts-migrate(2749) FIXME: 'DialogPropType' refers to a value, but is being u... Remove this comment to see the full error message
|
||||
dialog: DialogPropType;
|
||||
isNew?: boolean;
|
||||
text?: string;
|
||||
};
|
||||
|
||||
type Props = OwnProps & typeof TextboxDialog.defaultProps;
|
||||
|
||||
function TextboxDialog({ dialog, isNew, ...props }: Props) {
|
||||
const [text, setText] = useState(toString(props.text));
|
||||
const [preview, setPreview] = useState(null);
|
||||
|
||||
@@ -37,6 +47,7 @@ function TextboxDialog({ dialog, isNew, ...props }) {
|
||||
|
||||
const saveWidget = useCallback(() => {
|
||||
dialog.close(text).catch(() => {
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'string' is not assignable to par... Remove this comment to see the full error message
|
||||
notification.error(isNew ? "Widget could not be added" : "Widget could not be saved");
|
||||
});
|
||||
}, [dialog, isNew, text]);
|
||||
@@ -71,6 +82,7 @@ function TextboxDialog({ dialog, isNew, ...props }) {
|
||||
<div className="textbox-dialog">
|
||||
<Input.TextArea
|
||||
className="resize-vertical"
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'number | ... Remove this comment to see the full error message
|
||||
rows="5"
|
||||
value={text}
|
||||
onChange={handleInputChange}
|
||||
@@ -83,6 +95,7 @@ function TextboxDialog({ dialog, isNew, ...props }) {
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href="https://www.markdownguide.org/cheat-sheet/#basic-syntax">
|
||||
{/* @ts-expect-error ts-migrate(2747) FIXME: 'Tooltip' components don't accept text as child el... Remove this comment to see the full error message */}
|
||||
<Tooltip title="Markdown guide opens in new window">Markdown</Tooltip>
|
||||
</Link>
|
||||
.
|
||||
@@ -91,6 +104,7 @@ function TextboxDialog({ dialog, isNew, ...props }) {
|
||||
<React.Fragment>
|
||||
<Divider dashed />
|
||||
<strong className="preview-title">Preview:</strong>
|
||||
{/* @ts-expect-error ts-migrate(2322) FIXME: Type '{ children: null; className: string; }' is n... Remove this comment to see the full error message */}
|
||||
<HtmlContent className="preview markdown">{preview}</HtmlContent>
|
||||
</React.Fragment>
|
||||
)}
|
||||
@@ -99,12 +113,6 @@ function TextboxDialog({ dialog, isNew, ...props }) {
|
||||
);
|
||||
}
|
||||
|
||||
TextboxDialog.propTypes = {
|
||||
dialog: DialogPropType.isRequired,
|
||||
isNew: PropTypes.bool,
|
||||
text: PropTypes.string,
|
||||
};
|
||||
|
||||
TextboxDialog.defaultProps = {
|
||||
isNew: false,
|
||||
text: "",
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from "react";
|
||||
import Widget from "./Widget";
|
||||
|
||||
function RestrictedWidget(props) {
|
||||
function RestrictedWidget(props: any) {
|
||||
return (
|
||||
<Widget {...props} className="d-flex justify-content-center align-items-center widget-restricted">
|
||||
<div className="t-body scrollbox">
|
||||
@@ -1,19 +1,26 @@
|
||||
import React, { useState } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
// @ts-expect-error ts-migrate(7016) FIXME: Could not find a declaration file for module 'mark... Remove this comment to see the full error message
|
||||
import { markdown } from "markdown";
|
||||
import Menu from "antd/lib/menu";
|
||||
import HtmlContent from "@redash/viz/lib/components/HtmlContent";
|
||||
import TextboxDialog from "@/components/dashboards/TextboxDialog";
|
||||
import Widget from "./Widget";
|
||||
|
||||
function TextboxWidget(props) {
|
||||
type OwnProps = {
|
||||
widget: any;
|
||||
canEdit?: boolean;
|
||||
};
|
||||
|
||||
type Props = OwnProps & typeof TextboxWidget.defaultProps;
|
||||
|
||||
function TextboxWidget(props: Props) {
|
||||
const { widget, canEdit } = props;
|
||||
const [text, setText] = useState(widget.text);
|
||||
|
||||
const editTextBox = () => {
|
||||
TextboxDialog.showModal({
|
||||
text: widget.text,
|
||||
}).onClose(newText => {
|
||||
}).onClose((newText: any) => {
|
||||
widget.text = newText;
|
||||
setText(newText);
|
||||
return widget.save();
|
||||
@@ -31,17 +38,14 @@ function TextboxWidget(props) {
|
||||
}
|
||||
|
||||
return (
|
||||
// @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call.
|
||||
<Widget {...props} menuOptions={canEdit ? TextboxMenuOptions : null} className="widget-text">
|
||||
{/* @ts-expect-error ts-migrate(2322) FIXME: Type '{ children: any; className: string; }' is no... Remove this comment to see the full error message */}
|
||||
<HtmlContent className="body-row-auto scrollbox t-body p-15 markdown">{markdown.toHTML(text || "")}</HtmlContent>
|
||||
</Widget>
|
||||
);
|
||||
}
|
||||
|
||||
TextboxWidget.propTypes = {
|
||||
widget: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
|
||||
canEdit: PropTypes.bool,
|
||||
};
|
||||
|
||||
TextboxWidget.defaultProps = {
|
||||
canEdit: false,
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useState } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { compact, isEmpty, invoke } from "lodash";
|
||||
// @ts-expect-error ts-migrate(7016) FIXME: Could not find a declaration file for module 'mark... Remove this comment to see the full error message
|
||||
import { markdown } from "markdown";
|
||||
import cx from "classnames";
|
||||
import Menu from "antd/lib/menu";
|
||||
@@ -12,22 +12,28 @@ import Link from "@/components/Link";
|
||||
import Parameters from "@/components/Parameters";
|
||||
import TimeAgo from "@/components/TimeAgo";
|
||||
import Timer from "@/components/Timer";
|
||||
// @ts-expect-error ts-migrate(6133) FIXME: 'Moment' is declared but its value is never read.
|
||||
import { Moment } from "@/components/proptypes";
|
||||
import QueryLink from "@/components/QueryLink";
|
||||
// @ts-expect-error ts-migrate(6133) FIXME: 'FiltersType' is declared but its value is never r... Remove this comment to see the full error message
|
||||
import { FiltersType } from "@/components/Filters";
|
||||
import ExpandedWidgetDialog from "@/components/dashboards/ExpandedWidgetDialog";
|
||||
import EditParameterMappingsDialog from "@/components/dashboards/EditParameterMappingsDialog";
|
||||
import VisualizationRenderer from "@/components/visualizations/VisualizationRenderer";
|
||||
import Widget from "./Widget";
|
||||
|
||||
function visualizationWidgetMenuOptions({ widget, canEditDashboard, onParametersEdit }) {
|
||||
function visualizationWidgetMenuOptions({
|
||||
widget,
|
||||
canEditDashboard,
|
||||
onParametersEdit
|
||||
}: any) {
|
||||
const canViewQuery = currentUser.hasPermission("view_query");
|
||||
const canEditParameters = canEditDashboard && !isEmpty(invoke(widget, "query.getParametersDefs"));
|
||||
const widgetQueryResult = widget.getQueryResult();
|
||||
const isQueryResultEmpty = !widgetQueryResult || !widgetQueryResult.isEmpty || widgetQueryResult.isEmpty();
|
||||
|
||||
const downloadLink = fileType => widgetQueryResult.getLink(widget.getQuery().id, fileType);
|
||||
const downloadName = fileType => widgetQueryResult.getName(widget.getQuery().name, fileType);
|
||||
const downloadLink = (fileType: any) => widgetQueryResult.getLink(widget.getQuery().id, fileType);
|
||||
const downloadName = (fileType: any) => widgetQueryResult.getName(widget.getQuery().name, fileType);
|
||||
return compact([
|
||||
<Menu.Item key="download_csv" disabled={isQueryResultEmpty}>
|
||||
{!isQueryResultEmpty ? (
|
||||
@@ -70,7 +76,14 @@ function visualizationWidgetMenuOptions({ widget, canEditDashboard, onParameters
|
||||
]);
|
||||
}
|
||||
|
||||
function RefreshIndicator({ refreshStartedAt }) {
|
||||
type OwnRefreshIndicatorProps = {
|
||||
// @ts-expect-error ts-migrate(2749) FIXME: 'Moment' refers to a value, but is being used as a... Remove this comment to see the full error message
|
||||
refreshStartedAt?: Moment;
|
||||
};
|
||||
|
||||
type RefreshIndicatorProps = OwnRefreshIndicatorProps & typeof RefreshIndicator.defaultProps;
|
||||
|
||||
function RefreshIndicator({ refreshStartedAt }: RefreshIndicatorProps) {
|
||||
return (
|
||||
<div className="refresh-indicator">
|
||||
<div className="refresh-icon">
|
||||
@@ -80,11 +93,19 @@ function RefreshIndicator({ refreshStartedAt }) {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
RefreshIndicator.propTypes = { refreshStartedAt: Moment };
|
||||
RefreshIndicator.defaultProps = { refreshStartedAt: null };
|
||||
|
||||
function VisualizationWidgetHeader({ widget, refreshStartedAt, parameters, onParametersUpdate }) {
|
||||
type OwnVisualizationWidgetHeaderProps = {
|
||||
widget: any;
|
||||
// @ts-expect-error ts-migrate(2749) FIXME: 'Moment' refers to a value, but is being used as a... Remove this comment to see the full error message
|
||||
refreshStartedAt?: Moment;
|
||||
parameters?: any[];
|
||||
onParametersUpdate?: (...args: any[]) => any;
|
||||
};
|
||||
|
||||
type VisualizationWidgetHeaderProps = OwnVisualizationWidgetHeaderProps & typeof VisualizationWidgetHeader.defaultProps;
|
||||
|
||||
function VisualizationWidgetHeader({ widget, refreshStartedAt, parameters, onParametersUpdate }: VisualizationWidgetHeaderProps) {
|
||||
const canViewQuery = currentUser.hasPermission("view_query");
|
||||
|
||||
return (
|
||||
@@ -93,9 +114,11 @@ function VisualizationWidgetHeader({ widget, refreshStartedAt, parameters, onPar
|
||||
<div className="t-header widget clearfix">
|
||||
<div className="th-title">
|
||||
<p>
|
||||
{/* @ts-expect-error ts-migrate(2322) FIXME: Type 'any' is not assignable to type 'never'. */}
|
||||
<QueryLink query={widget.getQuery()} visualization={widget.visualization} readOnly={!canViewQuery} />
|
||||
</p>
|
||||
{!isEmpty(widget.getQuery().description) && (
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '{ children: any; className: string; }' is no... Remove this comment to see the full error message
|
||||
<HtmlContent className="text-muted markdown query--description">
|
||||
{markdown.toHTML(widget.getQuery().description || "")}
|
||||
</HtmlContent>
|
||||
@@ -111,27 +134,30 @@ function VisualizationWidgetHeader({ widget, refreshStartedAt, parameters, onPar
|
||||
);
|
||||
}
|
||||
|
||||
VisualizationWidgetHeader.propTypes = {
|
||||
widget: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
|
||||
refreshStartedAt: Moment,
|
||||
parameters: PropTypes.arrayOf(PropTypes.object),
|
||||
onParametersUpdate: PropTypes.func,
|
||||
};
|
||||
|
||||
VisualizationWidgetHeader.defaultProps = {
|
||||
refreshStartedAt: null,
|
||||
onParametersUpdate: () => {},
|
||||
parameters: [],
|
||||
};
|
||||
|
||||
function VisualizationWidgetFooter({ widget, isPublic, onRefresh, onExpand }) {
|
||||
type OwnVisualizationWidgetFooterProps = {
|
||||
widget: any;
|
||||
isPublic?: boolean;
|
||||
onRefresh: (...args: any[]) => any;
|
||||
onExpand: (...args: any[]) => any;
|
||||
};
|
||||
|
||||
type VisualizationWidgetFooterProps = OwnVisualizationWidgetFooterProps & typeof VisualizationWidgetFooter.defaultProps;
|
||||
|
||||
function VisualizationWidgetFooter({ widget, isPublic, onRefresh, onExpand }: VisualizationWidgetFooterProps) {
|
||||
const widgetQueryResult = widget.getQueryResult();
|
||||
const updatedAt = invoke(widgetQueryResult, "getUpdatedAt");
|
||||
const [refreshClickButtonId, setRefreshClickButtonId] = useState();
|
||||
|
||||
const refreshWidget = buttonId => {
|
||||
const refreshWidget = (buttonId: any) => {
|
||||
if (!refreshClickButtonId) {
|
||||
setRefreshClickButtonId(buttonId);
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'null' is not assignable to param... Remove this comment to see the full error message
|
||||
onRefresh().finally(() => setRefreshClickButtonId(null));
|
||||
}
|
||||
};
|
||||
@@ -173,28 +199,27 @@ function VisualizationWidgetFooter({ widget, isPublic, onRefresh, onExpand }) {
|
||||
) : null;
|
||||
}
|
||||
|
||||
VisualizationWidgetFooter.propTypes = {
|
||||
widget: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
|
||||
isPublic: PropTypes.bool,
|
||||
onRefresh: PropTypes.func.isRequired,
|
||||
onExpand: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
VisualizationWidgetFooter.defaultProps = { isPublic: false };
|
||||
|
||||
class VisualizationWidget extends React.Component {
|
||||
static propTypes = {
|
||||
widget: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
|
||||
dashboard: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
|
||||
filters: FiltersType,
|
||||
isPublic: PropTypes.bool,
|
||||
isLoading: PropTypes.bool,
|
||||
canEdit: PropTypes.bool,
|
||||
onLoad: PropTypes.func,
|
||||
onRefresh: PropTypes.func,
|
||||
onDelete: PropTypes.func,
|
||||
onParameterMappingsChange: PropTypes.func,
|
||||
};
|
||||
type OwnVisualizationWidgetProps = {
|
||||
widget: any;
|
||||
dashboard: any;
|
||||
// @ts-expect-error ts-migrate(2749) FIXME: 'FiltersType' refers to a value, but is being used... Remove this comment to see the full error message
|
||||
filters?: FiltersType;
|
||||
isPublic?: boolean;
|
||||
isLoading?: boolean;
|
||||
canEdit?: boolean;
|
||||
onLoad?: (...args: any[]) => any;
|
||||
onRefresh?: (...args: any[]) => any;
|
||||
onDelete?: (...args: any[]) => any;
|
||||
onParameterMappingsChange?: (...args: any[]) => any;
|
||||
};
|
||||
|
||||
type VisualizationWidgetState = any;
|
||||
|
||||
type VisualizationWidgetProps = OwnVisualizationWidgetProps & typeof VisualizationWidget.defaultProps;
|
||||
|
||||
class VisualizationWidget extends React.Component<VisualizationWidgetProps, VisualizationWidgetState> {
|
||||
|
||||
static defaultProps = {
|
||||
filters: [],
|
||||
@@ -207,7 +232,7 @@ class VisualizationWidget extends React.Component {
|
||||
onParameterMappingsChange: () => {},
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
constructor(props: VisualizationWidgetProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
localParameters: props.widget.getLocalParameters(),
|
||||
@@ -222,7 +247,7 @@ class VisualizationWidget extends React.Component {
|
||||
onLoad();
|
||||
}
|
||||
|
||||
onLocalFiltersChange = localFilters => {
|
||||
onLocalFiltersChange = (localFilters: any) => {
|
||||
this.setState({ localFilters });
|
||||
};
|
||||
|
||||
@@ -235,7 +260,7 @@ class VisualizationWidget extends React.Component {
|
||||
EditParameterMappingsDialog.showModal({
|
||||
dashboard,
|
||||
widget,
|
||||
}).onClose(valuesChanged => {
|
||||
}).onClose((valuesChanged: any) => {
|
||||
// refresh widget if any parameter value has been updated
|
||||
if (valuesChanged) {
|
||||
onRefresh();
|
||||
@@ -267,6 +292,7 @@ class VisualizationWidget extends React.Component {
|
||||
visualization={widget.visualization}
|
||||
queryResult={widgetQueryResult}
|
||||
filters={filters}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '(localFilters: any) => void' is not assignab... Remove this comment to see the full error message
|
||||
onFiltersChange={this.onLocalFiltersChange}
|
||||
context="widget"
|
||||
/>
|
||||
@@ -290,6 +316,7 @@ class VisualizationWidget extends React.Component {
|
||||
const isRefreshing = isLoading && !!(widgetQueryResult && widgetQueryResult.getStatus());
|
||||
|
||||
return (
|
||||
// @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call.
|
||||
<Widget
|
||||
{...this.props}
|
||||
className="widget-visualization"
|
||||
@@ -1,16 +1,24 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import cx from "classnames";
|
||||
import { isEmpty } from "lodash";
|
||||
import Dropdown from "antd/lib/dropdown";
|
||||
import Modal from "antd/lib/modal";
|
||||
import Menu from "antd/lib/menu";
|
||||
import recordEvent from "@/services/recordEvent";
|
||||
// @ts-expect-error ts-migrate(6133) FIXME: 'Moment' is declared but its value is never read.
|
||||
import { Moment } from "@/components/proptypes";
|
||||
|
||||
import "./Widget.less";
|
||||
|
||||
function WidgetDropdownButton({ extraOptions, showDeleteOption, onDelete }) {
|
||||
type OwnWidgetDropdownButtonProps = {
|
||||
extraOptions?: React.ReactNode;
|
||||
showDeleteOption?: boolean;
|
||||
onDelete?: (...args: any[]) => any;
|
||||
};
|
||||
|
||||
type WidgetDropdownButtonProps = OwnWidgetDropdownButtonProps & typeof WidgetDropdownButton.defaultProps;
|
||||
|
||||
function WidgetDropdownButton({ extraOptions, showDeleteOption, onDelete }: WidgetDropdownButtonProps) {
|
||||
const WidgetMenu = (
|
||||
<Menu data-test="WidgetDropdownButtonMenu">
|
||||
{extraOptions}
|
||||
@@ -30,19 +38,19 @@ function WidgetDropdownButton({ extraOptions, showDeleteOption, onDelete }) {
|
||||
);
|
||||
}
|
||||
|
||||
WidgetDropdownButton.propTypes = {
|
||||
extraOptions: PropTypes.node,
|
||||
showDeleteOption: PropTypes.bool,
|
||||
onDelete: PropTypes.func,
|
||||
};
|
||||
|
||||
WidgetDropdownButton.defaultProps = {
|
||||
extraOptions: null,
|
||||
showDeleteOption: false,
|
||||
onDelete: () => {},
|
||||
};
|
||||
|
||||
function WidgetDeleteButton({ onClick }) {
|
||||
type OwnWidgetDeleteButtonProps = {
|
||||
onClick?: (...args: any[]) => any;
|
||||
};
|
||||
|
||||
type WidgetDeleteButtonProps = OwnWidgetDeleteButtonProps & typeof WidgetDeleteButton.defaultProps;
|
||||
|
||||
function WidgetDeleteButton({ onClick }: WidgetDeleteButtonProps) {
|
||||
return (
|
||||
<div className="widget-menu-remove">
|
||||
<a className="action" title="Remove From Dashboard" onClick={onClick} data-test="WidgetDeleteButton">
|
||||
@@ -51,24 +59,25 @@ function WidgetDeleteButton({ onClick }) {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
WidgetDeleteButton.propTypes = { onClick: PropTypes.func };
|
||||
WidgetDeleteButton.defaultProps = { onClick: () => {} };
|
||||
|
||||
class Widget extends React.Component {
|
||||
static propTypes = {
|
||||
widget: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
|
||||
className: PropTypes.string,
|
||||
children: PropTypes.node,
|
||||
header: PropTypes.node,
|
||||
footer: PropTypes.node,
|
||||
canEdit: PropTypes.bool,
|
||||
isPublic: PropTypes.bool,
|
||||
refreshStartedAt: Moment,
|
||||
menuOptions: PropTypes.node,
|
||||
tileProps: PropTypes.object, // eslint-disable-line react/forbid-prop-types
|
||||
onDelete: PropTypes.func,
|
||||
};
|
||||
type OwnWidgetProps = {
|
||||
widget: any;
|
||||
className?: string;
|
||||
header?: React.ReactNode;
|
||||
footer?: React.ReactNode;
|
||||
canEdit?: boolean;
|
||||
isPublic?: boolean;
|
||||
// @ts-expect-error ts-migrate(2749) FIXME: 'Moment' refers to a value, but is being used as a... Remove this comment to see the full error message
|
||||
refreshStartedAt?: Moment;
|
||||
menuOptions?: React.ReactNode;
|
||||
tileProps?: any;
|
||||
onDelete?: (...args: any[]) => any;
|
||||
};
|
||||
|
||||
type WidgetProps = OwnWidgetProps & typeof Widget.defaultProps;
|
||||
|
||||
class Widget extends React.Component<WidgetProps> {
|
||||
|
||||
static defaultProps = {
|
||||
className: "",
|
||||
@@ -85,6 +94,7 @@ class Widget extends React.Component {
|
||||
|
||||
componentDidMount() {
|
||||
const { widget } = this.props;
|
||||
// @ts-expect-error ts-migrate(2554) FIXME: Expected 4 arguments, but got 3.
|
||||
recordEvent("view", "widget", widget.id);
|
||||
}
|
||||
|
||||
@@ -12,19 +12,37 @@ import helper from "./dynamicFormHelper";
|
||||
|
||||
import "./DynamicForm.less";
|
||||
|
||||
const ActionType = PropTypes.shape({
|
||||
name: PropTypes.string.isRequired,
|
||||
callback: PropTypes.func.isRequired,
|
||||
type: PropTypes.string,
|
||||
pullRight: PropTypes.bool,
|
||||
disabledWhenDirty: PropTypes.bool,
|
||||
type ActionType = {
|
||||
name: string;
|
||||
callback: (...args: any[]) => any;
|
||||
type?: string;
|
||||
pullRight?: boolean;
|
||||
disabledWhenDirty?: boolean;
|
||||
};
|
||||
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'Requireable<InferProps<{ name: Validator<str... Remove this comment to see the full error message
|
||||
const ActionType: PropTypes.Requireable<ActionType> = PropTypes.shape({
|
||||
name: PropTypes.string.isRequired,
|
||||
callback: PropTypes.func.isRequired,
|
||||
type: PropTypes.string,
|
||||
pullRight: PropTypes.bool,
|
||||
disabledWhenDirty: PropTypes.bool,
|
||||
});
|
||||
|
||||
const AntdFormType = PropTypes.shape({
|
||||
validateFieldsAndScroll: PropTypes.func,
|
||||
type AntdFormType = {
|
||||
validateFieldsAndScroll?: (...args: any[]) => any;
|
||||
};
|
||||
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'Requireable<InferProps<{ validateFieldsAndSc... Remove this comment to see the full error message
|
||||
const AntdFormType: PropTypes.Requireable<AntdFormType> = PropTypes.shape({
|
||||
validateFieldsAndScroll: PropTypes.func,
|
||||
});
|
||||
|
||||
const fieldRules = ({ type, required, minLength }) => {
|
||||
const fieldRules = ({
|
||||
type,
|
||||
required,
|
||||
minLength
|
||||
}: any) => {
|
||||
const requiredRule = required;
|
||||
const minLengthRule = minLength && includes(["text", "email", "password"], type);
|
||||
const emailTypeRule = type === "email";
|
||||
@@ -36,7 +54,7 @@ const fieldRules = ({ type, required, minLength }) => {
|
||||
].filter(rule => rule);
|
||||
};
|
||||
|
||||
function normalizeEmptyValuesToNull(fields, values) {
|
||||
function normalizeEmptyValuesToNull(fields: any, values: any) {
|
||||
return mapValues(values, (value, key) => {
|
||||
const { initialValue } = find(fields, { name: key }) || {};
|
||||
if ((initialValue === null || initialValue === undefined || initialValue === "") && value === "") {
|
||||
@@ -46,7 +64,15 @@ function normalizeEmptyValuesToNull(fields, values) {
|
||||
});
|
||||
}
|
||||
|
||||
function DynamicFormFields({ fields, feedbackIcons, form }) {
|
||||
type OwnDynamicFormFieldsProps = {
|
||||
fields?: FieldType[];
|
||||
feedbackIcons?: boolean;
|
||||
form: AntdFormType;
|
||||
};
|
||||
|
||||
type DynamicFormFieldsProps = OwnDynamicFormFieldsProps & typeof DynamicFormFields.defaultProps;
|
||||
|
||||
function DynamicFormFields({ fields, feedbackIcons, form }: DynamicFormFieldsProps) {
|
||||
return fields.map(field => {
|
||||
const { name, type, initialValue, contentAfter } = field;
|
||||
const fieldLabel = getFieldLabel(field);
|
||||
@@ -63,9 +89,11 @@ function DynamicFormFields({ fields, feedbackIcons, form }) {
|
||||
|
||||
if (type === "file") {
|
||||
formItemProps.valuePropName = "data-value";
|
||||
formItemProps.getValueFromEvent = e => {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'getValueFromEvent' does not exist on typ... Remove this comment to see the full error message
|
||||
formItemProps.getValueFromEvent = (e: any) => {
|
||||
if (e && e.fileList[0]) {
|
||||
helper.getBase64(e.file).then(value => {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'setFieldsValue' does not exist on type '... Remove this comment to see the full error message
|
||||
form.setFieldsValue({ [name]: value });
|
||||
});
|
||||
}
|
||||
@@ -76,26 +104,22 @@ function DynamicFormFields({ fields, feedbackIcons, form }) {
|
||||
return (
|
||||
<React.Fragment key={name}>
|
||||
<Form.Item {...formItemProps}>
|
||||
{/* @ts-expect-error ts-migrate(2322) FIXME: Type '{ field: FieldType; form: AntdFormType; }' i... Remove this comment to see the full error message */}
|
||||
<DynamicFormField field={field} form={form} />
|
||||
</Form.Item>
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'getFieldValue' does not exist on type 'A... Remove this comment to see the full error message */}
|
||||
{isFunction(contentAfter) ? contentAfter(form.getFieldValue(name)) : contentAfter}
|
||||
</React.Fragment>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
DynamicFormFields.propTypes = {
|
||||
fields: PropTypes.arrayOf(FieldType),
|
||||
feedbackIcons: PropTypes.bool,
|
||||
form: AntdFormType.isRequired,
|
||||
};
|
||||
|
||||
DynamicFormFields.defaultProps = {
|
||||
fields: [],
|
||||
feedbackIcons: false,
|
||||
};
|
||||
|
||||
const reducerForActionSet = (state, action) => {
|
||||
const reducerForActionSet = (state: any, action: any) => {
|
||||
if (action.inProgress) {
|
||||
state.add(action.actionName);
|
||||
} else {
|
||||
@@ -104,7 +128,14 @@ const reducerForActionSet = (state, action) => {
|
||||
return new Set(state);
|
||||
};
|
||||
|
||||
function DynamicFormActions({ actions, isFormDirty }) {
|
||||
type OwnDynamicFormActionsProps = {
|
||||
actions?: ActionType[];
|
||||
isFormDirty?: boolean;
|
||||
};
|
||||
|
||||
type DynamicFormActionsProps = OwnDynamicFormActionsProps & typeof DynamicFormActions.defaultProps;
|
||||
|
||||
function DynamicFormActions({ actions, isFormDirty }: DynamicFormActionsProps) {
|
||||
const [inProgressActions, setActionInProgress] = useReducer(reducerForActionSet, new Set());
|
||||
|
||||
const handleAction = useCallback(action => {
|
||||
@@ -121,7 +152,9 @@ function DynamicFormActions({ actions, isFormDirty }) {
|
||||
key={action.name}
|
||||
htmlType="button"
|
||||
className={cx("m-t-10", { "pull-right": action.pullRight })}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string | undefined' is not assignable to typ... Remove this comment to see the full error message
|
||||
type={action.type}
|
||||
// @ts-expect-error ts-migrate(2551) FIXME: Property 'disableWhenDirty' does not exist on type... Remove this comment to see the full error message
|
||||
disabled={isFormDirty && action.disableWhenDirty}
|
||||
loading={inProgressActions.has(action.name)}
|
||||
onClick={() => handleAction(action)}>
|
||||
@@ -130,26 +163,25 @@ function DynamicFormActions({ actions, isFormDirty }) {
|
||||
));
|
||||
}
|
||||
|
||||
DynamicFormActions.propTypes = {
|
||||
actions: PropTypes.arrayOf(ActionType),
|
||||
isFormDirty: PropTypes.bool,
|
||||
};
|
||||
|
||||
DynamicFormActions.defaultProps = {
|
||||
actions: [],
|
||||
isFormDirty: false,
|
||||
};
|
||||
|
||||
export default function DynamicForm({
|
||||
id,
|
||||
fields,
|
||||
actions,
|
||||
feedbackIcons,
|
||||
hideSubmitButton,
|
||||
defaultShowExtraFields,
|
||||
saveText,
|
||||
onSubmit,
|
||||
}) {
|
||||
type OwnDynamicFormProps = {
|
||||
id?: string;
|
||||
fields?: FieldType[];
|
||||
actions?: ActionType[];
|
||||
feedbackIcons?: boolean;
|
||||
hideSubmitButton?: boolean;
|
||||
defaultShowExtraFields?: boolean;
|
||||
saveText?: string;
|
||||
onSubmit?: (...args: any[]) => any;
|
||||
};
|
||||
|
||||
type DynamicFormProps = OwnDynamicFormProps & typeof DynamicForm.defaultProps;
|
||||
|
||||
export default function DynamicForm({ id, fields, actions, feedbackIcons, hideSubmitButton, defaultShowExtraFields, saveText, onSubmit, }: DynamicFormProps) {
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const [showExtraFields, setShowExtraFields] = useState(defaultShowExtraFields);
|
||||
const [form] = Form.useForm();
|
||||
@@ -160,15 +192,16 @@ export default function DynamicForm({
|
||||
values => {
|
||||
setIsSubmitting(true);
|
||||
values = normalizeEmptyValuesToNull(fields, values);
|
||||
// @ts-expect-error ts-migrate(2349) FIXME: This expression is not callable.
|
||||
onSubmit(
|
||||
values,
|
||||
msg => {
|
||||
(msg: any) => {
|
||||
const { setFieldsValue, getFieldsValue } = form;
|
||||
setIsSubmitting(false);
|
||||
setFieldsValue(getFieldsValue()); // reset form touched state
|
||||
notification.success(msg);
|
||||
},
|
||||
msg => {
|
||||
(msg: any) => {
|
||||
setIsSubmitting(false);
|
||||
notification.error(msg);
|
||||
}
|
||||
@@ -192,6 +225,7 @@ export default function DynamicForm({
|
||||
layout="vertical"
|
||||
onFinish={handleFinish}
|
||||
onFinishFailed={handleFinishFailed}>
|
||||
{/* @ts-expect-error ts-migrate(2786) FIXME: 'DynamicFormFields' cannot be used as a JSX compon... Remove this comment to see the full error message */}
|
||||
<DynamicFormFields fields={regularFields} feedbackIcons={feedbackIcons} form={form} />
|
||||
{!isEmpty(extraFields) && (
|
||||
<div className="extra-options">
|
||||
@@ -199,11 +233,13 @@ export default function DynamicForm({
|
||||
type="dashed"
|
||||
block
|
||||
className="extra-options-button"
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'boolean' is not assignable to type 'never'.
|
||||
onClick={() => setShowExtraFields(currentShowExtraFields => !currentShowExtraFields)}>
|
||||
Additional Settings
|
||||
<i className={cx("fa m-l-5", { "fa-caret-up": showExtraFields, "fa-caret-down": !showExtraFields })} />
|
||||
</Button>
|
||||
<Collapse collapsed={!showExtraFields} className="extra-options-content">
|
||||
{/* @ts-expect-error ts-migrate(2322) FIXME: Type 'Element' is not assignable to type 'null | u... Remove this comment to see the full error message */}
|
||||
<DynamicFormFields fields={extraFields} feedbackIcons={feedbackIcons} form={form} />
|
||||
</Collapse>
|
||||
</div>
|
||||
@@ -213,22 +249,12 @@ export default function DynamicForm({
|
||||
{saveText}
|
||||
</Button>
|
||||
)}
|
||||
{/* @ts-expect-error ts-migrate(2786) FIXME: 'DynamicFormActions' cannot be used as a JSX compo... Remove this comment to see the full error message */}
|
||||
<DynamicFormActions actions={actions} isFormDirty={form.isFieldsTouched()} />
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
|
||||
DynamicForm.propTypes = {
|
||||
id: PropTypes.string,
|
||||
fields: PropTypes.arrayOf(FieldType),
|
||||
actions: PropTypes.arrayOf(ActionType),
|
||||
feedbackIcons: PropTypes.bool,
|
||||
hideSubmitButton: PropTypes.bool,
|
||||
defaultShowExtraFields: PropTypes.bool,
|
||||
saveText: PropTypes.string,
|
||||
onSubmit: PropTypes.func,
|
||||
};
|
||||
|
||||
DynamicForm.defaultProps = {
|
||||
id: null,
|
||||
fields: [],
|
||||
@@ -1,82 +0,0 @@
|
||||
import React from "react";
|
||||
import { get } from "lodash";
|
||||
import PropTypes from "prop-types";
|
||||
import getFieldLabel from "./getFieldLabel";
|
||||
|
||||
import {
|
||||
AceEditorField,
|
||||
CheckboxField,
|
||||
ContentField,
|
||||
FileField,
|
||||
InputField,
|
||||
NumberField,
|
||||
SelectField,
|
||||
TextAreaField,
|
||||
} from "./fields";
|
||||
|
||||
export const FieldType = PropTypes.shape({
|
||||
name: PropTypes.string.isRequired,
|
||||
title: PropTypes.string,
|
||||
type: PropTypes.oneOf([
|
||||
"ace",
|
||||
"text",
|
||||
"textarea",
|
||||
"email",
|
||||
"password",
|
||||
"number",
|
||||
"checkbox",
|
||||
"file",
|
||||
"select",
|
||||
"content",
|
||||
]).isRequired,
|
||||
initialValue: PropTypes.oneOfType([
|
||||
PropTypes.string,
|
||||
PropTypes.number,
|
||||
PropTypes.bool,
|
||||
PropTypes.arrayOf(PropTypes.string),
|
||||
PropTypes.arrayOf(PropTypes.number),
|
||||
]),
|
||||
content: PropTypes.node,
|
||||
mode: PropTypes.string,
|
||||
required: PropTypes.bool,
|
||||
extra: PropTypes.bool,
|
||||
readOnly: PropTypes.bool,
|
||||
autoFocus: PropTypes.bool,
|
||||
minLength: PropTypes.number,
|
||||
placeholder: PropTypes.string,
|
||||
contentAfter: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),
|
||||
loading: PropTypes.bool,
|
||||
props: PropTypes.object, // eslint-disable-line react/forbid-prop-types
|
||||
});
|
||||
|
||||
const FieldTypeComponent = {
|
||||
checkbox: CheckboxField,
|
||||
file: FileField,
|
||||
select: SelectField,
|
||||
number: NumberField,
|
||||
textarea: TextAreaField,
|
||||
ace: AceEditorField,
|
||||
content: ContentField,
|
||||
};
|
||||
|
||||
export default function DynamicFormField({ form, field, ...otherProps }) {
|
||||
const { name, type, readOnly, autoFocus } = field;
|
||||
const fieldLabel = getFieldLabel(field);
|
||||
|
||||
const fieldProps = {
|
||||
...field.props,
|
||||
className: "w-100",
|
||||
name,
|
||||
type,
|
||||
readOnly,
|
||||
autoFocus,
|
||||
placeholder: field.placeholder,
|
||||
"data-test": fieldLabel,
|
||||
...otherProps,
|
||||
};
|
||||
|
||||
const FieldComponent = get(FieldTypeComponent, type, InputField);
|
||||
return <FieldComponent {...fieldProps} form={form} field={field} />;
|
||||
}
|
||||
|
||||
DynamicFormField.propTypes = { field: FieldType.isRequired };
|
||||
105
client/app/components/dynamic-form/DynamicFormField.tsx
Normal file
105
client/app/components/dynamic-form/DynamicFormField.tsx
Normal file
@@ -0,0 +1,105 @@
|
||||
import React from "react";
|
||||
import { get } from "lodash";
|
||||
import PropTypes from "prop-types";
|
||||
import getFieldLabel from "./getFieldLabel";
|
||||
|
||||
import {
|
||||
AceEditorField,
|
||||
CheckboxField,
|
||||
ContentField,
|
||||
FileField,
|
||||
InputField,
|
||||
NumberField,
|
||||
SelectField,
|
||||
TextAreaField,
|
||||
} from "./fields";
|
||||
|
||||
type FieldType = {
|
||||
name: string;
|
||||
title?: string;
|
||||
type: "ace" | "text" | "textarea" | "email" | "password" | "number" | "checkbox" | "file" | "select" | "content";
|
||||
initialValue?: string | number | boolean | string[] | number[];
|
||||
content?: React.ReactNode;
|
||||
mode?: string;
|
||||
required?: boolean;
|
||||
extra?: boolean;
|
||||
readOnly?: boolean;
|
||||
autoFocus?: boolean;
|
||||
minLength?: number;
|
||||
placeholder?: string;
|
||||
contentAfter?: React.ReactNode | ((...args: any[]) => any);
|
||||
loading?: boolean;
|
||||
props?: any;
|
||||
};
|
||||
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'Requireable<InferProps<{ name: Validator<str... Remove this comment to see the full error message
|
||||
const FieldType: PropTypes.Requireable<FieldType> = PropTypes.shape({
|
||||
name: PropTypes.string.isRequired,
|
||||
title: PropTypes.string,
|
||||
type: PropTypes.oneOf([
|
||||
"ace",
|
||||
"text",
|
||||
"textarea",
|
||||
"email",
|
||||
"password",
|
||||
"number",
|
||||
"checkbox",
|
||||
"file",
|
||||
"select",
|
||||
"content",
|
||||
]).isRequired,
|
||||
initialValue: PropTypes.oneOfType([
|
||||
PropTypes.string,
|
||||
PropTypes.number,
|
||||
PropTypes.bool,
|
||||
PropTypes.arrayOf(PropTypes.string),
|
||||
PropTypes.arrayOf(PropTypes.number),
|
||||
]),
|
||||
content: PropTypes.node,
|
||||
mode: PropTypes.string,
|
||||
required: PropTypes.bool,
|
||||
extra: PropTypes.bool,
|
||||
readOnly: PropTypes.bool,
|
||||
autoFocus: PropTypes.bool,
|
||||
minLength: PropTypes.number,
|
||||
placeholder: PropTypes.string,
|
||||
contentAfter: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),
|
||||
loading: PropTypes.bool,
|
||||
props: PropTypes.object,
|
||||
});
|
||||
export { FieldType };
|
||||
|
||||
const FieldTypeComponent = {
|
||||
checkbox: CheckboxField,
|
||||
file: FileField,
|
||||
select: SelectField,
|
||||
number: NumberField,
|
||||
textarea: TextAreaField,
|
||||
ace: AceEditorField,
|
||||
content: ContentField,
|
||||
};
|
||||
|
||||
type Props = {
|
||||
field: FieldType;
|
||||
};
|
||||
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'form' does not exist on type 'Props'.
|
||||
export default function DynamicFormField({ form, field, ...otherProps }: Props) {
|
||||
const { name, type, readOnly, autoFocus } = field;
|
||||
const fieldLabel = getFieldLabel(field);
|
||||
|
||||
const fieldProps = {
|
||||
...field.props,
|
||||
className: "w-100",
|
||||
name,
|
||||
type,
|
||||
readOnly,
|
||||
autoFocus,
|
||||
placeholder: field.placeholder,
|
||||
"data-test": fieldLabel,
|
||||
...otherProps,
|
||||
};
|
||||
|
||||
const FieldComponent = get(FieldTypeComponent, type, InputField);
|
||||
return <FieldComponent {...fieldProps} form={form} field={field} />;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from "react";
|
||||
import { each, includes, isUndefined, isEmpty, isNil, map, get, some } from "lodash";
|
||||
|
||||
function orderedInputs(properties, order, targetOptions) {
|
||||
function orderedInputs(properties: any, order: any, targetOptions: any) {
|
||||
const inputs = new Array(order.length);
|
||||
Object.keys(properties).forEach(key => {
|
||||
const position = order.indexOf(key);
|
||||
@@ -17,6 +17,7 @@ function orderedInputs(properties, order, targetOptions) {
|
||||
|
||||
if (input.type === "select") {
|
||||
input.placeholder = "Select an option";
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'options' does not exist on type '{ name:... Remove this comment to see the full error message
|
||||
input.options = properties[key].options;
|
||||
}
|
||||
|
||||
@@ -29,7 +30,7 @@ function orderedInputs(properties, order, targetOptions) {
|
||||
return inputs;
|
||||
}
|
||||
|
||||
function normalizeSchema(configurationSchema) {
|
||||
function normalizeSchema(configurationSchema: any) {
|
||||
each(configurationSchema.properties, (prop, name) => {
|
||||
if (name === "password" || name === "passwd") {
|
||||
prop.type = "password";
|
||||
@@ -64,23 +65,26 @@ function normalizeSchema(configurationSchema) {
|
||||
configurationSchema.order = configurationSchema.order || [];
|
||||
}
|
||||
|
||||
function setDefaultValueToFields(configurationSchema, options = {}) {
|
||||
function setDefaultValueToFields(configurationSchema: any, options = {}) {
|
||||
const properties = configurationSchema.properties;
|
||||
Object.keys(properties).forEach(key => {
|
||||
const property = properties[key];
|
||||
// set default value for checkboxes
|
||||
if (!isUndefined(property.default) && property.type === "checkbox") {
|
||||
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||
options[key] = property.default;
|
||||
}
|
||||
// set default or first value when value has predefined options
|
||||
if (property.type === "select") {
|
||||
const optionValues = map(property.options, option => option.value);
|
||||
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||
options[key] = includes(optionValues, property.default) ? property.default : optionValues[0];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getFields(type = {}, target = { options: {} }) {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'configuration_schema' does not exist on ... Remove this comment to see the full error message
|
||||
const configurationSchema = type.configuration_schema;
|
||||
normalizeSchema(configurationSchema);
|
||||
const hasTargetObject = Object.keys(target.options).length > 0;
|
||||
@@ -88,6 +92,7 @@ function getFields(type = {}, target = { options: {} }) {
|
||||
setDefaultValueToFields(configurationSchema, target.options);
|
||||
}
|
||||
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'id' does not exist on type '{ options: {... Remove this comment to see the full error message
|
||||
const isNewTarget = !target.id;
|
||||
const inputs = [
|
||||
{
|
||||
@@ -95,8 +100,10 @@ function getFields(type = {}, target = { options: {} }) {
|
||||
title: "Name",
|
||||
type: "text",
|
||||
required: true,
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'name' does not exist on type '{ options:... Remove this comment to see the full error message
|
||||
initialValue: target.name,
|
||||
contentAfter: React.createElement("hr"),
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'name' does not exist on type '{}'.
|
||||
placeholder: `My ${type.name}`,
|
||||
autoFocus: isNewTarget,
|
||||
},
|
||||
@@ -106,7 +113,7 @@ function getFields(type = {}, target = { options: {} }) {
|
||||
return inputs;
|
||||
}
|
||||
|
||||
function updateTargetWithValues(target, values) {
|
||||
function updateTargetWithValues(target: any, values: any) {
|
||||
target.name = values.name;
|
||||
Object.keys(values).forEach(key => {
|
||||
if (key !== "name") {
|
||||
@@ -115,16 +122,17 @@ function updateTargetWithValues(target, values) {
|
||||
});
|
||||
}
|
||||
|
||||
function getBase64(file) {
|
||||
function getBase64(file: any) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.readAsDataURL(file);
|
||||
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||
reader.onload = () => resolve(reader.result.substr(reader.result.indexOf(",") + 1));
|
||||
reader.onerror = error => reject(error);
|
||||
});
|
||||
}
|
||||
|
||||
function hasFilledExtraField(type, target) {
|
||||
function hasFilledExtraField(type: any, target: any) {
|
||||
const extraOptions = get(type, "configuration_schema.extra_options", []);
|
||||
return some(extraOptions, optionName => {
|
||||
const defaultOptionValue = get(type, ["configuration_schema", "properties", optionName, "default"]);
|
||||
@@ -1,6 +1,10 @@
|
||||
import React from "react";
|
||||
import AceEditorInput from "@/components/AceEditorInput";
|
||||
|
||||
export default function AceEditorField({ form, field, ...otherProps }) {
|
||||
export default function AceEditorField({
|
||||
form,
|
||||
field,
|
||||
...otherProps
|
||||
}: any) {
|
||||
return <AceEditorInput {...otherProps} />;
|
||||
}
|
||||
@@ -2,7 +2,11 @@ import React from "react";
|
||||
import Checkbox from "antd/lib/checkbox";
|
||||
import getFieldLabel from "../getFieldLabel";
|
||||
|
||||
export default function CheckboxField({ form, field, ...otherProps }) {
|
||||
export default function CheckboxField({
|
||||
form,
|
||||
field,
|
||||
...otherProps
|
||||
}: any) {
|
||||
const fieldLabel = getFieldLabel(field);
|
||||
return <Checkbox {...otherProps}>{fieldLabel}</Checkbox>;
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
export default function ContentField({ field }) {
|
||||
return field.content;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
export default function ContentField({
|
||||
field
|
||||
}: any) {
|
||||
return field.content;
|
||||
}
|
||||
@@ -3,7 +3,11 @@ import Button from "antd/lib/button";
|
||||
import Upload from "antd/lib/upload";
|
||||
import UploadOutlinedIcon from "@ant-design/icons/UploadOutlined";
|
||||
|
||||
export default function FileField({ form, field, ...otherProps }) {
|
||||
export default function FileField({
|
||||
form,
|
||||
field,
|
||||
...otherProps
|
||||
}: any) {
|
||||
const { name, initialValue } = field;
|
||||
const { getFieldValue } = form;
|
||||
const disabled = getFieldValue(name) !== undefined && getFieldValue(name) !== initialValue;
|
||||
@@ -1,6 +1,10 @@
|
||||
import React from "react";
|
||||
import Input from "antd/lib/input";
|
||||
|
||||
export default function InputField({ form, field, ...otherProps }) {
|
||||
export default function InputField({
|
||||
form,
|
||||
field,
|
||||
...otherProps
|
||||
}: any) {
|
||||
return <Input {...otherProps} />;
|
||||
}
|
||||
@@ -1,6 +1,10 @@
|
||||
import React from "react";
|
||||
import InputNumber from "antd/lib/input-number";
|
||||
|
||||
export default function NumberField({ form, field, ...otherProps }) {
|
||||
export default function NumberField({
|
||||
form,
|
||||
field,
|
||||
...otherProps
|
||||
}: any) {
|
||||
return <InputNumber {...otherProps} />;
|
||||
}
|
||||
@@ -1,7 +1,11 @@
|
||||
import React from "react";
|
||||
import Select from "antd/lib/select";
|
||||
|
||||
export default function SelectField({ form, field, ...otherProps }) {
|
||||
export default function SelectField({
|
||||
form,
|
||||
field,
|
||||
...otherProps
|
||||
}: any) {
|
||||
const { readOnly } = field;
|
||||
return (
|
||||
<Select
|
||||
@@ -11,11 +15,9 @@ export default function SelectField({ form, field, ...otherProps }) {
|
||||
mode={field.mode}
|
||||
getPopupContainer={trigger => trigger.parentNode}>
|
||||
{field.options &&
|
||||
field.options.map(option => (
|
||||
<Select.Option key={`${option.value}`} value={option.value} disabled={readOnly}>
|
||||
{option.name || option.value}
|
||||
</Select.Option>
|
||||
))}
|
||||
field.options.map((option: any) => <Select.Option key={`${option.value}`} value={option.value} disabled={readOnly}>
|
||||
{option.name || option.value}
|
||||
</Select.Option>)}
|
||||
</Select>
|
||||
);
|
||||
}
|
||||
@@ -1,6 +1,10 @@
|
||||
import React from "react";
|
||||
import Input from "antd/lib/input";
|
||||
|
||||
export default function TextAreaField({ form, field, ...otherProps }) {
|
||||
export default function TextAreaField({
|
||||
form,
|
||||
field,
|
||||
...otherProps
|
||||
}: any) {
|
||||
return <Input.TextArea {...otherProps} />;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { toHuman } from "@/lib/utils";
|
||||
|
||||
export default function getFieldLabel(field) {
|
||||
export default function getFieldLabel(field: any) {
|
||||
const { title, name } = field;
|
||||
return title || toHuman(name);
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { getDynamicDateFromString } from "@/services/parameters/DateParameter";
|
||||
import DynamicDatePicker from "@/components/dynamic-parameters/DynamicDatePicker";
|
||||
|
||||
@@ -22,18 +21,21 @@ const DYNAMIC_DATE_OPTIONS = [
|
||||
},
|
||||
];
|
||||
|
||||
function DateParameter(props) {
|
||||
type OwnProps = {
|
||||
type?: string;
|
||||
className?: string;
|
||||
value?: any;
|
||||
parameter?: any;
|
||||
onSelect?: (...args: any[]) => any;
|
||||
};
|
||||
|
||||
type Props = OwnProps & typeof DateParameter.defaultProps;
|
||||
|
||||
function DateParameter(props: Props) {
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '{ name: string; value: any; label: () => any... Remove this comment to see the full error message
|
||||
return <DynamicDatePicker dynamicButtonOptions={{ options: DYNAMIC_DATE_OPTIONS }} {...props} />;
|
||||
}
|
||||
|
||||
DateParameter.propTypes = {
|
||||
type: PropTypes.string,
|
||||
className: PropTypes.string,
|
||||
value: PropTypes.any, // eslint-disable-line react/forbid-prop-types
|
||||
parameter: PropTypes.any, // eslint-disable-line react/forbid-prop-types
|
||||
onSelect: PropTypes.func,
|
||||
};
|
||||
|
||||
DateParameter.defaultProps = {
|
||||
type: "",
|
||||
className: "",
|
||||
@@ -1,5 +1,4 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { includes } from "lodash";
|
||||
import { getDynamicDateRangeFromString } from "@/services/parameters/DateRangeParameter";
|
||||
import DynamicDateRangePicker from "@/components/dynamic-parameters/DynamicDateRangePicker";
|
||||
@@ -128,19 +127,22 @@ const DYNAMIC_DATETIME_OPTIONS = [
|
||||
...DYNAMIC_DATE_OPTIONS,
|
||||
];
|
||||
|
||||
function DateRangeParameter(props) {
|
||||
type OwnProps = {
|
||||
type?: string;
|
||||
className?: string;
|
||||
value?: any;
|
||||
parameter?: any;
|
||||
onSelect?: (...args: any[]) => any;
|
||||
};
|
||||
|
||||
type Props = OwnProps & typeof DateRangeParameter.defaultProps;
|
||||
|
||||
function DateRangeParameter(props: Props) {
|
||||
const options = includes(props.type, "datetime-range") ? DYNAMIC_DATETIME_OPTIONS : DYNAMIC_DATE_OPTIONS;
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '({ name: string; value: any; label: () => an... Remove this comment to see the full error message
|
||||
return <DynamicDateRangePicker {...props} dynamicButtonOptions={{ options }} />;
|
||||
}
|
||||
|
||||
DateRangeParameter.propTypes = {
|
||||
type: PropTypes.string,
|
||||
className: PropTypes.string,
|
||||
value: PropTypes.any, // eslint-disable-line react/forbid-prop-types
|
||||
parameter: PropTypes.any, // eslint-disable-line react/forbid-prop-types
|
||||
onSelect: PropTypes.func,
|
||||
};
|
||||
|
||||
DateRangeParameter.defaultProps = {
|
||||
type: "",
|
||||
className: "",
|
||||
@@ -1,10 +1,11 @@
|
||||
import React, { useRef } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { isFunction, get, findIndex } from "lodash";
|
||||
import Dropdown from "antd/lib/dropdown";
|
||||
import Menu from "antd/lib/menu";
|
||||
import Typography from "antd/lib/typography";
|
||||
// @ts-expect-error ts-migrate(6133) FIXME: 'DynamicDateType' is declared but its value is nev... Remove this comment to see the full error message
|
||||
import { DynamicDateType } from "@/services/parameters/DateParameter";
|
||||
// @ts-expect-error ts-migrate(6133) FIXME: 'DynamicDateRangeType' is declared but its value i... Remove this comment to see the full error message
|
||||
import { DynamicDateRangeType } from "@/services/parameters/DateRangeParameter";
|
||||
|
||||
import ArrowLeftOutlinedIcon from "@ant-design/icons/ArrowLeftOutlined";
|
||||
@@ -15,11 +16,23 @@ import "./DynamicButton.less";
|
||||
|
||||
const { Text } = Typography;
|
||||
|
||||
function DynamicButton({ options, selectedDynamicValue, onSelect, enabled, staticValueLabel }) {
|
||||
type OwnProps = {
|
||||
options?: any[];
|
||||
// @ts-expect-error ts-migrate(2749) FIXME: 'DynamicDateType' refers to a value, but is being ... Remove this comment to see the full error message
|
||||
selectedDynamicValue?: DynamicDateType | DynamicDateRangeType;
|
||||
onSelect?: (...args: any[]) => any;
|
||||
enabled?: boolean;
|
||||
staticValueLabel?: string;
|
||||
};
|
||||
|
||||
type Props = OwnProps & typeof DynamicButton.defaultProps;
|
||||
|
||||
function DynamicButton({ options, selectedDynamicValue, onSelect, enabled, staticValueLabel }: Props) {
|
||||
const menu = (
|
||||
<Menu
|
||||
className="dynamic-menu"
|
||||
onClick={({ key }) => onSelect(get(options, key, "static"))}
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type '{ value: any; }' is not assignab... Remove this comment to see the full error message
|
||||
selectedKeys={[`${findIndex(options, { value: selectedDynamicValue })}`]}
|
||||
data-test="DynamicButtonMenu">
|
||||
{options.map((option, index) => (
|
||||
@@ -55,6 +68,7 @@ function DynamicButton({ options, selectedDynamicValue, onSelect, enabled, stati
|
||||
<ThunderboltOutlinedIcon className="dynamic-icon" />
|
||||
)
|
||||
}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '() => null' is not assignable to type '(trig... Remove this comment to see the full error message
|
||||
getPopupContainer={() => containerRef.current}
|
||||
data-test="DynamicButton"
|
||||
/>
|
||||
@@ -63,14 +77,6 @@ function DynamicButton({ options, selectedDynamicValue, onSelect, enabled, stati
|
||||
);
|
||||
}
|
||||
|
||||
DynamicButton.propTypes = {
|
||||
options: PropTypes.arrayOf(PropTypes.object), // eslint-disable-line react/forbid-prop-types
|
||||
selectedDynamicValue: PropTypes.oneOfType([DynamicDateType, DynamicDateRangeType]),
|
||||
onSelect: PropTypes.func,
|
||||
enabled: PropTypes.bool,
|
||||
staticValueLabel: PropTypes.string,
|
||||
};
|
||||
|
||||
DynamicButton.defaultProps = {
|
||||
options: [],
|
||||
selectedDynamicValue: null,
|
||||
@@ -1,5 +1,4 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import classNames from "classnames";
|
||||
import moment from "moment";
|
||||
import { includes } from "lodash";
|
||||
@@ -10,26 +9,26 @@ import DynamicButton from "@/components/dynamic-parameters/DynamicButton";
|
||||
|
||||
import "./DynamicParameters.less";
|
||||
|
||||
class DynamicDatePicker extends React.Component {
|
||||
static propTypes = {
|
||||
type: PropTypes.string,
|
||||
className: PropTypes.string,
|
||||
value: PropTypes.any, // eslint-disable-line react/forbid-prop-types
|
||||
parameter: PropTypes.any, // eslint-disable-line react/forbid-prop-types
|
||||
onSelect: PropTypes.func,
|
||||
dynamicButtonOptions: PropTypes.shape({
|
||||
staticValueLabel: PropTypes.string,
|
||||
options: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
name: PropTypes.string,
|
||||
value: PropTypes.object,
|
||||
label: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
|
||||
})
|
||||
),
|
||||
}),
|
||||
dateOptions: PropTypes.any, // eslint-disable-line react/forbid-prop-types
|
||||
};
|
||||
type OwnProps = {
|
||||
type?: string;
|
||||
className?: string;
|
||||
value?: any;
|
||||
parameter?: any;
|
||||
onSelect?: (...args: any[]) => any;
|
||||
dynamicButtonOptions?: {
|
||||
staticValueLabel?: string;
|
||||
options?: {
|
||||
name?: string;
|
||||
value?: any;
|
||||
label?: string | ((...args: any[]) => any);
|
||||
}[];
|
||||
};
|
||||
dateOptions?: any;
|
||||
};
|
||||
|
||||
type Props = OwnProps & typeof DynamicDatePicker.defaultProps;
|
||||
|
||||
class DynamicDatePicker extends React.Component<Props> {
|
||||
static defaultProps = {
|
||||
type: "",
|
||||
className: "",
|
||||
@@ -41,12 +40,14 @@ class DynamicDatePicker extends React.Component {
|
||||
onSelect: () => {},
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
dateComponentRef: any;
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.dateComponentRef = React.createRef();
|
||||
}
|
||||
|
||||
onDynamicValueSelect = dynamicValue => {
|
||||
onDynamicValueSelect = (dynamicValue: any) => {
|
||||
const { onSelect, parameter } = this.props;
|
||||
if (dynamicValue === "static") {
|
||||
const parameterValue = parameter.getExecutionValue();
|
||||
@@ -73,17 +74,21 @@ class DynamicDatePicker extends React.Component {
|
||||
if (isDateTime) {
|
||||
DateComponent = DateTimeInput;
|
||||
if (includes(type, "with-seconds")) {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'withSeconds' does not exist on type '{}'... Remove this comment to see the full error message
|
||||
additionalAttributes.withSeconds = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (moment.isMoment(value) || value === null) {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'value' does not exist on type '{}'.
|
||||
additionalAttributes.value = value;
|
||||
}
|
||||
|
||||
if (hasDynamicValue) {
|
||||
const dynamicDate = value;
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'placeholder' does not exist on type '{}'... Remove this comment to see the full error message
|
||||
additionalAttributes.placeholder = dynamicDate && dynamicDate.name;
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'value' does not exist on type '{}'.
|
||||
additionalAttributes.value = null;
|
||||
}
|
||||
|
||||
@@ -102,6 +107,7 @@ class DynamicDatePicker extends React.Component {
|
||||
staticValueLabel={dynamicButtonOptions.staticValueLabel}
|
||||
selectedDynamicValue={hasDynamicValue ? value : null}
|
||||
enabled={hasDynamicValue}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '(dynamicValue: any) => void' is not assignab... Remove this comment to see the full error message
|
||||
onSelect={this.onDynamicValueSelect}
|
||||
/>
|
||||
</div>
|
||||
@@ -1,5 +1,4 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import classNames from "classnames";
|
||||
import moment from "moment";
|
||||
import { includes, isArray, isObject } from "lodash";
|
||||
@@ -10,30 +9,30 @@ import DynamicButton from "@/components/dynamic-parameters/DynamicButton";
|
||||
|
||||
import "./DynamicParameters.less";
|
||||
|
||||
function isValidDateRangeValue(value) {
|
||||
function isValidDateRangeValue(value: any) {
|
||||
return isArray(value) && value.length === 2 && moment.isMoment(value[0]) && moment.isMoment(value[1]);
|
||||
}
|
||||
|
||||
class DynamicDateRangePicker extends React.Component {
|
||||
static propTypes = {
|
||||
type: PropTypes.oneOf(["date-range", "datetime-range", "datetime-range-with-seconds"]).isRequired,
|
||||
className: PropTypes.string,
|
||||
value: PropTypes.any, // eslint-disable-line react/forbid-prop-types
|
||||
parameter: PropTypes.any, // eslint-disable-line react/forbid-prop-types
|
||||
onSelect: PropTypes.func,
|
||||
dynamicButtonOptions: PropTypes.shape({
|
||||
staticValueLabel: PropTypes.string,
|
||||
options: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
name: PropTypes.string,
|
||||
value: PropTypes.object,
|
||||
label: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
|
||||
})
|
||||
),
|
||||
}),
|
||||
dateRangeOptions: PropTypes.any, // eslint-disable-line react/forbid-prop-types
|
||||
};
|
||||
type OwnProps = {
|
||||
type: "date-range" | "datetime-range" | "datetime-range-with-seconds";
|
||||
className?: string;
|
||||
value?: any;
|
||||
parameter?: any;
|
||||
onSelect?: (...args: any[]) => any;
|
||||
dynamicButtonOptions?: {
|
||||
staticValueLabel?: string;
|
||||
options?: {
|
||||
name?: string;
|
||||
value?: any;
|
||||
label?: string | ((...args: any[]) => any);
|
||||
}[];
|
||||
};
|
||||
dateRangeOptions?: any;
|
||||
};
|
||||
|
||||
type Props = OwnProps & typeof DynamicDateRangePicker.defaultProps;
|
||||
|
||||
class DynamicDateRangePicker extends React.Component<Props> {
|
||||
static defaultProps = {
|
||||
type: "date-range",
|
||||
className: "",
|
||||
@@ -45,16 +44,20 @@ class DynamicDateRangePicker extends React.Component {
|
||||
onSelect: () => {},
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
dateRangeComponentRef: any;
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.dateRangeComponentRef = React.createRef();
|
||||
}
|
||||
|
||||
onDynamicValueSelect = dynamicValue => {
|
||||
onDynamicValueSelect = (dynamicValue: any) => {
|
||||
const { onSelect, parameter } = this.props;
|
||||
if (dynamicValue === "static") {
|
||||
const parameterValue = parameter.getExecutionValue();
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'start' does not exist on type 'object'.
|
||||
if (isObject(parameterValue) && parameterValue.start && parameterValue.end) {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'start' does not exist on type 'object'.
|
||||
onSelect([moment(parameterValue.start), moment(parameterValue.end)]);
|
||||
} else {
|
||||
onSelect(null);
|
||||
@@ -77,16 +80,20 @@ class DynamicDateRangePicker extends React.Component {
|
||||
if (isDateTimeRange) {
|
||||
DateRangeComponent = DateTimeRangeInput;
|
||||
if (includes(type, "with-seconds")) {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'withSeconds' does not exist on type '{}'... Remove this comment to see the full error message
|
||||
additionalAttributes.withSeconds = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (isValidDateRangeValue(value) || value === null) {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'value' does not exist on type '{}'.
|
||||
additionalAttributes.value = value;
|
||||
}
|
||||
|
||||
if (hasDynamicValue) {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'placeholder' does not exist on type '{}'... Remove this comment to see the full error message
|
||||
additionalAttributes.placeholder = [value && value.name];
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'value' does not exist on type '{}'.
|
||||
additionalAttributes.value = null;
|
||||
}
|
||||
|
||||
@@ -105,6 +112,7 @@ class DynamicDateRangePicker extends React.Component {
|
||||
staticValueLabel={dynamicButtonOptions.staticValueLabel}
|
||||
selectedDynamicValue={hasDynamicValue ? value : null}
|
||||
enabled={hasDynamicValue}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '(dynamicValue: any) => void' is not assignab... Remove this comment to see the full error message
|
||||
onSelect={this.onDynamicValueSelect}
|
||||
/>
|
||||
</div>
|
||||
@@ -1,6 +1,5 @@
|
||||
import { keys, some } from "lodash";
|
||||
import React, { useCallback } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import classNames from "classnames";
|
||||
import CloseOutlinedIcon from "@ant-design/icons/CloseOutlined";
|
||||
import Link from "@/components/Link";
|
||||
@@ -10,7 +9,19 @@ import { currentUser } from "@/services/auth";
|
||||
import organizationStatus from "@/services/organizationStatus";
|
||||
import "./empty-state.less";
|
||||
|
||||
export function Step({ show, completed, text, url, urlTarget, urlText, onClick }) {
|
||||
type OwnStepProps = {
|
||||
show: boolean;
|
||||
completed: boolean;
|
||||
text?: React.ReactNode;
|
||||
url?: string;
|
||||
urlTarget?: string;
|
||||
urlText?: React.ReactNode;
|
||||
onClick?: (...args: any[]) => any;
|
||||
};
|
||||
|
||||
type StepProps = OwnStepProps & typeof Step.defaultProps;
|
||||
|
||||
export function Step({ show, completed, text, url, urlTarget, urlText, onClick }: StepProps) {
|
||||
if (!show) {
|
||||
return null;
|
||||
}
|
||||
@@ -25,16 +36,6 @@ export function Step({ show, completed, text, url, urlTarget, urlText, onClick }
|
||||
);
|
||||
}
|
||||
|
||||
Step.propTypes = {
|
||||
show: PropTypes.bool.isRequired,
|
||||
completed: PropTypes.bool.isRequired,
|
||||
text: PropTypes.node,
|
||||
url: PropTypes.string,
|
||||
urlTarget: PropTypes.string,
|
||||
urlText: PropTypes.node,
|
||||
onClick: PropTypes.func,
|
||||
};
|
||||
|
||||
Step.defaultProps = {
|
||||
url: null,
|
||||
urlTarget: null,
|
||||
@@ -43,10 +44,15 @@ Step.defaultProps = {
|
||||
onClick: null,
|
||||
};
|
||||
|
||||
export function EmptyStateHelpMessage({ helpTriggerType }) {
|
||||
type EmptyStateHelpMessageProps = {
|
||||
helpTriggerType: string;
|
||||
};
|
||||
|
||||
export function EmptyStateHelpMessage({ helpTriggerType }: EmptyStateHelpMessageProps) {
|
||||
return (
|
||||
<p>
|
||||
Need more support?{" "}
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<HelpTrigger className="f-14" type={helpTriggerType} showTooltip={false}>
|
||||
See our Help
|
||||
</HelpTrigger>
|
||||
@@ -54,26 +60,26 @@ export function EmptyStateHelpMessage({ helpTriggerType }) {
|
||||
);
|
||||
}
|
||||
|
||||
EmptyStateHelpMessage.propTypes = {
|
||||
helpTriggerType: PropTypes.string.isRequired,
|
||||
type OwnEmptyStateProps = {
|
||||
icon?: string;
|
||||
header?: string;
|
||||
description: string;
|
||||
illustration: string;
|
||||
illustrationPath?: string;
|
||||
helpMessage?: React.ReactNode;
|
||||
closable?: boolean;
|
||||
onClose?: (...args: any[]) => any;
|
||||
onboardingMode?: boolean;
|
||||
showAlertStep?: boolean;
|
||||
showDashboardStep?: boolean;
|
||||
showDataSourceStep?: boolean;
|
||||
showInviteStep?: boolean;
|
||||
getStepItems?: (...args: any[]) => any;
|
||||
};
|
||||
|
||||
function EmptyState({
|
||||
icon,
|
||||
header,
|
||||
description,
|
||||
illustration,
|
||||
helpMessage,
|
||||
closable,
|
||||
onClose,
|
||||
onboardingMode,
|
||||
showAlertStep,
|
||||
showDashboardStep,
|
||||
showDataSourceStep,
|
||||
showInviteStep,
|
||||
getStepsItems,
|
||||
illustrationPath,
|
||||
}) {
|
||||
type EmptyStateProps = OwnEmptyStateProps & typeof EmptyState.defaultProps;
|
||||
|
||||
function EmptyState({ icon, header, description, illustration, helpMessage, closable, onClose, onboardingMode, showAlertStep, showDashboardStep, showDataSourceStep, showInviteStep, getStepsItems, illustrationPath, }: EmptyStateProps) {
|
||||
const isAvailable = {
|
||||
dataSource: showDataSourceStep,
|
||||
query: true,
|
||||
@@ -91,10 +97,12 @@ function EmptyState({
|
||||
};
|
||||
|
||||
const showCreateDashboardDialog = useCallback(() => {
|
||||
// @ts-expect-error ts-migrate(2554) FIXME: Expected 1 arguments, but got 0.
|
||||
CreateDashboardDialog.showModal();
|
||||
}, []);
|
||||
|
||||
// Show if `onboardingMode=false` or any requested step not completed
|
||||
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||
const shouldShow = !onboardingMode || some(keys(isAvailable), step => isAvailable[step] && !isCompleted[step]);
|
||||
|
||||
if (!shouldShow) {
|
||||
@@ -105,10 +113,14 @@ function EmptyState({
|
||||
if (currentUser.isAdmin) {
|
||||
return (
|
||||
<Step
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'never'.
|
||||
key="dataSources"
|
||||
show={isAvailable.dataSource}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'boolean' is not assignable to type 'never'.
|
||||
completed={isCompleted.dataSource}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'never'.
|
||||
url="data_sources/new"
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'never'.
|
||||
urlText="Connect a Data Source"
|
||||
/>
|
||||
);
|
||||
@@ -116,9 +128,12 @@ function EmptyState({
|
||||
|
||||
return (
|
||||
<Step
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'never'.
|
||||
key="dataSources"
|
||||
show={isAvailable.dataSource}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'boolean' is not assignable to type 'never'.
|
||||
completed={isCompleted.dataSource}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'never'.
|
||||
text="Ask an account admin to connect a data source"
|
||||
/>
|
||||
);
|
||||
@@ -133,10 +148,15 @@ function EmptyState({
|
||||
key: "queries",
|
||||
node: (
|
||||
<Step
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'never'.
|
||||
key="queries"
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'boolean' is not assignable to type 'never'.
|
||||
show={isAvailable.query}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'boolean' is not assignable to type 'never'.
|
||||
completed={isCompleted.query}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'never'.
|
||||
url="queries/new"
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'never'.
|
||||
urlText="Create your first Query"
|
||||
/>
|
||||
),
|
||||
@@ -145,10 +165,14 @@ function EmptyState({
|
||||
key: "alerts",
|
||||
node: (
|
||||
<Step
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'never'.
|
||||
key="alerts"
|
||||
show={isAvailable.alert}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'boolean' is not assignable to type 'never'.
|
||||
completed={isCompleted.alert}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'never'.
|
||||
url="alerts/new"
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'never'.
|
||||
urlText="Create your first Alert"
|
||||
/>
|
||||
),
|
||||
@@ -157,10 +181,14 @@ function EmptyState({
|
||||
key: "dashboards",
|
||||
node: (
|
||||
<Step
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'never'.
|
||||
key="dashboards"
|
||||
show={isAvailable.dashboard}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'boolean' is not assignable to type 'never'.
|
||||
completed={isCompleted.dashboard}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '() => void' is not assignable to type 'never... Remove this comment to see the full error message
|
||||
onClick={showCreateDashboardDialog}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'never'.
|
||||
urlText="Create your first Dashboard"
|
||||
/>
|
||||
),
|
||||
@@ -169,16 +197,21 @@ function EmptyState({
|
||||
key: "users",
|
||||
node: (
|
||||
<Step
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'never'.
|
||||
key="users"
|
||||
show={isAvailable.inviteUsers}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'boolean' is not assignable to type 'never'.
|
||||
completed={isCompleted.inviteUsers}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'never'.
|
||||
url="users/new"
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'never'.
|
||||
urlText="Invite your team members"
|
||||
/>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
// @ts-expect-error ts-migrate(2349) FIXME: This expression is not callable.
|
||||
const stepsItems = getStepsItems ? getStepsItems(defaultStepsItems) : defaultStepsItems;
|
||||
const imageSource = illustrationPath ? illustrationPath : "static/images/illustrations/" + illustration + ".svg";
|
||||
|
||||
@@ -195,7 +228,7 @@ function EmptyState({
|
||||
</div>
|
||||
<div className="empty-state__steps">
|
||||
<h4>Let's get started</h4>
|
||||
<ol>{stepsItems.map(item => item.node)}</ol>
|
||||
<ol>{stepsItems.map((item: any) => item.node)}</ol>
|
||||
{helpMessage}
|
||||
</div>
|
||||
</div>
|
||||
@@ -208,25 +241,6 @@ function EmptyState({
|
||||
);
|
||||
}
|
||||
|
||||
EmptyState.propTypes = {
|
||||
icon: PropTypes.string,
|
||||
header: PropTypes.string,
|
||||
description: PropTypes.string.isRequired,
|
||||
illustration: PropTypes.string.isRequired,
|
||||
illustrationPath: PropTypes.string,
|
||||
helpMessage: PropTypes.node,
|
||||
closable: PropTypes.bool,
|
||||
onClose: PropTypes.func,
|
||||
|
||||
onboardingMode: PropTypes.bool,
|
||||
showAlertStep: PropTypes.bool,
|
||||
showDashboardStep: PropTypes.bool,
|
||||
showDataSourceStep: PropTypes.bool,
|
||||
showInviteStep: PropTypes.bool,
|
||||
|
||||
getStepItems: PropTypes.func,
|
||||
};
|
||||
|
||||
EmptyState.defaultProps = {
|
||||
icon: null,
|
||||
header: null,
|
||||
@@ -1,12 +1,17 @@
|
||||
import React from "react";
|
||||
import Modal from "antd/lib/modal";
|
||||
import Input from "antd/lib/input";
|
||||
// @ts-expect-error ts-migrate(6133) FIXME: 'DialogPropType' is declared but its value is neve... Remove this comment to see the full error message
|
||||
import { wrap as wrapDialog, DialogPropType } from "@/components/DialogWrapper";
|
||||
|
||||
class CreateGroupDialog extends React.Component {
|
||||
static propTypes = {
|
||||
dialog: DialogPropType.isRequired,
|
||||
};
|
||||
type Props = {
|
||||
// @ts-expect-error ts-migrate(2749) FIXME: 'DialogPropType' refers to a value, but is being u... Remove this comment to see the full error message
|
||||
dialog: DialogPropType;
|
||||
};
|
||||
|
||||
type State = any;
|
||||
|
||||
class CreateGroupDialog extends React.Component<Props, State> {
|
||||
|
||||
state = {
|
||||
name: "",
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user