Compare commits

...

19 Commits

Author SHA1 Message Date
Elad Ossadon
521ca6afa4 8 2020-12-16 08:30:47 -08:00
Elad Ossadon
1ba94d30a1 7 2020-12-16 08:25:37 -08:00
Elad Ossadon
e4d2c82338 6 2020-12-16 08:25:36 -08:00
Elad Ossadon
95621a93bc 5 2020-12-16 08:25:06 -08:00
Elad Ossadon
2f1ed63bd5 4 2020-12-16 08:25:05 -08:00
Elad Ossadon
f23f1d1924 3 2020-12-16 08:24:36 -08:00
Elad Ossadon
c426379bef [ts-migrate][client] Run TS Migrate
Co-authored-by: ts-migrate <>
2020-12-16 08:24:26 -08:00
Elad Ossadon
501ca0bef8 [ts-migrate][client] Rename files from JS/JSX to TS/TSX
Co-authored-by: ts-migrate <>
2020-12-16 08:23:08 -08:00
Elad Ossadon
4c385f85f1 2 2020-12-16 08:22:53 -08:00
Elad Ossadon
698d87ed48 ts-migrate pkg 2020-12-15 20:59:50 -08:00
Elad Ossadon
c290864ccd Convert viz-lib to TypeScript (#5310)
Co-authored-by: ts-migrate <>
2020-12-15 18:21:37 -08:00
Rafael Wendel
b70e95a323 added eslint no-console (#5305)
* added eslint no-console

* Update client/.eslintrc.js to allow warnings

Co-authored-by: Gabriel Dutra <nesk.frz@gmail.com>

Co-authored-by: Gabriel Dutra <nesk.frz@gmail.com>
2020-12-14 10:09:43 -03:00
Elad Ossadon
18ee5343aa Sync date format from settings with clientConfig (#5299) 2020-12-10 11:16:31 -08:00
Elad Ossadon
fdf636a393 Fix disabled hot reload flow (#5306) 2020-12-07 16:02:52 -08:00
Rafael Wendel
88c13868a3 removed leftover console.log (#5303) 2020-12-07 17:21:40 -03:00
Elad Ossadon
aab11dc79b Add React Fast Refresh + Hot Module Reloading (#5291) 2020-12-07 11:46:46 -08:00
Elad Ossadon
00c77cf36e Redesign desktop nav bar (#5294) 2020-12-06 12:09:19 -08:00
Rafael Wendel
6e2631dec2 Changed 'Delete Alert' into 'Delete' for consistency (#5287) 2020-11-30 18:48:35 -03:00
Rafael Wendel
4b88959341 Fix QuerySourceDropdown value type (#5284) 2020-11-24 11:42:20 -03:00
536 changed files with 14467 additions and 5953 deletions

View File

@@ -20,6 +20,7 @@ module.exports = {
// allow debugger during development
"no-debugger": process.env.NODE_ENV === "production" ? 2 : 0,
"jsx-a11y/anchor-is-valid": "off",
"no-console": ["warn", { allow: ["warn", "error"] }],
"no-restricted-imports": [
"error",
{
@@ -50,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",
},
},
],

View File

@@ -1,4 +0,0 @@
import { configure } from "enzyme";
import Adapter from "enzyme-adapter-react-16";
configure({ adapter: new Adapter() });

View 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() });

View File

@@ -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

View File

@@ -1,12 +1,17 @@
@backgroundColor: #001529;
@dividerColor: rgba(255, 255, 255, 0.5);
@textColor: rgba(255, 255, 255, 0.75);
@brandColor: #ff7964; // Redash logo color
@activeItemColor: @brandColor;
@iconSize: 26px;
.desktop-navbar {
background: @backgroundColor;
display: flex;
flex-direction: column;
height: 100%;
width: 80px;
overflow: hidden;
&-spacer {
flex: 1 1 auto;
@@ -21,12 +26,6 @@
height: 40px;
transition: all 270ms;
}
&.ant-menu-inline-collapsed {
img {
height: 20px;
}
}
}
.help-trigger {
@@ -34,26 +33,19 @@
}
.ant-menu {
&:not(.ant-menu-inline-collapsed) {
width: 170px;
}
&.ant-menu-inline-collapsed > .ant-menu-submenu-title span img + span,
&.ant-menu-inline-collapsed > .ant-menu-item i + span {
display: inline-block;
max-width: 0;
opacity: 0;
}
.ant-menu-item-divider {
background: @dividerColor;
}
.ant-menu-item,
.ant-menu-submenu {
font-weight: 500;
color: @textColor;
&.navbar-active-item {
box-shadow: inset 3px 0 0 @activeItemColor;
.anticon {
color: @activeItemColor;
}
}
&.ant-menu-submenu-open,
&.ant-menu-submenu-active,
&:hover,
@@ -61,6 +53,16 @@
color: #fff;
}
.anticon {
font-size: @iconSize;
margin: 0;
}
.desktop-navbar-label {
margin-top: 4px;
font-size: 11px;
}
a,
span,
.anticon {
@@ -71,21 +73,33 @@
.ant-menu-submenu-arrow {
display: none;
}
}
.ant-btn.desktop-navbar-collapse-button {
background-color: @backgroundColor;
border: 0;
border-radius: 0;
color: @textColor;
&:hover,
&:active {
color: #fff;
.ant-menu-item,
.ant-menu-submenu {
padding: 0;
height: 60px;
display: flex;
align-items: center;
flex-direction: column;
justify-content: center;
}
&:after {
animation: 0s !important;
.ant-menu-submenu-title {
width: 100%;
padding: 0;
}
a,
&.ant-menu-vertical > .ant-menu-submenu > .ant-menu-submenu-title,
.ant-menu-submenu-title {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
line-height: normal;
height: auto;
background: none;
color: inherit;
}
}
@@ -99,37 +113,8 @@
.profile__image_thumb {
margin: 0;
vertical-align: middle;
}
.profile__image_thumb + span {
flex: 1 1 auto;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
margin-left: 10px;
vertical-align: middle;
display: inline-block;
// styles from Antd
opacity: 1;
transition: opacity 0.3s cubic-bezier(0.645, 0.045, 0.355, 1),
margin-left 0.3s cubic-bezier(0.645, 0.045, 0.355, 1), width 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
}
}
&.ant-menu-inline-collapsed {
.ant-menu-submenu-title {
padding-left: 16px !important;
padding-right: 16px !important;
}
.desktop-navbar-profile-menu-title {
.profile__image_thumb + span {
opacity: 0;
max-width: 0;
margin-left: 0;
}
width: @iconSize;
height: @iconSize;
}
}
}

View File

@@ -1,12 +1,13 @@
import { first } from "lodash";
import React, { useState } from "react";
import Button from "antd/lib/button";
import React, { useMemo } from "react";
import { first, includes } from "lodash";
import Menu from "antd/lib/menu";
import Link from "@/components/Link";
import HelpTrigger from "@/components/HelpTrigger";
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";
@@ -15,37 +16,66 @@ import AlertOutlinedIcon from "@ant-design/icons/AlertOutlined";
import PlusOutlinedIcon from "@ant-design/icons/PlusOutlined";
import QuestionCircleOutlinedIcon from "@ant-design/icons/QuestionCircleOutlined";
import SettingOutlinedIcon from "@ant-design/icons/SettingOutlined";
import MenuUnfoldOutlinedIcon from "@ant-design/icons/MenuUnfoldOutlined";
import MenuFoldOutlinedIcon from "@ant-design/icons/MenuFoldOutlined";
import VersionInfo from "./VersionInfo";
import "./DesktopNavbar.less";
function NavbarSection({ inlineCollapsed, children, ...props }) {
function NavbarSection({
children,
...props
}: any) {
return (
<Menu
selectable={false}
mode={inlineCollapsed ? "inline" : "vertical"}
inlineCollapsed={inlineCollapsed}
theme="dark"
{...props}>
<Menu selectable={false} mode="vertical" theme="dark" {...props}>
{children}
</Menu>
);
}
export default function DesktopNavbar() {
const [collapsed, setCollapsed] = useState(true);
function useNavbarActiveState() {
const currentRoute = useCurrentRoute();
return useMemo(
() => ({
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(
[
"Queries.List",
"Queries.Favorites",
"Queries.Archived",
"Queries.My",
"Queries.View",
"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]
);
}
export default function DesktopNavbar() {
const firstSettingsTab = first(settingsMenu.getAvailableItems());
const activeState = useNavbarActiveState();
const canCreateQuery = currentUser.hasPermission("create_query");
const canCreateDashboard = currentUser.hasPermission("create_dashboard");
const canCreateAlert = currentUser.hasPermission("list_alerts");
return (
<div className="desktop-navbar">
<NavbarSection inlineCollapsed={collapsed} className="desktop-navbar-logo">
<NavbarSection className="desktop-navbar-logo">
<div>
<Link href="./">
<img src={logoUrl} alt="Redash" />
@@ -53,45 +83,46 @@ export default function DesktopNavbar() {
</div>
</NavbarSection>
<NavbarSection inlineCollapsed={collapsed}>
<NavbarSection>
{currentUser.hasPermission("list_dashboards") && (
<Menu.Item key="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 />
<span>Dashboards</span>
<span className="desktop-navbar-label">Dashboards</span>
</Link>
</Menu.Item>
)}
{currentUser.hasPermission("view_query") && (
<Menu.Item key="queries">
// @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 />
<span>Queries</span>
<span className="desktop-navbar-label">Queries</span>
</Link>
</Menu.Item>
)}
{currentUser.hasPermission("list_alerts") && (
<Menu.Item key="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 />
<span>Alerts</span>
<span className="desktop-navbar-label">Alerts</span>
</Link>
</Menu.Item>
)}
</NavbarSection>
<NavbarSection inlineCollapsed={collapsed} className="desktop-navbar-spacer">
{(canCreateQuery || canCreateDashboard || canCreateAlert) && <Menu.Divider />}
<NavbarSection className="desktop-navbar-spacer">
{(canCreateQuery || canCreateDashboard || canCreateAlert) && (
<Menu.SubMenu
key="create"
popupClassName="desktop-navbar-submenu"
data-test="CreateButton"
title={
<React.Fragment>
<span data-test="CreateButton">
<PlusOutlinedIcon />
<span>Create</span>
</span>
<PlusOutlinedIcon />
<span className="desktop-navbar-label">Create</span>
</React.Fragment>
}>
{canCreateQuery && (
@@ -103,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>
@@ -119,32 +151,34 @@ export default function DesktopNavbar() {
)}
</NavbarSection>
<NavbarSection inlineCollapsed={collapsed}>
<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>Help</span>
<span className="desktop-navbar-label">Help</span>
</HelpTrigger>
</Menu.Item>
{firstSettingsTab && (
<Menu.Item key="settings">
// @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>Settings</span>
<span className="desktop-navbar-label">Settings</span>
</Link>
</Menu.Item>
)}
<Menu.Divider />
</NavbarSection>
<NavbarSection inlineCollapsed={collapsed} className="desktop-navbar-profile-menu">
<NavbarSection className="desktop-navbar-profile-menu">
<Menu.SubMenu
key="profile"
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>{currentUser.name}</span>
</span>
}>
<Menu.Item key="profile">
@@ -167,10 +201,6 @@ export default function DesktopNavbar() {
</Menu.Item>
</Menu.SubMenu>
</NavbarSection>
<Button onClick={() => setCollapsed(!collapsed)} className="desktop-navbar-collapse-button">
{collapsed ? <MenuUnfoldOutlinedIcon /> : <MenuFoldOutlinedIcon />}
</Button>
</div>
);
}

View File

@@ -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,
};

View File

@@ -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 */}

View File

@@ -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,
};

View File

@@ -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);

View File

@@ -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,
};

View File

@@ -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,
};

View File

@@ -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>;
}

View File

@@ -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: () => {},

View File

@@ -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") {

View File

@@ -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} />;
}

View File

@@ -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;

View File

@@ -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} />,
};
}

View File

@@ -1,5 +1,4 @@
import React, { useEffect, useState } from "react";
// @ts-expect-error (Must be removed after adding @redash/viz typing)
import ErrorBoundary, { ErrorBoundaryContext } from "@redash/viz/lib/components/ErrorBoundary";
import { Auth } from "@/services/auth";
import { policy } from "@/services/policy";
@@ -61,10 +60,12 @@ 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 ts-migrate(2769) FIXME: No overload matches this call. */}
<ErrorBoundary renderError={(error: Error) => <ErrorMessage error={error} />}>
<ErrorBoundaryContext.Consumer>
{({ handleError }: { handleError: UserSessionWrapperRenderChildrenProps<P>["onError"] }) =>
{({ handleError } /* : { handleError: UserSessionWrapperRenderChildrenProps<P>["onError"] } FIXME bring back type */) =>
render({ ...currentRoute.routeParams, pageTitle: currentRoute.title, onError: handleError })
}
</ErrorBoundaryContext.Consumer>

View File

@@ -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" />
</>
}

View File

@@ -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,

View File

@@ -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

View File

@@ -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,

View File

@@ -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>,

View File

@@ -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;

View 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;

View File

@@ -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;

View 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;

View File

@@ -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;

View 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;

View File

@@ -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,

View File

@@ -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,
};

View File

@@ -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,

View File

@@ -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>

View File

@@ -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: [],
};

View File

@@ -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,

View File

@@ -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",

View File

@@ -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: "",
};

View File

@@ -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&apos;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",

View File

@@ -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;

View File

@@ -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: () => {},
};

View File

@@ -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;

View File

@@ -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();

View File

@@ -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} />;
}

