@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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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>
    )
}