@ant-design/icons#EyeOutlined TypeScript Examples

The following examples show how to use @ant-design/icons#EyeOutlined. 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: GlobalMenu.tsx    From ant-extensions with MIT License 6 votes vote down vote up
GlobalMenu: React.FC<{ disabled: boolean }> = React.memo(({ disabled }) => {
  const { t } = useTranslation(I18nKey);
  const { filters, enableAll, toggleExclude, removeAll } = useContext(Context);

  const menu = useMemo(() => {
    const someEnabled = filters.some((f) => !f.required && f.active);
    const someDisabled = filters.some((f) => !f.required && !f.active);
    const hasNotRequired = filters.some((f) => !f.required);

    return (
      <Menu>
        <h4 style={{ padding: "0 16px" }}>{t("label.all_filters")}</h4>
        <Menu.Item disabled={!someDisabled} onClick={() => enableAll(true)}>
          <EyeOutlined /> {t("label.enable_all")}
        </Menu.Item>
        <Menu.Item disabled={!someEnabled} onClick={() => enableAll(false)}>
          <EyeInvisibleOutlined /> {t("label.disable_all")}
        </Menu.Item>
        <Menu.Item disabled={!hasNotRequired} onClick={toggleExclude}>
          {<Icon component={TwoTone} />} {t("label.invert")}
        </Menu.Item>
        <Menu.Item
          className="ant-typography ant-typography-danger"
          disabled={!hasNotRequired}
          onClick={removeAll}
        >
          <DeleteOutlined /> {t("label.remove_all")}
        </Menu.Item>
      </Menu>
    );
  }, [filters, enableAll, removeAll, t, toggleExclude]);

  return (
    <Dropdown overlay={menu} trigger={["click"]} disabled={disabled || filters.length === 0}>
      <Button type="link" icon={<SettingOutlined />} />
    </Dropdown>
  );
})
Example #2
Source File: editor-operate.tsx    From electron-playground with MIT License 6 votes vote down vote up
WrapMenu = function ({ layout, setLayout }: MProp) {
  const visibleMosaics = getVisibleMosaics(layout)
  const menuItem = ['main.js', 'renderer.js', 'index.html', 'preload.js']

  const onItemClick = (str: string) => {
    return () => {
      let newMosaicsArrangement: Array<EditorId>

      if (visibleMosaics.includes(str as EditorId)) {
        newMosaicsArrangement = visibleMosaics.filter(i => i !== str)
      } else {
        newMosaicsArrangement = [...visibleMosaics, str as EditorId]
      }
      setLayout(createMosaicArrangement(newMosaicsArrangement))
    }
  }

  return (
    <Menu>
      {menuItem.map(item => (
        <Menu.Item
          key={item}
          onClick={onItemClick(item)}
          id={item}
          icon={
            visibleMosaics.includes(item as EditorId) ? <EyeOutlined /> : <EyeInvisibleOutlined />
          }>
          {item}
        </Menu.Item>
      ))}
    </Menu>
  )
}
Example #3
Source File: preview.tsx    From visual-layout with MIT License 5 votes vote down vote up
Preview: React.FC<{ projectService: ProjectService }> = ({
  projectService,
}) => {
  const page = projectService.getCurrentPage();
  const options = page?.options;

  return (
    <Popover
      content={
        <Checkbox.Group
          value={options?.previewStyle
            .filter(({ isCanUse }) => isCanUse)
            .map(({ key }) => key)}
          style={{ width: '100%' }}
          onChange={(checkedValue: CheckboxValueType[]) => {
            page.setOptions({
              previewStyle: options?.previewStyle.map(option => {
                return {
                  ...option,
                  isCanUse: checkedValue.includes(option.key) ? true : false,
                };
              }),
            });
          }}
        >
          {options?.previewStyle.map(style => {
            return (
              <Row key={style.key}>
                <Checkbox value={style.key}>{style?.title}</Checkbox>
              </Row>
            );
          })}
        </Checkbox.Group>
      }
      title="预览样式设置"
      placement="bottom"
    >
      <EyeOutlined style={{ fontSize: 20 }} />
    </Popover>
  );
}
Example #4
Source File: index.tsx    From jetlinks-ui-antd with MIT License 4 votes vote down vote up
Screen = (props: Props) => {
  // const [categoryList, setCategoryList] = useState([]);
  const [dataList, setDataList] = useState({
    data: [],
    pageIndex: 0,
    total: 0,
    pageSize: 0,
  });
  const [id, setId] = useState('');
  const [url, setUrl] = useState('');
  const [saveVisible, setSaveVisible] = useState(false);
  const [editVisible, setEditVisible] = useState(false);
  const [copyVisible, setCopyVisible] = useState(false);
  const [param, setParam] = useState({});
  const [searchParam, setSearchParam] = useState({
    pageSize: 8,
    pageIndex: 0,
    terms: { type: 'vis_configuration' },
  });
  const token = getAccessToken();

  const handleSearch = (params: any) => {
    setSearchParam(params);
    api.screen.query(encodeQueryParam(params)).then(res => {
      if (res.status === 200) {
        setDataList(res.result);
      }
    });
  };

  let delConfirm = (id: string) => {
    confirm({
      title: '删除组态',
      icon: <ExclamationCircleOutlined />,
      content: '确认删除该组态?',
      onOk() {
        api.screen.remove(id).then(res => {
          if (res.status === 200) {
            handleSearch(searchParam);
          }
        });
      },
      onCancel() {
        message.info('已取消');
      },
    });
  };
  let updateState = (state: string, id: string) => {
    confirm({
      title: `${state === 'enabled' ? '禁用' : '启用'}组态`,
      icon: <ExclamationCircleOutlined />,
      content: `确认${state === 'enabled' ? '禁用' : '启用'}该组态`,
      onOk() {
        api.screen
          .update(id, {
            state: {
              value: state === 'enabled' ? 'disabled' : 'enabled',
            },
          })
          .then(res => {
            if (res.status === 200) {
              handleSearch(searchParam);
            }
          });
      },
      onCancel() {
        message.info('已取消');
      },
    });
  };
  const uploadProps = (item: any) => {
    api.screen.save(item).then(res => {
      if (res.status === 200) {
        message.success('导入成功');
        handleSearch(searchParam);
      }
    });
  };

  const onListChange = (page: number, pageSize: number) => {
    console.log(page, pageSize, 'jahaha');
    handleSearch({
      pageIndex: page - 1,
      pageSize,
      terms: searchParam.terms,
    });
  };
  let getView = (view: any) => {
    let children = [];
    if (view.children && view.children.length > 0) {
      children = view.children.map((i: any) => {
        return getView(i);
      });
      return {
        id: view.id,
        children: children,
        pId: view.parentId,
        value: view.id,
        title: view.name,
      };
    } else {
      return {
        id: view.id,
        pId: view.parentId,
        value: view.id,
        title: view.name,
      };
    }
  };
  useEffect(() => {
    //获取跳转url
    api.screen.getUrl().then(res => {
      if (res.status === 200) {
        if (
          res.result.urls['vis-configuration'] !== '' &&
          res.result.urls['vis-configuration'] !== undefined
        ) {
          setUrl(res.result.urls['vis-configuration']);
        } else {
          message.error('配置错误,请联系管理员');
          // setUrl('http://localhost:8000/')
        }
      }
    });

    // api.categoty.queryNoPaging({}).then(res => {
    //   if (res.status === 200) {
    //     setCategoryList(res.result);
    //   }
    // });

    handleSearch(searchParam);
  }, []);

  // const findCategory = (id:string)=>{

  //   const category: Partial<CategoryItem> =
  //     categoryList.find((i:any) => i.id === id) || {};

  //   return category.name;
  // };

  return (
    <PageHeaderWrapper title="组态管理">
      <Card bordered={false}>
        <div className={styles.tableList}>
          <div>
            <SearchForm
              search={(params: any) => {
                handleSearch({
                  terms: { ...params, type: 'vis_configuration' },
                  pageSize: 8,
                });
              }}
              formItems={[
                {
                  label: '组态名称',
                  key: 'name$LIKE',
                  type: 'string',
                },
                // {
                //   label: '组态分类',
                //   key: 'classifiedId$LIKE',
                //   type: 'list',
                //   props: {
                //     data: categoryList,
                //     mode: 'default'
                //   }
                // }
              ]}
            />
          </div>

          <div className={styles.tableListOperator}>
            <Button icon="plus" type="primary" onClick={() => setSaveVisible(true)}>
              新建组态
            </Button>
            <Divider type="vertical" />
            <Upload
              action="/jetlinks/file/static"
              headers={{
                'X-Access-Token': getAccessToken(),
              }}
              showUploadList={false}
              accept=".json"
              beforeUpload={file => {
                const reader = new FileReader();
                reader.readAsText(file);
                reader.onload = result => {
                  try {
                    uploadProps(JSON.parse(result.target.result));
                  } catch (error) {
                    message.error('文件格式错误');
                  }
                };
              }}
            >
              <Button>
                <Icon type="upload" />
                快速导入
              </Button>
            </Upload>
          </div>
        </div>
      </Card>
      <div style={{ marginBottom: '30px' }}>
        <div className={styles.cardList}>
          <List<any>
            rowKey="id"
            grid={{ gutter: 24, xl: 4, lg: 3, md: 2, sm: 2, xs: 1 }}
            dataSource={dataList.data || []}
            pagination={{
              current: dataList.pageIndex + 1,
              total: dataList.total,
              pageSize: dataList.pageSize,
              onChange: (page, pageSize) => {
                onListChange(page, pageSize || 8);
              },
              onShowSizeChange: (page, size) => {
                onListChange(page, size);
              },
              showQuickJumper: true,
              showSizeChanger: true,
              // hideOnSinglePage: true,
              pageSizeOptions: ['8', '16', '40', '80'],
              style: { marginTop: -20 },
              showTotal: (total: number) =>
                `共 ${total} 条记录 第  ${dataList.pageIndex + 1}/${Math.ceil(
                  dataList.total / dataList.pageSize,
                )}页`,
            }}
            renderItem={item => {
              if (item && item.id) {
                let metadata =
                  item.metadata != undefined && item.metadata != ''
                    ? JSON.parse(item.metadata)
                    : {};
                return (
                  <List.Item key={item.id}>
                    <Card
                      hoverable
                      bodyStyle={{ paddingBottom: 20 }}
                      onMouseEnter={() => setId(item.id)}
                      onMouseLeave={() => setId('')}
                      actions={[
                        <Tooltip placement="bottom" title="编辑">
                          <EditOutlined
                            onClick={() => {
                              setEditVisible(true);
                              setParam({
                                id: item.id,
                                name: item.name,
                                description: item.description,
                                catalogId: item.catalogId,
                                url: url,
                              });
                            }}
                          />
                        </Tooltip>,
                        <Tooltip placement="bottom" title="预览">
                          <EyeOutlined
                            onClick={() => {
                              url != ''
                                ? window.open(url + `#/?id=${id}&token=${token}`, '_blank')
                                : message.error('配置错误,请联系管理员');
                            }}
                          />
                        </Tooltip>,
                        <Tooltip placement="bottom" title="复制">
                          <SwitcherOutlined
                            onClick={() => {
                              setCopyVisible(true);
                              setParam({ url: url, metadata: item.metadata });
                            }}
                          />
                        </Tooltip>,
                        <Tooltip placement="bottom" title="下载">
                          <Icon
                            type="download"
                            onClick={() => {
                              downloadObject(item, '组态');
                            }}
                          />
                        </Tooltip>,
                        <Tooltip key="more_actions" title="">
                          <Dropdown
                            overlay={
                              <Menu>
                                <Menu.Item key="1">
                                  <Button
                                    onClick={() => {
                                      updateState(item.state.value, item.id);
                                    }}
                                    icon={item.state.value === 'enabled' ? 'close' : 'check'}
                                    type="link"
                                  >
                                    {item.state.value === 'enabled' ? '禁用' : '启用'}
                                  </Button>
                                </Menu.Item>
                                {item.state.value === 'disabled' && (
                                  <Menu.Item key="2">
                                    <Button
                                      icon="delete"
                                      type="link"
                                      onClick={() => {
                                        delConfirm(item.id);
                                      }}
                                    >
                                      删除
                                    </Button>
                                  </Menu.Item>
                                )}
                              </Menu>
                            }
                          >
                            <Icon type="ellipsis" />
                          </Dropdown>
                        </Tooltip>,
                      ]}
                    >
                      <Card.Meta
                        avatar={
                          <Avatar
                            size={60}
                            src={
                              metadata.visual != undefined &&
                              metadata.visual.backgroundUrl != undefined
                                ? metadata.visual.backgroundUrl
                                : false
                            }
                          />
                        }
                        title={
                          <AutoHide title={item.name} style={{ width: '95%', fontWeight: 600 }} />
                        }
                        description={<AutoHide title={item.id} style={{ width: '95%' }} />}
                      />
                      <div className={styles.status}>
                        <div style={{ textAlign: 'center', minWidth: '80px' }}>
                          <p>
                            状态: <span style={{ fontWeight: 600 }}>已{item.state.text}</span>
                          </p>
                        </div>
                        <div style={{ textAlign: 'center', minWidth: '80px' }}>
                          {/* <p>分类: <span style={{fontWeight:600}}>{findCategory(item.catalogId)}</span></p> */}
                        </div>
                      </div>
                      <div
                        className={styles.edit}
                        style={{ display: item.id == id ? 'block' : 'none' }}
                      >
                        <div className={styles.editBtn}>
                          <a
                            onClick={() => {
                              url != ''
                                ? window.open(url + `#/?id=${id}&token=${token}`, '_blank')
                                : message.error('配置错误,请联系管理员');
                            }}
                          >
                            编辑
                          </a>
                        </div>
                      </div>
                    </Card>
                  </List.Item>
                );
              }
              return;
            }}
          />
        </div>
        {saveVisible && (
          <Save
            data={url}
            close={() => {
              setSaveVisible(false);
            }}
            save={() => {
              setSaveVisible(false);
              handleSearch(searchParam);
            }}
          />
        )}
        {copyVisible && (
          <Copy
            data={param}
            close={() => {
              setCopyVisible(false);
            }}
            save={() => {
              setCopyVisible(false);
              handleSearch(searchParam);
            }}
          />
        )}
        {editVisible && (
          <Edit
            data={param}
            close={() => {
              setEditVisible(false);
            }}
            save={() => {
              setEditVisible(false);
              handleSearch(searchParam);
            }}
          />
        )}
      </div>
    </PageHeaderWrapper>
  );
}
Example #5
Source File: index.tsx    From amiya with MIT License 4 votes vote down vote up
export default function Demo() {
  // 列表控制
  const listRef = useRef<any>()
  // 当前激活的 tab
  const [activeTab, setActiveTab] = useState<string>('')
  // 弹窗详情
  const [detail, setDetail] = useState<AnyKeyProps>({
    visible: false,
    data: {}
  })

  /**
   * 切换 tab 事件
   * @param value 当前 tab 值
   */
  const handleTabChange = (value: string) => {
    setActiveTab(value)
    listRef.current.reset()
  }

  /**
   * 查看详情
   * @param record 当前行数据
   */
  const goDetail = (record: Record) => {
    detailApi({ id: record.id }).then(res => {
      setDetail({
        visible: true,
        data: res.data
      })
    })
  }

  return (
    <div className="cnode-list">
      {/* tab 区域 */}
      <Tabs activeKey={activeTab} onChange={handleTabChange} type="card">
        {options.map(option => (
          <Tabs.TabPane tab={option.label} key={option.value} />
        ))}
      </Tabs>
      {/* 列表区域 */}
      <AySearchList
        api={listApi}
        extraVisible={false}
        listExtend={{ itemLayout: 'horizontal' }}
        extendSearchParams={{ tab: activeTab }}
        listHeader={<div style={{ height: 16 }}>{/* 占位空间 */}</div>}
        ref={listRef}
        onParamsChange={() => window.scrollTo({ behavior: 'smooth', top: 0 })}
        renderItem={(record: Record) => {
          return (
            <List.Item
              key={record.id}
              actions={[
                <AyAction icon={<MessageOutlined />} sub tooltip="最后回复时间">
                  <span>{moment(record.last_reply_at).fromNow()}</span>
                </AyAction>,
                <AyAction icon={<MessageOutlined />} sub tooltip="回复数">
                  <span>{record.reply_count}</span>
                </AyAction>,
                <AyAction icon={<EyeOutlined />} sub tooltip="阅读数">
                  <span>{record.visit_count}</span>
                </AyAction>
              ]}
            >
              <List.Item.Meta
                avatar={<Avatar src={record.author.avatar_url} />}
                title={
                  <Space>
                    <a onClick={() => goDetail(record)}>{record.title}</a>
                    <span>
                      {record.good && <Tag color="green">精品</Tag>}
                      {record.top && <Tag color="blue">置顶</Tag>}
                    </span>
                  </Space>
                }
                description={moment(record.create_at).fromNow()}
              />
            </List.Item>
          )
        }}
      />
      {/* 弹窗详情 */}
      <AyDialog
        drawer
        width={800}
        footer={false}
        destroyOnClose
        visible={detail.visible}
        setVisible={() => setDetail({ ...detail, visible: false })}
        title="文章详情"
      >
        <div dangerouslySetInnerHTML={{ __html: detail.data.content }}></div>
        <List
          itemLayout="horizontal"
          header={`${detail?.data?.replies?.length || 0} 条回复`}
          dataSource={detail?.data?.replies || []}
          renderItem={(comment: Record) => (
            <Comment
              key={comment.id}
              author={comment.author.loginname}
              avatar={<Avatar src={comment.author.avatar_url} alt={comment.author.avatar_url} />}
              content={<div dangerouslySetInnerHTML={{ __html: comment.content }}></div>}
              datetime={
                <Tooltip title={moment(comment.create_at).format('YYYY-MM-DD HH:mm:ss')}>
                  <span>{moment(comment.create_at).fromNow()}</span>
                </Tooltip>
              }
            />
          )}
        />
      </AyDialog>
    </div>
  )
}
Example #6
Source File: Results.tsx    From datart with Apache License 2.0 4 votes vote down vote up
Results = memo(({ height = 0, width = 0 }: ResultsProps) => {
  const { actions } = useViewSlice();
  const dispatch = useDispatch();
  const viewId = useSelector(state =>
    selectCurrentEditingViewAttr(state, { name: 'id' }),
  ) as string;
  const model = useSelector(state =>
    selectCurrentEditingViewAttr(state, { name: 'model' }),
  ) as HierarchyModel;
  const columnPermissions = useSelector(state =>
    selectCurrentEditingViewAttr(state, { name: 'columnPermissions' }),
  ) as ColumnPermission[];
  const stage = useSelector(state =>
    selectCurrentEditingViewAttr(state, { name: 'stage' }),
  ) as ViewViewModelStages;
  const previewResults = useSelector(state =>
    selectCurrentEditingViewAttr(state, { name: 'previewResults' }),
  ) as ViewViewModel['previewResults'];
  const roles = useSelector(selectRoles);
  const t = useI18NPrefix('view');

  const dataSource = useMemo(
    () => previewResults.map(o => ({ ...o, [ROW_KEY]: uuidv4() })),
    [previewResults],
  );

  const modelChange = useCallback(
    (columnName: string, column: Omit<Column, 'name'>) =>
      ({ key }) => {
        let value;
        if (key.includes('category')) {
          const category = key.split('-')[1];
          value = { ...column, category };
        } else {
          value = { ...column, type: key };
        }
        const clonedHierarchyModel = CloneValueDeep(model.hierarchy || {});
        if (columnName in clonedHierarchyModel) {
          clonedHierarchyModel[columnName] = value;
        } else {
          Object.values(clonedHierarchyModel)
            .filter(col => !isEmptyArray(col.children))
            .forEach(col => {
              const targetChildColumnIndex = col.children!.findIndex(
                child => child.name === columnName,
              );
              if (targetChildColumnIndex > -1) {
                col.children![targetChildColumnIndex] = value;
              }
            });
        }

        dispatch(
          actions.changeCurrentEditingView({
            model: {
              ...model,
              hierarchy: clonedHierarchyModel,
              version: APP_CURRENT_VERSION,
            },
          }),
        );
      },
    [dispatch, actions, model],
  );

  const roleDropdownData = useMemo(
    () =>
      roles.map(({ id, name }) => ({
        key: id,
        title: name,
        value: id,
        isLeaf: true,
      })),
    [roles],
  );

  const checkRoleColumnPermission = useCallback(
    columnName => checkedKeys => {
      const fullPermissions = Object.keys(model?.columns || {});
      dispatch(
        actions.changeCurrentEditingView({
          columnPermissions: roleDropdownData.reduce<ColumnPermission[]>(
            (updated, { key }) => {
              const permission = columnPermissions.find(
                ({ subjectId }) => subjectId === key,
              );
              const checkOnCurrentRole = checkedKeys.includes(key);
              if (permission) {
                if (checkOnCurrentRole) {
                  const updatedColumnPermission = Array.from(
                    new Set(permission.columnPermission.concat(columnName)),
                  );
                  return fullPermissions.sort().join(',') !==
                    updatedColumnPermission.sort().join(',')
                    ? updated.concat({
                        ...permission,
                        columnPermission: updatedColumnPermission,
                      })
                    : updated;
                } else {
                  return updated.concat({
                    ...permission,
                    columnPermission: permission.columnPermission.filter(
                      c => c !== columnName,
                    ),
                  });
                }
              } else {
                return !checkOnCurrentRole
                  ? updated.concat({
                      id: uuidv4(),
                      viewId,
                      subjectId: key,
                      subjectType: SubjectTypes.Role,
                      columnPermission: fullPermissions.filter(
                        c => c !== columnName,
                      ),
                    })
                  : updated;
              }
            },
            [],
          ),
        }),
      );
    },
    [dispatch, actions, viewId, model, columnPermissions, roleDropdownData],
  );

  const getExtraHeaderActions = useCallback(
    (name: string, column: Omit<Column, 'name'>) => {
      // 没有记录相当于对所有字段都有权限
      const checkedKeys =
        columnPermissions.length > 0
          ? roleDropdownData.reduce<string[]>((selected, { key }) => {
              const permission = columnPermissions.find(
                ({ subjectId }) => subjectId === key,
              );
              if (permission) {
                return permission.columnPermission.includes(name)
                  ? selected.concat(key)
                  : selected;
              } else {
                return selected.concat(key);
              }
            }, [])
          : roleDropdownData.map(({ key }) => key);
      return [
        <Popup
          key={`${name}_columnpermission`}
          trigger={['click']}
          placement="bottomRight"
          content={
            <Tree
              className="dropdown"
              treeData={roleDropdownData}
              checkedKeys={checkedKeys}
              loading={false}
              selectable={false}
              onCheck={checkRoleColumnPermission(name)}
              blockNode
              checkable
            />
          }
        >
          <Tooltip title={t('columnPermission.title')}>
            <ToolbarButton
              size="small"
              iconSize={FONT_SIZE_BASE}
              icon={
                checkedKeys.length > 0 ? (
                  <EyeOutlined
                    className={classnames({
                      partial: checkedKeys.length !== roleDropdownData.length,
                    })}
                  />
                ) : (
                  <EyeInvisibleOutlined />
                )
              }
            />
          </Tooltip>
        </Popup>,
      ];
    },
    [columnPermissions, roleDropdownData, checkRoleColumnPermission, t],
  );

  const pagination = useMemo(
    () => ({
      defaultPageSize: 100,
      pageSizeOptions: ['100', '200', '500', '1000'],
    }),
    [],
  );

  return stage > ViewViewModelStages.Fresh ? (
    <TableWrapper>
      <SchemaTable
        height={height ? height - 96 : 0}
        width={width}
        model={model.columns || {}}
        hierarchy={model.hierarchy || {}}
        dataSource={dataSource}
        pagination={pagination}
        getExtraHeaderActions={getExtraHeaderActions}
        onSchemaTypeChange={modelChange}
        hasCategory
      />
    </TableWrapper>
  ) : (
    <InitialDesc>
      <p>
        {t('resultEmpty1')}
        <CaretRightOutlined />
        {t('resultEmpty2')}
      </p>
    </InitialDesc>
  );
})
Example #7
Source File: index.tsx    From sidebar with Apache License 2.0 4 votes vote down vote up
MaterialListCard: React.FC<MaterialListProps> = (props) => {
  const {setKeyword, loading, items, allTags} = props;
  const [filterVisible, setFilterVisible] = useState(false);
  const [tagKeyword, setTagKeyword] = useState("");
  const [filteredTags, setFilteredTags] = useState<MaterialLibraryTag[]>([])
  const [selectedTags, setSelectedTags] = useState<MaterialLibraryTag[]>([])

  useEffect(() => {
    setFilteredTags(allTags.filter((tag) => tag.name.includes(tagKeyword)))
  }, [tagKeyword, allTags])

  return <>
    <div className={styles.searchBar}>
      <Input.Search placeholder="输入关键词" loading={loading} style={{marginRight: 12}} allowClear onSearch={(value) => {
        setKeyword(value);
      }}/>
      <Dropdown
        visible={filterVisible}
        overlay={
          <div className={styles.overlay}>
            <div style={{padding: '0 8px'}}>
              <div className={styles.overlayTitle}>素材标签 ( {allTags.length} )</div>
              <Form
                layout={'horizontal'}
              >
                <Input
                  allowClear={true}
                  placeholder={'输入关键词搜索标签'}
                  value={tagKeyword}
                  onChange={(e) => {
                    setTagKeyword(e.currentTarget.value)
                  }}
                />
                <div style={{padding: "12px 0"}}>
                  {filteredTags?.map((tag) => {
                    const isSelected = selectedTags.map((selectedTag) => selectedTag.id)?.includes(tag?.id);
                    return (
                      <Space>
                        <Tag
                          style={{cursor: 'pointer'}}
                          className={`tag-item ${isSelected ? ' selected-tag-item' : ''}`}
                          key={tag.id}
                          onClick={() => {
                            if (tag?.id && isSelected) {
                              setSelectedTags(selectedTags.filter((selectedTag) => {
                                return selectedTag.id !== tag?.id
                              }))
                            } else {
                              setSelectedTags([...selectedTags, tag])
                            }
                          }}
                        >
                          {tag.name}
                          {isSelected && (
                            <CloseOutlined style={{marginLeft: 6, fontSize: 11}}/>
                          )}
                        </Tag>
                      </Space>
                    )
                  })}
                </div>
                {allTags?.length === 0 && <Empty style={{marginTop: 36, marginBottom: 36}}/>}
                <div style={{display: 'flex', justifyContent: 'flex-end'}}>
                  <Button onClick={() => setFilterVisible(false)}>取消</Button>
                  <Button
                    style={{marginLeft: 6}}
                    type='primary'
                    htmlType="submit"
                    onClick={() => {
                      setFilterVisible(false)
                      if (props.setSelectedTags) {
                        props.setSelectedTags(selectedTags || [])
                      }
                    }}>完成</Button>
                </div>
              </Form>
            </div>
          </div>
        } trigger={['click']}>
        <div>
          <Button
            onClick={() => {
              setFilterVisible(!filterVisible)
            }}>筛选</Button>
        </div>
      </Dropdown>
    </div>

    {selectedTags.length > 0 && (
      <div className={styles.filterBar}>
        <div className={styles.tagList}>
          {selectedTags?.map((tag) => (
            <span
              key={tag.id}
              className={styles.tag}
              style={{cursor: 'pointer'}}
              onClick={() => {
                setSelectedTags(selectedTags.filter((item) => item.id !== tag.id))
              }}
            >
          {tag.name}
              <CloseOutlined style={{marginLeft: 6, fontSize: 11}}/>
        </span>
          ))}
        </div>
        {selectedTags.length > 0 && (
          <Button onClick={() => setSelectedTags([])} icon={<ClearOutlined/>} type={'link'}>清空筛选</Button>
        )}
      </div>
    )}

    <div>
      {items.length === 0 && (
        <Empty image={Empty.PRESENTED_IMAGE_SIMPLE}/>
      )}
      {items.length > 0 && (
        <Space direction={'vertical'} className={styles.materialList}>
          {items.map((item) => (
            <Space direction={'horizontal'} className={styles.materialItem} key={item.id}>
              <Space>
                 <span className={styles.sendButtonWrap}>
                  <Button
                    // 发送一组话术
                    onClick={async () => {
                      await SendMaterial(item);
                    }}
                    type={'link'}
                    className={styles.sendButton}
                    icon={getIcon('icon-fasong')}
                  />
                </span>
              </Space>
              <Space className={styles.materialPreview}>
                <div className={styles.leftPart}>
                  {item.material_type === 'poster' && (
                    <Image src={calFileIcon(item)} fallback={fileIconImage}
                           preview={item.material_type === 'poster' ? {mask: <EyeOutlined/>} : false}/>
                  )}
                  {item.material_type === 'link' && (
                    <Image style={{cursor: 'pointer'}} onClick={() => {
                      window.open(item.link)
                    }} src={calFileIcon(item)} fallback={fileIconImage}
                           preview={false}/>
                  )}
                  {["video", "pdf", "ppt", "excel", "word"].includes(item.material_type) && (
                    <Image style={{cursor: 'pointer'}} onClick={() => {
                      window.open(item.url)
                    }} src={calFileIcon(item)} fallback={fileIconImage}
                           preview={false}/>
                  )}
                </div>
                <div className={styles.rightPart}>
                  <div className={styles.title}>{item.title}</div>
                  <div className={styles.desc}>{item.digest}</div>
                  <div className={styles.tagList}>
                    {item?.tags?.map((tag) => (
                      <span key={tag.id} className={styles.tag}>{tag.name}</span>
                    ))}
                  </div>
                </div>
              </Space>
            </Space>
          ))}
        </Space>
      )}
    </div>
  </>
}
Example #8
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 #9
Source File: index.tsx    From foodie with MIT License 4 votes vote down vote up
Register: React.FC = () => {
    const [email, setEmail] = useState('');
    const [password, setPassword] = useState('');
    const [username, setUsername] = useState('');
    const [isPasswordVisible, setPasswordVisible] = useState(false);
    const dispatch = useDispatch();

    useDocumentTitle('Register to Foodie');
    useEffect(() => {
        return () => {
            dispatch(setAuthErrorMessage(null));
        }
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, []);

    const { error, isLoading } = useSelector((state: IRootReducer) => ({
        error: state.error.authError,
        isLoading: state.loading.isLoadingAuth
    }));

    const onEmailChange = (e: React.ChangeEvent<HTMLInputElement>) => {
        const val = e.target.value.trim();

        setEmail(val.toLowerCase());
    };

    const onPasswordChange = (e: React.ChangeEvent<HTMLInputElement>) => {
        const val = e.target.value.trim();

        setPassword(val);
    };

    const onUsernameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
        const val = e.target.value.trim();

        setUsername(val.toLowerCase());
    };

    const onSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
        e.preventDefault();

        if (email && password && username) {
            dispatch(registerStart({ email, password, username }));
        }
    };
    return (
        <div className="min-h-screen flex bg-white">
            <div
                className="relative hidden laptop:w-7/12 h-screen laptop:p-8 laptop:flex laptop:justify-start laptop:items-end !bg-cover !bg-no-repeat !bg-center"
                style={{
                    background: `#f7f7f7 url(${bg})`
                }}
            >
                {/* --- LOGO --- */}
                <Link className="absolute left-8 top-8" to="/">
                    <img src={logo} alt="Foodie Logo" className="w-24" />
                </Link>
                {/* -- INFO --- */}
                <h3 className="animate-fade text-white w-9/12 mb-14">
                    Create your account now and discover new ideas and connect with people.
                </h3>
                {/* --- CREDITS LINK --- */}
                <a
                    className="animate-fade absolute bottom-8 left-8 text-1xs text-white underline"
                    target="_blank"
                    rel="noreferrer"
                    href="https://infinityrimapts.com/5-reasons-host-dinner-party/friends-enjoying-a-meal/"
                >
                    Photo: Credits to the photo owner
                </a>
            </div>
            <div className="relative animate-fade w-full text-center laptop:w-5/12 laptop:text-left flex items-center flex-col justify-center pt-8 laptop:pt-0">
                <Link to="/">
                    <img
                        src={logo_dark}
                        alt="Foodie Logo"
                        className="w-24 relative mx-auto laptop:hidden"
                    />
                </Link>
                {error && (
                    <div className="p-4 w-full text-center bg-red-100 border-red-400 absolute top-0 left-0">
                        <p className="text-red-500 text-sm">{error?.error?.message || 'Something went wrong :('}</p>
                    </div>
                )}
                <div className="w-full px-8 laptop:px-14">
                    <div>
                        <h2 className="mt-6 text-xl laptop:text-2xl font-extrabold text-gray-900">
                            Create your account
                        </h2>
                    </div>
                    <form className="mt-8 space-y-6" onSubmit={onSubmit}>
                        <div className="rounded-md shadow-sm space-y-2">
                            <div>
                                <label htmlFor="email-address" className="sr-only">Username</label>
                                <input
                                    id="username"
                                    name="username"
                                    type="text"
                                    className={` ${error ? 'input--error' : ''}`}
                                    onChange={onUsernameChange}
                                    autoComplete="username"
                                    maxLength={30}
                                    required
                                    readOnly={isLoading}
                                    placeholder="Username"
                                    value={username}
                                />
                            </div>
                            <div>
                                <label htmlFor="email-address" className="sr-only">Email address</label>
                                <input
                                    id="email-address"
                                    name="email"
                                    type="email"
                                    className={` ${error ? 'input--error' : ''}`}
                                    onChange={onEmailChange}
                                    autoComplete="email"
                                    maxLength={64}
                                    required
                                    readOnly={isLoading}
                                    placeholder="Email Address"
                                    value={email}
                                />
                            </div>
                            <div className="relative">
                                <label htmlFor="password" className="sr-only">Password</label>
                                <input
                                    id="password"
                                    name="password"
                                    type={isPasswordVisible ? 'text' : 'password'}
                                    className={`!pr-12 ${error ? 'input--error' : ''}`}
                                    onChange={onPasswordChange}
                                    autoComplete="current-password"
                                    required
                                    minLength={8}
                                    maxLength={100}
                                    readOnly={isLoading}
                                    placeholder="Password"
                                    value={password}
                                />
                                <div className="absolute right-0 top-0 bottom-0 my-auto flex items-center justify-center w-12 h-12 hover:bg-gray-200 cursor-pointer rounded-tr-full rounded-br-full z-10">
                                    {isPasswordVisible ? (
                                        <EyeInvisibleOutlined
                                            className="h-full w-full outline-none text-gray-500"
                                            onClick={() => setPasswordVisible(false)}
                                        />
                                    ) : (
                                        <EyeOutlined
                                            className="h-full w-full outline-none"
                                            onClick={() => setPasswordVisible(true)}
                                        />
                                    )}
                                </div>
                            </div>
                        </div>
                        <div>
                            <button type="submit" className="button--stretch" disabled={isLoading}>
                                {isLoading ? 'Registering...' : 'Register'}
                            </button>
                        </div>
                        <i className="social-login-divider">OR</i>
                        <div className="flex justify-between space-x-2">
                            <SocialLogin isLoading={isLoading} />
                        </div>
                    </form>
                    <div className="text-center mt-8">
                        <Link
                            className="underline font-medium"
                            onClick={(e) => isLoading && e.preventDefault()}
                            to={LOGIN}
                        >
                            Login instead
                        </Link>
                    </div>
                    {/* --- COPYRIGHT -- */}
                    <span className="text-gray-400 text-xs mx-auto text-center block mt-4">
                        &copy;Copyright {new Date().getFullYear()} Foodie
                    </span>
                </div>
            </div>
        </div>
    );
}
Example #10
Source File: index.tsx    From foodie with MIT License 4 votes vote down vote up
Login: React.FC = () => {
    const [username, setUsername] = useState('');
    const [password, setPassword] = useState('');
    const [isPasswordVisible, setPasswordVisible] = useState(false);
    const dispatch = useDispatch();

    useDocumentTitle('Login to Foodie');
    useEffect(() => {
        return () => {
            dispatch(setAuthErrorMessage(null));
        }
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, []);

    const { error, isLoading } = useSelector((state: IRootReducer) => ({
        error: state.error.authError,
        isLoading: state.loading.isLoadingAuth
    }));

    const onUsernameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
        const val = e.target.value.trim();

        setUsername(val);
    };

    const onPasswordChange = (e: React.ChangeEvent<HTMLInputElement>) => {
        const val = e.target.value;

        setPassword(val);
    };

    const onSubmit = async (e: FormEvent) => {
        e.preventDefault();

        if (username && password) {
            dispatch(loginStart(username, password));
        }
    };

    return (
        <div className="min-h-screen flex bg-white">
            <div
                className="relative laptop:w-7/12 h-screen laptop:p-8 hidden laptop:justify-start laptop:items-end laptop:!bg-cover laptop:!bg-no-repeat laptop:!bg-center laptop:flex"
                style={{
                    background: `#f7f7f7 url(${bg})`
                }}
            >
                {/* --- LOGO --- */}
                <Link className="absolute left-8 top-8" to="/">
                    <img src={logo} alt="Foodie Logo" className="w-24" />
                </Link>
                {/* -- INFO --- */}
                <h3 className="animate-fade text-white w-9/12 mb-14">
                    Looking for a new idea for your next menu? You're in the right place.
                </h3>
                {/* --- CREDITS LINK --- */}
                <a
                    className="animate-fade absolute bottom-8 left-8 text-1xs text-white underline"
                    target="_blank"
                    rel="noreferrer"
                    href="https://infinityrimapts.com/5-reasons-host-dinner-party/friends-enjoying-a-meal/"
                >
                    Photo: Credits to the photo owner
                </a>
            </div>
            <div className="animate-fade laptop:w-5/12 w-full flex items-center flex-col justify-center pt-8 laptop:pt-0 relative">
                <Link to="/">
                    <img
                        src={logo_dark}
                        alt="Foodie Logo"
                        className="w-24 relative mx-auto laptop:hidden"
                    />
                </Link>
                {error && (
                    <div className="py-2 w-full text-center bg-red-100 border-red-300 absolute top-0 left-0">
                        <p className="text-red-500">{error?.error?.message || 'Something went wrong :('}</p>
                    </div>
                )}
                <div className="w-full laptop:px-14 px-8 text-center laptop:text-left">
                    <div>
                        <h2 className="mt-6 text-xl laptop:text-2xl font-extrabold text-gray-900">
                            Login to Foodie
                    </h2>
                    </div>
                    <form className="mt-8 space-y-6" onSubmit={onSubmit}>
                        <div className="rounded-md shadow-sm -space-y-px">
                            <div className="mb-2">
                                <label htmlFor="username" className="sr-only">Username</label>
                                <input
                                    id="username"
                                    name="username"
                                    type="text"
                                    autoComplete="username"
                                    value={username}
                                    required
                                    maxLength={30}
                                    className={`text-center ${error ? 'input--error' : ''} laptop:text-left`}
                                    placeholder="Username"
                                    readOnly={isLoading}
                                    onChange={onUsernameChange}
                                />
                            </div>
                            <div className="relative">
                                <label htmlFor="password" className="sr-only">Password</label>
                                <input
                                    id="password"
                                    name="password"
                                    type={isPasswordVisible ? 'text' : 'password'}
                                    autoComplete="current-password"
                                    required
                                    className={`text-center !pr-12 ${error ? 'input--error' : ''} laptop:text-left`}
                                    placeholder="Password"
                                    minLength={8}
                                    maxLength={100}
                                    onChange={onPasswordChange}
                                    readOnly={isLoading}
                                    value={password}
                                />
                                <div className="absolute right-0 top-0 bottom-0 my-auto flex items-center justify-center w-12 h-12 hover:bg-gray-200 cursor-pointer rounded-tr-full rounded-br-full z-10">
                                    {isPasswordVisible ? (
                                        <EyeInvisibleOutlined
                                            className="h-full w-full outline-none text-gray-500"
                                            onClick={() => setPasswordVisible(false)}
                                        />
                                    ) : (
                                        <EyeOutlined
                                            className="h-full w-full outline-none"
                                            onClick={() => setPasswordVisible(true)}
                                        />
                                    )}
                                </div>
                            </div>
                        </div>
                        <Link className="font-medium text-sm text-gray-400 inline-block laptop:block my-4  laptop:mb-0 hover:text-indigo-500 underline laptop:w-2/4 laptop:pl-4" to="/forgot-password">
                            Forgot your password?
                            </Link>
                        <button type="submit" className="button--stretch" disabled={isLoading}>
                            <LockFilled className="absolute left-8 top-0 bottom-0 my-auto" />
                            {isLoading ? 'Logging In...' : 'Login'}
                        </button>
                        {/* -- TOO HARD TO REPLICATE PSEUDO IN TAILWIND :() */}
                        <i className="social-login-divider">OR</i>
                        <div className="flex justify-between space-x-2">
                            <SocialLogin isLoading={isLoading} />
                        </div>
                    </form>
                    <div className="text-center mt-8">
                        <Link
                            className="underline font-medium"
                            onClick={(e) => isLoading && e.preventDefault()}
                            to={REGISTER}
                        >
                            I dont have an account
                        </Link>
                    </div>
                    {/* --- COPYRIGHT -- */}
                    <span className="text-gray-400 text-xs mx-auto text-center block mt-4">
                        &copy;Copyright {new Date().getFullYear()} Foodie
                    </span>
                </div>
            </div>
        </div>
    );
}
Example #11
Source File: PerformanceWaterfall.tsx    From posthog-foss with MIT License 4 votes vote down vote up
function EventsWithPerformanceTable(): JSX.Element {
    const { pageViewEventsLoading, pageViewEvents, eventToDisplay } = useValues(apmLogic)
    const { setEventToDisplay } = useActions(apmLogic)
    const columns: LemonTableColumns<EventType> = [
        {
            title: 'URL / Screen',
            key: 'url',
            render: function RenderURL(_: any, pageViewEvent: EventType) {
                let urlOrScene: { short: string; full: string }
                if (pageViewEvent.properties['$current_url']) {
                    const currentURL = pageViewEvent.properties['$current_url']
                    try {
                        const url = new URL(currentURL)
                        urlOrScene = { short: `${url.origin}${url.pathname}`, full: url.toString() }
                    } catch (e) {
                        urlOrScene = { short: currentURL, full: currentURL }
                    }
                } else {
                    urlOrScene = {
                        short: pageViewEvent.properties['$screen_name'],
                        full: pageViewEvent.properties['$screen_name'],
                    }
                }

                return (
                    <Tooltip title={urlOrScene.full}>
                        <Typography.Text style={{ width: 300 }} ellipsis={true}>
                            {urlOrScene.short}
                        </Typography.Text>
                    </Tooltip>
                )
            },
        },
        {
            title: 'Time',
            render: function RenderTime(_: any, pageViewEvent: EventType) {
                return <TZLabel time={dayjs(pageViewEvent.timestamp)} formatString="MMMM DD, YYYY h:mm" />
            },
        },
        {
            title: 'Page Load Time',
            render: function RenderPageLoad(_: any, pageViewEvent: EventType) {
                const duration = pageViewEvent.properties['$performance_page_loaded']
                return <span>{Math.round(duration)}ms</span>
            },
        },
        {
            render: function RenderButton(_: any, pageViewEvent: EventType) {
                return (
                    <div>
                        <Button data-attr={`view-waterfall-button-${pageViewEvent.id}`} icon={<EyeOutlined />}>
                            View waterfall chart
                        </Button>
                    </div>
                )
            },
        },
    ]

    return (
        <LemonTable
            dataSource={pageViewEvents || []}
            columns={columns}
            loading={pageViewEventsLoading}
            emptyState={
                pageViewEventsLoading ? (
                    <div>Loading last ten events with performance measures</div>
                ) : (
                    <div>No events available</div>
                )
            }
            rowClassName={(pageViewEvent) => {
                return clsx({
                    'current-event': pageViewEvent.id === eventToDisplay?.id,
                    'cursor-pointer': true,
                })
            }}
            onRow={(pageViewEvent) => ({
                onClick: () => {
                    setEventToDisplay(pageViewEvent)
                },
            })}
            data-attr="apm-waterfall-events-table"
        />
    )
}
Example #12
Source File: index.tsx    From jetlinks-ui-antd with MIT License 4 votes vote down vote up
Screen = (props: Props) => {

  const [categoryList, setCategoryList] = useState([]);
  const [dataList, setDataList] = useState({
    data: [],
    pageIndex: 0,
    total: 0,
    pageSize: 0
  });
  const [id, setId] = useState('');
  const [url, setUrl] = useState('');
  const [saveVisible, setSaveVisible] = useState(false);
  const [editVisible, setEditVisible] = useState(false);
  const [copyVisible, setCopyVisible] = useState(false);
  const [param, setParam] = useState({});
  const [searchParam, setSearchParam] = useState({pageSize: 12, pageIndex: 0, terms: {type: 'big_screen'}});
  const token = getAccessToken();

  const handleSearch = (params: any) => {
    setSearchParam(params);
    api.screen.query(encodeQueryParam(params)).then(res => {
      if (res.status === 200) {
        setDataList(res.result)
      }
    })
  };

  let delConfirm = (id: string) => {
    confirm({
      title: '删除大屏',
      icon: <ExclamationCircleOutlined/>,
      content: '确认删除该大屏?',
      onOk() {
        api.screen.remove(id).then(res => {
          if (res.status === 200) {
            handleSearch(searchParam);
          }
        })
      },
      onCancel() {
        message.info('已取消')
      }
    })
  };
  let updateState = (state: string, id: string) => {
    confirm({
      title: `${state === 'enabled' ? '禁用' : '启用'}大屏`,
      icon: <ExclamationCircleOutlined/>,
      content: `确认${state === 'enabled' ? '禁用' : '启用'}该大屏`,
      onOk() {
        api.screen.update(id, {
          state: {
            value: state === 'enabled' ? 'disabled' : 'enabled'
          }
        }).then(res => {
          if (res.status === 200) {
            handleSearch(searchParam);
          }
        })
      },
      onCancel() {
        message.info('已取消')
      }
    })
  };
  const uploadProps = (item: any) => {
    api.screen.save(item).then(res => {
      if (res.status === 200) {
        message.success('导入成功');
        handleSearch(searchParam);
      }
    })
  };

  const onChange = (page: number, pageSize: number) => {
    handleSearch({
      pageIndex: page - 1,
      pageSize,
      terms: searchParam.terms
    });
  };
  let getView = (view: any) => {
    let children = [];
    if (view.children && view.children.length > 0) {
      children = view.children.map((i: any) => {
        return getView(i)
      });
      return {
        id: view.id,
        children: children,
        pId: view.parentId,
        value: view.id,
        title: view.name
      }
    } else {
      return {
        id: view.id,
        pId: view.parentId,
        value: view.id,
        title: view.name
      }
    }
  };
  useEffect(() => {
    //获取跳转url
    api.screen.getUrl().then((res) => {
      if(res.status === 200){
        if(res.result.urls['big-screen-path'] != ''){
          setUrl(res.result.urls['big-screen-path'])
        }else{
          message.error('配置错误,请联系管理员');
        }
      }
    });

    api.categoty.queryNoPaging({}).then(res => {
      if (res.status === 200) {
        setCategoryList(res.result);
      }
    });

    handleSearch(searchParam);
  }, []);

  const findCategory = (id:string)=>{

    const category: Partial<CategoryItem> =
      categoryList.find((i:any) => i.id === id) || {};

    return category.name;
  };

  return (
    <PageHeaderWrapper title="大屏管理">
      <Card bordered={false}>
        <div className={styles.tableList}>
          <div>
            <SearchForm
              search={(params: any) => {
                handleSearch({
                  terms: {...params, type: 'big_screen'},
                  pageSize: 8,
                });
              }}
              formItems={[{
                label: '大屏名称',
                key: 'name$LIKE',
                type: 'string',
              },
                {
                  label: '大屏分类',
                  key: 'catalogId$LIKE',
                  type: 'list',
                  props: {
                    data: categoryList,
                    // mode: 'default',
                    showSearch:true
                  }
                }]}
            />
          </div>

          <div className={styles.tableListOperator}>
            <Button icon="plus" type="primary" onClick={() => setSaveVisible(true)}>新建大屏</Button>
            <Divider type="vertical"/>
            <Upload
            action="/jetlinks/file/static"
              headers={{
                'X-Access-Token': getAccessToken(),
              }}
            showUploadList={false} accept='.json' beforeUpload={(file) => {
              const reader = new FileReader();
              reader.readAsText(file);
              reader.onload = (result) => {
                try {
                  uploadProps(JSON.parse(result.target.result));
                } catch (error) {
                  message.error('文件格式错误');
                }
              }
            }}>
              <Button><Icon type="upload"/>快速导入</Button>
            </Upload>
          </div>
        </div>
      </Card>
      <div style={{marginBottom: '30px'}}>
        <div className={styles.cardList}>
          <List<any>
            rowKey="id"
            grid={{gutter: 24, xl: 4, lg: 3, md: 2, sm: 2, xs: 1}}
            dataSource={dataList.data || []}
            pagination={{
              current: dataList.pageIndex + 1,
              total: dataList.total,
              pageSize: dataList.pageSize,
              onChange,
              showQuickJumper: true,
              showSizeChanger: true,
              hideOnSinglePage: true,
              pageSizeOptions: ['8', '16', '40', '80'],
              style: {marginTop: -20},
              showTotal: (total: number) =>
                `共 ${total} 条记录 第  ${dataList.pageIndex + 1}/${Math.ceil(
                  dataList.total / dataList.pageSize,
                )}页`
            }}
            renderItem={item => {
              if (item && item.id) {
                let metadata = item.metadata != undefined && item.metadata != "" ? JSON.parse(item.metadata) : {};
                return (
                  <List.Item key={item.id}>
                    <Card hoverable bodyStyle={{paddingBottom: 20}}
                          onMouseEnter={() => setId(item.id)} onMouseLeave={() => setId('')}
                          actions={[
                            <Tooltip placement="bottom" title="编辑">
                              <EditOutlined onClick={() => {
                                setEditVisible(true);
                                setParam({
                                  id: item.id,
                                  name: item.name,
                                  description: item.description,
                                  catalogId: item.catalogId,
                                  url: url
                                })
                              }}/>
                            </Tooltip>,
                            <Tooltip placement="bottom" title="预览">
                              <EyeOutlined onClick={() => {
                                url != '' ? window.open(url + '#/view/' + item.id + '?token=' + token, '_blank') : message.error('配置错误,请联系管理员')
                              }}/>
                            </Tooltip>,
                            <Tooltip placement="bottom" title="复制">
                              <SwitcherOutlined onClick={() => {
                                setCopyVisible(true);
                                setParam({url: url, metadata: item.metadata})
                              }}/>
                            </Tooltip>,
                            <Tooltip placement="bottom" title="下载">
                              <Icon type="download" onClick={() => {
                                downloadObject(item, '大屏')
                              }}/>
                            </Tooltip>,
                            <Tooltip key="more_actions" title="">
                              <Dropdown overlay={
                                <Menu>
                                  <Menu.Item key="1">
                                    <Button onClick={() => {
                                      updateState(item.state.value, item.id)
                                    }} icon={item.state.value === 'enabled' ? 'close' : 'check'} type="link">
                                      {item.state.value === 'enabled' ? '禁用' : '启用'}
                                    </Button>
                                  </Menu.Item>
                                  {item.state.value === 'disabled' && (
                                    <Menu.Item key="2">
                                      <Button icon="delete" type="link" onClick={() => {
                                        delConfirm(item.id)
                                      }}>删除</Button>
                                    </Menu.Item>
                                  )}
                                </Menu>
                              }>
                                <Icon type="ellipsis"/>
                              </Dropdown>
                            </Tooltip>,
                          ]}
                    >
                      <Card.Meta
                        avatar={<Avatar size={60} src={ metadata.visual != undefined && metadata.visual.backgroundUrl != undefined ? metadata.visual.backgroundUrl : false }/>}
                        title={<AutoHide title={item.name} style={{width: '95%',fontWeight:600}}/>}
                        description={<AutoHide title={item.id} style={{width: '95%'}}/>}
                      />
                      <div className={styles.status}>
                        <div style={{textAlign: 'center', minWidth: '80px'}}>
                          <p>状态: <span style={{fontWeight:600}}>已{item.state.text}</span></p>
                        </div>
                        <div style={{textAlign: 'center', minWidth: '80px'}}>
                          <p>分类: <span style={{fontWeight:600}}>{findCategory(item.catalogId)}</span></p>
                        </div>
                      </div>
                      <div className={styles.edit} style={{display: item.id == id ? 'block' : 'none'}}>
                        <div className={styles.editBtn}><a onClick={() => {
                          url != '' ? window.open(url + `#/build/${id}?token=${token}`, '_blank') : message.error('配置错误,请联系管理员')
                        }}>编辑</a></div>
                      </div>
                    </Card>
                  </List.Item>
                );
              }
              return;
            }}
          />
        </div>
        {saveVisible && <Save data={url} close={() => {
          setSaveVisible(false)
        }} save={() => {
          setSaveVisible(false);
          handleSearch(searchParam);
        }}/>}
        {copyVisible && <Copy data={param} close={() => {
          setCopyVisible(false)
        }} save={() => {
          setCopyVisible(false);
          handleSearch(searchParam);
        }}/>}
        {editVisible && <Edit data={param} close={() => {
          setEditVisible(false)
        }} save={() => {
          setEditVisible(false);
          handleSearch(searchParam);
        }}/>}
      </div>
    </PageHeaderWrapper>
  )
}
Example #13
Source File: OpticalPathItem.tsx    From slim with Apache License 2.0 4 votes vote down vote up
render (): React.ReactNode {
    const identifier = this.props.opticalPath.identifier
    const description = this.props.opticalPath.description
    const attributes: Array<{ name: string, value: string }> = []
    if (this.props.opticalPath.illuminationWaveLength !== undefined) {
      attributes.push(
        {
          name: 'Illumination wavelength',
          value: `${this.props.opticalPath.illuminationWaveLength} nm`
        }
      )
    }
    if (this.props.opticalPath.illuminationColor !== undefined) {
      attributes.push(
        {
          name: 'Illumination color',
          value: this.props.opticalPath.illuminationColor.CodeMeaning
        }
      )
    }

    // TID 8001 "Specimen Preparation"
    const specimenDescriptions: dmv.metadata.SpecimenDescription[] = (
      this.props.metadata[0].SpecimenDescriptionSequence ?? []
    )
    specimenDescriptions.forEach(description => {
      const specimenPreparationSteps: dmv.metadata.SpecimenPreparation[] = (
        description.SpecimenPreparationSequence ?? []
      )
      specimenPreparationSteps.forEach(
        (step: dmv.metadata.SpecimenPreparation, index: number): void => {
          step.SpecimenPreparationStepContentItemSequence.forEach((
            item: (
              dcmjs.sr.valueTypes.CodeContentItem |
              dcmjs.sr.valueTypes.TextContentItem |
              dcmjs.sr.valueTypes.UIDRefContentItem |
              dcmjs.sr.valueTypes.PNameContentItem |
              dcmjs.sr.valueTypes.DateTimeContentItem
            ),
            index: number
          ) => {
            const name = new dcmjs.sr.coding.CodedConcept({
              value: item.ConceptNameCodeSequence[0].CodeValue,
              schemeDesignator:
                item.ConceptNameCodeSequence[0].CodingSchemeDesignator,
              meaning: item.ConceptNameCodeSequence[0].CodeMeaning
            })
            if (item.ValueType === dcmjs.sr.valueTypes.ValueTypes.CODE) {
              item = item as dcmjs.sr.valueTypes.CodeContentItem
              const value = new dcmjs.sr.coding.CodedConcept({
                value: item.ConceptCodeSequence[0].CodeValue,
                schemeDesignator:
                  item.ConceptCodeSequence[0].CodingSchemeDesignator,
                meaning: item.ConceptCodeSequence[0].CodeMeaning
              })
              if (!name.equals(SpecimenPreparationStepItems.PROCESSING_TYPE)) {
                if (name.equals(SpecimenPreparationStepItems.STAIN)) {
                  attributes.push({
                    name: 'Tissue stain',
                    value: value.CodeMeaning
                  })
                }
              }
            } else if (item.ValueType === dcmjs.sr.valueTypes.ValueTypes.TEXT) {
              item = item as dcmjs.sr.valueTypes.TextContentItem
              if (!name.equals(SpecimenPreparationStepItems.PROCESSING_TYPE)) {
                if (name.equals(SpecimenPreparationStepItems.STAIN)) {
                  attributes.push({
                    name: 'Tissue stain',
                    value: item.TextValue
                  })
                }
              }
            }
          })
        }
      )
    })

    const maxValue = Math.pow(2, this.props.metadata[0].BitsAllocated) - 1

    const title = (
      description != null ? `${identifier}: ${description}` : identifier
    )
    let settings
    let item
    if (this.props.opticalPath.isMonochromatic) {
      // monochrome images that can be pseudo-colored
      let colorSettings
      if (this.state.currentStyle.color != null) {
        colorSettings = (
          <>
            <Divider plain>
              Color
            </Divider>
            <Row justify='center' align='middle' gutter={[8, 8]}>
              <Col span={5}>
                Red
              </Col>
              <Col span={14}>
                <Slider
                  range={false}
                  min={0}
                  max={255}
                  step={1}
                  value={this.state.currentStyle.color[0]}
                  onChange={this.handleColorRChange}
                />
              </Col>
              <Col span={5}>
                <InputNumber
                  min={0}
                  max={255}
                  size='small'
                  style={{ width: '65px' }}
                  value={this.state.currentStyle.color[0]}
                  onChange={this.handleColorRChange}
                />
              </Col>
            </Row>

            <Row justify='center' align='middle' gutter={[8, 8]}>
              <Col span={5}>
                Green
              </Col>
              <Col span={14}>
                <Slider
                  range={false}
                  min={0}
                  max={255}
                  step={1}
                  value={this.state.currentStyle.color[1]}
                  onChange={this.handleColorGChange}
                />
              </Col>
              <Col span={5}>
                <InputNumber
                  min={0}
                  max={255}
                  size='small'
                  style={{ width: '65px' }}
                  value={this.state.currentStyle.color[1]}
                  onChange={this.handleColorGChange}
                />
              </Col>
            </Row>

            <Row justify='center' align='middle' gutter={[8, 8]}>
              <Col span={5}>
                Blue
              </Col>
              <Col span={14}>
                <Slider
                  range={false}
                  min={0}
                  max={255}
                  step={1}
                  value={this.state.currentStyle.color[2]}
                  onChange={this.handleColorBChange}
                />
              </Col>
              <Col span={5}>
                <InputNumber
                  min={0}
                  max={255}
                  size='small'
                  style={{ width: '65px' }}
                  value={this.state.currentStyle.color[2]}
                  onChange={this.handleColorBChange}
                />
              </Col>
            </Row>
          </>
        )
      }

      let windowSettings
      if (this.state.currentStyle.limitValues != null) {
        windowSettings = (
          <>
            <Divider plain>
              Values of interest
            </Divider>
            <Row justify='center' align='middle' gutter={[8, 8]}>
              <Col span={6}>
                <InputNumber
                  min={0}
                  max={this.state.currentStyle.limitValues[1]}
                  size='small'
                  style={{ width: '75px' }}
                  value={this.state.currentStyle.limitValues[0]}
                  onChange={this.handleLowerLimitChange}
                />
              </Col>
              <Col span={12}>
                <Slider
                  range
                  min={0}
                  max={maxValue}
                  step={1}
                  value={[
                    this.state.currentStyle.limitValues[0],
                    this.state.currentStyle.limitValues[1]
                  ]}
                  onChange={this.handleLimitChange}
                />
              </Col>
              <Col span={6}>
                <InputNumber
                  min={this.state.currentStyle.limitValues[0]}
                  max={maxValue}
                  size='small'
                  style={{ width: '75px' }}
                  value={this.state.currentStyle.limitValues[1]}
                  onChange={this.handleUpperLimitChange}
                />
              </Col>
            </Row>
          </>
        )
      }
      settings = (
        <div>
          {windowSettings}
          {colorSettings}
          <Divider plain />
          <Row justify='center' align='middle' gutter={[8, 8]}>
            <Col span={6}>
              Opacity
            </Col>
            <Col span={12}>
              <Slider
                range={false}
                min={0}
                max={1}
                step={0.01}
                value={this.state.currentStyle.opacity}
                onChange={this.handleOpacityChange}
              />
            </Col>
            <Col span={6}>
              <InputNumber
                min={0}
                max={1}
                size='small'
                step={0.1}
                style={{ width: '65px' }}
                value={this.state.currentStyle.opacity}
                onChange={this.handleOpacityChange}
              />
            </Col>
          </Row>
        </div>
      )
      const colors = this.getCurrentColors()
      item = (
        <Badge
          offset={[-20, 20]}
          count={' '}
          style={{
            borderStyle: 'solid',
            borderWidth: '1px',
            borderColor: 'gray',
            visibility: this.state.isVisible ? 'visible' : 'hidden',
            backgroundImage: `linear-gradient(to right, ${colors.toString()})`
          }}
        >
          <Description
            header={title}
            attributes={attributes}
            selectable
            hasLongValues
          />
        </Badge>
      )
    } else {
      // color images
      settings = (
        <div>
          <Row justify='center' align='middle' gutter={[8, 8]}>
            <Col span={6}>
              Opacity
            </Col>
            <Col span={12}>
              <Slider
                range={false}
                min={0}
                max={1}
                step={0.01}
                value={this.state.currentStyle.opacity}
                onChange={this.handleOpacityChange}
              />
            </Col>
            <Col span={6}>
              <InputNumber
                min={0}
                max={1}
                size='small'
                step={0.1}
                style={{ width: '60px' }}
                value={this.state.currentStyle.opacity}
                onChange={this.handleOpacityChange}
              />
            </Col>
          </Row>
        </div>
      )
      item = (
        <Description
          header={title}
          attributes={attributes}
          selectable
          hasLongValues
        />
      )
    }

    const buttons = []
    if (this.props.isRemovable) {
      buttons.push(
        <Tooltip title='Remove Optical Path'>
          <Button
            type='default'
            shape='circle'
            icon={<DeleteOutlined />}
            onClick={this.handleRemoval}
          />
        </Tooltip>
      )
    }

    const {
      defaultStyle,
      isRemovable,
      isVisible,
      metadata,
      onVisibilityChange,
      onStyleChange,
      onRemoval,
      opticalPath,
      ...otherProps
    } = this.props
    return (
      <Menu.Item
        style={{ height: '100%', paddingLeft: '3px' }}
        key={this.props.opticalPath.identifier}
        {...otherProps}
      >
        <Space align='start'>
          <div style={{ paddingLeft: '14px' }}>
            <Space direction='vertical' align='end'>
              <Switch
                size='small'
                checked={this.state.isVisible}
                onChange={this.handleVisibilityChange}
                checkedChildren={<EyeOutlined />}
                unCheckedChildren={<EyeInvisibleOutlined />}
              />
              <Popover
                placement='left'
                content={settings}
                overlayStyle={{ width: '350px' }}
                title='Display Settings'
              >
                <Button
                  type='primary'
                  shape='circle'
                  icon={<SettingOutlined />}
                />
              </Popover>
              {buttons}
            </Space>
          </div>
          {item}
        </Space>
      </Menu.Item>
    )
  }
