blob: d2b52e2a42c9d726874d230066e148cb50d24757 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import React, { useState, useEffect, useMemo } from 'react';
import { useHistory } from 'react-router-dom';
import { Icon, Button, Switch, Colors, Intent } from '@blueprintjs/core';
import dayjs from 'dayjs';
import { Table, ColumnType } from '@/components';
import { getCron, transformEntities } from '@/config';
import { PluginConfig, DataScopeList } from '@/plugins';
import type { BlueprintType } from '../../types';
import { ModeEnum } from '../../types';
import { validRawPlan } from '../../utils';
import { AdvancedEditor } from '../../components';
import type { ConfigConnectionItemType } from '../types';
import { UpdateNameDialog, UpdatePolicyDialog, AddScopeDialog, UpdateTransformationDialog } from '../components';
import * as S from '../styled';
type Type = 'name' | 'frequency' | 'scope' | 'transformation';
interface Props {
blueprint: BlueprintType;
operating: boolean;
onUpdate: (bp: any) => void;
onRefresh: () => void;
}
export const Configuration = ({ blueprint, operating, onUpdate, onRefresh }: Props) => {
const [type, setType] = useState<Type>();
const [curConnection, setCurConnection] = useState<ConfigConnectionItemType>();
const [rawPlan, setRawPlan] = useState('');
const history = useHistory();
useEffect(() => {
setRawPlan(JSON.stringify(blueprint.plan, null, ' '));
}, [blueprint]);
const cron = useMemo(() => getCron(blueprint.isManual, blueprint.cronConfig), [blueprint]);
const connections = useMemo(
() =>
blueprint.settings?.connections
.filter((cs) => cs.plugin !== 'webhook')
.map((cs: any) => {
const plugin = PluginConfig.find((p) => p.plugin === cs.plugin) as any;
return {
icon: plugin.icon,
name: plugin.name,
connectionId: cs.connectionId,
entities: plugin.entities,
selectedEntites: cs.scopes?.[0]?.entities ?? [],
plugin: cs.plugin,
scope: cs.scopes,
scopeIds: cs.scopes.map((sc: any) => sc.id),
};
})
.filter(Boolean),
[blueprint],
);
const handleCancel = () => {
setType(undefined);
};
const handleUpdateName = async (name: string) => {
await onUpdate({ name });
handleCancel();
};
const handleUpdatePolicy = async (policy: any) => {
await onUpdate(policy);
handleCancel();
};
const handleToggleEnabled = (checked: boolean) => onUpdate({ enable: checked });
const handleUpdateConnection = (updated: any) =>
onUpdate({
settings: {
...blueprint.settings,
connections: blueprint.settings.connections.map((cs) =>
cs.plugin === updated.plugin && cs.connectionId === updated.connectionId ? updated : cs,
),
},
});
const handleUpdatePlan = () =>
onUpdate({
plan: !validRawPlan(rawPlan) ? JSON.parse(rawPlan) : JSON.stringify([[]], null, ' '),
});
const columns = useMemo(
() =>
[
{
title: 'Data Connections',
dataIndex: ['icon', 'name'],
key: 'connection',
render: ({ icon, name }: Pick<ConfigConnectionItemType, 'icon' | 'name'>) => (
<S.ConnectionColumn>
<img src={icon} alt="" />
<span>{name}</span>
</S.ConnectionColumn>
),
},
{
title: 'Data Entities',
dataIndex: 'selectedEntites',
key: 'selectedEntites',
render: (val: string[]) => (
<>
{transformEntities(val).map(({ label, value }) => (
<div key={value}>{label}</div>
))}
</>
),
},
{
title: 'Data Scope and Transformation',
dataIndex: ['plugin', 'connectionId', 'scopeIds'],
key: 'sopce',
render: ({
plugin,
connectionId,
scopeIds,
}: Pick<ConfigConnectionItemType, 'plugin' | 'connectionId' | 'scopeIds'>) => (
<DataScopeList groupByTs plugin={plugin} connectionId={connectionId} scopeIds={scopeIds} />
),
},
{
title: '',
key: 'action',
align: 'center',
render: (_, row: ConfigConnectionItemType) => (
<S.ActionColumn>
<div
className="item"
onClick={() => {
setType('scope');
setCurConnection(row);
}}
>
<Icon icon="annotation" color={Colors.BLUE2} />
<span>Change Data Scope</span>
</div>
{row.plugin !== 'sonarqube' && (
<>
<div
className="item"
onClick={() => {
setType('transformation');
setCurConnection(row);
}}
>
<Icon icon="annotation" color={Colors.BLUE2} />
<span>Re-apply Transformation</span>
</div>
<div className="item" onClick={() => history.push('/transformations')}>
<Icon icon="cog" color={Colors.BLUE2} />
<span>Manage Transformations</span>
</div>
</>
)}
</S.ActionColumn>
),
},
] as ColumnType<ConfigConnectionItemType>,
[],
);
return (
<S.ConfigurationPanel>
<div className="top">
<div className="block">
<h3>Name</h3>
<div className="detail">
<span>{blueprint.name}</span>
<Icon icon="annotation" color={Colors.BLUE2} onClick={() => setType('name')} />
</div>
</div>
<div className="block">
<h3>Sync Policy</h3>
<div className="detail">
<span>
{cron.label} {cron.value !== 'manual' ? dayjs(cron.nextTime).format('HH:mm A') : null}
</span>
<Icon icon="annotation" color={Colors.BLUE2} onClick={() => setType('frequency')} />
</div>
</div>
<div className="block">
<h3>Enabled</h3>
<div className="detail">
<Switch
checked={blueprint.enable}
onChange={(e) => handleToggleEnabled((e.target as HTMLInputElement).checked)}
/>
</div>
</div>
</div>
{blueprint.mode === ModeEnum.normal && (
<div className="bottom">
<h3>Data Scope and Transformation</h3>
<Table columns={columns} dataSource={connections} />
</div>
)}
{blueprint.mode === ModeEnum.advanced && (
<div className="bottom">
<h3>JSON Configuration</h3>
<AdvancedEditor value={rawPlan} onChange={setRawPlan} />
<div className="btns">
<Button intent={Intent.PRIMARY} text="Save" onClick={handleUpdatePlan} />
</div>
</div>
)}
{type === 'name' && (
<UpdateNameDialog
name={blueprint.name}
operating={operating}
onCancel={handleCancel}
onSubmit={handleUpdateName}
/>
)}
{type === 'frequency' && (
<UpdatePolicyDialog
blueprint={blueprint}
isManual={blueprint.isManual}
cronConfig={blueprint.cronConfig}
skipOnFail={blueprint.skipOnFail}
timeAfter={blueprint.settings?.timeAfter}
operating={operating}
onCancel={handleCancel}
onSubmit={handleUpdatePolicy}
/>
)}
{type === 'scope' && (
<AddScopeDialog connection={curConnection} onCancel={handleCancel} onSubmit={handleUpdateConnection} />
)}
{type === 'transformation' && (
<UpdateTransformationDialog connection={curConnection} onCancel={handleCancel} onRefresh={onRefresh} />
)}
</S.ConfigurationPanel>
);
};