Added UI for tableau fields (#506)

This commit is contained in:
darth-coder00 2021-09-16 15:08:54 +05:30 committed by GitHub
parent 4af4a66bee
commit abbef2df8b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 409 additions and 93 deletions

View File

@ -20,6 +20,7 @@ import { ServiceTypes } from 'Models';
import React, { FunctionComponent, useEffect, useRef, useState } from 'react'; import React, { FunctionComponent, useEffect, useRef, useState } from 'react';
import { serviceTypes } from '../../../constants/services.const'; import { serviceTypes } from '../../../constants/services.const';
import { import {
DashboardServiceType,
MessagingServiceType, MessagingServiceType,
ServiceCategory, ServiceCategory,
} from '../../../enums/service.enum'; } from '../../../enums/service.enum';
@ -47,6 +48,12 @@ export type DataObj = {
dashboardUrl?: string; dashboardUrl?: string;
username?: string; username?: string;
password?: string; password?: string;
url?: string;
api_key?: string;
site_name?: string;
api_version?: string;
server?: string;
env?: string;
}; };
type DatabaseService = { type DatabaseService = {
@ -61,9 +68,15 @@ type MessagingService = {
}; };
type DashboardService = { type DashboardService = {
dashboardUrl: string; dashboardUrl?: string;
username: string; username?: string;
password: string; password?: string;
url?: string;
api_key?: string;
site_name?: string;
api_version?: string;
server?: string;
env?: string;
}; };
export type ServiceDataObj = { export type ServiceDataObj = {
@ -101,6 +114,11 @@ type ErrorMsg = {
dashboardUrl?: boolean; dashboardUrl?: boolean;
username?: boolean; username?: boolean;
password?: boolean; password?: boolean;
redashUrl?: boolean;
apiKey?: boolean;
siteName?: boolean;
apiVersion?: boolean;
server?: boolean;
}; };
type EditorContentRef = { type EditorContentRef = {
getEditorContent: () => string; getEditorContent: () => string;
@ -190,6 +208,12 @@ export const AddServiceModal: FunctionComponent<Props> = ({
const [dashboardUrl, setDashboardUrl] = useState(data?.dashboardUrl || ''); const [dashboardUrl, setDashboardUrl] = useState(data?.dashboardUrl || '');
const [username, setUsername] = useState(data?.username || ''); const [username, setUsername] = useState(data?.username || '');
const [password, setPassword] = useState(data?.password || ''); const [password, setPassword] = useState(data?.password || '');
const [redashUrl, setRedashUrl] = useState(data?.url || '');
const [apiKey, setApiKey] = useState(data?.api_key || '');
const [siteName, setSiteName] = useState(data?.site_name || '');
const [apiVersion, setApiVersion] = useState(data?.api_version || '');
const [server, setServer] = useState(data?.server || '');
const [env, setEnv] = useState(data?.env || '');
const [frequency, setFrequency] = useState( const [frequency, setFrequency] = useState(
fromISOString(data?.ingestionSchedule?.repeatFrequency) fromISOString(data?.ingestionSchedule?.repeatFrequency)
); );
@ -198,10 +222,16 @@ export const AddServiceModal: FunctionComponent<Props> = ({
name: false, name: false,
url: false, url: false,
// port: false, // port: false,
// userName: false,
// password: false,
driverClass: false, driverClass: false,
broker: false, broker: false,
dashboardUrl: false,
username: false,
password: false,
redashUrl: false,
apiKey: false,
siteName: false,
apiVersion: false,
server: false,
}); });
const [sameNameError, setSameNameError] = useState(false); const [sameNameError, setSameNameError] = useState(false);
const markdownRef = useRef<EditorContentRef>(); const markdownRef = useRef<EditorContentRef>();
@ -284,6 +314,11 @@ export const AddServiceModal: FunctionComponent<Props> = ({
dashboardUrl, dashboardUrl,
username, username,
password, password,
redashUrl,
apiKey,
siteName,
apiVersion,
server,
} = value; } = value;
return ( return (
@ -295,7 +330,12 @@ export const AddServiceModal: FunctionComponent<Props> = ({
!broker && !broker &&
!dashboardUrl && !dashboardUrl &&
!username && !username &&
!password !password &&
!redashUrl &&
!apiKey &&
!siteName &&
!apiVersion &&
!server
); );
}; };
@ -326,12 +366,43 @@ export const AddServiceModal: FunctionComponent<Props> = ({
break; break;
case ServiceCategory.DASHBOARD_SERVICES: case ServiceCategory.DASHBOARD_SERVICES:
{ {
setMsg = { switch (selectService) {
...setMsg, case DashboardServiceType.REDASH:
dashboardUrl: !dashboardUrl, {
username: !username, setMsg = {
password: !password, ...setMsg,
}; redashUrl: !redashUrl,
apiKey: !apiKey,
};
}
break;
case DashboardServiceType.TABLEAU:
{
setMsg = {
...setMsg,
dashboardUrl: !dashboardUrl,
siteName: !siteName,
username: !username,
password: !password,
apiVersion: !apiVersion,
server: !server,
};
}
break;
default:
{
setMsg = {
...setMsg,
dashboardUrl: !dashboardUrl,
username: !username,
password: !password,
};
}
break;
}
} }
break; break;
@ -381,12 +452,46 @@ export const AddServiceModal: FunctionComponent<Props> = ({
break; break;
case ServiceCategory.DASHBOARD_SERVICES: case ServiceCategory.DASHBOARD_SERVICES:
{ {
dataObj = { switch (selectService) {
...dataObj, case DashboardServiceType.REDASH:
dashboardUrl: dashboardUrl, {
username: username, dataObj = {
password: password, ...dataObj,
}; url: redashUrl,
// eslint-disable-next-line @typescript-eslint/camelcase
api_key: apiKey,
};
}
break;
case DashboardServiceType.TABLEAU:
{
dataObj = {
...dataObj,
dashboardUrl: dashboardUrl,
// eslint-disable-next-line @typescript-eslint/camelcase
site_name: siteName,
username: username,
password: password,
// eslint-disable-next-line @typescript-eslint/camelcase
api_version: apiVersion,
server: server,
};
}
break;
default:
{
dataObj = {
...dataObj,
dashboardUrl: dashboardUrl,
username: username,
password: password,
};
}
break;
}
} }
break; break;
@ -496,55 +601,215 @@ export const AddServiceModal: FunctionComponent<Props> = ({
}; };
const getDashboardFields = (): JSX.Element => { const getDashboardFields = (): JSX.Element => {
return ( let elemFields: JSX.Element;
<> switch (selectService) {
<div className="tw-mt-4"> case DashboardServiceType.REDASH: {
<label className="tw-block tw-form-label" htmlFor="dashboard-url"> elemFields = (
{requiredField('Dashboard Url:')} <>
</label> <div className="tw-mt-4">
<input <label className="tw-block tw-form-label" htmlFor="url">
className="tw-form-inputs tw-px-3 tw-py-1" {requiredField('Url:')}
id="dashboard-url" </label>
name="dashboard-url" <input
placeholder="http(s)://hostname:port" className="tw-form-inputs tw-px-3 tw-py-1"
type="text" id="url"
value={dashboardUrl} name="url"
onChange={(e) => setDashboardUrl(e.target.value)} placeholder="http(s)://hostname:port"
/> type="text"
{showErrorMsg.dashboardUrl && errorMsg('Dashboard url is required')} value={redashUrl}
</div> onChange={(e) => setRedashUrl(e.target.value)}
<div className="tw-mt-4"> />
<label className="tw-block tw-form-label" htmlFor="username"> {showErrorMsg.redashUrl && errorMsg('Url is required')}
{requiredField('Username:')} </div>
</label> <div className="tw-mt-4">
<input <label className="tw-block tw-form-label" htmlFor="api-key">
className="tw-form-inputs tw-px-3 tw-py-1" {requiredField('Api key:')}
id="username" </label>
name="username" <input
placeholder="username" className="tw-form-inputs tw-px-3 tw-py-1"
type="text" id="api-key"
value={username} name="api-key"
onChange={(e) => setUsername(e.target.value)} placeholder="api key"
/> type="password"
{showErrorMsg.username && errorMsg('Username is required')} value={apiKey}
</div> onChange={(e) => setApiKey(e.target.value)}
<div className="tw-mt-4"> />
<label className="tw-block tw-form-label" htmlFor="password"> {showErrorMsg.apiKey && errorMsg('Api key is required')}
{requiredField('Password:')} </div>
</label> </>
<input );
className="tw-form-inputs tw-px-3 tw-py-1"
id="password" break;
name="password" }
placeholder="password" case DashboardServiceType.TABLEAU: {
type="password" elemFields = (
value={password} <>
onChange={(e) => setPassword(e.target.value)} <div className="tw-mt-4">
/> <label className="tw-block tw-form-label" htmlFor="site-name">
{showErrorMsg.password && errorMsg('Password is required')} {requiredField('Site Name:')}
</div> </label>
</> <input
); className="tw-form-inputs tw-px-3 tw-py-1"
id="site-name"
name="site-name"
placeholder="site name"
type="text"
value={siteName}
onChange={(e) => setSiteName(e.target.value)}
/>
{showErrorMsg.siteName && errorMsg('Site name is required')}
</div>
<div className="tw-mt-4">
<label className="tw-block tw-form-label" htmlFor="dashboard-url">
{requiredField('Site Url:')}
</label>
<input
className="tw-form-inputs tw-px-3 tw-py-1"
id="dashboard-url"
name="dashboard-url"
placeholder="http(s)://hostname:port"
type="text"
value={dashboardUrl}
onChange={(e) => setDashboardUrl(e.target.value)}
/>
{showErrorMsg.dashboardUrl && errorMsg('Site url is required')}
</div>
<div className="tw-mt-4">
<label className="tw-block tw-form-label" htmlFor="username">
{requiredField('Username:')}
</label>
<input
className="tw-form-inputs tw-px-3 tw-py-1"
id="username"
name="username"
placeholder="username"
type="text"
value={username}
onChange={(e) => setUsername(e.target.value)}
/>
{showErrorMsg.username && errorMsg('Username is required')}
</div>
<div className="tw-mt-4">
<label className="tw-block tw-form-label" htmlFor="password">
{requiredField('Password:')}
</label>
<input
className="tw-form-inputs tw-px-3 tw-py-1"
id="password"
name="password"
placeholder="password"
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
{showErrorMsg.password && errorMsg('Password is required')}
</div>
<div className="tw-mt-4">
<label className="tw-block tw-form-label" htmlFor="server">
{requiredField('Server:')}
</label>
<input
className="tw-form-inputs tw-px-3 tw-py-1"
id="server"
name="server"
placeholder="http(s)://hostname:port"
type="text"
value={server}
onChange={(e) => setServer(e.target.value)}
/>
{showErrorMsg.server && errorMsg('Server is required')}
</div>
<div className="tw-mt-4">
<label className="tw-block tw-form-label" htmlFor="api-version">
{requiredField('Api Version:')}
</label>
<input
className="tw-form-inputs tw-px-3 tw-py-1"
id="api-version"
name="api-version"
placeholder="api version"
type="text"
value={apiVersion}
onChange={(e) => setApiVersion(e.target.value)}
/>
{showErrorMsg.apiVersion && errorMsg('Api version is required')}
</div>
<div className="tw-mt-4">
<label className="tw-block tw-form-label" htmlFor="env">
Environment:
</label>
<input
className="tw-form-inputs tw-px-3 tw-py-1"
id="env"
name="env"
placeholder="environment"
type="text"
value={env}
onChange={(e) => setEnv(e.target.value)}
/>
</div>
</>
);
break;
}
default: {
elemFields = (
<>
<div className="tw-mt-4">
<label className="tw-block tw-form-label" htmlFor="dashboard-url">
{requiredField('Dashboard Url:')}
</label>
<input
className="tw-form-inputs tw-px-3 tw-py-1"
id="dashboard-url"
name="dashboard-url"
placeholder="http(s)://hostname:port"
type="text"
value={dashboardUrl}
onChange={(e) => setDashboardUrl(e.target.value)}
/>
{showErrorMsg.dashboardUrl &&
errorMsg('Dashboard url is required')}
</div>
<div className="tw-mt-4">
<label className="tw-block tw-form-label" htmlFor="username">
{requiredField('Username:')}
</label>
<input
className="tw-form-inputs tw-px-3 tw-py-1"
id="username"
name="username"
placeholder="username"
type="text"
value={username}
onChange={(e) => setUsername(e.target.value)}
/>
{showErrorMsg.username && errorMsg('Username is required')}
</div>
<div className="tw-mt-4">
<label className="tw-block tw-form-label" htmlFor="password">
{requiredField('Password:')}
</label>
<input
className="tw-form-inputs tw-px-3 tw-py-1"
id="password"
name="password"
placeholder="password"
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
{showErrorMsg.password && errorMsg('Password is required')}
</div>
</>
);
break;
}
}
return elemFields;
}; };
const getOptionalFields = (): JSX.Element => { const getOptionalFields = (): JSX.Element => {

View File

@ -71,8 +71,8 @@ export const serviceTypes: Record<ServiceTypes, Array<string>> = {
'Athena', 'Athena',
'Presto', 'Presto',
], ],
messagingServices: ['Kafka', 'Pulsar'], messagingServices: ['Kafka'],
dashboardServices: ['Superset', 'Looker', 'Tableau', 'Redash'], dashboardServices: ['Superset', 'Looker', 'Tableau'],
}; };
export const arrServiceTypes: Array<ServiceTypes> = [ export const arrServiceTypes: Array<ServiceTypes> = [

View File

@ -36,7 +36,10 @@ import { ModalWithMarkdownEditor } from '../../components/Modals/ModalWithMarkdo
import Tags from '../../components/tags/tags'; import Tags from '../../components/tags/tags';
import { pagingObject } from '../../constants/constants'; import { pagingObject } from '../../constants/constants';
import { SearchIndex } from '../../enums/search.enum'; import { SearchIndex } from '../../enums/search.enum';
import { ServiceCategory } from '../../enums/service.enum'; import {
DashboardServiceType,
ServiceCategory,
} from '../../enums/service.enum';
import { Dashboard } from '../../generated/entity/data/dashboard'; import { Dashboard } from '../../generated/entity/data/dashboard';
import { Topic } from '../../generated/entity/data/topic'; import { Topic } from '../../generated/entity/data/topic';
import useToastContext from '../../hooks/useToastContext'; import useToastContext from '../../hooks/useToastContext';
@ -244,27 +247,68 @@ const ServicePage: FunctionComponent = () => {
); );
} }
case ServiceCategory.DASHBOARD_SERVICES: { case ServiceCategory.DASHBOARD_SERVICES: {
return ( let elemFields: JSX.Element;
<span> switch (serviceType) {
<span className="tw-text-grey-muted tw-font-normal"> // case DashboardServiceType.REDASH:
Dashboard Url : // {
</span>{' '} // // TODO: add Redash fields if required
<span className="tw-pl-1tw-font-normal "> // }
{serviceDetails?.dashboardUrl ? (
<a // break;
className="link-text" case DashboardServiceType.TABLEAU:
href={serviceDetails.dashboardUrl} {
rel="noopener noreferrer" elemFields = (
target="_blank"> <>
{serviceDetails.dashboardUrl} <span>
</a> <span className="tw-text-grey-muted tw-font-normal">
) : ( Site Url :
'--' </span>{' '}
)} <span className="tw-pl-1tw-font-normal ">
</span> {serviceDetails?.dashboardUrl ? (
<span className="tw-mx-3 tw-text-grey-muted"></span> <a
</span> className="link-text"
); href={serviceDetails.dashboardUrl}
rel="noopener noreferrer"
target="_blank">
{serviceDetails.dashboardUrl}
</a>
) : (
'--'
)}
</span>
<span className="tw-mx-3 tw-text-grey-muted"></span>
</span>
</>
);
}
break;
default: {
elemFields = (
<span>
<span className="tw-text-grey-muted tw-font-normal">
Dashboard Url :
</span>{' '}
<span className="tw-pl-1tw-font-normal ">
{serviceDetails?.dashboardUrl ? (
<a
className="link-text"
href={serviceDetails.dashboardUrl}
rel="noopener noreferrer"
target="_blank">
{serviceDetails.dashboardUrl}
</a>
) : (
'--'
)}
</span>
<span className="tw-mx-3 tw-text-grey-muted"></span>
</span>
);
}
}
return elemFields;
} }
default: { default: {
return <></>; return <></>;

View File

@ -48,7 +48,10 @@ import {
PLUS, PLUS,
servicesDisplayName, servicesDisplayName,
} from '../../constants/services.const'; } from '../../constants/services.const';
import { ServiceCategory } from '../../enums/service.enum'; import {
DashboardServiceType,
ServiceCategory,
} from '../../enums/service.enum';
import { getCountBadge, getTabClasses } from '../../utils/CommonUtils'; import { getCountBadge, getTabClasses } from '../../utils/CommonUtils';
import { getFrequencyTime, serviceTypeLogo } from '../../utils/ServiceUtils'; import { getFrequencyTime, serviceTypeLogo } from '../../utils/ServiceUtils';
import SVGIcons from '../../utils/SvgUtils'; import SVGIcons from '../../utils/SvgUtils';
@ -239,7 +242,11 @@ const ServicesPage = () => {
return ( return (
<> <>
<div className="tw-mb-1"> <div className="tw-mb-1">
<label className="tw-mb-0">Dashboard URL:</label> <label className="tw-mb-0">
{service.serviceType === DashboardServiceType.TABLEAU
? 'Site URL:'
: 'Dashboard URL:'}
</label>
<span className=" tw-ml-1 tw-font-normal tw-text-grey-body"> <span className=" tw-ml-1 tw-font-normal tw-text-grey-body">
{service.dashboardUrl} {service.dashboardUrl}
</span> </span>