Browse Source

[Feature][UI Next] Add the page of rule management in the module of data quality. (#8317)

3.0.0/version-upgrade
calvin 3 years ago committed by GitHub
parent
commit
b75f67a56a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2156
      dolphinscheduler-ui-next/pnpm-lock.yaml
  2. 8
      dolphinscheduler-ui-next/src/layouts/content/use-dataList.ts
  3. 67
      dolphinscheduler-ui-next/src/locales/modules/en_US.ts
  4. 66
      dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts
  5. 9
      dolphinscheduler-ui-next/src/router/modules/data-quality.ts
  6. 22
      dolphinscheduler-ui-next/src/service/modules/data-quality/types.ts
  7. 102
      dolphinscheduler-ui-next/src/views/data-quality/rule/components/rule-modal.tsx
  8. 74
      dolphinscheduler-ui-next/src/views/data-quality/rule/components/table-action.tsx
  9. 26
      dolphinscheduler-ui-next/src/views/data-quality/rule/index.module.scss
  10. 157
      dolphinscheduler-ui-next/src/views/data-quality/rule/index.tsx
  11. 146
      dolphinscheduler-ui-next/src/views/data-quality/rule/use-table.ts
  12. 3
      dolphinscheduler-ui-next/src/views/projects/task/definition/index.module.scss
  13. 64
      dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag.module.scss

2156
dolphinscheduler-ui-next/pnpm-lock.yaml

File diff suppressed because it is too large Load Diff

8
dolphinscheduler-ui-next/src/layouts/content/use-dataList.ts

@ -44,7 +44,8 @@ import {
SafetyOutlined,
GroupOutlined,
ContainerOutlined,
ApartmentOutlined
ApartmentOutlined,
BarsOutlined
} from '@vicons/antd'
import { useMenuStore } from '@/store/menu/menu'
@ -184,6 +185,11 @@ export function useDataList() {
label: t('menu.task_result'),
key: `/data-quality/task-result`,
icon: renderIcon(ApartmentOutlined)
},
{
label: t('menu.rule'),
key: `/data-quality/rule`,
icon: renderIcon(BarsOutlined)
}
]
},

67
dolphinscheduler-ui-next/src/locales/modules/en_US.ts

@ -78,7 +78,8 @@ const menu = {
task_group_option: 'Task Group Option',
task_group_queue: 'Task Group Queue',
data_quality: 'Data Quality',
task_result: 'Task Result'
task_result: 'Task Result',
rule: 'Rule management'
}
const home = {
@ -771,6 +772,70 @@ const data_quality = {
expected_and_actual: 'Expected - Actual',
actual_and_expected: 'Actual - Expected',
actual_or_expected: 'Actual / Expected x 100%'
},
rule: {
actions: 'Actions',
name: 'Rule Name',
type: 'Rule Type',
username: 'User Name',
create_time: 'Create Time',
update_time: 'Update Time',
input_item: 'Rule input item',
view_input_item: 'View input items',
input_item_title: 'Input item title',
input_item_placeholder: 'Input item placeholder',
input_item_type: 'Input item type',
src_connector_type: 'SrcConnType',
src_datasource_id: 'SrcSource',
src_table: 'SrcTable',
src_filter: 'SrcFilter',
src_field: 'SrcField',
statistics_name: 'ActualValName',
check_type: 'CheckType',
operator: 'Operator',
threshold: 'Threshold',
failure_strategy: 'FailureStrategy',
target_connector_type: 'TargetConnType',
target_datasource_id: 'TargetSourceId',
target_table: 'TargetTable',
target_filter: 'TargetFilter',
mapping_columns: 'OnClause',
statistics_execute_sql: 'ActualValExecSql',
comparison_name: 'ExceptedValName',
comparison_execute_sql: 'ExceptedValExecSql',
comparison_type: 'ExceptedValType',
writer_connector_type: 'WriterConnType',
writer_datasource_id: 'WriterSourceId',
target_field: 'TargetField',
field_length: 'FieldLength',
logic_operator: 'LogicOperator',
regexp_pattern: 'RegexpPattern',
deadline: 'Deadline',
datetime_format: 'DatetimeFormat',
enum_list: 'EnumList',
begin_time: 'BeginTime',
fix_value: 'FixValue',
null_check: 'NullCheck',
custom_sql: 'Custom Sql',
single_table: 'Single Table',
single_table_custom_sql: 'Single Table Custom Sql',
multi_table_accuracy: 'Multi Table Accuracy',
multi_table_value_comparison: 'Multi Table Compare',
field_length_check: 'FieldLengthCheck',
uniqueness_check: 'UniquenessCheck',
regexp_check: 'RegexpCheck',
timeliness_check: 'TimelinessCheck',
enumeration_check: 'EnumerationCheck',
table_count_check: 'TableCountCheck',
All: 'All',
FixValue: 'FixValue',
DailyFluctuation: 'DailyFluctuation',
WeeklyFluctuation: 'WeeklyFluctuation',
MonthlyFluctuation: 'MonthlyFluctuation',
Last7DayFluctuation: 'Last7DayFluctuation',
Last30DayFluctuation: 'Last30DayFluctuation',
SrcTableTotalRows: 'SrcTableTotalRows',
TargetTableTotalRows: 'TargetTableTotalRows'
}
}

