Commit 3601754d by zhaochengxiang

服务最新代码移植

parent dd7135b0
......@@ -120,3 +120,23 @@ export function* saveOwner(payload) {
export function* changeOwner(payload) {
return yield call(pds.changeOwner, payload)
}
export function* saveCols(payload) {
return yield call(pds.saveCols, payload);
}
export function* getCols(payload) {
return yield call(pds.getCols, payload);
}
export function* getAttrs(payload) {
return yield call(pds.getAttrs, payload);
}
export function* getJdbcInformation() {
return yield call(pds.getJdbcInformation);
}
export function* subscribe(payload) {
return yield call(pds.subscribe, payload);
}
\ No newline at end of file
import { PostFile, GetJSON, PostJSON, Post, Get } from "../util/axios"
import { PostFile, GetJSON, PostJSON, Post, Get, GetJSONRaw, callFetchRaw } from "../util/axios"
import { ContextPath } from "../util";
export function refreshCatalog() {
return GetJSON("/pdataservice/pdsCURD/refreshDataServiceCatalog")
......@@ -119,3 +120,23 @@ export function saveOwner(payload) {
export function changeOwner(payload) {
return PostJSON("/pdataservice/pdsCURD/changeOwnerOfDataService", payload)
}
export function saveCols(payload) {
return PostJSON("/pdataservice/pdsModel/saveVisibleTitle", payload);
}
export function getCols(payload) {
return GetJSON("/pdataservice/pdsModel/getVisibleTitle", payload);
}
export function getAttrs(payload) {
return GetJSON("/pdataservice/pdsModel/attrs", payload);
}
export function getJdbcInformation() {
return GetJSON('/pdataservice/pdsDriver/url');
}
export function subscribe(payload) {
return callFetchRaw('post', '/pdataservice/pdsSub/subscribeMsg', payload)
}
\ No newline at end of file
......@@ -176,3 +176,27 @@ export function PostFile(url, payload, fileName='file') {
callback
)
}
let config = {
baseURL,
headers: {
'Content-Type': 'multipart/form-data',
},
cache: 'no-cache',
}
export const callFetchRaw = (method, url, options) => {
const { params, ...reqConfig } = options;
var bodyFormData = new FormData();
Object.keys(params||[]).forEach(key => {
bodyFormData.append(key, params[key]);
});
return axios.request({
method,
url,
data: bodyFormData,
...config,
...reqConfig
})
}
\ No newline at end of file
......@@ -2,40 +2,50 @@ import { useState, useEffect } from 'react';
import { Modal, Button, Switch, Row, Col, Checkbox, Typography } from 'antd';
import { dispatch } from '../../../../model';
const cols = [
{title: '模型名称', require: true},
{title: '中文名称'},
{title: '路径'},
{title: '状态'},
{title: '创建人'},
{title: '版本号'},
{title: '模型描述'},
];
import { showMessage } from '../../../../util';
const ColSettingModal = (props) => {
const {visible, onCancel} = props;
const [loadingAttrs, setLoadingAttrs] = useState(false);
const [attrs, setAttrs] = useState(undefined);
const [catagories, setCatagories] = useState(undefined);
const [checkedKeys, setCheckedKeys] = useState([]);
const [confirmLoading, setConfirmLoading] = useState(false);
useEffect(() => {
if (visible) {
getAttrs();
getPreference();
}
//eslint-disable-next-line react-hooks/exhaustive-deps
}, [visible]);
const getPreference = () => {
const getAttrs = () => {
setLoadingAttrs(true);
dispatch({
type: 'datamodel.getPreference',
type: 'pds.getAttrs',
payload: {
modelName: 'DataService'
},
callback: data => {
if ((data.cols||'') === '') {
onCheckAllChange(true);
} else {
setCheckedKeys(data.cols.split(','));
setAttrs(data);
setCatagories(Array.from(new Set((data||[]).map(item => item.status))));
setLoadingAttrs(false);
},
error: () => {
setLoadingAttrs(false);
}
})
}
const getPreference = () => {
dispatch({
type: 'pds.getCols',
payload: {
modelName: 'DataService'
},
callback: data => {
setCheckedKeys(data?.map(item => item.titleCnName));
}
})
}
......@@ -44,14 +54,8 @@ const ColSettingModal = (props) => {
const newCheckedKeys = [];
if (checked) {
cols.forEach(col => {
newCheckedKeys.push(col.title);
});
} else {
cols.forEach(col => {
if (col.require) {
newCheckedKeys.push(col.title);
}
attrs?.forEach(col => {
newCheckedKeys.push(col.name);
});
}
......@@ -74,17 +78,24 @@ const ColSettingModal = (props) => {
}
const onModalOk = () => {
if ((checkedKeys||[]).length === 0) {
showMessage('warn', '不可进行全不选操作');
return;
}
setConfirmLoading(true);
dispatch({
type: 'datamodel.savePreference',
type: 'pds.saveCols',
payload: {
data: {
cols: checkedKeys.join(',')
}
params: {modelName: 'DataService'},
data: checkedKeys?.map(item => {
return { titleCnName: item }
})
},
callback: () => {
setConfirmLoading(false);
onCancel && onCancel(true);
showMessage('success', '操作成功');
},
error: () => {
setConfirmLoading(false);
......@@ -123,16 +134,24 @@ const ColSettingModal = (props) => {
/>
</div>
<div className='mt-3' style={{ maxHeight: 450, overflow: 'auto' }}>
{
catagories?.map((catagory, index) => {
return (
<div key={index}>
<div className='flex' style={{ alignItems: 'center', padding: '5px 0 15px' }}>
<div style={{ width: 3, height: 14, backgroundColor: '#0069AC', marginRight: 5 }} />
<span style={{ fontWeight: 'bold', color: '#464646' }}>{catagory}</span>
</div>
<Row>
{
cols.map((col, index) => {
attrs?.filter(col => col.status===catagory)?.map((col, index) => {
return (
<Col className='mb-3' key={index} md={6}>
<div className='d-flex'>
<Checkbox checked={ checkedKeys.indexOf(col.title||'')!==-1 } value={col.title} onChange={onCheckChange} disabled={col.require} >
<Checkbox checked={ checkedKeys.indexOf(col.name||'')!==-1 } value={col.name} onChange={onCheckChange} >
</Checkbox>
<Typography.Paragraph className='ml-1' title={col.title} ellipsis>
{col.title}
<Typography.Paragraph className='ml-1' title={col.name} ellipsis>
{col.name}
</Typography.Paragraph>
</div>
</Col>
......@@ -141,6 +160,10 @@ const ColSettingModal = (props) => {
}
</Row>
</div>
)
})
}
</div>
</Modal>
)
}
......
import React, { useEffect, useState, useContext } from 'react';
import { Spin } from 'antd';
import React, { useEffect, useState, useContext, useMemo } from 'react';
import { Spin, Tooltip, Typography, Pagination, Table } from 'antd';
import { AppContext } from '../../../../App';
import { dispatch } from '../../../../model';
import ModelTable from "./ModelTable";
import HistoryAndVersionDrawer from './HistoryAndVersionDrawer';
import { paginate } from '../../../../util';
const FC = (props) => {
const app = useContext(AppContext);
const [loading, setLoading] = useState(false);
const [data, setData] = useState([]);
const [historyParams, setHistoryParams] = useState({visible: false, id: undefined })
const [pagination, setPagination] = useState({pageNum: 1, pageSize: 20});
const {pageNum, pageSize} = pagination;
const cols = [
{
title: '序号',
dataIndex: 'key',
render: (text, record, index) => {
return (index+1).toString();
},
width: 60,
ellipsis: true,
},
{
title: '数据服务资产编码',
dataIndex: 'code',
ellipsis: true,
render: (_, record) => record.basicInfo?.code
},
{
title: '数据服务名称',
dataIndex: 'name',
ellipsis: true,
render: (_, record) => record.basicInfo?.name
},
{
title: 'URI',
dataIndex: 'odata',
ellipsis: true,
render: (text, _, __) => {
return (
<React.Fragment>
{
text ? <div className='flex'>
<Tooltip title={text||''} overlayClassName='tooltip-common'>
<Typography.Text ellipsis={true}>
{text||''}
</Typography.Text>
</Tooltip>
<Typography.Text copyable={{ text }}></Typography.Text>
</div> : ''
}
</React.Fragment>
);
}
},
{
title: '操作',
dataIndex: 'action',
width: 80,
fixed: 'right',
render: (_, record) => {
return (
<a onClick={() => {
app.openDetail?.({ service: record })
}}>详情</a>
)
}
}
];
useEffect(() => {
getServices();
}, [])
const tableData = useMemo(() => {
if (data) {
return paginate(data, pagination.pageNum, pagination.pageSize);
}
return [];
}, [data, pagination])
const getServices = () => {
setLoading(true);
dispatch({
......@@ -33,28 +99,32 @@ const FC = (props) => {
});
}
const onHistory = (id) => {
setHistoryParams({visible: true, id});
}
const onHistoryCancel = () => {
setHistoryParams({visible: false, id: undefined});
}
return (
<div>
<Spin spinning={loading}>
<ModelTable
user={app?.user}
view='grant'
data={data}
onHistory={onHistory}
{...props} />
</Spin>
<HistoryAndVersionDrawer
id={historyParams?.id}
visible={historyParams?.visible}
onCancel={onHistoryCancel}
<Table
extraColWidth={10}
loading={loading}
columns={cols||[]}
dataSource={tableData}
pagination={false}
scroll={{y: (tableData||[]).length===0?null:'calc(100vh - 121px - 57px - 24px - 38px - 44px)'}}
/>
<Pagination
className="text-center mt-3"
showSizeChanger
showQuickJumper
onChange={(_pageNum, _pageSize) => {
setPagination({ pageNum: _pageNum, pageSize: _pageSize || 20 });
}}
onShowSizeChange={(_pageNum, _pageSize) => {
setPagination({ pageNum: 1, pageSize: _pageSize });
}}
current={pageNum}
pageSize={pageSize}
defaultCurrent={1}
total={(data||[]).length}
pageSizeOptions={[10,20,50,100]}
showTotal={total => ` ${total} `}
/>
</div>
)
......
import React, { useEffect, useState } from 'react';
import { Modal, Typography, Button, Space, Tooltip, Spin } from 'antd';
import { CopyOutlined, DownloadOutlined } from '@ant-design/icons';
import copy from 'copy-to-clipboard';
import { dispatch } from '../../../../model';
import { showMessage } from '../../../../util';
const FC = (props) => {
const { visible, onCancel } = props;
const [information, setInformation] = useState(undefined);
const [loading, setLoading] = useState(false);
useEffect(() => {
if (visible) {
getInformation();
}
}, [visible])
const getInformation = () => {
setLoading(true);
dispatch({
type: 'pds.getJdbcInformation',
callback: data => {
setLoading(false);
setInformation(data);
},
error: () => {
setLoading(false);
}
})
}
return (
<Modal
title='JDBC信息'
width={540}
visible={visible}
onCancel={onCancel}
footer={null}
>
<Spin spinning={loading}>
<div className='flex mb-3' style={{ justifyContent: 'space-between', alignItems: 'baseline' }}>
<div style={{ width: 400 }}>
<Typography.Text>
{`impala JDBC地址: ${information?.impala?.url}`}
</Typography.Text>
</div>
<Space>
<Tooltip title={information?.impala?.urlTip}>
<Button type='link' icon={<CopyOutlined />} onClick={() => {
if (information?.impala?.url) {
copy(information?.impala?.url);
showMessage('success', '复制成功');
}
}} />
</Tooltip>
<Tooltip title={information?.impala?.downloadTip}>
<Button type='link' icon={<DownloadOutlined />} onClick={() => {
if (information?.impala?.downloadUrl) {
copy(information?.impala?.downloadUrl);
showMessage('success', '复制成功');
}
}} />
</Tooltip>
</Space>
</div>
<div className='flex' style={{ justifyContent: 'space-between', alignItems: 'baseline' }}>
<div style={{ width: 400 }}>
<Typography.Text>
{`Hana JDBC地址: ${information?.hana?.url}`}
</Typography.Text>
</div>
<Space>
<Tooltip title={information?.hana?.urlTip}>
<Button type='link' icon={<CopyOutlined />} onClick={() => {
if (information?.hana?.url) {
copy(information?.hana?.url);
showMessage('success', '复制成功');
}
}} />
</Tooltip>
<Tooltip title={information?.hana?.downloadTip}>
<Button type='link' icon={<DownloadOutlined />} onClick={() => {
if (information?.hana?.downloadUrl) {
copy(information?.hana?.downloadUrl);
showMessage('success', '复制成功');
}
}} />
</Tooltip>
</Space>
</div>
</Spin>
</Modal>
)
}
export default FC;
\ No newline at end of file
......@@ -562,6 +562,7 @@ const ModelTree = (props) => {
allowClear
value={searchKeyword}
style={{ marginBottom: 10, width: '100%' }}
placeholder='搜索目录'
onSelect={onAutoCompleteSelect}
onSearch={onAutoCompleteSearch}
onChange={onAutoCompleteChange}
......
......@@ -40,7 +40,7 @@ const FC = (props) => {
callback: () => {
reset();
showMessage('success', '申请成功')
showMessage('success', '下线成功')
onCancel && onCancel(true);
},
error: () => {
......@@ -78,7 +78,7 @@ const FC = (props) => {
<Form.Item
label="下线原因"
name="desc"
rules={[{ required: true, message: '请填写下线原因' }]}
// rules={[{ required: true, message: '请填写下线原因' }]}
>
<Input.TextArea rows={6} />
</Form.Item>
......
import React from 'react';
import { Button, Space, Spin, Input, Select, Tooltip, Dropdown, Menu } from 'antd';
import { Button, Space, Spin, Input, Select, Tooltip, Dropdown, Menu, Modal } from 'antd';
import copy from "copy-to-clipboard";
import { CaretLeftOutlined, CaretRightOutlined } from '@ant-design/icons';
import { ResizableBox } from 'react-resizable';
......@@ -14,6 +14,7 @@ import ExportOtherModal from './Component/ExportOtherModal';
import RecatalogModal from './Component/RecatalogModal';
import HistoryAndVersionDrawer from './Component/HistoryAndVersionDrawer';
import StartFlowModal from './Component/StartFlowModal';
import JDBCInformation from './Component/JDBCInformation';
import { showMessage, showNotifaction, inputWidth, DeleteTipModal, getDataModelerRole } from '../../../util';
import { dispatch, dispatchLatestHomepage } from '../../../model';
import { Action, CatalogId, ModelerId, Hints, ModelerData, PermitCheckOut, Editable, StateId, Holder, DDL, DataModelerRoleReader, ReadOnly } from '../../../util/constant';
......@@ -69,12 +70,13 @@ class Model extends React.Component {
},
startReleaseVisible: false,
offlineVisible: false,
jdbcInformationVisible: false,
}
}
componentDidMount() {
this.getModelStates();
// this.getPreference();
this.getPreference();
window?.addEventListener("storage", this.modelEventChange);
}
......@@ -111,14 +113,12 @@ class Model extends React.Component {
getPreference = () => {
dispatch({
type: 'datamodel.getPreference',
type: 'pds.getCols',
payload: {
modelName: 'DataService'
},
callback: data => {
this.setState();
if ((data.cols||'') === '') {
this.setState({visibleColNames: []});
} else {
this.setState({visibleColNames: data.cols.split(',')});
}
this.setState({visibleColNames: data?.map(item => item.titleCnName)});
}
})
}
......@@ -346,6 +346,34 @@ class Model extends React.Component {
this.setState({ startReleaseVisible: true })
}
onSubscribeBtnClick = () => {
const { selectModelerIds } = this.state;
const { modal } = this.props;
if ((selectModelerIds||[]).length === 0) {
showMessage('info', '请先选择服务');
return;
}
modal?.confirm({
title: '提示',
content: '是否确认订阅选中服务?',
onOk: () => {
dispatch({
type: 'pds.subscribe',
payload: {
params: {
ids: (selectModelerIds||[]).join(','),
}
},
callback: () => {
showMessage('success', '订阅成功');
this.setState({ selectModelerIds: [] });
}
})
},
});
}
onOfflineBtnClick = () => {
const { selectModelerIds } = this.state;
if ((selectModelerIds||[]).length === 0) {
......@@ -627,6 +655,9 @@ class Model extends React.Component {
overlay={
<Menu>
<Menu.Item onClick={() => {
app?.editServer?.({ dirId: catalogId, type: 'register' });
}}>注册服务</Menu.Item>
<Menu.Item onClick={() => {
app?.editServer?.({ dirId: catalogId, type: 'drag' });
}}>拖拉创建服务</Menu.Item>
<Menu.Item onClick={() => {
......@@ -653,11 +684,11 @@ class Model extends React.Component {
</Tooltip>
</Space> */}
<Space>
{/* <Space>
<Tooltip title={(selectModelerIds||[]).length===0?'请先选择服务':''}>
<Button onClick={this.onRecatalogBtnClick} disabled={(selectModelerIds||[]).length===0}>变更目录</Button>
</Tooltip>
</Space>
</Space> */}
{/* <Space>
<Tooltip title={(selectModelerIds||[]).length===0?'请先选择服务':''}>
......@@ -665,11 +696,11 @@ class Model extends React.Component {
</Tooltip>
</Space> */}
<Space>
{/* <Space>
<Tooltip title={(selectModelerIds||[]).length===0?'请先选择服务':''}>
<Button onClick={this.onReleaseBtnClick} disabled={(selectModelerIds||[]).length===0}>发布</Button>
</Tooltip>
</Space>
</Space> */}
{/* <Space>
<Tooltip title={(selectModelerIds||[]).length===0?'请先选择服务':''}>
......@@ -681,8 +712,20 @@ class Model extends React.Component {
</Space> */}
</React.Fragment>
}
<Space>
<Button onClick={this.onVisibleColSettingClick}>可见列设置</Button>
</Space>
<Space>
<Button onClick={() => { this.setState({jdbcInformationVisible: true}); }}>JDBC信息</Button>
</Space>
{
(getDataModelerRole(app?.user)!==DataModelerRoleReader) && isOnlyEnding &&
<Tooltip title={(selectModelerIds||[]).length===0?'请先选择服务':''}>
<Button onClick={this.onSubscribeBtnClick} disabled={(selectModelerIds||[]).length===0}>订阅</Button>
</Tooltip>
}
{
currentView==='dir' && (getDataModelerRole(app?.user)!==DataModelerRoleReader) && isOnlyEnding &&
(getDataModelerRole(app?.user)!==DataModelerRoleReader) && isOnlyEnding &&
<Tooltip title={(selectModelerIds||[]).length===0?'请先选择服务':''}>
<Button onClick={this.onOfflineBtnClick} disabled={(selectModelerIds||[]).length===0}>下线</Button>
</Tooltip>
......@@ -712,7 +755,7 @@ class Model extends React.Component {
</Space>
}
<Space>
<span>OData状态:</span>
{/* <span>OData状态:</span>
<Select
style={{ width: 120 }}
onChange={(value) => {
......@@ -723,7 +766,7 @@ class Model extends React.Component {
<Option value='0'>所有状态</Option>
<Option value='1'>已启动</Option>
<Option value='2'>未启动</Option>
</Select>
</Select> */}
</Space>
<Space>
<InputDebounce
......@@ -792,6 +835,16 @@ class Model extends React.Component {
ids={selectModelerIds}
onCancel={this.onOfflineCancel}
/>
<ColSettingModal
visible={colSettingModalVisible}
onCancel={this.onColSettingModalCancel}
/>
<JDBCInformation
visible={this.state.jdbcInformationVisible}
onCancel={() => { this.setState({ jdbcInformationVisible: false }) }}
/>
</div>
);
}
......@@ -799,10 +852,15 @@ class Model extends React.Component {
}
const WrapModel = (props) => {
const [modal, contextHolder] = Modal.useModal();
return (
<AppContext.Consumer>
{
value => <Model app={value} {...props} />
value => <React.Fragment>
<Model app={value} modal={modal} {...props} />
{contextHolder}
</React.Fragment>
}
</AppContext.Consumer>
)
......
import React, { useEffect, useState, useRef, useMemo } from 'react';
import { Table } from 'antd';
import { Resizable } from 'react-resizable';
import ResizeObserver from 'rc-resize-observer'
const scrollbarWidth = getScrollbarWidth()
const ResizeableHeaderCell = props => {
const { onResize, width, onClick, ...restProps } = props;
if (!width) {
return <th {...restProps} />;
}
return (
<Resizable
width={width}
height={0}
handle={
<span
className="react-resizable-handle"
onClick={(e) => {
e.stopPropagation();
}}
/>
}
onResize={onResize}
draggableOpts={{ enableUserSelectHack: false }}
>
<th
onClick={onClick}
{...restProps}
/>
</Resizable>
);
};
const ResizeableTable = (props) => {
const { columns, extraColWidth = 0, ...restProps } = props
const [tableWidth, setTableWidth] = useState(0)
const paddingCol = useRef({
key: 'padding',
width: 0,
render: () => undefined
})
const handleResize = (index) => (e, { size }) => {
setCols((prevCols) => {
const nextColumns = [...(prevCols ?? [])];
nextColumns[index] = {
...nextColumns[index],
width: size.width,
};
return nextColumns;
});
};
const [cols, setCols] = useState();
useEffect(() => {
if (!!columns && tableWidth > 0) {
const contentWidth = getWidth(tableWidth, extraColWidth)
setDefaultWidth(columns, contentWidth)
paddingCol.current.width = 0
const cols = columns
.map((col, index) => {
const colWidth = col.width ?? 100;
return {
...col,
width: colWidth,
ellipsis: true,
onHeaderCell: (column: any) => ({
width: column.width,
onResize: handleResize(index),
}),
};
})
setCols(cols)
}
}, [columns, tableWidth, extraColWidth])
const cols1 = useMemo(() => !!cols ? [...cols, paddingCol.current] : undefined, [cols])
return (
<ResizeObserver
onResize={({ width }) => {
setTableWidth(width)
}}
>
<Table
components={{
header: {
cell: ResizeableHeaderCell,
}
}}
columns={cols1}
{ ...restProps }
/>
</ResizeObserver>
);
}
export default ResizeableTable;
function getWidth(tableWidth, extraColWidth) {
// FIXME 判断没有选择列时,32为0
return tableWidth - scrollbarWidth - extraColWidth // scrollbar width, checkbox column
}
function setDefaultWidth(columns, width) {
let rowWidth = 0, count = 0
for (const col of columns) {
if (typeof col.width === 'number') {
rowWidth += col.width
} else {
count++
}
}
if (count > 0) {
let defaultW = (rowWidth > width ? 0 : width - rowWidth) / count
if (defaultW < 80) {
defaultW = 80
}
for (const col of columns) {
if (typeof col.width !== 'number') {
col.width = defaultW
}
}
}
}
export function getScrollbarWidth() {
// Creating invisible container
const outer = document.createElement('div');
outer.style.visibility = 'hidden';
outer.style.overflow = 'scroll'; // forcing scrollbar to appear
outer.style.msOverflowStyle = 'scrollbar'; // needed for WinJS apps
document.body.appendChild(outer);
// Creating inner element and placing it in the container
const inner = document.createElement('div');
outer.appendChild(inner);
// Calculating difference between container's full width and the child width
const scrollbarWidth = (outer.offsetWidth - inner.offsetWidth);
// Removing temporary elements from the DOM
outer.parentNode?.removeChild(outer);
return scrollbarWidth;
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment