parent
e10e627d1c
commit
c12b30ffef
@ -331,9 +331,10 @@ export class BuiltInPlugin extends Plugin {
|
|||||||
name: 'pinned-list',
|
name: 'pinned-list',
|
||||||
config: {
|
config: {
|
||||||
items: {
|
items: {
|
||||||
ui: { order: 100, component: 'DesignableSwitch', pin: true, snippet: 'ui.*' },
|
wf: { order: 100, component: 'WorkflowLink', pin: true, snippet: 'pm.*' },
|
||||||
pm: { order: 200, component: 'PluginManagerLink', pin: true, snippet: 'pm' },
|
ds: { order: 200, component: 'DatasourceLink', pin: true, snippet: 'pm.*' },
|
||||||
sc: { order: 300, component: 'SettingsCenterDropdown', pin: true, snippet: 'pm.*' },
|
pm: { order: 300, component: 'PluginManagerLink', pin: true, snippet: 'pm' },
|
||||||
|
sc: { order: 400, component: 'SettingsCenterDropdown', pin: true, snippet: 'pm.*' },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -5,7 +5,7 @@ import { Plugin } from '../../application/Plugin';
|
|||||||
import { BlockTemplatesPane } from '../../schema-templates';
|
import { BlockTemplatesPane } from '../../schema-templates';
|
||||||
import { SystemSettingsPane } from '../system-settings';
|
import { SystemSettingsPane } from '../system-settings';
|
||||||
import { PluginManager } from './PluginManager';
|
import { PluginManager } from './PluginManager';
|
||||||
import { PluginManagerLink, SettingsCenterDropdown } from './PluginManagerLink';
|
import { DatasourceLink, PluginManagerLink, SettingsCenterDropdown, WorkflowLink } from './PluginManagerLink';
|
||||||
import { AdminSettingsLayout } from './PluginSetting';
|
import { AdminSettingsLayout } from './PluginSetting';
|
||||||
|
|
||||||
export * from './PluginManager';
|
export * from './PluginManager';
|
||||||
|
@ -1,23 +1,67 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useDesignable } from '@tachybase/client';
|
import { css, useDesignable } from '@tachybase/client';
|
||||||
|
|
||||||
import { CalculatorOutlined, CommentOutlined, HighlightOutlined, ToolFilled, ToolOutlined } from '@ant-design/icons';
|
import { CalculatorOutlined, CommentOutlined, HighlightOutlined, ToolOutlined } from '@ant-design/icons';
|
||||||
import { FloatButton } from 'antd';
|
import { FloatButton } from 'antd';
|
||||||
|
import { createPortal } from 'react-dom';
|
||||||
|
|
||||||
import { useContextMenu } from '../context-menu/useContextMenu';
|
import { useContextMenu } from '../context-menu/useContextMenu';
|
||||||
|
import { CalculatorWrapper } from './calculator/Calculator';
|
||||||
|
|
||||||
export const AssistantProvider = ({ children }) => {
|
export const AssistantProvider = ({ children }) => {
|
||||||
const { designable, setDesignable } = useDesignable();
|
const { designable, setDesignable } = useDesignable();
|
||||||
const { contextMenuEnabled, setContextMenuEnable } = useContextMenu();
|
const { contextMenuEnabled, setContextMenuEnable } = useContextMenu();
|
||||||
const ContextMenuIcon = contextMenuEnabled ? ToolFilled : ToolOutlined;
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{children}
|
{children}
|
||||||
<FloatButton.Group trigger="hover" type="primary" style={{ right: 24, zIndex: 1250 }} icon={<ToolOutlined />}>
|
<FloatButton.Group trigger="hover" type="default" style={{ right: 24, zIndex: 1250 }} icon={<ToolOutlined />}>
|
||||||
<FloatButton icon={<HighlightOutlined />} onClick={() => setDesignable(!designable)} />
|
<FloatButton
|
||||||
<FloatButton icon={<CalculatorOutlined />} />
|
icon={<HighlightOutlined />}
|
||||||
|
type={designable ? 'primary' : 'default'}
|
||||||
|
onClick={() => setDesignable(!designable)}
|
||||||
|
/>
|
||||||
|
<FloatButton
|
||||||
|
icon={<CalculatorOutlined />}
|
||||||
|
onClick={() => {
|
||||||
|
createPortal(
|
||||||
|
// <div
|
||||||
|
// className={css`
|
||||||
|
// position: fixed;
|
||||||
|
// top: 0;
|
||||||
|
// left: 0;
|
||||||
|
// width: 1000px;
|
||||||
|
// height: 1000px;
|
||||||
|
// z-index: 9999;
|
||||||
|
// background-color: red;
|
||||||
|
// `}
|
||||||
|
// >
|
||||||
|
// <div />
|
||||||
|
// {/* <CalculatorWrapper /> */}
|
||||||
|
// </div>,
|
||||||
|
<div
|
||||||
|
className={css`
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
z-index: 9000;
|
||||||
|
display: 'flex';
|
||||||
|
flex-direction: column;
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
dsfasdfasfasdfadsf
|
||||||
|
</div>,
|
||||||
|
document.body,
|
||||||
|
);
|
||||||
|
alert('---');
|
||||||
|
}}
|
||||||
|
/>
|
||||||
<FloatButton icon={<CommentOutlined />} />
|
<FloatButton icon={<CommentOutlined />} />
|
||||||
<FloatButton icon={<ContextMenuIcon onClick={() => setContextMenuEnable(!contextMenuEnabled)} />} />
|
<FloatButton
|
||||||
|
type={contextMenuEnabled ? 'primary' : 'default'}
|
||||||
|
icon={<ToolOutlined onClick={() => setContextMenuEnable(!contextMenuEnabled)} />}
|
||||||
|
/>
|
||||||
</FloatButton.Group>
|
</FloatButton.Group>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -0,0 +1,33 @@
|
|||||||
|
import React, { useEffect, useRef, useState } from 'react';
|
||||||
|
|
||||||
|
export const AutoScalingText = ({ children }) => {
|
||||||
|
const ref = useRef<HTMLDivElement>();
|
||||||
|
const [scale, setScale] = useState<number>(1);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!ref.current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const node = ref.current;
|
||||||
|
const parentNode = node.parentNode;
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
const availableWidth = parentNode.offsetWidth;
|
||||||
|
const actualWidth = node.offsetWidth;
|
||||||
|
const actualScale = availableWidth / actualWidth;
|
||||||
|
|
||||||
|
if (scale === actualScale) return;
|
||||||
|
|
||||||
|
if (actualScale < 1) {
|
||||||
|
setScale(actualScale);
|
||||||
|
} else if (scale < 1) {
|
||||||
|
setScale(1);
|
||||||
|
}
|
||||||
|
}, [scale]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="auto-scaling-text" style={{ transform: `scale(${scale},${scale})` }} ref={ref}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,247 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { CalculatorDisplay } from './CalculatorDisplay';
|
||||||
|
import { CalculatorKey } from './CalculatorKey';
|
||||||
|
import { useStyles } from './style';
|
||||||
|
|
||||||
|
const CalculatorOperations = {
|
||||||
|
'/': (prevValue, nextValue) => prevValue / nextValue,
|
||||||
|
'*': (prevValue, nextValue) => prevValue * nextValue,
|
||||||
|
'+': (prevValue, nextValue) => prevValue + nextValue,
|
||||||
|
'-': (prevValue, nextValue) => prevValue - nextValue,
|
||||||
|
'=': (prevValue, nextValue) => nextValue,
|
||||||
|
};
|
||||||
|
|
||||||
|
class Calculator extends React.Component {
|
||||||
|
state = {
|
||||||
|
value: null,
|
||||||
|
displayValue: '0',
|
||||||
|
operator: null,
|
||||||
|
waitingForOperand: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
clearAll() {
|
||||||
|
this.setState({
|
||||||
|
value: null,
|
||||||
|
displayValue: '0',
|
||||||
|
operator: null,
|
||||||
|
waitingForOperand: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
clearDisplay() {
|
||||||
|
this.setState({
|
||||||
|
displayValue: '0',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
clearLastChar() {
|
||||||
|
const { displayValue } = this.state;
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
displayValue: displayValue.substring(0, displayValue.length - 1) || '0',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleSign() {
|
||||||
|
const { displayValue } = this.state;
|
||||||
|
const newValue = parseFloat(displayValue) * -1;
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
displayValue: String(newValue),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
inputPercent() {
|
||||||
|
const { displayValue } = this.state;
|
||||||
|
const currentValue = parseFloat(displayValue);
|
||||||
|
|
||||||
|
if (currentValue === 0) return;
|
||||||
|
|
||||||
|
const fixedDigits = displayValue.replace(/^-?\d*\.?/, '');
|
||||||
|
const newValue = parseFloat(displayValue) / 100;
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
displayValue: String(newValue.toFixed(fixedDigits.length + 2)),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
inputDot() {
|
||||||
|
const { displayValue } = this.state;
|
||||||
|
|
||||||
|
if (!/\./.test(displayValue)) {
|
||||||
|
this.setState({
|
||||||
|
displayValue: displayValue + '.',
|
||||||
|
waitingForOperand: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inputDigit(digit) {
|
||||||
|
const { displayValue, waitingForOperand } = this.state;
|
||||||
|
|
||||||
|
if (waitingForOperand) {
|
||||||
|
this.setState({
|
||||||
|
displayValue: String(digit),
|
||||||
|
waitingForOperand: false,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.setState({
|
||||||
|
displayValue: displayValue === '0' ? String(digit) : displayValue + digit,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
performOperation(nextOperator) {
|
||||||
|
const { value, displayValue, operator } = this.state;
|
||||||
|
const inputValue = parseFloat(displayValue);
|
||||||
|
|
||||||
|
if (value == null) {
|
||||||
|
this.setState({
|
||||||
|
value: inputValue,
|
||||||
|
});
|
||||||
|
} else if (operator) {
|
||||||
|
const currentValue = value || 0;
|
||||||
|
const newValue = CalculatorOperations[operator](currentValue, inputValue);
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
value: newValue,
|
||||||
|
displayValue: String(newValue),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
waitingForOperand: true,
|
||||||
|
operator: nextOperator,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleKeyDown = (event) => {
|
||||||
|
let { key } = event;
|
||||||
|
|
||||||
|
if (key === 'Enter') key = '=';
|
||||||
|
|
||||||
|
if (/\d/.test(key)) {
|
||||||
|
event.preventDefault();
|
||||||
|
this.inputDigit(parseInt(key, 10));
|
||||||
|
} else if (key in CalculatorOperations) {
|
||||||
|
event.preventDefault();
|
||||||
|
this.performOperation(key);
|
||||||
|
} else if (key === '.') {
|
||||||
|
event.preventDefault();
|
||||||
|
this.inputDot();
|
||||||
|
} else if (key === '%') {
|
||||||
|
event.preventDefault();
|
||||||
|
this.inputPercent();
|
||||||
|
} else if (key === 'Backspace') {
|
||||||
|
event.preventDefault();
|
||||||
|
this.clearLastChar();
|
||||||
|
} else if (key === 'Clear') {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
if (this.state.displayValue !== '0') {
|
||||||
|
this.clearDisplay();
|
||||||
|
} else {
|
||||||
|
this.clearAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
document.addEventListener('keydown', this.handleKeyDown);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
document.removeEventListener('keydown', this.handleKeyDown);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { displayValue } = this.state;
|
||||||
|
|
||||||
|
const clearDisplay = displayValue !== '0';
|
||||||
|
const clearText = clearDisplay ? 'C' : 'AC';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={this.props.className}>
|
||||||
|
<div className="calculator">
|
||||||
|
<CalculatorDisplay value={displayValue} />
|
||||||
|
<div className="calculator-keypad">
|
||||||
|
<div className="input-keys">
|
||||||
|
<div className="function-keys">
|
||||||
|
<CalculatorKey
|
||||||
|
className="key-clear"
|
||||||
|
onPress={() => (clearDisplay ? this.clearDisplay() : this.clearAll())}
|
||||||
|
>
|
||||||
|
{clearText}
|
||||||
|
</CalculatorKey>
|
||||||
|
<CalculatorKey className="key-sign" onPress={() => this.toggleSign()}>
|
||||||
|
±
|
||||||
|
</CalculatorKey>
|
||||||
|
<CalculatorKey className="key-percent" onPress={() => this.inputPercent()}>
|
||||||
|
%
|
||||||
|
</CalculatorKey>
|
||||||
|
</div>
|
||||||
|
<div className="digit-keys">
|
||||||
|
<CalculatorKey className="key-0" onPress={() => this.inputDigit(0)}>
|
||||||
|
0
|
||||||
|
</CalculatorKey>
|
||||||
|
<CalculatorKey className="key-dot" onPress={() => this.inputDot()}>
|
||||||
|
●
|
||||||
|
</CalculatorKey>
|
||||||
|
<CalculatorKey className="key-1" onPress={() => this.inputDigit(1)}>
|
||||||
|
1
|
||||||
|
</CalculatorKey>
|
||||||
|
<CalculatorKey className="key-2" onPress={() => this.inputDigit(2)}>
|
||||||
|
2
|
||||||
|
</CalculatorKey>
|
||||||
|
<CalculatorKey className="key-3" onPress={() => this.inputDigit(3)}>
|
||||||
|
3
|
||||||
|
</CalculatorKey>
|
||||||
|
<CalculatorKey className="key-4" onPress={() => this.inputDigit(4)}>
|
||||||
|
4
|
||||||
|
</CalculatorKey>
|
||||||
|
<CalculatorKey className="key-5" onPress={() => this.inputDigit(5)}>
|
||||||
|
5
|
||||||
|
</CalculatorKey>
|
||||||
|
<CalculatorKey className="key-6" onPress={() => this.inputDigit(6)}>
|
||||||
|
6
|
||||||
|
</CalculatorKey>
|
||||||
|
<CalculatorKey className="key-7" onPress={() => this.inputDigit(7)}>
|
||||||
|
7
|
||||||
|
</CalculatorKey>
|
||||||
|
<CalculatorKey className="key-8" onPress={() => this.inputDigit(8)}>
|
||||||
|
8
|
||||||
|
</CalculatorKey>
|
||||||
|
<CalculatorKey className="key-9" onPress={() => this.inputDigit(9)}>
|
||||||
|
9
|
||||||
|
</CalculatorKey>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="operator-keys">
|
||||||
|
<CalculatorKey className="key-divide" onPress={() => this.performOperation('/')}>
|
||||||
|
÷
|
||||||
|
</CalculatorKey>
|
||||||
|
<CalculatorKey className="key-multiply" onPress={() => this.performOperation('*')}>
|
||||||
|
×
|
||||||
|
</CalculatorKey>
|
||||||
|
<CalculatorKey className="key-subtract" onPress={() => this.performOperation('-')}>
|
||||||
|
−
|
||||||
|
</CalculatorKey>
|
||||||
|
<CalculatorKey className="key-add" onPress={() => this.performOperation('+')}>
|
||||||
|
+
|
||||||
|
</CalculatorKey>
|
||||||
|
<CalculatorKey className="key-equals" onPress={() => this.performOperation('=')}>
|
||||||
|
=
|
||||||
|
</CalculatorKey>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CalculatorWrapper = () => {
|
||||||
|
const { styles } = useStyles();
|
||||||
|
return <Calculator className={styles.container} />;
|
||||||
|
};
|
@ -0,0 +1,22 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { AutoScalingText } from './AutoScalingText';
|
||||||
|
|
||||||
|
export const CalculatorDisplay = ({ value, ...props }) => {
|
||||||
|
const language = navigator.language || 'en-US';
|
||||||
|
let formattedValue = parseFloat(value).toLocaleString(language, {
|
||||||
|
useGrouping: true,
|
||||||
|
maximumFractionDigits: 6,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add back missing .0 in e.g. 12.0
|
||||||
|
const match = value.match(/\.\d*?(0*)$/);
|
||||||
|
|
||||||
|
if (match) formattedValue += /[1-9]/.test(match[0]) ? match[1] : match[0];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div {...props} className="calculator-display">
|
||||||
|
<AutoScalingText>{formattedValue}</AutoScalingText>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,5 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
export const CalculatorKey = ({ onPress, className, ...props }) => {
|
||||||
|
return <button onClick={onPress} className={`calculator-key ${className}`} {...props} />;
|
||||||
|
};
|
@ -0,0 +1,132 @@
|
|||||||
|
import { createStyles } from '@tachybase/client';
|
||||||
|
|
||||||
|
export const useStyles = createStyles(({ css }) => {
|
||||||
|
return {
|
||||||
|
container: css`
|
||||||
|
button {
|
||||||
|
display: block;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
font-family: inherit;
|
||||||
|
user-select: none;
|
||||||
|
cursor: pointer;
|
||||||
|
outline: none;
|
||||||
|
|
||||||
|
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
button:active {
|
||||||
|
box-shadow: inset 0px 0px 80px 0px rgba(0, 0, 0, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
#wrapper {
|
||||||
|
height: 100vh;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app {
|
||||||
|
width: 320px;
|
||||||
|
height: 520px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calculator {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: black;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
#wrapper .calculator {
|
||||||
|
box-shadow: 0px 0px 20px 0px #aaa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calculator-display {
|
||||||
|
color: white;
|
||||||
|
background: #1c191c;
|
||||||
|
line-height: 130px;
|
||||||
|
font-size: 6em;
|
||||||
|
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auto-scaling-text {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calculator-display .auto-scaling-text {
|
||||||
|
padding: 0 30px;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
transform-origin: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calculator-keypad {
|
||||||
|
height: 400px;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calculator .input-keys {
|
||||||
|
width: 240px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calculator .function-keys {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calculator .digit-keys {
|
||||||
|
background: #e0e0e7;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap-reverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calculator-key {
|
||||||
|
width: 80px;
|
||||||
|
height: 80px;
|
||||||
|
border-top: 1px solid #777;
|
||||||
|
border-right: 1px solid #666;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 80px;
|
||||||
|
}
|
||||||
|
.calculator .function-keys .calculator-key {
|
||||||
|
font-size: 2em;
|
||||||
|
}
|
||||||
|
.calculator .function-keys .key-multiply {
|
||||||
|
line-height: 50px;
|
||||||
|
}
|
||||||
|
.calculator .digit-keys .calculator-key {
|
||||||
|
font-size: 2.25em;
|
||||||
|
}
|
||||||
|
.calculator .digit-keys .key-0 {
|
||||||
|
width: 160px;
|
||||||
|
text-align: left;
|
||||||
|
padding-left: 32px;
|
||||||
|
}
|
||||||
|
.calculator .digit-keys .key-dot {
|
||||||
|
padding-top: 1em;
|
||||||
|
font-size: 0.75em;
|
||||||
|
}
|
||||||
|
.calculator .operator-keys .calculator-key {
|
||||||
|
color: white;
|
||||||
|
border-right: 0;
|
||||||
|
font-size: 3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calculator .function-keys {
|
||||||
|
background: linear-gradient(to bottom, rgba(202, 202, 204, 1) 0%, rgba(196, 194, 204, 1) 100%);
|
||||||
|
}
|
||||||
|
.calculator .operator-keys {
|
||||||
|
background: linear-gradient(to bottom, rgba(252, 156, 23, 1) 0%, rgba(247, 126, 27, 1) 100%);
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
@ -0,0 +1,25 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { useToken } from '@tachybase/client';
|
||||||
|
|
||||||
|
import { DatabaseOutlined } from '@ant-design/icons';
|
||||||
|
import { Button, Tooltip } from 'antd';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
|
import { useTranslation } from '../locale';
|
||||||
|
|
||||||
|
export const DatasourceLink = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const { token } = useToken();
|
||||||
|
return (
|
||||||
|
<Tooltip title={t('Data sources')}>
|
||||||
|
<Button
|
||||||
|
icon={<DatabaseOutlined style={{ color: token.colorTextHeaderMenu }} />}
|
||||||
|
title={t('Data sources')}
|
||||||
|
onClick={() => {
|
||||||
|
navigate('/admin/settings/data-source-manager/main/collections');
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
};
|
@ -4,6 +4,7 @@ import { Plugin } from '@tachybase/client';
|
|||||||
import { BreadcumbTitle } from './component/BreadcumbTitle';
|
import { BreadcumbTitle } from './component/BreadcumbTitle';
|
||||||
import { CollectionManagerPage } from './component/CollectionsManager';
|
import { CollectionManagerPage } from './component/CollectionsManager';
|
||||||
import { DatabaseConnectionManagerPane } from './component/DatabaseConnectionManager';
|
import { DatabaseConnectionManagerPane } from './component/DatabaseConnectionManager';
|
||||||
|
import { DatasourceLink } from './component/DatasourceLink';
|
||||||
import { MainDataSourceManager } from './component/MainDataSourceManager';
|
import { MainDataSourceManager } from './component/MainDataSourceManager';
|
||||||
import { DataSourcePermissionManager } from './component/PermissionManager';
|
import { DataSourcePermissionManager } from './component/PermissionManager';
|
||||||
import { DatabaseConnectionProvider } from './DatabaseConnectionProvider';
|
import { DatabaseConnectionProvider } from './DatabaseConnectionProvider';
|
||||||
@ -16,6 +17,7 @@ export class PluginDataSourceManagerClient extends Plugin {
|
|||||||
// 注册组件
|
// 注册组件
|
||||||
this.app.addComponents({
|
this.app.addComponents({
|
||||||
DataSourcePermissionManager,
|
DataSourcePermissionManager,
|
||||||
|
DatasourceLink,
|
||||||
});
|
});
|
||||||
this.app.use(DatabaseConnectionProvider);
|
this.app.use(DatabaseConnectionProvider);
|
||||||
this.app.pluginSettingsManager.add(NAMESPACE, {
|
this.app.pluginSettingsManager.add(NAMESPACE, {
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
import { i18n } from '@tachybase/client';
|
import { i18n, useTranslation as useT } from '@tachybase/client';
|
||||||
|
|
||||||
export const NAMESPACE = 'data-source-manager';
|
export const NAMESPACE = 'data-source-manager';
|
||||||
|
|
||||||
export function lang(key: string, options = {}) {
|
export function lang(key: string, options = {}) {
|
||||||
return i18n.t(key, { ...options, ns: NAMESPACE });
|
return i18n.t(key, { ...options, ns: NAMESPACE });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const useTranslation = (options?) => {
|
||||||
|
return useT([NAMESPACE, 'client'], options);
|
||||||
|
}
|
||||||
|
@ -2,6 +2,7 @@ import React from 'react';
|
|||||||
import { Plugin } from '@tachybase/client';
|
import { Plugin } from '@tachybase/client';
|
||||||
import { Registry } from '@tachybase/utils/client';
|
import { Registry } from '@tachybase/utils/client';
|
||||||
|
|
||||||
|
import { WorkflowLink } from './components/WorkflowLink';
|
||||||
import { ExecutionPage } from './ExecutionPage';
|
import { ExecutionPage } from './ExecutionPage';
|
||||||
import { PluginActionTrigger } from './features/action-trigger';
|
import { PluginActionTrigger } from './features/action-trigger';
|
||||||
import { PluginAggregate } from './features/aggregate';
|
import { PluginAggregate } from './features/aggregate';
|
||||||
@ -127,6 +128,7 @@ export class PluginWorkflow extends Plugin {
|
|||||||
|
|
||||||
addComponents() {
|
addComponents() {
|
||||||
this.app.addComponents({
|
this.app.addComponents({
|
||||||
|
WorkflowLink,
|
||||||
WorkflowPage,
|
WorkflowPage,
|
||||||
ExecutionPage,
|
ExecutionPage,
|
||||||
});
|
});
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { useToken } from '@tachybase/client';
|
||||||
|
|
||||||
|
import { PartitionOutlined } from '@ant-design/icons';
|
||||||
|
import { Button, Tooltip } from 'antd';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
|
import { useWorkflowTranslation } from '../locale';
|
||||||
|
|
||||||
|
export const WorkflowLink = () => {
|
||||||
|
const { t } = useWorkflowTranslation();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const { token } = useToken();
|
||||||
|
return (
|
||||||
|
<Tooltip title={t('Workflow')}>
|
||||||
|
<Button
|
||||||
|
icon={<PartitionOutlined style={{ color: token.colorTextHeaderMenu }} />}
|
||||||
|
title={t('Workflow')}
|
||||||
|
onClick={() => {
|
||||||
|
navigate('/admin/settings/workflow');
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user