66
dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts

@ -78,7 +78,8 @@ const menu = {
task_group_option: '任务组配置',
task_group_queue: '任务组队列',
data_quality: '数据质量',
task_result: '任务结果'
task_result: '任务结果',
rule: '规则管理'
}
const home = {
@ -765,6 +766,69 @@ const data_quality = {
expected_and_actual: '期望值-实际值',
actual_and_expected: '实际值-期望值',
actual_or_expected: '实际值/期望值 x 100%'
},
rule: {
actions: '操作',
name: '规则名称',
type: '规则类型',
username: '用户名',
create_time: '创建时间',
update_time: '更新时间',
input_item: '规则输入项',
view_input_item: '查看规则输入项信息',
input_item_title: '输入项标题',
input_item_placeholder: '输入项占位符',
input_item_type: '输入项类型',
src_connector_type: '源数据类型',
src_datasource_id: '源数据源',
src_table: '源数据表',
src_filter: '源表过滤条件',
src_field: '源表检测列',
statistics_name: '实际值名',
check_type: '校验方式',
operator: '校验操作符',
threshold: '阈值',
failure_strategy: '失败策略',
target_connector_type: '目标数据类型',
target_datasource_id: '目标数据源',
target_table: '目标数据表',
target_filter: '目标表过滤条件',
mapping_columns: 'ON语句',
statistics_execute_sql: '实际值计算SQL',
comparison_name: '期望值名',
comparison_execute_sql: '期望值计算SQL',
comparison_type: '期望值类型',
writer_connector_type: '输出数据类型',
writer_datasource_id: '输出数据源',
target_field: '目标表检测列',
field_length: '字段长度限制',
logic_operator: '逻辑操作符',
regexp_pattern: '正则表达式',
deadline: '截止时间',
datetime_format: '时间格式',
enum_list: '枚举值列表',
begin_time: '起始时间',
fix_value: '固定值',
null_check: '空值检测',
custom_sql: '自定义SQL',
single_table: '单表检测',
multi_table_accuracy: '多表准确性',
multi_table_value_comparison: '两表值比对',
field_length_check: '字段长度校验',
uniqueness_check: '唯一性校验',
regexp_check: '正则表达式',
timeliness_check: '及时性校验',
enumeration_check: '枚举值校验',
table_count_check: '表行数校验',
all: '全部',
FixValue: '固定值',
DailyFluctuation: '日波动',
WeeklyFluctuation: '周波动',
MonthlyFluctuation: '月波动',
Last7DayFluctuation: '最近7天波动',
Last30DayFluctuation: '最近30天波动',
SrcTableTotalRows: '源表总行数',
TargetTableTotalRows: '目标表总行数'
}
}

