Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Misc changes to codebase back ported from internal fork #5129

Merged
merged 13 commits into from
Aug 25, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 14 additions & 10 deletions client/.babelrc
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
{
"presets": [
["@babel/preset-env", {
"exclude": [
"@babel/plugin-transform-async-to-generator",
"@babel/plugin-transform-arrow-functions"
],
"useBuiltIns": "usage"
}],
[
"@babel/preset-env",
{
"exclude": ["@babel/plugin-transform-async-to-generator", "@babel/plugin-transform-arrow-functions"],
"corejs": "2",
"useBuiltIns": "usage"
}
],
"@babel/preset-react",
"@babel/preset-typescript"
],
"plugins": [
"@babel/plugin-proposal-class-properties",
"@babel/plugin-transform-object-assign",
["babel-plugin-transform-builtin-extend", {
"globals": ["Error"]
}]
[
"babel-plugin-transform-builtin-extend",
{
"globals": ["Error"]
}
]
]
}
18 changes: 13 additions & 5 deletions client/app/components/ApplicationArea/Router.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { isFunction, startsWith, trimStart, trimEnd } from "lodash";
import React, { useState, useEffect, useRef } from "react";
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";
Expand All @@ -14,6 +14,12 @@ function generateRouteKey() {
.substr(2);
}

export const CurrentRouteContext = React.createContext(null);

export function useCurrentRoute() {
return useContext(CurrentRouteContext);
}

export function stripBase(href) {
// Resolve provided link and '' (root) relative to document's base.
// If provided href is not related to current document (does not
Expand Down Expand Up @@ -53,7 +59,7 @@ export default function Router({ routes, onRouteChange }) {
errorHandlerRef.current.reset();
}

const pathname = stripBase(location.path);
const pathname = stripBase(location.path) || "/";

// This is a optimization for route resolver: if current route was already resolved
// from this path - do nothing. It also prevents router from using outdated route in a case
Expand Down Expand Up @@ -109,9 +115,11 @@ export default function Router({ routes, onRouteChange }) {
}

return (
<ErrorBoundary ref={errorHandlerRef} renderError={error => <ErrorMessage error={error} />}>
{currentRoute.render(currentRoute)}
</ErrorBoundary>
<CurrentRouteContext.Provider value={currentRoute}>
<ErrorBoundary ref={errorHandlerRef} renderError={error => <ErrorMessage error={error} />}>
{currentRoute.render(currentRoute)}
</ErrorBoundary>
</CurrentRouteContext.Provider>
);
}

Expand Down
30 changes: 30 additions & 0 deletions client/app/components/DialogWrapper.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { ModalProps } from "antd/lib/modal/Modal";

export interface DialogProps<ROk, RCancel> {
props: ModalProps;
close: (result: ROk) => void;
dismiss: (result: RCancel) => void;
}

export type DialogWrapperChildProps<ROk, RCancel> = {
dialog: DialogProps<ROk, RCancel>;
};

export type DialogComponentType<ROk = void, P = {}, RCancel = void> = React.ComponentType<
DialogWrapperChildProps<ROk, RCancel> & P
>;