Example #14
Source File: Responsive.tsx    From yugong with MIT License 4 votes vote down vote up
Responsive: React.FC<Props> = () => {
  useEffect(() => {
    trackPageView('/首页');
  }, []);
  /**
   * ----------
   * 定义编辑模式
   * ----------
   */
  const { isEditing, auth } = useSelector(
    (state: RootState) => state.controller,
  );

  const history = useHistory();

  const appData = useSelector((state: RootState) => state.appData);
  const activationItem = useSelector(
    (state: RootState) => state.activationItem,
  );
  const stateTag = useSelector((state: RootState) => state.controller.stateTag);

  const forceUpdateByStateTag =
    useDispatch<Dispatch>().controller.forceUpdateByStateTag;
  const setIsEditing = useDispatch<Dispatch>().controller.setIsEditing;
  const updateAppData = useDispatch<Dispatch>().appData.updateAppData;
  const updatePageData = useDispatch<Dispatch>().pageData.updatePage;
  const setWindowHeight = useDispatch<Dispatch>().pageData.setWindowHeight;
  const setWindowWidth = useDispatch<Dispatch>().pageData.setWindowWidth;
  const updateActivationItem =
    useDispatch<Dispatch>().activationItem.updateActivationItem;
  const removeActivationItem =
    useDispatch<Dispatch>().activationItem.removeActivationItem;

  const setRunningTimes = useDispatch<Dispatch>().runningTimes.setRunningTimes;

  const ref = useRef(null);

  const pageData = useSelector((state: RootState) => state.pageData);
  const runningTimes = useSelector((state: RootState) => state.runningTimes);
  const setIsReady = useDispatch<Dispatch>().record.setIsReady;

  const [, setLocalPageData] = useLocalStorage('pageData', null);

  const [showDrawer, setShowDrawer] = useState(false);
  const [showPageDrawer, setShowPageDrawer] = useState(false);
  const [isCreate, setIsCreate] = useState(true);
  const [showTemplateModal, setShowTemplateModal] = useState(false);
  const [hideIframe, sethideIframe] = useState(true);
  const [visibleQrcode, setVisibleQrcode] = useState(false);

  // 创建postmessage通信 usePostMessage收集数据 redux 更新数据
  const sendMessage = usePostMessage(({ tag, value }) => {
    switch (tag) {
      case 'setIsEditing':
        setIsEditing(value);
        break;
      case 'updateAppData':
        updateAppData(value);
        // 同步更新被选模块的属性
        if (activationItem.moduleId === undefined) return;
        const asynAcactivationItem = (value as AppDataListTypes).find(
          (item) => item.moduleId === activationItem.moduleId,
        );
        if (asynAcactivationItem?.moduleId) {
          updateActivationItem(asynAcactivationItem);
        }
        break;
      case 'updateRunningTimes':
        setRunningTimes(value);
        break;
      case 'updatePage':
        updatePageData(value);
        break;
      case 'id':
        // 设置当前项正在被编辑
        // 禁止重复设置当前编辑项
        if (activationItem.moduleId === value) return;
        for (let index = 0; index < appData.length; index++) {
          const element = appData[index];
          if (element.moduleId === value) {
            updateActivationItem({ ...element });
            break;
          }
        }
        setShowDashboard(true);
        break;
      case 'record':
        saveRecord(value)
        break
      default:
        break;
    }
  });

  // 收发处理,子窗口onload时向子窗口发送信息, 通知当前正处于编辑模式下,
  const win: Window | null = ref.current
    ? (ref.current as any).contentWindow
    : null;

  useEffect(() => {
    const windows = (document.getElementById('wrapiframe') as any)
      ?.contentWindow;
    if (windows && !isCreate) {
      windows.onload = () => {
        sendMessage({ tag: 'setIsEditing', value: true }, windows);
        setIsEditing(true);
        setIsReady(true);
        sethideIframe(false);
      };
    }
  }, [sendMessage, setIsEditing, isCreate, setIsReady]);

  useEffect(() => {
    sendMessage({ tag: 'setIsEditing', value: true }, win);
    setIsEditing(true);
  }, [sendMessage, setIsEditing, win]);

  const toggleEdit = useCallback(() => {
    const states = !isEditing;
    sendMessage({ tag: 'setIsEditing', value: states }, win);
    setIsEditing(states);
  }, [isEditing, sendMessage, setIsEditing, win]);

  const toggleCreate = useCallback(() => {
    setIsCreate(!isCreate);
  }, [isCreate]);

  // 收发处理,编辑完数据后通过sendMessage向子窗口发送最新数据。
  useEffect(() => {
    sendMessage(
      {
        tag: 'updateAppData',
        value: appData,
      },
      win,
    );
  }, [sendMessage, win, appData]);

  const onChangeRule = (
    width: number,
    height: number = window.innerHeight - 140,
  ) => {
    setWindowWidth(width);
    setWindowHeight(height);
    const optPageData = { ...pageData };
    optPageData.windowWidth = width;
    optPageData.windowHeight = height;
    setLocalPageData(optPageData);
    if (win) {
      sendMessage({ tag: 'updatePage', value: true }, win);
      sendMessage({ tag: 'setIsEditing', value: isEditing }, win);
    }
    setIsEditing(true);
    forceUpdateByStateTag();
  };

  const [showDashboard, setShowDashboard] = useState(false);
  const [opacity, setOpacity] = useState('1');
  // 无激活模块时隐藏设置面板
  useEffect(() => {
    if (!activationItem.moduleId) {
      setShowDashboard(false);
    }
  }, [activationItem]);

  const hideDashboard = useCallback(() => {
    setShowDashboard(false);
    removeActivationItem();
    if (win) {
      sendMessage({ tag: 'removeActivationItem', value: undefined }, win);
    }
  }, [removeActivationItem, sendMessage, win]);

  const updateProject = useCallback(
    (data: Template) => {
      data.id = pageData.template?.id;
      return updateTemplate(data);
    },
    [pageData],
  );

  interface TemplateAll extends Template {
    pageData: string;
    appData: string;
  }

  // 保存或更新项目
  const onSaveProject = useCallback(
    async ({
      cove = [],
      terminal,
      isPublic,
      describe,
      tag,
      title,
      id,
    }: TemplateInfo) => {
      if (!auth?.isLogin) {
        history.push('/login');
        return;
      }

      // copy
      const pageDataCopy = cloneDeep(pageData);

      // template数据
      const templateData: Template = {
        title: title || pageData.pageTitle,
        terminal,
        cove: cove[0]?.thumbUrl,
        describe,
        tag: tag?.join(','),
        isPublic: isPublic === true ? 1 : 0,
      };
      // 存入模板信息到pageData
      if (!pageDataCopy.template) {
        pageDataCopy.template = templateData;
      }

      // 完整数据
      /**
       * 完整数据包含页面数据、组件数据与模板信息三个部分,
       * 页面数据同时也包含一份模板信息供页面处理
       */
      const params: TemplateAll = {
        pageData: JSON.stringify(pageData),
        appData: JSON.stringify(appData),
        id,
        userId: auth.session?.id,
        ...templateData,
      };
      try {
        loading.show();
        // 更新
        if (!!pageData.template?.id) {
          await updateProject(params);
        } else {
          // 新增
          const newId = await createTemplate(params);
          pageDataCopy.template.id = newId;
        }
        message.success('已发布');
        // 更新
        updatePageData(pageDataCopy);
        // 关闭弹窗
        setShowTemplateModal(false);
        // todo 展示二维码与模板访问链接,支持扫码访问
        setVisibleQrcode(true);
        loading.hide();
      } catch (error) {
        console.error(error);
        loading.hide();
      }
      
    },
    [
      appData,
      auth?.isLogin,
      auth?.session?.id,
      history,
      pageData,
      updatePageData,
      updateProject,
    ],
  );

  const showPublishModal = useCallback(() => {
    if (!auth?.isLogin) {
      history.push('/login');
    }
    setShowTemplateModal(true);
  }, [auth?.isLogin, history]);

  const pageSearch = stringify({ tpl: pageData.template?.id, ...runningTimes.search });

  const codeViewUrl = `${process.env.REACT_APP_SITE_PATH || ''}${pageSearch ? `?${pageSearch}` : ''}`;

  const viewUrl = `${process.env.REACT_APP_SITE_PATH || ''}${window.location.search || '?isediting'
    }`


  return (
    <>
      {isCreate ? (
        <CreateProject goBack={() => toggleCreate()} />
      ) : (
        <div className={s.main}>
          {showDashboard && isEditing ? (
            <Draggable
              axis="both"
              handle={`.${s.header}`}
              onDrag={() => setOpacity('0.5')}
              onStop={() => setOpacity('1')}
            >
              <div className={s.dashboard} style={{ opacity }}>
                <div className={s.header}>
                  <h3>设置面板</h3>
                  <CloseOutlined className={s.icon} onClick={hideDashboard} />
                </div>
                <MiniDashboard />
              </div>
            </Draggable>
          ) : null}
          <div className={s.topmenu}>
            <div className={s.create}>
              <Button
                type="primary"
                onClick={toggleCreate}
                icon={<FileAddOutlined />}
              />
              &nbsp;
              {!isEditing ? (
                <Button
                  type="default"
                  className={s.toggle}
                  onClick={toggleEdit}
                  icon={<EditOutlined />}
                />
              ) : null}
              {isEditing ? (
                <Button
                  type="default"
                  className={s.toggle}
                  onClick={toggleEdit}
                  icon={<EyeOutlined />}
                />
              ) : null}
              &nbsp;
              <Button
                type="default"
                icon={<SettingOutlined />}
                onClick={() => setShowPageDrawer(true)}
              >
                页面
              </Button>
              &nbsp;
              <Button
                type="default"
                icon={<PlusOutlined />}
                onClick={() => setShowDrawer(true)}
              >
                组件
              </Button>
              
              <Undo />
              &nbsp;
              <a href="https://github.com/eightfeet/yugong">
                <Button type="default" icon={<GithubOutlined />}>
                  github
                </Button>
              </a>
            </div>
            <div className={s.save}>
              <Button
                type="primary"
                icon={<CloudUploadOutlined />}
                onClick={showPublishModal}
              >
                {pageData.template?.id ? '修改' : '发布'}
              </Button>
              {pageData.template?.id ? <>
                &nbsp;
                <Button
                  icon={<QrcodeOutlined />}
                  onClick={() => setVisibleQrcode(true)}
                />
              </> : null}

            </div>
          </div>
          <Ruler onChange={onChangeRule} />
          <Drawer
            className={s.drawer}
            title="页面设置"
            width={580}
            onClose={() => setShowPageDrawer(false)}
            visible={showPageDrawer}
            bodyStyle={{ padding: '0', overflow: 'auto' }}
            maskStyle={{ backgroundColor: 'transparent' }}
            footer={null}
          >
            {showPageDrawer ? <PageSetting /> : null}
          </Drawer>
          <Drawer
            className={s.drawer}
            title="组件库"
            width={580}
            onClose={() => setShowDrawer(false)}
            visible={showDrawer}
            bodyStyle={{ padding: '0px' }}
            maskStyle={{ backgroundColor: 'transparent' }}
            footer={null}
          >
            <Repository />
          </Drawer>
          <div className={s.box}>
            <div
              className={classNames({
                [s.viewbg]: !isEditing,
              })}
              style={{ transition: 'all 0.5s' }}
            />
            {!stateTag ? (
              <div
                className={s.iframebox}
                style={{
                  width:
                    pageData.windowWidth === -1
                      ? `100%`
                      : `${pageData.windowWidth}px`,
                  height: `${pageData.windowHeight}px`,
                }}
              >
                <LoadingAnimate />
                <iframe
                  ref={ref}
                  id="wrapiframe"
                  title="wrapiframe"
                  src={viewUrl}
                  style={{
                    border: 'none',
                    opacity: hideIframe ? 0 : 1,
                    minWidth: '100%',
                    minHeight: `${pageData.windowHeight}px`,
                  }}
                />
              </div>
            ) : null}
          </div>
        </div>
      )}
      <TemplateInfoModal
        visible={showTemplateModal}
        onOk={onSaveProject}
        onCancel={() => setShowTemplateModal(false)}
      />
      <QrcodeModal
        visible={visibleQrcode}
        onCancel={() => setVisibleQrcode(false)}
        sourceData={codeViewUrl}
        title="请扫码访问"
        info={<div className={s.viewurl}>访问地址:<a href={codeViewUrl} target={'_blank'} rel="noreferrer">{codeViewUrl}</a></div>}
        options={{
          width: 122,
          margin: 1
        }}
      />
    </>
  );
}
Example #15
Source File: Upload.tsx    From yugong with MIT License 4 votes vote down vote up
Upload: React.FC<UploadProps> = ({ label, defaultImg, onChange }) => {
  const [img, setimg] = useState<string>();
  const [isloading, setIsloading] = useState(false);
  const [viewImg, setViewImg] = useState(false);
  const [wh, setWh] = useState(' ');
  const moduleId = useSelector(
    (state: RootState) => state.activationItem.moduleId,
  );
  const [csrfToken] = useCookie('csrfToken')
  
  const ref = useRef(null);

  // 创建临时图片文件
  const createTempImg = useCallback((url: string) => {
    const wrap = ref.current as any;
    if (wrap) {
      (ref.current as any).innerHTML = '';
      const image = new Image();
      image.src = url;
      image.onload = () => {};
      (ref.current as any).appendChild(image);
    }
  }, []);

  // 获取文件宽高属性
  const getTempImgWH = useCallback(() => {
    const image = (ref.current as any)?.querySelector('img');
    if (image) {
      const str = `宽:${image.offsetWidth}px 高:${image.offsetHeight}px`;
      setWh(str);
    }
  }, []);

  // 删除临时文件

  useEffect(() => {
    setimg(defaultImg);
    if (defaultImg) {
      createTempImg(defaultImg);
    }
  }, [createTempImg, defaultImg, moduleId]);

  const onChangeUpload = useCallback(
    (info: UploadChangeParam) => {
      if (info.file.status === 'uploading') {
        setIsloading(true);
      }

      if (info.file.status === 'error') {
        setIsloading(false);
      }

      if (info.file.response) {
        setTimeout(() => {
          setIsloading(false);
          setimg(info.file.response.fileUrl);
          createTempImg(info.file.response.fileUrl);
        }, 1000);

        if (onChange instanceof Function) {
          onChange(info.file.response.fileUrl);
        }
      }
    },
    [createTempImg, onChange],
  );

  const hideView = useCallback(() => {
    setViewImg(false);
  }, []);

  const showView = useCallback(() => {
    getTempImgWH();
    setViewImg(true);
  }, [getTempImgWH]);

  const deleteImage = useCallback(() => {
    setimg('');
    if (onChange instanceof Function) {
      onChange('');
    }
  }, [onChange]);

  const inputOnChange = useCallback(
    (e) => {
      const url = e.target.value;
      if (onChange instanceof Function && isUrl(url)) {
        onChange(url);
        setimg(url);
        createTempImg(url);
      }
    },
    [createTempImg, onChange],
  );

  return (
    <>
      <Row className={s.row} gutter={4}>
        <Col className={s.label} span={7}>
          {label || ''}
        </Col>
        <Col span={14}>
          <div className={s.button}>
            {process.env.REACT_APP_DEMO === 'true' ? (
              <Tooltip
              overlayInnerStyle={{width: 400}}
                title={
                  <Input style={{width: '100%'}} value={img} onChange={inputOnChange} placeholder="输入图片url" />
                }
              >
                <span
                  className={classNames(s.uploadicon, s.empty, s.flid)}
                  style={{
                    backgroundImage: `url(${!isloading && img ? img : ''})`,
                  }}
                >
                  {isloading ? antIcon : null}
                  {!img ? <PictureOutlined /> : null}
                </span>
              </Tooltip>
            ) : (
              <UploadPic
                accept=".jpg,.jpeg,.png"
                action={'/api/upload'}
                onChange={onChangeUpload}
                showUploadList={false}
                disabled={isloading}
                headers={{
                  'x-csrf-token': csrfToken || ''
                }}
              >
                <span
                  className={classNames(s.uploadicon, s.empty, s.flid)}
                  style={{
                    backgroundImage: `url(${!isloading && img ? img : ''})`,
                  }}
                >
                  {isloading ? antIcon : null}
                  {!img ? <PictureOutlined /> : null}
                </span>
              </UploadPic>
            )}
          </div>

          {!isloading && img ? (
            <>
              <Tooltip
                placement="top"
                trigger="hover"
                mouseEnterDelay={2}
                title="预览"
              >
                <Button
                  className={s.view}
                  type="link"
                  size={'small'}
                  onClick={showView}
                  icon={<EyeOutlined />}
                />
              </Tooltip>
              <Tooltip
                placement="top"
                trigger="hover"
                mouseEnterDelay={2}
                title="删除"
              >
                <Button
                  type="link"
                  danger
                  size={'small'}
                  onClick={deleteImage}
                  icon={<DeleteOutlined />}
                />
              </Tooltip>
            </>
          ) : null}
        </Col>
      </Row>
      <Modal visible={viewImg} onCancel={hideView} title={wh} footer={null}>
        <div className={s.ref}>
          {img ? <img ref={ref} src={img} alt={''} /> : null}
        </div>
      </Modal>
      {!isloading && img ? <div className={s.imgtemp} ref={ref} /> : null}
    </>
  );
}
Example #16
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 #17
Source File: FilterTag.tsx    From ant-extensions with MIT License 4 votes vote down vote up
FilterTag: React.FC<{
  filter: IFilterObject;
  index: number;
  disabled: boolean;
}> = React.memo(({ index, filter, disabled }) => {
  const { t } = useTranslation(I18nKey);

  const { field, operator, type, value, label, compare, active, negative, required } = filter;

  const [open, setOpen] = useState(false);
  const [editing, setEditing] = useState(required);
  const { fields, updateFilter, removeFilter } = useContext(Context);

  const displayValue = useMemo(() => {
    const _field = fields.find((f) => f.key === field);
    const _compare = fields.find((f) => f.key === compare);
    let _value = value ? `"${value.toString()}"` : "";
    if (type === "compare") {
      _value = _compare ? _compare.name : compare || "";
    }
    return _value ? (
      <span className="ant-ext-sb__filterTag--clip">
        {_field && value && _field.type === EnumFieldType.DATE
          ? DateUtils.label(value.toString())
          : _value}
      </span>
    ) : undefined;
  }, [fields, value, type, field, compare]);

  const displayLabel = useMemo(() => {
    const _field = fields.find((f) => f.key === field);
    return (
      <>
        <span className="ant-ext-sb__filterTag--clip">{_field ? _field.name : field}</span>
        <b>&nbsp;{t(`operator.${operator}`)}&nbsp;</b>
        {displayValue}
      </>
    );
  }, [field, operator, displayValue, fields, t]);

  const menuOverlay = useMemo(
    () => (
      <Menu className="ant-ext-sb__dropdown">
        <Menu.Item onClick={() => setEditing(true)}>
          <EditOutlined /> {t(`label.edit`)}
        </Menu.Item>
        <Menu.Item onClick={() => updateFilter(index, { active: !active })}>
          {active ? <EyeOutlined /> : <EyeInvisibleOutlined />}{" "}
          {t(`label.${active ? "disable" : "enable"}`)}
        </Menu.Item>
        <Menu.Item onClick={() => updateFilter(index, { negative: !negative })}>
          <Icon component={TwoTone} /> {t(`label.${negative ? "include" : "exclude"}`)}
        </Menu.Item>
        <Menu.Item
          className="ant-typography ant-typography-danger"
          onClick={() => removeFilter(index)}
        >
          <DeleteOutlined /> {t("label.remove")}
        </Menu.Item>
      </Menu>
    ),
    [active, negative, index, removeFilter, t, updateFilter]
  );

  const formOverlay = useMemo(
    () => (
      <div className="ant-ext-sb__dropdown" data-for-required={required}>
        <FilterForm
          filter={filter}
          index={index}
          onCancel={() => [setOpen(false), setEditing(required)]}
        />
      </div>
    ),
    [filter, index, required]
  );

  const color = useMemo(
    () =>
      negative ? (type === "filter" ? "red" : "orange") : type === "filter" ? "blue" : "geekblue",
    [negative, type]
  );

  return (
    <Tag
      className="ant-ext-sb__filterTag"
      color={color}
      data-active={active && !disabled}
      data-negative={negative}
      closable={!required}
      onClose={() => removeFilter(index)}
    >
      {!required && (
        <Checkbox
          style={{ gridArea: "check" }}
          checked={active}
          disabled={disabled}
          onChange={(e) => updateFilter(index, { active: e.target.checked })}
        />
      )}
      <Tooltip overlay={displayLabel} trigger="hover">
        <Dropdown
          overlay={editing ? formOverlay : menuOverlay}
          trigger={["click"]}
          visible={open}
          disabled={disabled}
          overlayStyle={{ zIndex: 1010 }}
          onVisibleChange={(visible) => [setOpen(visible), !visible && setEditing(required)]}
        >
          <span className="ant-ext-sb__filterTag--label" onClick={() => setOpen(true)}>
            {label ? label : displayLabel}
          </span>
        </Dropdown>
      </Tooltip>
    </Tag>
  );
})