9
dolphinscheduler-ui-next/src/router/modules/data-quality.ts

@ -37,6 +37,15 @@ export default {
title: '数据质量-task-result',
showSide: true
}
},
{
path: '/data-quality/rule',
name: 'data-quality-rule',
component: components['data-quality-rule'],
meta: {
title: '数据质量-rule',
showSide: true
}
}
]
}

22
dolphinscheduler-ui-next/src/service/modules/data-quality/types.ts

@ -71,4 +71,24 @@ interface ResultListRes {
start: number
}
export { RuleListReq, ResultListReq, ResultItem, ResultListRes }
interface Rule {
id: number
name: string
ruleJson: string
type: number
userId: number
userName: string
createTime: string
updateTime: string
}
interface RuleRes {
totalList: Rule[]
total: number
totalPage: number
pageSize: number
currentPage: number
start: number
}
export { RuleListReq, ResultListReq, ResultItem, ResultListRes, Rule, RuleRes }

102
dolphinscheduler-ui-next/src/views/data-quality/rule/components/rule-modal.tsx

@ -0,0 +1,102 @@
/*
* 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 { defineComponent, h, PropType, reactive, ref, toRefs, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { NDataTable } from 'naive-ui'
import Modal from '@/components/modal'
import styles from '../index.module.scss'
import { TableColumns } from 'naive-ui/es/data-table/src/interface'
const props = {
show: {
type: Boolean as PropType<boolean>,
default: false
},
data: {
type: String as PropType<string>,
default: ''
}
}
export default defineComponent({
name: 'ruleInputEntry',
props,
emits: ['cancel', 'confirm'],
setup(props, ctx) {
const { t } = useI18n()
const ruleInputEntryList = JSON.parse(props.data).ruleInputEntryList
ruleInputEntryList.forEach((item: any) => {
item.title = t(
'data_quality.rule.' + item.title.substring(3, item.title.length - 1)
)
})
const columns: TableColumns<any> = [
{
title: t('data_quality.rule.input_item_title'),
key: 'title'
},
{
title: t('data_quality.rule.input_item_placeholder'),
key: 'field'
},
{
title: t('data_quality.rule.input_item_type'),
key: 'type'
}
]
const onCancel = () => {
ctx.emit('cancel')
}
const onConfirm = () => {
ctx.emit('confirm')
}
return {
onCancel,
onConfirm,
columns,
ruleInputEntryList
}
},
render() {
const { t } = useI18n()
return (
<Modal
show={this.$props.show}
title={t('data_quality.rule.input_item')}
cancelShow={false}
onConfirm={this.onConfirm}
>
<NDataTable
columns={this.columns}
data={this.ruleInputEntryList}
striped
size={'small'}
class={styles.table}
/>
</Modal>
)
}
})

74
dolphinscheduler-ui-next/src/views/data-quality/rule/components/table-action.tsx

@ -0,0 +1,74 @@
/*
* 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 { defineComponent, PropType } from 'vue'
import { useI18n } from 'vue-i18n'
import { NSpace, NTooltip, NButton, NIcon } from 'naive-ui'
import { InfoCircleFilled } from '@vicons/antd'
import type { Rule } from '@/service/modules/data-quality/types'
interface ItemRow extends Rule {}
const props = {
row: {
type: Object as PropType<ItemRow>,
default: {}
}
}
const TableAction = defineComponent({
name: 'TableAction',
props,
emits: ['viewRuleEntry'],
setup(props, { emit }) {
const { t } = useI18n()
const viewRuleEntryDetails = (detail: string) => {
emit('viewRuleEntry', detail)
}
return { t, viewRuleEntryDetails }
},
render() {
const { t, viewRuleEntryDetails } = this
return (
<NSpace>
<NTooltip trigger={'hover'}>
{{
default: () => t('data_quality.rule.view_input_item'),
trigger: () => (
<NButton
size='small'
type='primary'
tag='div'
onClick={() => viewRuleEntryDetails(this.row.ruleJson)}
circle
>
<NIcon>
<InfoCircleFilled />
</NIcon>
</NButton>
)
}}
</NTooltip>
</NSpace>
)
}
})
export default TableAction

26
dolphinscheduler-ui-next/src/views/data-quality/rule/index.module.scss

@ -0,0 +1,26 @@
/*
* 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.
*/
.table-card {
margin-top: 8px;
.pagination {
margin-top: 20px;
display: flex;
justify-content: center;
}
}