export function wrap<ROk = void, P = {}, RCancel = void>(
DialogComponent: DialogComponentType<ROk, P, RCancel>
): {
Component: DialogComponentType<ROk, P, RCancel>;
showModal: (
props?: P
) => {
update: (props: P) => void;
onClose: (handler: (result: ROk) => Promise<void>) => void;
onDismiss: (handler: (result: RCancel) => Promise<void>) => void;
close: (result: ROk) => void;
dismiss: (result: RCancel) => void;
};
};
2 changes: 1 addition & 1 deletion client/app/components/PreviewCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ UserPreviewCard.defaultProps = {
// DataSourcePreviewCard

export function DataSourcePreviewCard({ dataSource, withLink, children, ...props }) {
const imageUrl = `/static/images/db-logos/${dataSource.type}.png`;
const imageUrl = `static/images/db-logos/${dataSource.type}.png`;
const title = withLink ? <a href={"data_sources/" + dataSource.id}>{dataSource.name}</a> : dataSource.name;
return (
<PreviewCard {...props} imageUrl={imageUrl} title={title}>
Expand Down
27 changes: 25 additions & 2 deletions client/app/components/empty-state/EmptyState.d.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,41 @@
import React from "react";

export interface EmptyStateProps {
type DefaultStepKey = "dataSources" | "queries" | "alerts" | "dashboards" | "users";
export type StepKey<K> = DefaultStepKey | K;

export interface StepItem<K> {
key: StepKey<K>;
node: React.ReactNode;
}

export interface EmptyStateProps<K = unknown> {
header?: string;
icon?: string;
description: string;
illustration: string;
illustrationPath?: string;
helpLink: string;

onboardingMode?: boolean;
showAlertStep?: boolean;
showDashboardStep?: boolean;
showDataSourceStep?: boolean;
showInviteStep?: boolean;

getStepsItems?: (items: Array<StepItem<K>>) => Array<StepItem<K>>;
}

declare const EmptyState: React.FunctionComponent<EmptyStateProps>;
declare class EmptyState<R> extends React.Component<EmptyStateProps<R>> {}

export default EmptyState;

export interface StepProps {
show: boolean;
completed: boolean;
url?: string;
urlText?: string;
text: string;
onClick?: () => void;
}

export declare const Step: React.FunctionComponent<StepProps>;
151 changes: 98 additions & 53 deletions client/app/components/empty-state/EmptyState.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { currentUser } from "@/services/auth";
import organizationStatus from "@/services/organizationStatus";
import "./empty-state.less";

function Step({ show, completed, text, url, urlText, onClick }) {
export function Step({ show, completed, text, url, urlText, onClick }) {
if (!show) {
return null;
}
Expand Down Expand Up @@ -46,10 +46,13 @@ function EmptyState({
onboardingMode,
showAlertStep,
showDashboardStep,
showDataSourceStep,
showInviteStep,
getStepsItems,
illustrationPath,
}) {
const isAvailable = {
dataSource: true,
dataSource: showDataSourceStep,
query: true,
alert: showAlertStep,
dashboard: showDashboardStep,
Expand All @@ -75,6 +78,92 @@ function EmptyState({
return null;
}

const renderDataSourcesStep = () => {
if (currentUser.isAdmin) {
return (
<Step
key="dataSources"
show={isAvailable.dataSource}
completed={isCompleted.dataSource}
url="data_sources/new"
urlText="Connect"
text="a Data Source"
/>
);
}

return (
<Step
key="dataSources"
show={isAvailable.dataSource}
completed={isCompleted.dataSource}
text="Ask an account admin to connect a data source"
/>
);
};

const defaultStepsItems = [
{
key: "dataSources",
node: renderDataSourcesStep(),
},
{
key: "queries",
node: (
<Step
key="queries"
show={isAvailable.query}
completed={isCompleted.query}
url="queries/new"
urlText="Create"
text="your first Query"
/>
),
},
{
key: "alerts",
node: (
<Step
key="alerts"
show={isAvailable.alert}
completed={isCompleted.alert}
url="alerts/new"
urlText="Create"
text="your first Alert"
/>
),
},
{
key: "dashboards",
node: (
<Step
key="dashboards"
show={isAvailable.dashboard}
completed={isCompleted.dashboard}
onClick={showCreateDashboardDialog}
urlText="Create"
text="your first Dashboard"
/>
),
},
{
key: "users",
node: (
<Step
key="users"
show={isAvailable.inviteUsers}
completed={isCompleted.inviteUsers}
url="users/new"
urlText="Invite"
text="your team members"
/>
),
},
];

const stepsItems = getStepsItems ? getStepsItems(defaultStepsItems) : defaultStepsItems;
const imageSource = illustrationPath ? illustrationPath : "static/images/illustrations/" + illustration + ".svg";

return (
<div className="empty-state bg-white tiled">
<div className="empty-state__summary">
Expand All @@ -83,60 +172,11 @@ function EmptyState({
<i className={icon} />
</h2>
<p>{description}</p>
<img
src={"/static/images/illustrations/" + illustration + ".svg"}
alt={illustration + " Illustration"}
width="75%"
/>
<img src={imageSource} alt={illustration + " Illustration"} width="75%" />
</div>
<div className="empty-state__steps">
<h4>Let&apos;s get started</h4>
<ol>
{currentUser.isAdmin && (
<Step
show={isAvailable.dataSource}
completed={isCompleted.dataSource}
url="data_sources/new"
urlText="Connect"
text="a Data Source"
/>
)}
{!currentUser.isAdmin && (
<Step
show={isAvailable.dataSource}
completed={isCompleted.dataSource}
text="Ask an account admin to connect a data source"
/>
)}
<Step
show={isAvailable.query}
completed={isCompleted.query}
url="queries/new"
urlText="Create"
text="your first Query"
/>
<Step
show={isAvailable.alert}
completed={isCompleted.alert}
url="alerts/new"
urlText="Create"
text="your first Alert"
/>
<Step
show={isAvailable.dashboard}
completed={isCompleted.dashboard}
onClick={showCreateDashboardDialog}
urlText="Create"
text="your first Dashboard"
/>
<Step
show={isAvailable.inviteUsers}
completed={isCompleted.inviteUsers}
url="users/new"
urlText="Invite"
text="your team members"
/>
</ol>
<ol>{stepsItems.map(item => item.node)}</ol>
<p>
Need more support?{" "}
<a href={helpLink} target="_blank" rel="noopener noreferrer">
Expand All @@ -154,12 +194,16 @@ EmptyState.propTypes = {
header: PropTypes.string,
description: PropTypes.string.isRequired,
illustration: PropTypes.string.isRequired,
illustrationPath: PropTypes.string,
helpLink: PropTypes.string.isRequired,

onboardingMode: PropTypes.bool,
showAlertStep: PropTypes.bool,
showDashboardStep: PropTypes.bool,
showDataSourceStep: PropTypes.bool,
showInviteStep: PropTypes.bool,

getStepItems: PropTypes.func,
};

EmptyState.defaultProps = {
Expand All @@ -169,6 +213,7 @@ EmptyState.defaultProps = {
onboardingMode: false,
showAlertStep: false,
showDashboardStep: false,
showDataSourceStep: true,
showInviteStep: false,
};

Expand Down
Loading