View File

@@ -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&nbsp;
<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,
};

View 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&nbsp;
{/* @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call. */}
<TagsControl className="inline-tags-control" tags={Array.from(tags)} tagSeparator={"+"} />.
</BigMessage>
);
}

View File

@@ -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,

View File

@@ -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: () => {},

View File

@@ -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;

View File

@@ -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}

View File

@@ -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))} />

View File

@@ -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}`} />}

View File

@@ -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);

View File

@@ -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,

View File

@@ -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 (

View File

@@ -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,

View File

@@ -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",

View File

@@ -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`

View File

@@ -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%",

View File

@@ -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>

View File

@@ -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: "",

View File

@@ -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,
};

View File

@@ -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,

View File

@@ -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,

View File

@@ -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;

View File

@@ -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

View File

@@ -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);

View File

@@ -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;
};
}

View File

@@ -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);

View File

@@ -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}

View File

@@ -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>

View File

@@ -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: [],
};

View File

@@ -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: "",

View File

@@ -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">

View File

@@ -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,
};

View File

@@ -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"

View File

@@ -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);
}

View File

@@ -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: [],

View File

@@ -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 };

View 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} />;
}

View File

@@ -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"]);

View File

@@ -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} />;
}

View File

@@ -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>;
}

View File

@@ -1,3 +0,0 @@
export default function ContentField({ field }) {
return field.content;
}

View File

@@ -0,0 +1,5 @@
export default function ContentField({
field
}: any) {
return field.content;
}

View File

@@ -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;

View File

@@ -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} />;
}

View File

@@ -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} />;
}

View File

@@ -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>
);
}

View File

@@ -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} />;
}

View File

@@ -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);
}

View File

@@ -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: "",

View File

@@ -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: "",

View File

@@ -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,

View File

@@ -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>

View File

@@ -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>

View File

@@ -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&apos;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,

Some files were not shown because too many files have changed in this diff Show More