@ant-design/icons#CodeOutlined TypeScript Examples
The following examples show how to use
@ant-design/icons#CodeOutlined.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: PluginImage.tsx From posthog-foss with MIT License | 6 votes |
export function PluginImage({
url,
pluginType,
size = 'medium',
}: {
url?: string
pluginType?: PluginInstallationType
size?: 'medium' | 'large'
}): JSX.Element {
const [state, setState] = useState({ image: imgPluginDefault })
const pixelSize = size === 'large' ? 100 : 60
useEffect(() => {
if (url?.includes('github.com')) {
const { user, repo } = parseGithubRepoURL(url)
setState({ ...state, image: `https://raw.githubusercontent.com/${user}/${repo}/main/logo.png` })
}
}, [url])
return pluginType === 'source' ? (
<CodeOutlined style={{ fontSize: pixelSize }} className="plugin-image" />
) : (
<div
className="plugin-image"
style={{
width: pixelSize,
height: pixelSize,
backgroundImage: `url(${state.image})`,
backgroundSize: 'contain',
backgroundRepeat: 'no-repeat',
}}
onError={() => setState({ ...state, image: imgPluginDefault })}
/>
)
}
Example #2
Source File: index.tsx From memex with MIT License | 6 votes |
BLOCK_TYPES = [
{ label: 'H1', style: 'header-one' },
{ label: 'H2', style: 'header-two' },
{ label: 'H3', style: 'header-three' },
// {label: 'H4', style: 'header-four'},
// {label: 'H5', style: 'header-five'},
// {label: 'H6', style: 'header-six'},
{ label: 'Blockquote', style: 'blockquote', icon: <MenuUnfoldOutlined /> },
{
label: 'Unordered List',
style: 'unordered-list-item',
icon: <UnorderedListOutlined />,
},
{
label: 'Ordered List',
style: 'ordered-list-item',
icon: <OrderedListOutlined />,
},
{ label: 'Code Block', style: 'code-block', icon: <CodeOutlined /> },
]
Example #3
Source File: Footer.tsx From disco-cube-admin with MIT License | 6 votes |
Footer: React.FC<Props> = ({ currentPath, onGotoPath }) => {
console.log("currentPath", currentPath);
return (
<Segment style={{ padding: 8 }} spacing={10} width="100%" maxWidth={500}>
<Horizontal horizontalAlign="center">
<Menu selectedKeys={["/" + currentPath.split("/")[1]]} mode="horizontal">
<Menu.Item key="/stats" onClick={() => onGotoPath(routes.stats.path())}>
<DashboardOutlined style={{ fontSize: "2em" }} />
</Menu.Item>
<Menu.Item key="/terminal" onClick={() => onGotoPath(routes.terminal.path())}>
<CodeOutlined style={{ fontSize: "2em" }} />
</Menu.Item>
<Menu.Item key="/apps" onClick={() => onGotoPath(routes.apps.path())}>
<AppstoreOutlined style={{ fontSize: "2em" }} />
</Menu.Item>
<Menu.Item key="/account" onClick={() => onGotoPath(routes.account.path())}>
<UserOutlined style={{ fontSize: "2em" }} />
</Menu.Item>
</Menu>
</Horizontal>
</Segment>
);
}
Example #4
Source File: personalizationOptions.tsx From posthog-foss with MIT License | 5 votes |
ROLES: RadioSelectType[] = [
{
key: 'engineer',
label: 'Engineer',
icon: <CodeOutlined />,
},
{
key: 'product',
label: 'Product Manager',
icon: <RocketOutlined />,
},
{
key: 'management',
label: 'Management',
icon: <ClusterOutlined />,
},
{
key: 'marketing',
label: 'Marketing',
icon: <NotificationOutlined />,
},
{
key: 'sales',
label: 'Sales',
icon: <DollarOutlined />,
},
{
key: 'cx',
label: 'Customer success',
icon: <SmileOutlined />,
},
{
key: 'ops',
label: 'Operations',
icon: <ToolOutlined />,
},
{
key: 'other',
label: 'Other',
icon: <BlockOutlined />,
},
]
Example #5
Source File: routeSpec.tsx From yakit with GNU Affero General Public License v3.0 | 5 votes |
RouteMenuData: MenuDataProps[] = [
// {key: Route.MITM, label: "HTTP(S) 中间人劫持", icon: <FireOutlined/>},
{
key: Route.PenTest, label: "手工渗透测试", icon: <AimOutlined/>,
subMenuData: [
{key: Route.HTTPHacker, label: "MITM", icon: <FireOutlined/>},
{key: Route.HTTPFuzzer, label: "Web Fuzzer", icon: <AimOutlined/>},
],
},
{
key: Route.GeneralModule, label: "基础安全工具", icon: <RocketOutlined/>,
subMenuData: [
{key: Route.Mod_ScanPort, label: "扫描端口/指纹", icon: <EllipsisOutlined/>},
{key: Route.Mod_Brute, label: "爆破与未授权", icon: <EllipsisOutlined/>, disabled: false},
// {key: Route.Mod_Subdomain, label: "子域名发现", icon: <EllipsisOutlined/>, disabled: true},
// {key: Route.Mod_Crawler, label: "基础爬虫", icon: <EllipsisOutlined/>, disabled: true},
// {key: Route.Mod_SpaceEngine, label: "空间引擎", icon: <EllipsisOutlined/>, disabled: true},
],
},
{
key: Route.PoC, label: "专项漏洞检测",
icon: <FunctionOutlined/>,
},
{
key: Route.ModManagerDetail, label: "插件管理", icon: <AppstoreOutlined/>,
subMenuData: [
{key: Route.ModManager, label: "插件仓库", icon: <AppstoreOutlined/>},
{key: Route.BatchExecutorPage, label: "插件批量执行", icon: <AppstoreOutlined/>},
]
},
{key: Route.PayloadManager, label: "Payload 管理", icon: <AuditOutlined/>},
{key: Route.YakScript, label: "Yak Runner", icon: <CodeOutlined/>},
{
key: Route.ReverseManager, label: "反连管理", icon: <AppstoreOutlined/>,
subMenuData: [
{key: Route.ShellReceiver, label: "端口监听器", icon: <OneToOneOutlined/>},
{key: Route.ReverseServer, label: "反连服务器", icon: <OneToOneOutlined/>},
{key: Route.DNSLog, label: "DNSLog", icon: <OneToOneOutlined/>},
{key: Route.ICMPSizeLog, label: "ICMP-SizeLog", icon: <OneToOneOutlined/>},
{key: Route.TCPPortLog, label: "TCP-PortLog", icon: <OneToOneOutlined/>},
]
},
{
key: Route.DataHandler, label: "数据处理",
icon: <FunctionOutlined/>,
subMenuData: [
{key: Route.Codec, label: "Codec", icon: <FireOutlined/>},
{key: Route.DataCompare, label: "数据对比", icon: <OneToOneOutlined/>},
],
},
{
key: Route.Database, label: "数据库",
icon: <FunctionOutlined/>,
subMenuData: [
{key: Route.DB_HTTPHistory, label: "HTTP History", icon: <OneToOneOutlined/>},
{key: Route.DB_Ports, label: "端口资产", icon: <OneToOneOutlined/>},
{key: Route.DB_Domain, label: "域名资产", icon: <FireOutlined/>},
{key: Route.DB_ExecResults, label: "插件执行结果", icon: <FireOutlined/>},
{key: Route.DB_Risk, label: "漏洞与风险", icon: <BugOutlined/>},
{key: Route.DB_Report, label: "报告(Beta*)", icon: <FireOutlined/>},
],
},
// {
// key: Route.IGNORE, label: "常用工具包", icon: <FireOutlined/>,
// subMenuData: [
// {key: Route.Codec, label: "编码与解码", icon: <EllipsisOutlined/>},
// {key: Route.ShellReceiver, label: "端口开放助手", icon: <FireOutlined/>},
// ],
// },
]
Example #6
Source File: PluginList.tsx From yakit with GNU Affero General Public License v3.0 | 5 votes |
YakScriptCheckbox: React.FC<YakScriptCheckboxProp> = React.memo((props) => {
const {info, selected, vlistWidth, selectScript, unSelectScript,} = props;
return <div key={info.ScriptName} className='list-opt'>
{props.readOnly ? <OneLine width={vlistWidth} overflow={"hidden"}>
<div>
{info.ScriptName}
</div>
</OneLine> : <Checkbox
disabled={props.disabled}
checked={selected.includes(info.ScriptName)}
onChange={(r) => {
if (r.target.checked) selectScript(info)
else unSelectScript(info)
}}
>
<OneLine width={vlistWidth} overflow={"hidden"}>
<div>
{info.ScriptName}
</div>
</OneLine>
</Checkbox>}
<div style={{flex: 1, textAlign: "right"}}>
{info.Help && (
<a
onClick={() => {
showModal({
width: "40%",
title: "Help",
content: <>{info.Help}</>
})
}}
href={"#"} style={{marginLeft: 2, marginRight: 2}}
><QuestionCircleOutlined/></a>
)}
{info.Author && (
<Tooltip title={info.Author}>
<a href={"#"} style={{marginRight: 2, marginLeft: 2}}><UserOutlined/></a>
</Tooltip>
)}
{!!info.Content && props.readOnly && (
<a href={"#"}
style={{marginRight: 2, marginLeft: 2}}
onClick={() => {
showModal({
title: info.ScriptName, width: "60%",
content: (
<div style={{height: 400}}>
<YakEditor
type={info.Type === "nuclei" ? "yaml" : "yak"}
readOnly={true}
value={info.Content}
/>
</div>
)
})
}}
><CodeOutlined/></a>
)}
</div>
</div>
})
Example #7
Source File: index.tsx From fe-v5 with Apache License 2.0 | 5 votes |
index = (_props: any) => {
const history = useHistory();
const { t, i18n } = useTranslation();
const [query, setQuery] = useState('');
const [mine, setMine] = useState(true);
const [days, setDays] = useState(7);
const { curBusiItem } = useSelector<RootState, CommonStoreState>((state) => state.common);
const { tableProps } = useAntdTable((options) => getTableData(options, curBusiItem.id, query, mine, days), { refreshDeps: [curBusiItem.id, query, mine, days] });
const columns: ColumnProps<DataItem>[] = [
{
title: 'ID',
dataIndex: 'id',
width: 100,
},
{
title: t('task.title'),
dataIndex: 'title',
width: 200,
render: (text, record) => {
return <Link to={{ pathname: `/job-tasks/${record.id}/result` }}>{text}</Link>;
},
},
{
title: t('table.operations'),
width: 150,
render: (_text, record) => {
return (
<span>
<Link to={{ pathname: '/job-tasks/add', search: `task=${record.id}` }}>{t('task.clone')}</Link>
<Divider type='vertical' />
<Link to={{ pathname: `/job-tasks/${record.id}/detail` }}>{t('task.meta')}</Link>
</span>
);
},
},
{
title: t('task.creator'),
dataIndex: 'create_by',
width: 100,
},
{
title: t('task.created'),
dataIndex: 'create_at',
width: 160,
render: (text) => {
return moment.unix(text).format('YYYY-MM-DD HH:mm:ss');
},
},
];
return (
<PageLayout
hideCluster
title={
<>
<CodeOutlined />
{t('执行历史')}
</>
}
>
<div style={{ display: 'flex' }}>
<LeftTree></LeftTree>
{curBusiItem.id ? (
<div style={{ flex: 1, padding: 10 }}>
<Row>
<Col span={16} className='mb10'>
<Input
style={{ width: 200, marginRight: 10 }}
prefix={<SearchOutlined />}
defaultValue={query}
onPressEnter={(e) => {
setQuery(e.currentTarget.value);
}}
placeholder='搜索标题'
/>
<Select
style={{ marginRight: 10 }}
value={days}
onChange={(val: number) => {
setDays(val);
}}
>
<Select.Option value={7}>{t('last.7.days')}</Select.Option>
<Select.Option value={15}>{t('last.15.days')}</Select.Option>
<Select.Option value={30}>{t('last.30.days')}</Select.Option>
<Select.Option value={60}>{t('last.60.days')}</Select.Option>
<Select.Option value={90}>{t('last.90.days')}</Select.Option>
</Select>
<Checkbox
checked={mine}
onChange={(e) => {
setMine(e.target.checked);
}}
>
{t('task.only.mine')}
</Checkbox>
</Col>
<Col span={8} style={{ textAlign: 'right' }}>
<Button
type='primary'
ghost
onClick={() => {
history.push('/job-tasks/add');
}}
>
{t('task.temporary.create')}
</Button>
</Col>
</Row>
<Table
rowKey='id'
columns={columns as any}
{...(tableProps as any)}
pagination={
{
...tableProps.pagination,
showSizeChanger: true,
pageSizeOptions: ['10', '50', '100', '500', '1000'],
showTotal: (total) => {
return i18n.language == 'en' ? `Total ${total} items` : `共 ${total} 条`;
},
} as any
}
/>
</div>
) : (
<BlankBusinessPlaceholder text={t('执行历史')}></BlankBusinessPlaceholder>
)}
</div>
</PageLayout>
);
}
Example #8
Source File: index.tsx From visual-layout with MIT License | 5 votes |
Code: React.FC<{ project: ProjectService }> = ({ project }) => {
const [codeConfig, setCodeConfig] = useState<CodeConfig>(
getInitCodeConfig(project),
);
return (
<Visible>
{({ visible, setVisible }) => (
<>
<Drawer
title="代码"
placement="right"
width={'calc(100% - 420px)'}
onClose={() => setVisible(false)}
visible={visible}
destroyOnClose
>
<div className={styles.container}>
<div className={styles.leftContainer}>
<div className={styles.download}>
<Button
type="primary"
shape="round"
icon={<DownloadOutlined />}
onClick={() => exportCode(project, codeConfig)}
>
导出
</Button>
</div>
<BaseInfo project={project} />
<Config setCodeConfig={setCodeConfig} codeConfig={codeConfig} />
</div>
<div className={styles.rightContainer}>
<CodeEdit project={project} codeConfig={codeConfig} />
</div>
</div>
</Drawer>
<Tooltip placement="top" title="代码">
<CodeOutlined
style={{ fontSize: 20 }}
onClick={() => setVisible(true)}
/>
</Tooltip>
</>
)}
</Visible>
);
}
Example #9
Source File: node.tsx From imove with MIT License | 5 votes |
nodeMenuConfig = [
{
key: 'copy',
title: '复制',
icon: <CopyOutlined />,
handler: shortcuts.copy.handler,
},
{
key: 'delete',
title: '删除',
icon: <DeleteOutlined />,
handler: shortcuts.delete.handler,
},
{
key: 'rename',
title: '编辑文本',
icon: <EditOutlined />,
showDividerBehind: true,
handler() {
// TODO
},
},
{
key: 'bringToTop',
title: '置于顶层',
icon: <XIcon type={'icon-bring-to-top'} />,
handler: shortcuts.bringToTop.handler,
},
{
key: 'bringToBack',
title: '置于底层',
icon: <XIcon type={'icon-bring-to-bottom'} />,
showDividerBehind: true,
handler: shortcuts.bringToBack.handler,
},
{
key: 'editCode',
title: '编辑代码',
icon: <FormOutlined />,
disabled(flowChart: Graph) {
return getSelectedNodes(flowChart).length !== 1;
},
handler(flowChart: Graph) {
flowChart.trigger('graph:editCode');
},
},
{
key: 'executeCode',
title: '执行代码',
icon: <CodeOutlined />,
disabled(flowChart: Graph) {
return getSelectedNodes(flowChart).length !== 1;
},
handler(flowChart: Graph) {
flowChart.trigger('graph:runCode');
},
},
]
Example #10
Source File: ContextItem.tsx From next-basics with GNU General Public License v3.0 | 5 votes |
export function ContextItem({
index,
data,
canDrag,
highlighted,
handleDropItem,
handleItemClick,
handleItemDelete,
handleItemHover,
}: ContextItemProps): React.ReactElement {
const ref = useRef();
const [{ isOver, dropClassName }, drop] = useDrop({
accept: type,
collect: (monitor) => {
const { index: dragIndex } = monitor.getItem() || {};
if (dragIndex === index) {
return {};
}
return {
isOver: monitor.isOver(),
dropClassName:
dragIndex < index
? `${styles.dropOverDownward}`
: `${styles.dropOverUpward}`,
};
},
drop: (item: any) => {
handleDropItem(item.index, index);
},
});
const [{ isDragging }, drag] = useDrag({
item: { type, index },
canDrag,
collect: (monitor) => ({
isDragging: monitor.isDragging(),
}),
});
drop(drag(ref));
const handleMouseEnter = (): void => {
handleItemHover(data.name);
};
const handleMouseLeave = (): void => {
handleItemHover();
};
return (
<div
ref={ref}
className={classNames(styles.varItem, {
[dropClassName]: isOver,
[styles.highlighted]: highlighted,
})}
onClick={handleItemClick}
key={data.name}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
{data.resolve ? (
<LinkOutlined style={{ color: "var(--theme-orange-color)" }} />
) : (
<CodeOutlined style={{ color: "var(--theme-green-color)" }} />
)}
<span className={styles.varName}>{data.name}</span>
<Button
type="link"
danger
icon={<DeleteOutlined />}
className={styles.deleteIcon}
onClick={handleItemDelete}
/>
</div>
);
}
Example #11
Source File: ContextItem.spec.tsx From next-basics with GNU General Public License v3.0 | 5 votes |
describe("ContextItem", () => {
it("should work", () => {
const handleItemClick = jest.fn();
const handleItemDelete = jest.fn();
const handleDropItem = jest.fn();
const handleItemHover = jest.fn();
const wrapper = shallow(
<ContextItem
data={{
name: "data-b",
value: {
id: 1,
},
}}
handleItemClick={handleItemClick}
handleItemDelete={handleItemDelete}
handleDropItem={handleDropItem}
index={1}
canDrag={true}
handleItemHover={handleItemHover}
/>
);
expect(wrapper.find(CodeOutlined).length).toBe(1);
wrapper.find(".deleteIcon").simulate("click");
expect(handleItemDelete).toBeCalled();
wrapper.setProps({
data: {
name: "data-a",
resolve: {
useProvider: "provider-a",
args: ["args1"],
if: false,
transform: {
value: "<% DATA %>",
},
},
},
});
expect(wrapper.find(LinkOutlined).length).toBe(1);
wrapper.find(".varItem").simulate("click");
expect(handleItemClick).toBeCalled();
wrapper.find(".varItem").invoke("onMouseEnter")({} as any);
expect(handleItemHover).toBeCalledWith("data-a");
handleItemHover.mockClear();
wrapper.find(".varItem").invoke("onMouseLeave")({} as any);
expect(handleItemHover).toBeCalledWith();
});
});
Example #12
Source File: Dashboard.tsx From yugong with MIT License | 4 votes |
Dashboard: React.FC<Props> = () => {
// 复制模块
const [showCopyedModal, setShowCopyedModal] = useState(false);
// 复制模块名称
const [newModalName, setNewModalName] = useState<string>();
const [showRunningTimes, setShowRunningTimes] = useState(false);
const runningTimes = useSelector((state: RootState) => state.runningTimes);
// appdata
const appData = useSelector((state: RootState) => state.appData);
const pageData = useSelector((state: RootState) => state.pageData);
// 模板ID
const moduleId = useSelector(
(state: RootState) => state.activationItem.moduleId,
);
const activationItem = useSelector(
(state: RootState) => state.activationItem,
);
const updateActivationItem =
useDispatch<Dispatch>().activationItem.updateActivationItem;
const updateAppData = useDispatch<Dispatch>().appData.updateAppData;
const removeActivationItem =
useDispatch<Dispatch>().activationItem.removeActivationItem;
// 样式与设置菜单面板
const [mainTag, setMainTag] = useState('config');
const onSelectMainTag = useCallback((e) => {
setMainTag(e.key);
}, []);
const sendMessage = usePostMessage(() => {});
// 收发处理,子窗口onload时向子窗口发送信息, 通知当前正处于编辑模式下,
// 重置当前被选择项
const onChangeSelect = useCallback(
(e) => {
if (activationItem.moduleId === e) return;
for (let index = 0; index < appData.length; index++) {
const element = appData[index];
if (element.moduleId === e) {
const value = { ...element };
updateActivationItem(value);
const win = (
document.getElementById('wrapiframe') as HTMLIFrameElement
).contentWindow;
if (win) {
sendMessage({ tag: 'id', value: element.moduleId }, win);
}
break;
}
}
},
[activationItem.moduleId, appData, sendMessage, updateActivationItem],
);
// =====================================模块删除=======================================//
const [isDeleteComp, setIsDeleteComp] = useState(false);
const delModule = useCallback(() => {
const optAppData = produce(reject([...appData], { moduleId }), undefined, createDesc('删除',`组件${activationItem.moduleName}`) );
const win = (document.getElementById('wrapiframe') as HTMLIFrameElement)
.contentWindow;
updateAppData(optAppData);
removeActivationItem();
sendMessage(
{
tag: 'updateAppData',
value: optAppData,
},
win,
);
sendMessage(
{
tag: 'removeActivationItem',
value: undefined,
},
win,
);
setIsDeleteComp(false);
}, [activationItem.moduleName, appData, moduleId, removeActivationItem, sendMessage, updateAppData]);
const confirmModal = useCallback(() => {
if (isDeleteComp) return;
setIsDeleteComp(true);
confirm({
content: (
<div>
<h3>确定删除</h3>
<br />
模块名称:{activationItem.moduleName}
<br />
Id: {activationItem.moduleId}
<br />
<span className={s.warn}>
当前模块将被移除,请手动清除其他模块事件中引用的当前模块方法。
</span>
</div>
),
okText: '确定',
cancelText: '取消',
onCancel: () => setIsDeleteComp(false),
onOk: delModule,
});
}, [
isDeleteComp,
activationItem.moduleName,
activationItem.moduleId,
delModule,
]);
// 模块删除快捷键
// key deletd
useKeyDown((event) => {
event.preventDefault();
confirmModal();
}, 'Delete');
// =====================================模块复制=======================================//
// copyData
const beforCopyModule = useCallback(() => {
setNewModalName(`${activationItem.moduleName} 拷贝`);
setShowCopyedModal(true);
}, [activationItem.moduleName]);
// 初始化或,取消复制弹窗
const initCopyModule = useCallback(() => {
setShowCopyedModal(false);
setNewModalName(undefined);
}, []);
// 方法,复制当前选中的组件
const copyModule = useCallback(() => {
// 准备创建
const oprateActivationItem = cloneDeep(activationItem);
const moduleId = nanoid();
oprateActivationItem.moduleId = moduleId;
oprateActivationItem.layout!.i = moduleId;
oprateActivationItem.moduleName =
newModalName || `${activationItem.moduleName} 拷贝`;
// 模块垂直位置
let y = 0;
// 行高
let rowHeight = pageData.rowHeight || GRID_DEFAULT_ROWHEIGHT;
if (typeof rowHeight === 'string') rowHeight = getResult(rowHeight);
// 滚动条高度
const iframeNode = document.getElementById(
'wrapiframe',
) as HTMLIFrameElement | null;
const scrollTop =
iframeNode?.contentDocument?.documentElement.scrollTop || 0;
// 通过滚动条定位计算新增元素应该在当前视窗内
y = (scrollTop + 100) / (rowHeight as number);
oprateActivationItem.layout!.y = y;
// 复制模块,更新当前模块到全局并设为当前被选择模块
updateAppData(produce([...appData, oprateActivationItem], undefined, createDesc('复制',`新组件${oprateActivationItem.moduleName}`)));
updateActivationItem(oprateActivationItem);
// 初始化复制窗口
initCopyModule();
}, [activationItem, appData, newModalName, pageData.rowHeight, updateAppData, updateActivationItem, initCopyModule]);
// 处理键盘事件
// 模拟模块复制
// useKeyDown(
// () => {
// beforCopyModule();
// },
// 'c',
// 'ctrlKey',
// );
// // 确认复制模块
useKeyDown((event) => {
if (showCopyedModal) {
event.preventDefault();
copyModule();
}
}, 'Enter');
const CodeEditor = useMemo(
() => lazy(() => import(`../CodeEditor/index`)),
[],
);
return (
<>
<div className={s.headtab}>
<div className={s.moduleselect}>
<Select
onChange={onChangeSelect}
className={s.select}
value={moduleId}
showSearch
placeholder="请选择编辑模块"
optionFilterProp="children"
filterOption={
(input, option) => {
const str = option?.children?.join('').toLowerCase();
if (str?.indexOf(input) !== -1) {
return true;
}
return false;
}
// option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
}
>
{appData.map((item) => (
<Select.Option value={item.moduleId} key={item.moduleId}>
{item.moduleName || '(未标题)'}-{item.type}
</Select.Option>
))}
</Select>
</div>
<Menu
onClick={() => setMainTag('config')}
onSelect={onSelectMainTag}
selectedKeys={[mainTag]}
mode="horizontal"
className={s.contentmenu}
>
<Menu.Item key="config" icon={<ToolOutlined />}>
设置
</Menu.Item>
<Menu.Item key="style" icon={<FormatPainterOutlined />}>
样式
</Menu.Item>
<Menu.Item key="code" icon={<CodeOutlined />}>
code
</Menu.Item>
</Menu>
<div className={s.info}>
<Tooltip placement="bottomRight" title="查看全局发布变量">
<ClusterOutlined
className={s.delete}
onClick={() => setShowRunningTimes(true)}
/>
</Tooltip>
</div>
<div className={s.info}>
<Tooltip
placement="bottomRight"
title={
<div className={s.tips}>
<h3>复制为新模块</h3>
当前模块信息
<br />
模块:{activationItem.moduleName}
<br />
类型:{activationItem.type}
<br />
Id:{activationItem.moduleId}
</div>
}
>
<CopyOutlined alt="复制模块" onClick={beforCopyModule} />
</Tooltip>
</div>
<div>
<Tooltip
placement="bottomRight"
title={`删除 ${
activationItem.moduleName || activationItem.moduleId
}`}
>
<DeleteOutlined className={s.delete} onClick={confirmModal} />
</Tooltip>
</div>
</div>
<div
className={s.root}
style={{ height: `${window.innerHeight - 80}px` }}
>
<div
className={s.controllerwrap}
style={{ display: mainTag === 'style' ? 'block' : 'none' }}
>
<StyleController />
</div>
<div
className={s.controllerwrap}
style={{ display: mainTag === 'config' ? 'block' : 'none' }}
>
<ConfigurationController />
</div>
<div
className={s.controllerwrap}
style={{ display: mainTag === 'code' ? 'block' : 'none' }}
>
<CodeEditor />
</div>
</div>
<Modal
title={`复制${activationItem?.moduleName || ''}(${
activationItem?.type || ''
})模块`}
visible={!!showCopyedModal}
footer={null}
onCancel={initCopyModule}
>
<Row gutter={[16, 16]}>
<Col span={3}></Col>
<Col span={15}>
<Input
type="text"
value={newModalName as any}
onChange={(e) => setNewModalName(e.target.value || undefined)}
placeholder={`请输入${activationItem?.type || ''}模块的别名`}
/>
</Col>
<Col span={6}>
<Button type="primary" onClick={copyModule}>
确定
</Button>
</Col>
</Row>
<br />
</Modal>
<RunningTimesModal
visible={showRunningTimes}
data={runningTimes}
onCancel={() => setShowRunningTimes(false)}
/>
</>
);
}
Example #13
Source File: FunctionDebuggerSidebar.tsx From next-basics with GNU General Public License v3.0 | 4 votes |
export function FunctionDebuggerSidebar({
functionName,
functionModified,
activeTab,
tests,
onActiveTabSwitch,
onRunAllTests,
onAddTest,
}: FunctionDebuggerSidebarProps): React.ReactElement {
const [currentTab, setCurrentTab] = useState<string>(activeTab ?? "function");
useEffect(() => {
setCurrentTab(activeTab ?? "function");
}, [activeTab]);
const groups: SidebarGroup[] = useMemo(() => {
const refinedTests = Array.isArray(tests) ? tests : [];
return [
{
label: "Function",
value: "function",
items: [
{
label: functionName,
value: "function",
icon: <CodeOutlined />,
modified: functionModified,
},
],
},
{
label: "Debug",
value: "debug",
items: [
{
label: "Debug",
value: "debug",
icon: <BugOutlined />,
},
],
},
{
label: `Tests (${refinedTests.length})`,
value: "tests",
items: refinedTests.map((test, index) => ({
label: test.name ?? `Case ${index + 1}`,
value: `test:${String(index)}`,
modified: test.testModified,
...(test.testMatched
? {
icon: <CheckOutlined />,
className: styles.matched,
}
: test.testMatched === false
? {
icon: <CloseOutlined />,
className: styles.notMatched,
}
: {
icon: <QuestionOutlined />,
}),
})),
},
];
}, [functionModified, functionName, tests]);
const switchActiveTab = useCallback(
(tab: string) => {
if (currentTab !== tab) {
setCurrentTab(tab);
onActiveTabSwitch?.(tab);
}
},
[currentTab, onActiveTabSwitch]
);
return (
<div
className={`${styles.sidebarContainer} ${sharedStyles.customScrollbarContainer}`}
data-override-theme="dark"
>
<ul className={styles.sidebarGroups}>
{groups.map((group) => (
<li key={group.label}>
<div className={styles.sidebarGroupLabel}>
<span className={styles.groupText}>{group.label}</span>
{group.value === "tests" && (
<div className={styles.groupIconContainer}>
{group.items.length > 0 && (
<span
className={styles.groupIcon}
title="Run All Tests"
onClick={onRunAllTests}
>
<PlayCircleOutlined />
</span>
)}
<span
className={styles.groupIcon}
title="Add Test"
onClick={onAddTest}
>
<PlusCircleOutlined />
</span>
</div>
)}
</div>
<ul className={styles.sidebarItems}>
{group.items.map((item) => (
<li
key={item.label}
className={classNames({
[styles.active]: item.value === currentTab,
})}
onClick={() => switchActiveTab(item.value)}
>
<span className={classNames(styles.icon, item.className)}>
{item.icon}
</span>
<span className={styles.text}>{item.label}</span>
{item.modified && <span className={styles.modified}></span>}
</li>
))}
</ul>
</li>
))}
</ul>
</div>
);
}
Example #14
Source File: CodeDebugger.tsx From jitsu with MIT License | 4 votes |
ControlsComponent: React.FC<ControlsProps> = ({
inputChecked,
codeChecked,
outputChecked,
codeSaved,
toggleInput,
toggleCode,
toggleOutput,
handleExit: handleCloseWithoutSaving,
handleSave,
handleRun,
}) => {
const [isClosePopoverVisible, setIsClosePopoverVisible] = useState(false)
const handleClose = () => {
if (!codeSaved.current) {
setIsClosePopoverVisible(true)
return
}
handleCloseWithoutSaving()
}
useEffect(() => {
const handleToggleInput = () => {
toggleInput()
return false // to prevent browsers' default behaviour
}
const handleToggleCode = () => {
toggleCode()
return false
}
const handleToggleOutput = () => {
toggleOutput()
return false
}
const _handleSave = (e: KeyboardEvent) => {
e.preventDefault()
handleSave()
return false
}
const _handleRun = (e: KeyboardEvent) => {
e.stopPropagation()
handleRun()
return false
}
const handleEscape = e => {
if (e.key === "Escape") {
handleClose()
}
}
hotkeys.filter = () => true // to enable hotkeys everywhere, even in input fields
hotkeys("cmd+i,ctrl+i", handleToggleInput)
hotkeys("cmd+u,ctrl+u", handleToggleCode)
hotkeys("cmd+o,ctrl+o", handleToggleOutput)
hotkeys("cmd+s,ctrl+s", _handleSave)
hotkeys("cmd+enter,ctrl+enter", _handleRun)
document.addEventListener("keydown", handleEscape, true)
return () => {
hotkeys.unbind("cmd+i,ctrl+i", handleToggleInput)
hotkeys.unbind("cmd+u,ctrl+u", handleToggleCode)
hotkeys.unbind("cmd+o,ctrl+o", handleToggleOutput)
hotkeys.unbind("cmd+s,ctrl+s", _handleSave)
hotkeys.unbind("cmd+enter,ctrl+enter", _handleRun)
document.removeEventListener("keydown", handleEscape, true)
}
}, [])
return (
<div className="flex items-stretch w-full h-full">
<Popconfirm
title="You have some unsaved expression code. Do you want to quit?"
placement="rightBottom"
className="max-w-xs mr-4"
visible={isClosePopoverVisible}
onCancel={() => setIsClosePopoverVisible(false)}
onConfirm={() => {
handleCloseWithoutSaving()
setIsClosePopoverVisible(false)
}}
>
<Button size="middle" className="flex-grow-0" onClick={handleClose}>
<CloseOutlined className={styles.adaptiveIcon} />
<span className={`${styles.adaptiveLabel} ${styles.noMargins}`}>{"Close"}</span>
</Button>
</Popconfirm>
<div className="flex justify-center items-center flex-auto min-w-0">
<Tooltip title={`${OS_CMD_CTRL_KEY}+I`} mouseEnterDelay={1}>
<Checkbox
checked={inputChecked}
className={cn("relative", styles.checkbox, styles.hideAntdCheckbox, styles.checkboxLabel, {
[styles.checkboxChecked]: inputChecked,
})}
onClick={toggleInput}
>
<i className="block absolute left-0.5">{inputChecked ? <EyeFilled /> : <EyeInvisibleFilled />}</i>
<span className={styles.adaptiveIcon}>{"{ }"}</span>
<span className={`${styles.adaptiveLabel} ${styles.noMargins}`}>{"Input"}</span>
</Checkbox>
</Tooltip>
<Tooltip title={`${OS_CMD_CTRL_KEY}+U`} mouseEnterDelay={1}>
<Checkbox
checked={codeChecked}
className={cn("relative", styles.checkbox, styles.hideAntdCheckbox, styles.checkboxLabel, {
[styles.checkboxChecked]: codeChecked,
})}
onClick={toggleCode}
>
<i className="block absolute left-0.5">{codeChecked ? <EyeFilled /> : <EyeInvisibleFilled />}</i>
<span className={styles.adaptiveIcon}>{"</>"}</span>
<span className={`${styles.adaptiveLabel} ${styles.noMargins}`}>{"Expression"}</span>
</Checkbox>
</Tooltip>
<Tooltip title={`${OS_CMD_CTRL_KEY}+O`} mouseEnterDelay={1}>
<Checkbox
checked={outputChecked}
className={cn("relative", styles.checkbox, styles.hideAntdCheckbox, styles.checkboxLabel, {
[styles.checkboxChecked]: outputChecked,
})}
onClick={toggleOutput}
>
<i className="block absolute left-0.5">{outputChecked ? <EyeFilled /> : <EyeInvisibleFilled />}</i>
<CodeOutlined className={styles.adaptiveIcon} />
<span className={`${styles.adaptiveLabel} ${styles.noMargins}`}>{"Result"}</span>
</Checkbox>
</Tooltip>
</div>
<div className="flex-grow-0 ant-btn-group">
<Tooltip title={`${OS_CMD_CTRL_KEY}+↵`} mouseEnterDelay={1}>
<Button
size="middle"
type="primary"
icon={<CaretRightOutlined />}
className={`${styles.buttonGreen}`}
onClick={handleRun}
>
<span className={`${styles.adaptiveLabel}`}>{"Run"}</span>
</Button>
</Tooltip>
<Tooltip title={`${OS_CMD_CTRL_KEY}+S`} mouseEnterDelay={1}>
<Button size="middle" type="primary" onClick={handleSave} icon={<DownloadOutlined />}>
<span className={`${styles.adaptiveLabel}`}>{"Save"}</span>
</Button>
</Tooltip>
</div>
</div>
)
}
Example #15
Source File: ConfigurableFieldsForm.tsx From jitsu with MIT License | 4 votes |
ConfigurableFieldsFormComponent = ({
fieldsParamsList,
form,
extraForms,
initialValues,
availableOauthBackendSecrets,
hideFields,
handleTouchAnyField,
setFormValues,
setInitialFormValues,
}: Props) => {
const [debugModalsStates, setDebugModalsStates] = useState<{ [id: string]: boolean }>({})
const [debugModalsValues, setDebugModalsValues] = useState<{ [id: string]: string }>({})
const forceUpdateAll = useForceUpdate()
const { forceUpdatedTargets, forceUpdateTheTarget } = useForceUpdateTarget()
const handleTouchField = debounce(handleTouchAnyField ?? (() => {}), 1000)
const handleChangeIntInput = useCallback(
(id: string) => (value: number) => {
form.setFieldsValue({ [id]: value })
},
[form]
)
const handleChangeTextInput = useCallback(
(id: string) => (value: string) => {
form.setFieldsValue({ [id]: value })
},
[form]
)
const handleChangeSwitch = useCallback(
(id: string) => (value: boolean) => {
form.setFieldsValue({ [id]: value })
handleTouchAnyField?.()
forceUpdateAll()
handleTouchField()
},
[form, forceUpdateAll]
)
const handleOpenDebugger = useCallback(
(id: string) => {
setDebugModalsValues({ ...debugModalsValues, [id]: form.getFieldValue(id) })
setDebugModalsStates({ ...debugModalsStates, [id]: true })
},
[form]
)
const handleJsonChange = (id: string) => (value: string) => {
const values = {
[id]: value ? value : "",
}
form.setFieldsValue(values)
setFormValues?.(form.getFieldsValue())
handleTouchField()
}
const getInitialValue = (id: string, defaultValue: any, constantValue: any, type: string) => {
const initial = get(initialValues, id)
if (typeof initial !== "undefined") {
return initial
}
let calcValue: any
if (typeof defaultValue !== "undefined") {
calcValue = defaultValue
} else if (typeof constantValue !== "undefined") {
calcValue = constantValue
} else if (type === "boolean") {
calcValue = false
} else if (type === "json") {
calcValue = {}
} else if (type === "javascript") {
calcValue = "return {}"
} else if (type === "html") {
calcValue = "<script>\n</script>"
} else if (type.indexOf("array/") === 0) {
calcValue = []
} else {
calcValue = ""
}
return type === "json" ? JSON.stringify(calcValue) : calcValue
}
const getFieldComponent = (
type: ParameterType<any>,
id: string,
defaultValue?: any,
constantValue?: any,
jsDebugger?: "object" | "string" | null,
bigField?: boolean,
displayName?: string,
codeSuggestions?: string,
documentation?: React.ReactNode,
validationRules?: FormItemProps["rules"]
) => {
const defaultValueToDisplay =
form.getFieldValue(id) ?? getInitialValue(id, defaultValue, constantValue, type?.typeName)
form.setFieldsValue({ ...form.getFieldsValue(), [id]: defaultValueToDisplay })
const className = hideFields?.some(field => field === getFieldNameById(id)) ? "hidden" : ""
const formItemWrapperProps: FormItemWrapperProps = {
type,
id,
bigField,
displayName,
documentation,
validationRules,
className,
}
switch (type?.typeName) {
case "password":
return (
<FormItemWrapper key={id} {...formItemWrapperProps}>
<Input.Password
autoComplete="off"
iconRender={visible => (visible ? <EyeOutlined /> : <EyeInvisibleOutlined />)}
/>
</FormItemWrapper>
)
case "int": {
return (
<FormItemWrapper key={id} {...formItemWrapperProps}>
<InputNumber autoComplete="off" inputMode="numeric" onChange={handleChangeIntInput(id)} />
</FormItemWrapper>
)
}
case "selection": {
return (
<FormItemWrapper key={id} {...formItemWrapperProps}>
<Select
allowClear
mode={type.data.maxOptions > 1 ? "multiple" : undefined}
onChange={() => forceUpdateTheTarget("select")}
>
{type.data.options.map(({ id, displayName }: Option) => {
return (
<Select.Option value={id} key={id}>
{displayName}
</Select.Option>
)
})}
</Select>
</FormItemWrapper>
)
}
case "array/string":
return (
<FormItemWrapper key={id} {...formItemWrapperProps}>
<EditableList initialValue={defaultValueToDisplay} />
</FormItemWrapper>
)
case "javascript":
case "html":
case "json": {
return (
<FormItemWrapper key={id} {...formItemWrapperProps}>
<CodeEditor
initialValue={defaultValueToDisplay}
className={styles.codeEditor}
extraSuggestions={codeSuggestions}
language={type?.typeName}
handleChange={handleJsonChange(id)}
/>
<span className="z-50">
{jsDebugger && (
<>
{bigField ? (
<Button
size="large"
className="absolute mr-0 mt-0 top-0 right-0"
type="text"
onClick={() => handleOpenDebugger(id)}
icon={<CodeOutlined />}
>
Open Debugger
</Button>
) : (
<Tooltip title="Debug expression">
<span className="absolute top-1.5 right-3">
<BugIcon onClick={() => handleOpenDebugger(id)} className={styles.bugIcon} />
</span>
</Tooltip>
)}
</>
)}
</span>
</FormItemWrapper>
)
}
case "boolean":
return (
<FormItemWrapper key={id} {...formItemWrapperProps}>
{bigField ? (
<SwitchWithLabel
label={displayName}
id={id}
onChange={handleChangeSwitch(id)}
defaultChecked={!!defaultValueToDisplay}
/>
) : (
<Switch className={"mb-0.5"} onChange={handleChangeSwitch(id)} defaultChecked={!!defaultValueToDisplay} />
)}
</FormItemWrapper>
)
case "file":
return (
<FormItemWrapper key={id} {...formItemWrapperProps}>
<InputWithUpload onChange={handleChangeTextInput(id)} value={defaultValueToDisplay} />
</FormItemWrapper>
)
case "description":
return (
<div key={id} className="ant-row ant-form-item form-field_fixed-label">
<div className="ant-col ant-col-4 ant-form-item-label">
<label>{displayName}:</label>
</div>
<div className="ant-col ant-col-20 ant-form-item-control pt-1.5">{defaultValue}</div>
</div>
)
case "oauthSecret":
case "string":
default: {
const backendSecretAvailable =
type?.typeName === "oauthSecret" &&
(availableOauthBackendSecrets === "all_from_config" ||
availableOauthBackendSecrets?.some(name => getFieldNameById(id) === name))
if (backendSecretAvailable) {
formItemWrapperProps.validationRules = validationRules.filter(value => !value["required"])
}
const placeholder = backendSecretAvailable
? "Leave this field empty to use a value provided by Jitsu"
: undefined
return (
<FormItemWrapper key={id} {...formItemWrapperProps}>
<InputWithDebug
id={id}
placeholder={placeholder}
jsDebugger={jsDebugger}
onButtonClick={() => handleOpenDebugger(id)}
/>
</FormItemWrapper>
)
}
}
}
const handleDebuggerRun = async (field: string, debuggerType: "object" | "string", values: DebuggerFormValues) => {
let transform = {}
if (field === "_transform") {
transform = {
_transform_enabled: true,
_transform: values.code,
}
}
const configForm = extraForms && extraForms[0]
const mappingForm = extraForms && extraForms[1]
const data = {
reformat: debuggerType == "string",
uid: initialValues._uid,
type: initialValues._type,
field: field,
expression: values.code,
object: JSON.parse(values.object),
config: makeObjectFromFieldsValues({
...initialValues,
...configForm?.getFieldsValue(),
...mappingForm?.getFieldsValue(),
...transform,
}),
template_variables: Object.entries((configForm || form).getFieldsValue())
.filter(v => v[0].startsWith("_formData._"))
.reduce((accumulator: any, currentValue: [string, unknown]) => {
set(accumulator, currentValue[0].replace("_formData._", ""), currentValue[1])
return accumulator
}, {}),
}
return services.backendApiClient.post(`/destinations/evaluate?project_id=${services.activeProject.id}`, data)
}
const handleCloseDebugger = id => setDebugModalsStates({ ...debugModalsStates, [id]: false })
const handleSaveDebugger = (id, value: string) => {
form.setFieldsValue({ [id]: value })
handleCloseDebugger(id)
}
/**
* Runs after every re-render caused by `Select` field change
* to pick up the values of conditionally rendered fields.
*/
useEffect(() => {
const isInitialRender = !forceUpdatedTargets["select"]
if (!isInitialRender) setFormValues?.(form.getFieldsValue())
}, [forceUpdatedTargets["select"]])
useEffect(() => {
/**
*
* 1st render:
* component creates fields, fills them with values,
* lets the `form` instance to pick them
*
*/
let formValues = {}
const formFields: Parameters<typeof form.setFields>[0] = []
fieldsParamsList.forEach((param: Parameter) => {
const initConfig = makeObjectFromFieldsValues(formValues)
const fieldNeeded = !param.omitFieldRule?.(initConfig)
const id = param.id
const constantValue = typeof param.constant === "function" ? param.constant?.(initConfig) : param.constant
const initialValue = getInitialValue(id, param.defaultValue, constantValue, param.type?.typeName)
if (fieldNeeded) {
formValues[id] = initialValue
formFields.push({
name: id,
value: initialValue,
touched: false,
})
}
})
form.setFields(formFields)
/**
* @reason
* `formValues` holds correct values for dynamically rendered fields
* @warning
* Using `form.getFieldsValue()` instead of `formValues` is not recommended because
* it needs form to re-render once to pick up values of dynamically rendered fields
*/
setInitialFormValues?.(formValues)
/**
*
* 2nd render: component removes/adds fields conditionally
* depending on the form values
*
*/
forceUpdateAll()
}, [])
return (
<>
{fieldsParamsList.map(
({
id,
documentation,
displayName,
type,
defaultValue,
required,
constant,
omitFieldRule,
jsDebugger,
bigField,
codeSuggestions,
validator,
}: Parameter) => {
const currentFormValues = form.getFieldsValue() ?? {}
const defaultFormValues = fieldsParamsList.reduce(
(result, { id, defaultValue }) => ({
...result,
[id]: defaultValue,
}),
{}
)
const formItemName = id
const formValues = {
...defaultFormValues,
...currentFormValues,
}
const parsedFormValues = makeObjectFromFieldsValues(formValues)
const constantValue = typeof constant === "function" ? constant?.(parsedFormValues) : constant
const isHidden = constantValue !== undefined
const isOmitted = omitFieldRule ? omitFieldRule(parsedFormValues) : false
const validationRules: FormItemProps["rules"] = []
if (!isHidden) {
const isRequired = typeof required === "boolean" ? required : required?.(parsedFormValues)
if (isRequired)
validationRules.push({
required: true,
message: `${displayName} field is required.`,
})
if (type?.typeName === "isoUtcDate")
validationRules.push(isoDateValidator(`${displayName} field is required.`))
}
if (validator) {
validationRules.push({ validator: validator })
}
return isOmitted ? null : !isHidden ? (
<Row key={id} className={cn(isHidden && "hidden")}>
<Col span={24}>
{jsDebugger ? (
<CodeDebuggerModal
visible={debugModalsStates[id]}
codeFieldLabelDebugger="Expression"
extraSuggestionsDebugger={codeSuggestions}
defaultCodeValueDebugger={debugModalsValues[id]}
handleCloseDebugger={() => handleCloseDebugger(id)}
runDebugger={values => handleDebuggerRun(id, jsDebugger, values)}
handleSaveCodeDebugger={value => handleSaveDebugger(id, value)}
/>
) : null}
{getFieldComponent(
type,
id,
defaultValue,
constantValue,
jsDebugger,
bigField,
displayName,
codeSuggestions,
documentation,
validationRules
)}
</Col>
</Row>
) : (
<Form.Item key={formItemName} name={formItemName} hidden={true} initialValue={constantValue} />
)
}
)}
</>
)
}
Example #16
Source File: index.tsx From fe-v5 with Apache License 2.0 | 4 votes |
SideMenu: FC = () => {
const { t, i18n } = useTranslation();
const menuList = [
{
key: 'targets',
icon: <DatabaseOutlined />,
title: t('监控对象'),
children: [
{
key: '/targets',
title: t('对象列表'),
},
],
},
{
key: 'monitor',
icon: <LineChartOutlined />,
title: t('监控看图'),
children: [
{
key: '/metric/explorer',
title: t('即时查询'),
},
{
key: '/object/explorer',
title: t('快捷视图'),
},
{
key: '/dashboards',
title: t('监控大盘'),
},
],
},
{
key: 'alarm',
icon: <AlertOutlined />,
title: t('告警管理'),
children: [
{
key: '/alert-rules',
title: t('告警规则'),
},
{
key: '/alert-mutes',
title: t('屏蔽规则'),
},
{
key: '/alert-subscribes',
title: t('订阅规则'),
},
{
key: '/alert-cur-events',
title: t('活跃告警'),
},
{
key: '/alert-his-events',
title: t('历史告警'),
},
],
},
{
key: 'job',
icon: <CodeOutlined />,
title: t('告警自愈'),
children: [
{
key: '/job-tpls',
title: t('自愈脚本'),
},
{
key: '/job-tasks',
title: t('执行历史'),
},
],
},
{
key: 'manage',
icon: <UserOutlined />,
title: t('人员组织'),
children: [
{
key: '/users',
title: t('用户管理'),
},
{
key: '/user-groups',
title: t('团队管理'),
},
{
key: '/busi-groups',
title: t('业务组管理'),
},
],
},
{
key: 'help',
icon: <Icon component={SystemInfoSvg as any} />,
title: t('系统信息'),
children: [
{
key: '/help/version',
title: t('系统版本'),
},
{
key: '/help/contact',
title: t('联系我们'),
},
{
key: '/help/migrate',
title: t('管理员迁移'),
},
],
},
];
const [menus, setMenus] = useState(menuList);
const history = useHistory();
const location = useLocation();
const { pathname } = location;
let { profile } = useSelector<AccountRootState, accountStoreState>((state) => state.account);
const [collapsed, setCollapsed] = useState(localStorage.getItem('menuCollapsed') === '1');
const [selectedKeys, setSelectedKeys] = useState<string[]>([defaultSelectedKey(menus, pathname)]);
const [openKeys, setOpenKeys] = useState<string[]>(collapsed ? [] : [getDefaultOpenKey(menus, pathname)]);
const toggleCollapsed = () => {
setCollapsed(!collapsed);
localStorage.setItem('menuCollapsed', !collapsed ? '1' : '0');
};
const handleClick: MenuClickEventHandler = ({ key }) => {
setSelectedKeys([key as string]);
// 写两个key as string 感觉有点傻
if (key === 'changeLanguage') {
let language = i18n.language == 'en' ? 'zh' : 'en';
i18n.changeLanguage(language);
localStorage.setItem('language', language);
}
if ((key as string).startsWith('/')) {
history.push(key as string);
}
};
const hideSideMenu = () => location.pathname === '/login' || location.pathname.startsWith('/chart/') || location.pathname === '/callback';
useEffect(() => {
setSelectedKeys([defaultSelectedKey(menus, pathname)]);
if (!collapsed) {
setOpenKeys(_.union([...openKeys, getDefaultOpenKey(menus, pathname)]));
}
}, [pathname, collapsed]);
useEffect(() => {
if (profile.roles.length > 0) {
if (profile.roles.indexOf('Admin') === -1) {
getMenuPerm().then((res) => {
const { dat } = res;
const newMenus = [...menuList];
newMenus.forEach((menu) => {
menu.children = menu.children.filter((item) => dat.includes(item.key));
});
setMenus(newMenus);
});
} else {
setMenus(menuList);
}
}
}, [profile.roles]);
return hideSideMenu() ? null : (
<div
style={{
display: 'flex',
flexDirection: 'column',
}}
>
<div className={`home ${collapsed ? 'collapse' : ''}`}>
<div className='name' onClick={() => history.push('/metric/explorer')} key='overview'>
<img src={collapsed ? '/image/logo.svg' : '/image/logo-l.svg'} alt='' className='logo' />
</div>
</div>
<Menu
className='left-menu-container'
theme='dark'
inlineCollapsed={collapsed}
openKeys={openKeys}
selectedKeys={selectedKeys}
onClick={handleClick}
mode='inline'
onOpenChange={(openKeys: string[]) => {
setOpenKeys(openKeys);
}}
>
{_.map(menus, (subMenus) => {
return (
subMenus.children.length > 0 && (
<SubMenu key={subMenus.key} icon={subMenus.icon} title={subMenus.title}>
{_.map(subMenus.children, (menu) => {
return <Menu.Item key={menu.key}>{menu.title}</Menu.Item>;
})}
</SubMenu>
)
);
})}
{lazyMenu.sort((a, b) => b.weight - a.weight).map((item) => item.content)}
</Menu>
<Button type='text' onClick={toggleCollapsed} className='collapseBtn'>
{React.createElement(collapsed ? MenuUnfoldOutlined : MenuFoldOutlined)}
</Button>
</div>
);
}
Example #17
Source File: BrickBook.tsx From next-basics with GNU General Public License v3.0 | 4 votes |
export function BrickBook({
storyId,
storyType,
stories,
brickDoc,
titleLinkEnabled,
titleLinkTarget,
notToSetPageTitle,
renderDocLink,
}: BrickBookProps): React.ReactElement {
const story = findStoryById(storyId, storyType, stories);
const actions = story ? story.actions : null;
const confList: BrickConf[] = [].concat(story?.conf).filter(Boolean);
const developerStorage = storage.getItem(NS_DEVELOPERS) ?? {};
const { t } = useTranslation(NS_DEVELOPERS);
const [mode, setMode] = React.useState(developerStorage.mode ?? "json");
React.useEffect(() => {
if (story && !notToSetPageTitle) {
getRuntime().applyPageTitle(i18nText(story.text));
}
}, [notToSetPageTitle, story]);
if (!story) {
return null;
}
const onChange = (e: RadioChangeEvent): void => {
const value = e.target.value;
developerStorage.mode = value;
setMode(value);
storage.setItem(NS_DEVELOPERS, developerStorage);
};
const title = getStoryTitle(story);
const description = i18nText(story.description) || "";
return (
<>
<section>
<h1 style={{ fontSize: "16px", marginBottom: "10px" }}>
{titleLinkEnabled ? (
<Link
to={`/developers/brick-book/${story.type}/${story.storyId}`}
{...(titleLinkTarget ? { target: titleLinkTarget } : {})}
>
{title} <FileSearchOutlined style={{ fontSize: "16px" }} />
</Link>
) : (
title
)}
<span className={cssStyle.subTitle}> {story.author}</span>
</h1>
<p style={{ marginBottom: "20px", color: "#595959" }}>
{" "}
{description}{" "}
</p>
</section>
<section>
<div className={cssStyle.previewHeader}>
<div className={cssStyle.left}>
{" "}
{t(K.PREVIEW)} <AppstoreOutlined />
<span className={cssStyle.subTitle}>
{" "}
{story.category}:{story.type}:{story.storyId}
</span>
</div>
<Radio.Group
defaultValue={mode}
buttonStyle="solid"
onChange={onChange}
>
<Radio.Button value="json">JSON</Radio.Button>
<Radio.Button value="yaml">YAML</Radio.Button>
</Radio.Group>
</div>
<div
className={cssStyle.brickPreview}
style={{
gridTemplateColumns: `repeat(${story.previewColumns || 1}, 1fr)`,
}}
>
{confList.map((item, i) => (
<BrickDemo
key={`${storyId}-${i}`}
mode={mode}
defaultConf={item}
actions={actions}
/>
))}
</div>
</section>
<section className={cssStyle.sectionTitle}>
<h2 style={{ marginBottom: "10px" }}>
API <CodeOutlined />
</h2>
{
// 兼容第二版构件文档(demo和doc都在stories.json里)
(story?.doc as StoryDoc)?.id ? (
<BrickDocument
storyId={storyId}
storyType={storyType}
doc={story?.doc as StoryDoc}
renderLink={renderDocLink}
/>
) : brickDoc ? (
// 兼容第一版构件文档(docs.jsons)
<BrickDocument
storyId={storyId}
storyType={storyType}
doc={brickDoc}
renderLink={renderDocLink}
/>
) : (
// 兼容最老的一般文档(手写markdown)
<BrickDoc doc={story.doc as string} />
)
}
</section>
</>
);
}
Example #18
Source File: index.tsx From fe-v5 with Apache License 2.0 | 4 votes |
index = (_props: any) => {
const { t, i18n } = useTranslation();
const searchRef = useRef<Input>(null);
const [query, setQuery] = useState('');
const { curBusiItem } = useSelector<RootState, CommonStoreState>((state) => state.common);
const busiId = curBusiItem.id;
const [selectedIds, setSelectedIds] = useState([] as any[]);
const { tableProps, refresh } = useAntdTable<any, any>((options) => getTableData(options, busiId, query), { refreshDeps: [busiId, query] });
function handleTagClick(tag: string) {
if (!_.includes(query, tag)) {
const newQuery = query ? `${query} ${tag}` : tag;
setQuery(newQuery);
searchRef.current?.setValue(newQuery);
}
}
function handleDelBtnClick(id: number) {
if (busiId) {
request(`${api.tasktpl(busiId)}/${id}`, {
method: 'DELETE',
}).then(() => {
message.success(t('msg.delete.success'));
refresh();
});
}
}
function handleBatchBindTags() {
if (!_.isEmpty(selectedIds)) {
BindTags({
language: i18n.language,
selectedIds,
busiId,
onOk: () => {
refresh();
},
});
}
}
function handleBatchUnBindTags() {
if (!_.isEmpty(selectedIds)) {
let uniqueTags = [] as any[];
_.each(tableProps.dataSource, (item) => {
const tags = item.tags;
uniqueTags = _.union(uniqueTags, tags);
});
UnBindTags({
language: i18n.language,
selectedIds,
uniqueTags,
busiId,
onOk: () => {
refresh();
},
});
}
}
const columns: ColumnProps<Tpl>[] = [
{
title: 'ID',
dataIndex: 'id',
},
{
title: t('tpl.title'),
dataIndex: 'title',
render: (text, record) => {
return <Link to={{ pathname: `/job-tpls/${record.id}/detail` }}>{text}</Link>;
},
},
{
title: t('tpl.tags'),
dataIndex: 'tags',
render: (text) => {
return _.map(text, (item) => (
<Tag color='blue' key={item} onClick={() => handleTagClick(item)}>
{item}
</Tag>
));
},
},
{
title: t('tpl.creator'),
dataIndex: 'create_by',
width: 100,
},
{
title: t('tpl.last_updated'),
dataIndex: 'update_at',
width: 160,
render: (text) => {
return moment.unix(text).format('YYYY-MM-DD HH:mm:ss');
},
},
{
title: t('table.operations'),
width: 220,
render: (_text, record) => {
return (
<span>
<Link to={{ pathname: `/job-tpls/add/task`, search: `tpl=${record.id}` }}>{t('task.create')}</Link>
<Divider type='vertical' />
<Link to={{ pathname: `/job-tpls/${record.id}/modify` }}>{t('table.modify')}</Link>
<Divider type='vertical' />
<Link to={{ pathname: `/job-tpls/${record.id}/clone` }}>{t('table.clone')}</Link>
<Divider type='vertical' />
<Popconfirm
title={<div style={{ width: 100 }}>{t('table.delete.sure')}</div>}
onConfirm={() => {
handleDelBtnClick(record.id);
}}
>
<a style={{ color: 'red' }}>{t('table.delete')}</a>
</Popconfirm>
</span>
);
},
},
];
return (
<PageLayout
hideCluster
title={
<>
<CodeOutlined />
{t('自愈脚本')}
</>
}
>
<div style={{ display: 'flex' }}>
<LeftTree></LeftTree>
{busiId ? (
<div style={{ flex: 1, padding: 20 }}>
<Row>
<Col span={14} className='mb10'>
<Input
style={{ width: 200 }}
ref={searchRef}
prefix={<SearchOutlined />}
defaultValue={query}
onPressEnter={(e) => {
setQuery(e.currentTarget.value);
}}
placeholder='搜索标题、标签'
/>
</Col>
<Col span={10} className='textAlignRight'>
<Link to={{ pathname: `/job-tpls/add` }}>
<Button icon={<PlusOutlined />} style={{ marginRight: 10 }} type='primary' ghost>
{t('tpl.create')}
</Button>
</Link>
<Dropdown
overlay={
<Menu>
<Menu.Item>
<Button
type='link'
disabled={selectedIds.length === 0}
onClick={() => {
handleBatchBindTags();
}}
>
{t('tpl.tag.bind')}
</Button>
</Menu.Item>
<Menu.Item>
<Button
type='link'
disabled={selectedIds.length === 0}
onClick={() => {
handleBatchUnBindTags();
}}
>
{t('tpl.tag.unbind')}
</Button>
</Menu.Item>
</Menu>
}
>
<Button icon={<DownOutlined />}>{t('table.batch.operations')}</Button>
</Dropdown>
</Col>
</Row>
<Table
rowKey='id'
columns={columns}
{...(tableProps as any)}
rowSelection={{
selectedRowKeys: selectedIds,
onChange: (selectedRowKeys) => {
setSelectedIds(selectedRowKeys);
},
}}
pagination={
{
...tableProps.pagination,
showSizeChanger: true,
pageSizeOptions: ['10', '50', '100', '500', '1000'],
showTotal: (total) => {
return i18n.language == 'en' ? `Total ${total} items` : `共 ${total} 条`;
},
} as any
}
/>
</div>
) : (
<BlankBusinessPlaceholder text='自愈脚本' />
)}
</div>
</PageLayout>
);
}
Example #19
Source File: index.tsx From surveyo with Apache License 2.0 | 4 votes |
function DashboardHelper() {
const {user} = useAuth0();
const [state, setState] = useState([]);
const [deleteForm] = useMutation<DeleteForm, DeleteFormVariables>(
DELETE_FORM
);
const {loading, error, data} = useQuery<GetSurveys, GetSurveysVariables>(
GET_FORMS,
{
variables: {
email: user.email,
},
onCompleted: () => {
setState((data?.getUser?.forms || []) as any);
},
}
);
if (loading) {
return <Card loading />;
}
if (error) {
console.error(error);
return <Alert message={error.message} type="warning" />;
}
async function handleDelete(id: string) {
setState(state => state.filter((form: any) => form?.id !== id));
try {
await deleteForm({
variables: {
id,
},
});
} catch (e) {
console.error(e);
message.error('Internal error: could not delete form');
}
}
const tableCols = [
{
title: 'Title',
dataIndex: 'title',
key: 'title',
render: (text: any) => text,
},
{
title: 'Responses',
dataIndex: 'responses',
key: 'responses',
render: (_text: any, record: any) => record.responses?.length || 0,
},
{
title: 'Actions',
key: 'action',
render: (_text: any, record: any) => (
<Space size="middle">
<Tooltip title="Open form">
<Link to={`/form/${record.id}`} target="_blank">
<Button type="link" icon={<ExportOutlined />} />
</Link>
</Tooltip>
<Tooltip title="Download CSV">
<DownloadCsv id={record.id} title={record.title} />
</Tooltip>
<Tooltip title="Charts">
<Link to={`/charts/${record.id}`} target="_blank">
<Button type="link" icon={<LineChartOutlined />} />
</Link>
</Tooltip>
<Tooltip title="GraphiQL">
<Link to={`/graphiql/${record.id}`} target="_blank">
<Button type="link" icon={<CodeOutlined />} />
</Link>
</Tooltip>
<Tooltip title="Delete">
<Popconfirm
title="Are you sure you want to delete this form?"
onConfirm={() => handleDelete(record.id)}
okText="Yes"
cancelText="No"
>
<Button type="link" icon={<DeleteOutlined />} />
</Popconfirm>
</Tooltip>
</Space>
),
},
];
return <Table columns={tableCols as any} dataSource={state as any} />;
}
Example #20
Source File: Icon.tsx From html2sketch with MIT License | 4 votes |
IconSymbol: FC = () => {
return (
<Row>
{/*<CaretUpOutlined*/}
{/* className="icon"*/}
{/* symbolName={'1.General/2.Icons/1.CaretUpOutlined'}*/}
{/*/>*/}
{/* className="icon"*/}
{/* symbolName={'1.General/2.Icons/2.MailOutlined'}*/}
{/*/>*/}
{/*<StepBackwardOutlined*/}
{/* className="icon"*/}
{/* symbolName={'1.General/2.Icons/2.StepBackwardOutlined'}*/}
{/*/>*/}
{/*<StepForwardOutlined*/}
{/* className="icon"*/}
{/* symbolName={'1.General/2.Icons/2.StepBackwardOutlined'}*/}
{/*/>*/}
<StepForwardOutlined />
<ShrinkOutlined />
<ArrowsAltOutlined />
<DownOutlined />
<UpOutlined />
<LeftOutlined />
<RightOutlined />
<CaretUpOutlined />
<CaretDownOutlined />
<CaretLeftOutlined />
<CaretRightOutlined />
<VerticalAlignTopOutlined />
<RollbackOutlined />
<FastBackwardOutlined />
<FastForwardOutlined />
<DoubleRightOutlined />
<DoubleLeftOutlined />
<VerticalLeftOutlined />
<VerticalRightOutlined />
<VerticalAlignMiddleOutlined />
<VerticalAlignBottomOutlined />
<ForwardOutlined />
<BackwardOutlined />
<EnterOutlined />
<RetweetOutlined />
<SwapOutlined />
<SwapLeftOutlined />
<SwapRightOutlined />
<ArrowUpOutlined />
<ArrowDownOutlined />
<ArrowLeftOutlined />
<ArrowRightOutlined />
<LoginOutlined />
<LogoutOutlined />
<MenuFoldOutlined />
<MenuUnfoldOutlined />
<BorderBottomOutlined />
<BorderHorizontalOutlined />
<BorderInnerOutlined />
<BorderOuterOutlined />
<BorderLeftOutlined />
<BorderRightOutlined />
<BorderTopOutlined />
<BorderVerticleOutlined />
<PicCenterOutlined />
<PicLeftOutlined />
<PicRightOutlined />
<RadiusBottomleftOutlined />
<RadiusBottomrightOutlined />
<RadiusUpleftOutlined />
<RadiusUprightOutlined />
<FullscreenOutlined />
<FullscreenExitOutlined />
<QuestionOutlined />
<PauseOutlined />
<MinusOutlined />
<PauseCircleOutlined />
<InfoOutlined />
<CloseOutlined />
<ExclamationOutlined />
<CheckOutlined />
<WarningOutlined />
<IssuesCloseOutlined />
<StopOutlined />
<EditOutlined />
<CopyOutlined />
<ScissorOutlined />
<DeleteOutlined />
<SnippetsOutlined />
<DiffOutlined />
<HighlightOutlined />
<AlignCenterOutlined />
<AlignLeftOutlined />
<AlignRightOutlined />
<BgColorsOutlined />
<BoldOutlined />
<ItalicOutlined />
<UnderlineOutlined />
<StrikethroughOutlined />
<RedoOutlined />
<UndoOutlined />
<ZoomInOutlined />
<ZoomOutOutlined />
<FontColorsOutlined />
<FontSizeOutlined />
<LineHeightOutlined />
<SortAscendingOutlined />
<SortDescendingOutlined />
<DragOutlined />
<OrderedListOutlined />
<UnorderedListOutlined />
<RadiusSettingOutlined />
<ColumnWidthOutlined />
<ColumnHeightOutlined />
<AreaChartOutlined />
<PieChartOutlined />
<BarChartOutlined />
<DotChartOutlined />
<LineChartOutlined />
<RadarChartOutlined />
<HeatMapOutlined />
<FallOutlined />
<RiseOutlined />
<StockOutlined />
<BoxPlotOutlined />
<FundOutlined />
<SlidersOutlined />
<AndroidOutlined />
<AppleOutlined />
<WindowsOutlined />
<IeOutlined />
<ChromeOutlined />
<GithubOutlined />
<AliwangwangOutlined />
<DingdingOutlined />
<WeiboSquareOutlined />
<WeiboCircleOutlined />
<TaobaoCircleOutlined />
<Html5Outlined />
<WeiboOutlined />
<TwitterOutlined />
<WechatOutlined />
<AlipayCircleOutlined />
<TaobaoOutlined />
<SkypeOutlined />
<FacebookOutlined />
<CodepenOutlined />
<CodeSandboxOutlined />
<AmazonOutlined />
<GoogleOutlined />
<AlipayOutlined />
<AntDesignOutlined />
<AntCloudOutlined />
<ZhihuOutlined />
<SlackOutlined />
<SlackSquareOutlined />
<BehanceSquareOutlined />
<DribbbleOutlined />
<DribbbleSquareOutlined />
<InstagramOutlined />
<YuqueOutlined />
<AlibabaOutlined />
<YahooOutlined />
<RedditOutlined />
<SketchOutlined />
<AccountBookOutlined />
<AlertOutlined />
<ApartmentOutlined />
<ApiOutlined />
<QqOutlined />
<MediumWorkmarkOutlined />
<GitlabOutlined />
<MediumOutlined />
<GooglePlusOutlined />
<AppstoreAddOutlined />
<AppstoreOutlined />
<AudioOutlined />
<AudioMutedOutlined />
<AuditOutlined />
<BankOutlined />
<BarcodeOutlined />
<BarsOutlined />
<BellOutlined />
<BlockOutlined />
<BookOutlined />
<BorderOutlined />
<BranchesOutlined />
<BuildOutlined />
<BulbOutlined />
<CalculatorOutlined />
<CalendarOutlined />
<CameraOutlined />
<CarOutlined />
<CarryOutOutlined />
<CiCircleOutlined />
<CiOutlined />
<CloudOutlined />
<ClearOutlined />
<ClusterOutlined />
<CodeOutlined />
<CoffeeOutlined />
<CompassOutlined />
<CompressOutlined />
<ContactsOutlined />
<ContainerOutlined />
<ControlOutlined />
<CopyrightCircleOutlined />
<CopyrightOutlined />
<CreditCardOutlined />
<CrownOutlined />
<CustomerServiceOutlined />
<DashboardOutlined />
<DatabaseOutlined />
<DeleteColumnOutlined />
<DeleteRowOutlined />
<DisconnectOutlined />
<DislikeOutlined />
<DollarCircleOutlined />
<DollarOutlined />
<DownloadOutlined />
<EllipsisOutlined />
<EnvironmentOutlined />
<EuroCircleOutlined />
<EuroOutlined />
<ExceptionOutlined />
<ExpandAltOutlined />
<ExpandOutlined />
<ExperimentOutlined />
<ExportOutlined />
<EyeOutlined />
<FieldBinaryOutlined />
<FieldNumberOutlined />
<FieldStringOutlined />
<DesktopOutlined />
<DingtalkOutlined />
<FileAddOutlined />
<FileDoneOutlined />
<FileExcelOutlined />
<FileExclamationOutlined />
<FileOutlined />
<FileImageOutlined />
<FileJpgOutlined />
<FileMarkdownOutlined />
<FilePdfOutlined />
<FilePptOutlined />
<FileProtectOutlined />
<FileSearchOutlined />
<FileSyncOutlined />
<FileTextOutlined />
<FileUnknownOutlined />
<FileWordOutlined />
<FilterOutlined />
<FireOutlined />
<FlagOutlined />
<FolderAddOutlined />
<FolderOutlined />
<FolderOpenOutlined />
<ForkOutlined />
<FormatPainterOutlined />
<FrownOutlined />
<FunctionOutlined />
<FunnelPlotOutlined />
<GatewayOutlined />
<GifOutlined />
<GiftOutlined />
<GlobalOutlined />
<GoldOutlined />
<GroupOutlined />
<HddOutlined />
<HeartOutlined />
<HistoryOutlined />
<HomeOutlined />
<HourglassOutlined />
<IdcardOutlined />
<ImportOutlined />
<InboxOutlined />
<InsertRowAboveOutlined />
<InsertRowBelowOutlined />
<InsertRowLeftOutlined />
<InsertRowRightOutlined />
<InsuranceOutlined />
<InteractionOutlined />
<KeyOutlined />
<LaptopOutlined />
<LayoutOutlined />
<LikeOutlined />
<LineOutlined />
<LinkOutlined />
<Loading3QuartersOutlined />
<LoadingOutlined />
<LockOutlined />
<MailOutlined />
<ManOutlined />
<MedicineBoxOutlined />
<MehOutlined />
<MenuOutlined />
<MergeCellsOutlined />
<MessageOutlined />
<MobileOutlined />
<MoneyCollectOutlined />
<MonitorOutlined />
<MoreOutlined />
<NodeCollapseOutlined />
<NodeExpandOutlined />
<NodeIndexOutlined />
<NotificationOutlined />
<NumberOutlined />
<PaperClipOutlined />
<PartitionOutlined />
<PayCircleOutlined />
<PercentageOutlined />
<PhoneOutlined />
<PictureOutlined />
<PoundCircleOutlined />
<PoundOutlined />
<PoweroffOutlined />
<PrinterOutlined />
<ProfileOutlined />
<ProjectOutlined />
<PropertySafetyOutlined />
<PullRequestOutlined />
<PushpinOutlined />
<QrcodeOutlined />
<ReadOutlined />
<ReconciliationOutlined />
<RedEnvelopeOutlined />
<ReloadOutlined />
<RestOutlined />
<RobotOutlined />
<RocketOutlined />
<SafetyCertificateOutlined />
<SafetyOutlined />
<ScanOutlined />
<ScheduleOutlined />
<SearchOutlined />
<SecurityScanOutlined />
<SelectOutlined />
<SendOutlined />
<SettingOutlined />
<ShakeOutlined />
<ShareAltOutlined />
<ShopOutlined />
<ShoppingCartOutlined />
<ShoppingOutlined />
<SisternodeOutlined />
<SkinOutlined />
<SmileOutlined />
<SolutionOutlined />
<SoundOutlined />
<SplitCellsOutlined />
<StarOutlined />
<SubnodeOutlined />
<SyncOutlined />
<TableOutlined />
<TabletOutlined />
<TagOutlined />
<TagsOutlined />
<TeamOutlined />
<ThunderboltOutlined />
<ToTopOutlined />
<ToolOutlined />
<TrademarkCircleOutlined />
<TrademarkOutlined />
<TransactionOutlined />
<TrophyOutlined />
<UngroupOutlined />
<UnlockOutlined />
<UploadOutlined />
<UsbOutlined />
<UserAddOutlined />
<UserDeleteOutlined />
<UserOutlined />
<UserSwitchOutlined />
<UsergroupAddOutlined />
<UsergroupDeleteOutlined />
<VideoCameraOutlined />
<WalletOutlined />
<WifiOutlined />
<BorderlessTableOutlined />
<WomanOutlined />
<BehanceOutlined />
<DropboxOutlined />
<DeploymentUnitOutlined />
<UpCircleOutlined />
<DownCircleOutlined />
<LeftCircleOutlined />
<RightCircleOutlined />
<UpSquareOutlined />
<DownSquareOutlined />
<LeftSquareOutlined />
<RightSquareOutlined />
<PlayCircleOutlined />
<QuestionCircleOutlined />
<PlusCircleOutlined />
<PlusSquareOutlined />
<MinusSquareOutlined />
<MinusCircleOutlined />
<InfoCircleOutlined />
<ExclamationCircleOutlined />
<CloseCircleOutlined />
<CloseSquareOutlined />
<CheckCircleOutlined />
<CheckSquareOutlined />
<ClockCircleOutlined />
<FormOutlined />
<DashOutlined />
<SmallDashOutlined />
<YoutubeOutlined />
<CodepenCircleOutlined />
<AliyunOutlined />
<PlusOutlined />
<LinkedinOutlined />
<AimOutlined />
<BugOutlined />
<CloudDownloadOutlined />
<CloudServerOutlined />
<CloudSyncOutlined />
<CloudUploadOutlined />
<CommentOutlined />
<ConsoleSqlOutlined />
<EyeInvisibleOutlined />
<FileGifOutlined />
<DeliveredProcedureOutlined />
<FieldTimeOutlined />
<FileZipOutlined />
<FolderViewOutlined />
<FundProjectionScreenOutlined />
<FundViewOutlined />
<MacCommandOutlined />
<PlaySquareOutlined />
<OneToOneOutlined />
<RotateLeftOutlined />
<RotateRightOutlined />
<SaveOutlined />
<SwitcherOutlined />
<TranslationOutlined />
<VerifiedOutlined />
<VideoCameraAddOutlined />
<WhatsAppOutlined />
{/*</Col>*/}
</Row>
);
}
Example #21
Source File: ServerManager.tsx From anew-server with MIT License | 4 votes |
ServerManager: React.FC<FileManagerProps> = (props) => {
const { modalVisible, handleChange, setTtys, setActiveKey } = props;
const [treeData, setTreeData] = useState();
const [loadedKeys, setLoadedKeys] = useState<string[]>([]);
const [selectedKeys, setSelectedKeys] = useState<string[]>([]);
const [addTty, setAddTty] = useState<API.TtyList>();
const updateTreeData = (list: any, key: React.Key, children: any): any => {
return list.map((node: any) => {
if (node.key === key) {
return { ...node, children };
}
if (node.children) {
return { ...node, children: updateTreeData(node.children, key, children) };
}
return node;
})
};
const onLoadData = ({ key, children }: any) => {
return new Promise<void>(resolve => {
if (children) {
resolve();
return;
}
if (key === "0") {
queryHosts().then((res) => {
const selectHosts = Array.isArray(res.data.data) ? res.data.data.map((item: any) => ({
...item,
title: `${item.host_name} (${item.ip_address}:${item.port})`,
key: `key-${key}-${item.id}`,
isLeaf: true,
icon: <CodeOutlined />,
})) : null
setTreeData((origin) => updateTreeData(origin, key, selectHosts))
}
)
} else {
queryHostByGroupId(key).then((res) => {
const selectHosts = Array.isArray(res.data.data) ? res.data.data.map((item: any) => ({
...item,
title: `${item.host_name} (${item.ip_address}:${item.port})`,
key: `key-${key}-${item.id}`,
isLeaf: true,
icon: <CodeOutlined />,
})) : null
setTreeData((origin) => updateTreeData(origin, key, selectHosts))
}
)
}
setLoadedKeys([...loadedKeys, key])
resolve();
});
}
const onSelect = (selectedKeysValue: any, info: any) => {
setSelectedKeys(selectedKeysValue);
const key = selectedKeysValue[0].split("-")
if (key[0] === "key") {
const hostsObj = { hostname: info.node.host_name, ipaddr: info.node.ip_address, port: info.node.port, id: info.node.id.toString(), actKey: "tty1", secKey: null }
setAddTty(hostsObj)
}
};
const getHostDir = () => {
queryHostGroups({ all: true, not_null: true }).then((res) => {
if (Array.isArray(res.data.data)) {
var resp = [{ id: 0, name: '所有主机' }, ...res.data.data]
resp = resp.map(({ id, name, ...item }) => ({
...item,
title: name,
key: `${id}`,
}))
setLoadedKeys([]);
setTreeData(resp as any);
}
});
}
const tabcallback = (key: string) => {
switch (key) {
case "1":
getHostDir();
}
}
const handleOk = () => {
const key = selectedKeys[0].split("-");
if (key[0] === "key") {
let hosts = JSON.parse(localStorage.getItem('TABS_TTY_HOSTS') as string) || [];
if (hosts) {
let newAddtty = {};
Object.assign(newAddtty, addTty);
(newAddtty as API.TtyList).actKey = "tty" + (hosts.length + 1).toString();
hosts.push(newAddtty);
setTtys(hosts);
localStorage.setItem('TABS_TTY_HOSTS', JSON.stringify(hosts));
setActiveKey((newAddtty as API.TtyList).actKey);
}
handleChange(false);
} else {
message.info("未选择服务器");
}
}
useEffect(() => {
// 默认加载主机组目录
getHostDir();
}, []);
return (
<Modal
title="选择服务器"
visible={modalVisible}
onCancel={() => handleChange(false)}
onOk={handleOk}
okText="确认"
cancelText="取消"
>
<Tabs defaultActiveKey="1" onChange={tabcallback} tabPosition="left">
<TabPane tab="主机组" key="1">
<DirectoryTree loadData={onLoadData} treeData={treeData} loadedKeys={loadedKeys} selectedKeys={selectedKeys} onSelect={onSelect} />
</TabPane>
<TabPane tab="项目组" key="2">
项目分组
</TabPane>
</Tabs>
</Modal>
);
}
Example #22
Source File: PluginDrawer.tsx From posthog-foss with MIT License | 4 votes |
export function PluginDrawer(): JSX.Element {
const { user } = useValues(userLogic)
const { preflight } = useValues(preflightLogic)
const { editingPlugin, loading, editingSource, editingPluginInitialChanges } = useValues(pluginsLogic)
const { editPlugin, savePluginConfig, uninstallPlugin, setEditingSource, generateApiKeysIfNeeded, patchPlugin } =
useActions(pluginsLogic)
const [form] = Form.useForm()
const [invisibleFields, setInvisibleFields] = useState<string[]>([])
const [requiredFields, setRequiredFields] = useState<string[]>([])
useEffect(() => {
if (editingPlugin) {
form.setFieldsValue({
...(editingPlugin.pluginConfig.config || defaultConfigForPlugin(editingPlugin)),
__enabled: editingPlugin.pluginConfig.enabled,
...editingPluginInitialChanges,
})
generateApiKeysIfNeeded(form)
} else {
form.resetFields()
}
updateInvisibleAndRequiredFields()
}, [editingPlugin?.id, editingPlugin?.config_schema])
const updateInvisibleAndRequiredFields = (): void => {
determineAndSetInvisibleFields()
determineAndSetRequiredFields()
}
const determineAndSetInvisibleFields = (): void => {
const fieldsToSetAsInvisible = []
for (const field of Object.values(getConfigSchemaArray(editingPlugin?.config_schema || {}))) {
if (!field.visible_if || !field.key) {
continue
}
const shouldBeVisible = field.visible_if.every(
([targetFieldName, targetFieldValue]: Array<string | undefined>) =>
doFieldRequirementsMatch(form, targetFieldName, targetFieldValue)
)
if (!shouldBeVisible) {
fieldsToSetAsInvisible.push(field.key)
}
}
setInvisibleFields(fieldsToSetAsInvisible)
}
const determineAndSetRequiredFields = (): void => {
const fieldsToSetAsRequired = []
for (const field of Object.values(getConfigSchemaArray(editingPlugin?.config_schema || {}))) {
if (!field.required_if || !Array.isArray(field.required_if) || !field.key) {
continue
}
const shouldBeRequired = field.required_if.every(
([targetFieldName, targetFieldValue]: Array<string | undefined>) =>
doFieldRequirementsMatch(form, targetFieldName, targetFieldValue)
)
if (shouldBeRequired) {
fieldsToSetAsRequired.push(field.key)
}
}
setRequiredFields(fieldsToSetAsRequired)
}
const isValidChoiceConfig = (fieldConfig: PluginConfigChoice): boolean => {
return (
Array.isArray(fieldConfig.choices) &&
!!fieldConfig.choices.length &&
!fieldConfig.choices.find((c) => typeof c !== 'string') &&
!fieldConfig.secret
)
}
const isValidField = (fieldConfig: PluginConfigSchema): boolean =>
fieldConfig.type !== 'choice' || isValidChoiceConfig(fieldConfig)
return (
<>
<Drawer
forceRender={true}
visible={!!editingPlugin}
onClose={() => editPlugin(null)}
width="min(90vw, 500px)"
title={editingPlugin?.name}
data-attr="plugin-drawer"
footer={
<div style={{ display: 'flex' }}>
<Space style={{ flexGrow: 1 }}>
{editingPlugin &&
!editingPlugin.is_global &&
canInstallPlugins(user?.organization, editingPlugin.organization_id) && (
<Popconfirm
placement="topLeft"
title="Are you sure you wish to uninstall this plugin completely?"
onConfirm={() => uninstallPlugin(editingPlugin.name)}
okText="Uninstall"
cancelText="Cancel"
className="plugins-popconfirm"
>
<Button
style={{ color: 'var(--danger)', padding: 4 }}
type="text"
icon={<DeleteOutlined />}
data-attr="plugin-uninstall"
>
Uninstall
</Button>
</Popconfirm>
)}
{preflight?.cloud &&
editingPlugin &&
canGloballyManagePlugins(user?.organization) &&
(editingPlugin.is_global ? (
<Tooltip
title={
<>
This plugin can currently be used by other organizations in this
instance of PostHog. This action will <b>disable and hide it</b> for all
organizations other than yours.
</>
}
>
<Button
type="text"
icon={<RollbackOutlined />}
onClick={() => patchPlugin(editingPlugin.id, { is_global: false })}
style={{ padding: 4 }}
>
Make local
</Button>
</Tooltip>
) : (
<Tooltip
title={
<>
This action will mark this plugin as installed for{' '}
<b>all organizations</b> in this instance of PostHog.
</>
}
>
<Button
type="text"
icon={<GlobalOutlined />}
onClick={() => patchPlugin(editingPlugin.id, { is_global: true })}
style={{ padding: 4 }}
>
Make global
</Button>
</Tooltip>
))}
</Space>
<Space>
<Button onClick={() => editPlugin(null)} data-attr="plugin-drawer-cancel">
Cancel
</Button>
<Button
type="primary"
loading={loading}
onClick={form.submit}
data-attr="plugin-drawer-save"
>
Save
</Button>
</Space>
</div>
}
>
<Form form={form} layout="vertical" name="basic" onFinish={savePluginConfig}>
{editingPlugin ? (
<div>
<div style={{ display: 'flex', marginBottom: 16 }}>
<PluginImage
pluginType={editingPlugin.plugin_type}
url={editingPlugin.url}
size="large"
/>
<div style={{ flexGrow: 1, paddingLeft: 16 }}>
{endWithPunctation(editingPlugin.description)}
<div style={{ marginTop: 5 }}>
{editingPlugin?.plugin_type === 'local' && editingPlugin.url ? (
<LocalPluginTag url={editingPlugin.url} title="Installed Locally" />
) : editingPlugin.plugin_type === 'source' ? (
<SourcePluginTag />
) : null}
{editingPlugin.url && (
<a href={editingPlugin.url}>
<i>⤷ Learn more</i>
</a>
)}
</div>
<div style={{ display: 'flex', alignItems: 'center', marginTop: 5 }}>
<Form.Item
fieldKey="__enabled"
name="__enabled"
style={{ display: 'inline-block', marginBottom: 0 }}
data-attr="plugin-enabled-switch"
>
<EnabledDisabledSwitch />
</Form.Item>
</div>
</div>
</div>
{editingPlugin.plugin_type === 'source' ? (
<div>
<Button
type={editingSource ? 'default' : 'primary'}
icon={<CodeOutlined />}
onClick={() => setEditingSource(!editingSource)}
data-attr="plugin-edit-source"
>
Edit Source
</Button>
</div>
) : null}
{editingPlugin.capabilities && Object.keys(editingPlugin.capabilities).length > 0 ? (
<>
<h3 className="l3" style={{ marginTop: 32 }}>
Capabilities
</h3>
<div style={{ marginTop: 5 }}>
{[
...editingPlugin.capabilities.methods,
...editingPlugin.capabilities.scheduled_tasks,
]
.filter(
(capability) => !['setupPlugin', 'teardownPlugin'].includes(capability)
)
.map((capability) => (
<Tooltip title={capabilitiesInfo[capability] || ''} key={capability}>
<Tag className="plugin-capabilities-tag">{capability}</Tag>
</Tooltip>
))}
{editingPlugin.capabilities.jobs.map((jobName) => (
<Tooltip title="Custom job" key={jobName}>
<Tag className="plugin-capabilities-tag">{jobName}</Tag>
</Tooltip>
))}
</div>
</>
) : null}
{editingPlugin.pluginConfig.id && (
<PluginJobOptions
plugin={editingPlugin}
pluginConfigId={editingPlugin.pluginConfig.id}
/>
)}
<h3 className="l3" style={{ marginTop: 32 }}>
Configuration
</h3>
{getConfigSchemaArray(editingPlugin.config_schema).length === 0 ? (
<div>This plugin is not configurable.</div>
) : null}
{getConfigSchemaArray(editingPlugin.config_schema).map((fieldConfig, index) => (
<React.Fragment key={fieldConfig.key || `__key__${index}`}>
{fieldConfig.markdown && (
<ReactMarkdown source={fieldConfig.markdown} linkTarget="_blank" />
)}
{fieldConfig.type && isValidField(fieldConfig) ? (
<Form.Item
hidden={!!fieldConfig.key && invisibleFields.includes(fieldConfig.key)}
label={
<>
{fieldConfig.secret && <SecretFieldIcon />}
{fieldConfig.name || fieldConfig.key}
</>
}
extra={
fieldConfig.hint && (
<small>
<div style={{ height: 2 }} />
<ReactMarkdown source={fieldConfig.hint} linkTarget="_blank" />
</small>
)
}
name={fieldConfig.key}
required={
fieldConfig.required ||
(!!fieldConfig.key && requiredFields.includes(fieldConfig.key))
}
rules={[
{
required:
fieldConfig.required ||
(!!fieldConfig.key && requiredFields.includes(fieldConfig.key)),
message: 'Please enter a value!',
},
]}
>
<PluginField
fieldConfig={fieldConfig}
onChange={updateInvisibleAndRequiredFields}
/>
</Form.Item>
) : (
<>
{fieldConfig.type ? (
<p style={{ color: 'var(--danger)' }}>
Invalid config field <i>{fieldConfig.name || fieldConfig.key}</i>.
</p>
) : null}
</>
)}
</React.Fragment>
))}
</div>
) : null}
</Form>
</Drawer>
{editingPlugin?.plugin_type === 'source' ? <PluginSource /> : null}
</>
)
}
Example #23
Source File: OnboardingSetup.tsx From posthog-foss with MIT License | 4 votes |
export function OnboardingSetup(): JSX.Element {
const {
stepProjectSetup,
stepInstallation,
projectModalShown,
stepVerification,
currentSection,
teamInviteAvailable,
progressPercentage,
slackCalled,
} = useValues(onboardingSetupLogic)
const { switchToNonDemoProject, setProjectModalShown, completeOnboarding, callSlack } =
useActions(onboardingSetupLogic)
const { showInviteModal } = useActions(inviteLogic)
const { currentTeam, currentTeamLoading } = useValues(teamLogic)
const { updateCurrentTeam } = useActions(teamLogic)
const { currentOrganizationLoading } = useValues(organizationLogic)
const UTM_TAGS = 'utm_medium=in-product&utm_campaign=onboarding-setup-2822'
return (
<div className="onboarding-setup">
{currentSection ? (
<>
<Row gutter={16}>
<Col span={18}>
<PageHeader
title="Setup"
caption="Get your PostHog instance up and running with all the bells and whistles"
/>
</Col>
<Col span={6} style={{ display: 'flex', alignItems: 'center' }}>
<Progress percent={progressPercentage} strokeColor="var(--purple)" strokeWidth={16} />
</Col>
</Row>
<Collapse defaultActiveKey={currentSection} expandIconPosition="right" accordion>
<Panel
header={
<PanelHeader
title="Event Ingestion"
caption="First things first, you need to connect PostHog to your website. You’ll be able to add more sources later."
stepNumber={1}
/>
}
key="1"
>
<div className="step-list">
<OnboardingStep
label="Set up project"
icon={<ProjectOutlined />}
title="Step 1"
identifier="set-up-project"
completed={stepProjectSetup}
handleClick={() => setProjectModalShown(true)}
/>
<OnboardingStep
label="Install PostHog"
icon={<CodeOutlined />}
title="Step 2"
identifier="install-posthog"
disabled={!stepProjectSetup}
completed={stepInstallation}
handleClick={() => switchToNonDemoProject('/ingestion')}
/>
<OnboardingStep
label="Verify your events"
icon={<CheckOutlined />}
title="Step 3"
identifier="verify-events"
disabled={!stepProjectSetup || !stepInstallation}
completed={stepVerification}
handleClick={() => switchToNonDemoProject('/ingestion/verify')}
/>
</div>
</Panel>
<Panel
header={
<PanelHeader
title="Configuration"
caption="Tune the settings of PostHog to make sure it works best for you and your team."
stepNumber={2}
/>
}
key="2"
collapsible={currentSection < 2 ? 'disabled' : undefined}
>
<div className="step-list">
<OnboardingStep
title="Enable session recording"
icon={<PlaySquareOutlined />}
identifier="session-recording"
handleClick={() =>
updateCurrentTeam({
session_recording_opt_in: !currentTeam?.session_recording_opt_in,
})
}
caption={
<>
Play user interactions as if you were right there with them.{' '}
<Link
to={`https://posthog.com/docs/features/session-recording?${UTM_TAGS}`}
rel="noopener"
target="_blank"
>
Learn more
</Link>
.
</>
}
customActionElement={
<div style={{ fontWeight: 'bold' }}>
{currentTeam?.session_recording_opt_in ? (
<span style={{ color: 'var(--success)' }}>Enabled</span>
) : (
<span style={{ color: 'var(--danger)' }}>Disabled</span>
)}
<Switch
checked={currentTeam?.session_recording_opt_in}
loading={currentTeamLoading}
style={{ marginLeft: 6 }}
/>
</div>
}
analyticsExtraArgs={{
new_session_recording_enabled: !currentTeam?.session_recording_opt_in,
}}
/>
<OnboardingStep
title="Join us on Slack"
icon={<SlackOutlined />}
identifier="slack"
handleClick={() => {
callSlack()
window.open(`https://posthog.com/slack?s=app&${UTM_TAGS}`, '_blank')
}}
caption="Fastest way to reach the PostHog team and the community."
customActionElement={
<Button type={slackCalled ? 'default' : 'primary'} icon={<SlackOutlined />}>
Join us
</Button>
}
/>
{teamInviteAvailable && (
<OnboardingStep
title="Invite your team members"
icon={<UsergroupAddOutlined />}
identifier="invite-team"
handleClick={showInviteModal}
caption="Spread the knowledge, share insights with everyone in your team."
customActionElement={
<Button type="primary" icon={<PlusOutlined />}>
Invite my team
</Button>
}
/>
)}
</div>
<div className="text-center" style={{ marginTop: 32 }}>
<Button
type="default"
onClick={completeOnboarding}
loading={currentOrganizationLoading}
data-attr="onboarding-setup-complete"
>
Finish setup
</Button>
</div>
</Panel>
</Collapse>
<CreateProjectModal
isVisible={projectModalShown}
onClose={() => setProjectModalShown(false)}
title="Set up your first project"
caption={
<div className="mb">
<div>
Enter a <b>name</b> for your first project
</div>
<div className="text-muted">
It's helpful to separate your different apps in multiple projects. Read more about
our recommendations and{' '}
<Link
to={`https://posthog.com/docs/features/organizations?${UTM_TAGS}`}
rel="noopener"
target="_blank"
>
best practices <IconOpenInNew />
</Link>
</div>
</div>
}
/>
</>
) : (
<div className="already-completed">
<CheckCircleOutlined className="completed-icon" />{' '}
<h2 className="">Your organization is set up!</h2>
<div className="text-muted">
Looks like your organization is good to go. If you still need some help, check out{' '}
<Link
to={`https://posthog.com/docs?${UTM_TAGS}&utm_message=onboarding-completed`}
target="_blank"
>
our docs <IconOpenInNew />
</Link>
</div>
<div style={{ marginTop: 32 }}>
<LinkButton type="primary" to="/" data-attr="onbording-completed-insights">
Go to insights <ArrowRightOutlined />
</LinkButton>
</div>
</div>
)}
</div>
)
}