157
dolphinscheduler-ui-next/src/views/data-quality/rule/index.tsx

@ -0,0 +1,157 @@
/*
* 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 { defineComponent, onMounted, ref, toRefs, watch } from 'vue'
import {
NSpace,
NInput,
NButton,
NIcon,
NDataTable,
NPagination,
NCard
} from 'naive-ui'
import { SearchOutlined } from '@vicons/antd'
import { useTable } from './use-table'
import Card from '@/components/card'
import styles from './index.module.scss'
import RuleModal from './components/rule-modal'
const TaskResult = defineComponent({
name: 'rule',
setup() {
const { t, variables, getTableData } = useTable()
const showModalRef = ref(false)
const ruleEntryData = ref('')
const requestTableData = () => {
getTableData({
pageSize: variables.pageSize,
pageNo: variables.page,
startDate: '',
endDate: '',
searchVal: variables.searchVal
})
}
const onUpdatePageSize = () => {
variables.page = 1
requestTableData()
}
const onSearch = () => {
variables.page = 1
requestTableData()
}
const onCancel = () => {
showModalRef.value = false
}
const onConfirm = () => {
showModalRef.value = false
}
const viewRuleEntry = (ruleJson: string) => {
showModalRef.value = true
ruleEntryData.value = ruleJson
}
onMounted(() => {
requestTableData()
})
return {
t,
...toRefs(variables),
requestTableData,
onUpdatePageSize,
showModalRef,
onCancel,
onConfirm,
onSearch,
ruleEntryData,
viewRuleEntry
}
},
render() {
const {
t,
showModalRef,
requestTableData,
onUpdatePageSize,
onSearch,
onCancel,
onConfirm,
viewRuleEntry,
ruleEntryData
} = this
const { columns } = useTable(viewRuleEntry)
return (
<div>
<NCard>
<NSpace justify='end'>
<NInput
v-model={[this.searchVal, 'value']}
size='small'
placeholder={t('data_quality.rule.name')}
clearable
/>
<NButton size='small' type='primary' onClick={onSearch}>
{{
icon: () => (
<NIcon>
<SearchOutlined />
</NIcon>
)
}}
</NButton>
</NSpace>
</NCard>
<Card class={styles['table-card']}>
<NDataTable columns={columns} data={this.tableData} />
<div class={styles.pagination}>
<NPagination
v-model:page={this.page}
v-model:page-size={this.pageSize}
page-count={this.totalPage}
show-size-picker
page-sizes={[10, 30, 50]}
show-quick-jumper
onUpdatePage={requestTableData}
onUpdatePageSize={onUpdatePageSize}
/>
</div>
</Card>
{showModalRef && (
<RuleModal
show={showModalRef}
onCancel={onCancel}
onConfirm={onConfirm}
data={ruleEntryData}
/>
)}
</div>
)
}
})
export default TaskResult

146
dolphinscheduler-ui-next/src/views/data-quality/rule/use-table.ts

@ -0,0 +1,146 @@
/*
* 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 { useI18n } from 'vue-i18n'
import { h, reactive, ref } from 'vue'
import { useAsyncState } from '@vueuse/core'
import { queryRuleListPaging } from '@/service/modules/data-quality'
import type { Rule, RuleRes } from '@/service/modules/data-quality/types'
import TableAction from './components/table-action'
import _ from 'lodash'
import { format } from 'date-fns'
import { TableColumns } from 'naive-ui/es/data-table/src/interface'
export function useTable(viewRuleEntry = (ruleJson: string): void => {}) {
const { t } = useI18n()
const variables = reactive({
tableData: [],
page: ref(1),
pageSize: ref(10),
state: ref(null),
searchVal: ref(null),
totalPage: ref(1)
})
const columns: TableColumns<any> = [
{
title: t('data_quality.rule.name'),
key: 'ruleName'
},
{
title: t('data_quality.rule.type'),
key: 'ruleTypeName'
},
{
title: t('data_quality.rule.username'),
key: 'userName'
},
{
title: t('data_quality.rule.create_time'),
key: 'createTime'
},
{
title: t('data_quality.rule.update_time'),
key: 'updateTime'
},
{
title: t('data_quality.rule.actions'),
key: 'actions',
width: 150,
render: (row: any) =>
h(TableAction, {
row,
onViewRuleEntry: (ruleJson: string) => {
viewRuleEntry(ruleJson)
}
})
}
]
const ruleTypeMapping = [
{
code: -1,
label: t('data_quality.rule.all')
},
{
code: 0,
label: t('data_quality.rule.single_table')
},
{
code: 1,
label: t('data_quality.rule.custom_sql')
},
{
code: 2,
label: t('data_quality.rule.multi_table_accuracy')
},
{
code: 3,
label: t('data_quality.rule.multi_table_value_comparison')
}
]
const getTableData = (params: any) => {
const data = {
pageSize: params.pageSize,
pageNo: params.pageNo,
searchVal: params.searchVal,
startDate: params.startDate,
endDate: params.endDate
}
const { state } = useAsyncState(
queryRuleListPaging(data).then((res: RuleRes) => {
variables.tableData = res.totalList.map((item, index) => {
const ruleName =
'data_quality.rule.' + item.name.substring(3, item.name.length - 1)
const ruleNameLocale = t(ruleName)
const ruleType = _.find(ruleTypeMapping, { code: item.type })
let ruleTypeName = ''
if (ruleType) {
ruleTypeName = ruleType.label
}
item.createTime = format(
new Date(item.createTime),
'yyyy-MM-dd HH:mm:ss'
)
item.updateTime = format(
new Date(item.updateTime),
'yyyy-MM-dd HH:mm:ss'
)
return {
index: index + 1,
...item,
ruleName: ruleNameLocale,
ruleTypeName: ruleTypeName
}
}) as any
}),
{}
)
return state
}
return { t, variables, getTableData, columns }
}

3
dolphinscheduler-ui-next/src/views/projects/task/definition/index.module.scss

@ -26,7 +26,8 @@
align-items: center;
width: 300px;
button, input {
button,
input {
margin-left: 10px;
}
}

64
dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag.module.scss

@ -96,104 +96,104 @@ $bgLight: #ffffff;
background-size: 100% 100%;
margin-right: 10px;
&.icon-shell {
background-image: url("@/assets/images/task-icons/shell.png");
background-image: url('@/assets/images/task-icons/shell.png');
}
&.icon-sub_process {
background-image: url("@/assets/images/task-icons/sub_process.png");
background-image: url('@/assets/images/task-icons/sub_process.png');
}
&.icon-procedure {
background-image: url("@/assets/images/task-icons/procedure.png");
background-image: url('@/assets/images/task-icons/procedure.png');
}
&.icon-sql {
background-image: url("@/assets/images/task-icons/sql.png");
background-image: url('@/assets/images/task-icons/sql.png');
}
&.icon-flink {
background-image: url("@/assets/images/task-icons/flink.png");
background-image: url('@/assets/images/task-icons/flink.png');
}
&.icon-mr {
background-image: url("@/assets/images/task-icons/mr.png");
background-image: url('@/assets/images/task-icons/mr.png');
}
&.icon-python {
background-image: url("@/assets/images/task-icons/python.png");
background-image: url('@/assets/images/task-icons/python.png');
}
&.icon-dependent {
background-image: url("@/assets/images/task-icons/dependent.png");
background-image: url('@/assets/images/task-icons/dependent.png');
}
&.icon-http {
background-image: url("@/assets/images/task-icons/http.png");
background-image: url('@/assets/images/task-icons/http.png');
}
&.icon-datax {
background-image: url("@/assets/images/task-icons/datax.png");
background-image: url('@/assets/images/task-icons/datax.png');
}
&.icon-pigeon {
background-image: url("@/assets/images/task-icons/pigeon.png");
background-image: url('@/assets/images/task-icons/pigeon.png');
}
&.icon-sqoop {
background-image: url("@/assets/images/task-icons/sqoop.png");
background-image: url('@/assets/images/task-icons/sqoop.png');
}
&.icon-conditions {
background-image: url("@/assets/images/task-icons/conditions.png");
background-image: url('@/assets/images/task-icons/conditions.png');
}
&.icon-seatunnel {
background-image: url("@/assets/images/task-icons/seatunnel.png");
background-image: url('@/assets/images/task-icons/seatunnel.png');
}
&.icon-spark {
background-image: url("@/assets/images/task-icons/spark.png");
background-image: url('@/assets/images/task-icons/spark.png');
}
&.icon-switch {
background-image: url("@/assets/images/task-icons/switch.png");
background-image: url('@/assets/images/task-icons/switch.png');
}
}
&:hover {
.sidebar-icon {
&.icon-shell {
background-image: url("@/assets/images/task-icons/shell_hover.png");
background-image: url('@/assets/images/task-icons/shell_hover.png');
}
&.icon-sub_process {
background-image: url("@/assets/images/task-icons/sub_process_hover.png");
background-image: url('@/assets/images/task-icons/sub_process_hover.png');
}
&.icon-procedure {
background-image: url("@/assets/images/task-icons/procedure_hover.png");
background-image: url('@/assets/images/task-icons/procedure_hover.png');
}
&.icon-sql {
background-image: url("@/assets/images/task-icons/sql_hover.png");
background-image: url('@/assets/images/task-icons/sql_hover.png');
}
&.icon-flink {
background-image: url("@/assets/images/task-icons/flink_hover.png");
background-image: url('@/assets/images/task-icons/flink_hover.png');
}
&.icon-mr {
background-image: url("@/assets/images/task-icons/mr_hover.png");
background-image: url('@/assets/images/task-icons/mr_hover.png');
}
&.icon-python {
background-image: url("@/assets/images/task-icons/python_hover.png");
background-image: url('@/assets/images/task-icons/python_hover.png');
}
&.icon-dependent {
background-image: url("@/assets/images/task-icons/dependent_hover.png");
background-image: url('@/assets/images/task-icons/dependent_hover.png');
}
&.icon-http {
background-image: url("@/assets/images/task-icons/http_hover.png");
background-image: url('@/assets/images/task-icons/http_hover.png');
}
&.icon-datax {
background-image: url("@/assets/images/task-icons/datax_hover.png");
background-image: url('@/assets/images/task-icons/datax_hover.png');
}
&.icon-pigeon {
background-image: url("@/assets/images/task-icons/pigeon_hover.png");
background-image: url('@/assets/images/task-icons/pigeon_hover.png');
}
&.icon-sqoop {
background-image: url("@/assets/images/task-icons/sqoop_hover.png");
background-image: url('@/assets/images/task-icons/sqoop_hover.png');
}
&.icon-conditions {
background-image: url("@/assets/images/task-icons/conditions_hover.png");
background-image: url('@/assets/images/task-icons/conditions_hover.png');
}
&.icon-seatunnel {
background-image: url("@/assets/images/task-icons/seatunnel_hover.png");
background-image: url('@/assets/images/task-icons/seatunnel_hover.png');
}
&.icon-spark {
background-image: url("@/assets/images/task-icons/spark_hover.png");
background-image: url('@/assets/images/task-icons/spark_hover.png');
}
&.icon-switch {
background-image: url("@/assets/images/task-icons/switch_hover.png");
background-image: url('@/assets/images/task-icons/switch_hover.png');
}
}
}

Loading…
Cancel
Save