antd#Divider TypeScript Examples

The following examples show how to use antd#Divider. 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: ExampleCustomScreen.tsx    From jmix-frontend with Apache License 2.0 6 votes vote down vote up
ExampleCustomScreen = () => {
    const mainStore = useMainStore();

    const [contentDisplayMode, setContentDisplayMode] = useState(mainStore.contentDisplayMode);

    const handleContentDisplayModeChange = useCallback((e: RadioChangeEvent) => {
        if (Object.values(ContentDisplayMode).includes(e.target.value)) {
            mainStore.contentDisplayMode = e.target.value;
            setContentDisplayMode(mainStore.contentDisplayMode);
        }
    }, [mainStore, setContentDisplayMode]);

    return (
        <>
            <h2>
                Example Custom Screen
            </h2>
            <Divider/>
            <div>
                <div><code>ContentDisplayMode:</code></div>
                <Radio.Group onChange={handleContentDisplayModeChange} value={contentDisplayMode}>
                    <Space direction='vertical'>
                        <Radio value={ContentDisplayMode.ActivateExistingTab}>
                            <code>ContentDisplayMode.ActivateExistingTab</code>
                        </Radio>
                        <Radio value={ContentDisplayMode.AlwaysNewTab}>
                            <code>ContentDisplayMode.AlwaysNewTab</code>
                        </Radio>
                        <Radio value={ContentDisplayMode.NoTabs}>
                            <code>ContentDisplayMode.NoTabs</code>
                        </Radio>
                    </Space>
                </Radio.Group>
            </div>
        </>
    )
}
Example #2
Source File: PasswordReset.tsx    From posthog-foss with MIT License 6 votes vote down vote up
function EmailUnavailable(): JSX.Element {
    return (
        <div>
            <div>
                Self-serve password reset is unavailable. Please <b>contact your instance administrator</b> to reset
                your password.
            </div>
            <Divider />
            <div className="mt">
                If you're an administrator:
                <ul>
                    <li>
                        Password reset is unavailable because email service is not configured.{' '}
                        <a href="https://posthog.com/docs/self-host/configure/email?utm_medium=in-product&utm_campaign=password-reset">
                            Read the docs
                        </a>{' '}
                        on how to set this up.
                    </li>
                    <li>To reset the password manually, run the following command in your instance.</li>
                </ul>
                <CodeSnippet language={Language.Bash} wrap>
                    {'python manage.py changepassword [account email]'}
                </CodeSnippet>
            </div>
        </div>
    )
}
Example #3
Source File: DatePresets.tsx    From ant-extensions with MIT License 6 votes vote down vote up
DatePresets: React.FC<BaseProps> = React.memo((props) => {
  return (
    <div className="ant-ext-sd__quickForm">
      <QuickSelect {...props} />
      <Divider />
      <QuickPresets {...props} />
    </div>
  );
})
Example #4
Source File: AdvanceSetting.tsx    From next-basics with GNU General Public License v3.0 6 votes vote down vote up
export function AdvanceSetting(props: AdvanceSettingProps): React.ReactElement {
  const fold = (
    <div style={props.foldStyle} id="foldBrickButton" className="foldContainer">
      <span>{props.foldName}</span>
      {props.showFoldIcon && (
        <UpOutlined
          rotate={props.show ? 0 : 180}
          style={{ marginLeft: "15px", lineHeight: "0px" }}
        />
      )}
    </div>
  );

  return (
    <div>
      <FormItemWrapper {...props}>
        {props.showDivider ? (
          <Divider
            dashed={props.dividerDashed}
            orientation={props.dividerOrientation}
          >
            {fold}
          </Divider>
        ) : (
          fold
        )}
      </FormItemWrapper>
      <div
        className={classNames({
          foldActive: props.show,
          foldInactive: !props.show,
        })}
      >
        <slot name="content"></slot>
      </div>
    </div>
  );
}
Example #5
Source File: index.tsx    From jetlinks-ui-antd with MIT License 6 votes vote down vote up
CheckDevice = (props: Props) => {
  const [visible, setVisible] = useState<boolean>(false);
  const [deviceId, setDeviceId] = useState<string[]>([]);
  const productId = props.props['x-component-props']?.productId;

  return (
    <div style={{ width: '100%' }}>
      <Input
        value={deviceId}
        placeholder="全部设备"
        addonAfter={<>
            <Icon type="close" onClick={() => {
                setDeviceId([]);
                props.mutators.change([])
            }} />
            <Divider type="vertical"/>
            <Icon type="plus" onClick={() => setVisible(true)} /></>}
      />
      {visible && (
        <DeviceList
          data={deviceId}
          productId={productId}
          close={() => setVisible(false)}
          save={(data: string[]) => {
            setVisible(false);
            setDeviceId(data);
            props.mutators.change(data);
          }}
        />
      )}
    </div>
  );
}
Example #6
Source File: listings-skeleton.tsx    From tinyhouse with MIT License 6 votes vote down vote up
export function ListingsSkeleton({
    title,
    error = false,
}: ListingsSkeletonProp) {
    const errorAlert = error ? (
        <Alert
            type="error"
            message={
                <>
                    Oh no! Something went wrong - please try again later
                    <span role="img" aria-label="Sad face emoji">
                        ?
                    </span>
                </>
            }
            className="listing-skeleton__alert"
        />
    ) : null;
    return (
        <div className="listings-skeleton">
            {errorAlert}
            <h2>
                {title}
                {[...Array(3)].map((_, index) => (
                    <div key={index}>
                        <Skeleton active paragraph={{ rows: 1 }} />
                        <Divider />
                    </div>
                ))}
            </h2>
        </div>
    );
}
Example #7
Source File: LoginView.tsx    From tailchat with GNU General Public License v3.0 6 votes vote down vote up
OAuthLoginView: React.FC = React.memo(() => {
  return (
    <>
      <Divider>{t('或')}</Divider>

      <div className="bg-gray-400 w-1/3 px-4 py-1 text-3xl text-center rounded-md cursor-pointer shadow-md">
        <Icon className="mx-auto" icon="mdi:github" />
      </div>
    </>
  );
})
Example #8
Source File: index.tsx    From Aragorn with MIT License 6 votes vote down vote up
About = () => {
  function handleUpdate() {
    ipcRenderer.send('check-update', true);
  }

  return (
    <div className="info-wrapper">
      <header>
        <span>关于</span>
        <Divider />
      </header>
      <main>
        <h3>Aragorn</h3>
        <a
          style={{ margin: 10 }}
          onClick={() => {
            shell.openExternal(AppUrl);
          }}
        >
          {AppUrl}
        </a>
        <p className="desc">v{remote.app.getVersion()}</p>
        <Button type="primary" onClick={handleUpdate}>
          检查更新
        </Button>
      </main>
    </div>
  );
}
Example #9
Source File: ResidentActions.tsx    From condo with MIT License 6 votes vote down vote up
ResidentAppealDropdownOverlay = () => {
    return (
        <StyledMenu>
            <MenuItem
                menuItemWrapperProps={ResidentAppealDropDownMenuItemWrapperProps}
                path={'/ticket/create'}
                icon={AppealIcon}
                label={'CreateAppeal'}
            />
            <Divider style={{ margin: 0 }}/>
            <MenuItem
                menuItemWrapperProps={ResidentAppealDropDownMenuItemWrapperProps}
                path={'/meter/create'}
                icon={MeterIcon}
                label={'CreateMeterReading'}
            />
        </StyledMenu>
    )
}
Example #10
Source File: DataTableCustomFilter.tsx    From jmix-frontend with Apache License 2.0 5 votes vote down vote up
render() {
    return (
      <Form layout='inline' onFinish={this.handleFinish} ref={this.setFormRef}>
        <div className={styles.tableFilter}>
          <div className={styles.settings}>
            <div className={styles.controlsLayout}>
              <Form.Item className={classNames(
                styles.filterControl, 
                styles.propertyCaption)
              }>
                {this.propertyCaption}
              </Form.Item>
              <Form.Item className={styles.filterControl}
                         initialValue={this.getDefaultOperator()}
                         name={`${this.props.entityProperty}_operatorsDropdown`}
              >
                <Select
                  dropdownClassName={`cuba-operator-dropdown-${this.props.entityProperty}`}
                  dropdownMatchSelectWidth={false}
                  onChange={(operator: ComparisonType) => this.changeOperator(operator)}
                >
                    {this.operatorTypeOptions}
                </Select>
              </Form.Item>
              {this.simpleFilterEditor}
            </div>
            {this.complexFilterEditor}
          </div>
          <Divider className={styles.divider} />
          <div className={styles.footer}>
            <Button htmlType='submit'
                    type='link'>
              <FormattedMessage id='jmix.dataTable.ok'/>
            </Button>
            <Button
              htmlType='button'
              type='link'
              onClick={this.resetFilter}>
              <FormattedMessage id='jmix.dataTable.reset'/>
            </Button>
          </div>
        </div>
      </Form>
    );
  }
Example #11
Source File: PathCleanFilter.tsx    From posthog-foss with MIT License 5 votes vote down vote up
export function PathRegexPopup({ item, onComplete, onClose }: PathRegexPopupProps): JSX.Element {
    const [alias, setAlias] = useState(item['alias'])
    const [regex, setRegex] = useState(item['regex'])

    return (
        <div className="regex-popup">
            <Col>
                <b>New Wildcard</b>
                <Divider style={{ marginTop: 10, marginBottom: 10 }} />
                <span>Alias</span>
                <Input
                    defaultValue={alias}
                    onChange={(e) => setAlias(e.target.value)}
                    onPressEnter={() => false}
                    style={{ marginTop: 8, marginBottom: 12 }}
                />
                <span>Regex</span>
                <Input
                    defaultValue={regex}
                    onChange={(e) => setRegex(e.target.value)}
                    onPressEnter={() => false}
                    style={{ marginTop: 8, marginBottom: 0, fontFamily: 'monospace' }}
                />
                <div className="text-muted" style={{ marginBottom: 12 }}>
                    For example: <code>\/merchant\/\d+\/dashboard$</code>
                </div>
                <Row style={{ width: '100%', justifyContent: 'flex-end', marginTop: 12 }}>
                    <Button onClick={onClose} type="link">
                        {' '}
                        Cancel{' '}
                    </Button>
                    <Button onClick={() => onComplete({ alias, regex })} type="primary">
                        {' '}
                        Save{' '}
                    </Button>
                </Row>
            </Col>
        </div>
    )
}
Example #12
Source File: ToSketchLayout.tsx    From html2sketch with MIT License 5 votes vote down vote up
ToSketchLayout: FC<FooterProps> = ({ elements, children, buttons }) => {
  const { sketchJSON, generateGroup, generateSymbol } = useSketchJSON();
  const [showJSON, setShowJSON] = useState(false);

  return (
    <div>
      {children}
      <Divider dashed />
      <Row style={{ zIndex: 99999 }}>
        <Col span={24}>
          <Row justify="space-between">
            <Col>
              <Button
                disabled={!sketchJSON}
                onClick={() => {
                  setShowJSON(!showJSON);
                }}
              >
                {showJSON ? '隐藏' : '显示'} JSON
              </Button>
            </Col>
            <Col>
              <Space>
                {buttons?.map((button) => (
                  <Button key={button.name} onClick={button.onClick}>
                    {button.name}
                  </Button>
                ))}
                <Button
                  onClick={() => {
                    generateGroup(elements);
                  }}
                >
                  转换为 Group
                </Button>
                <Button
                  type="primary"
                  onClick={() => {
                    generateSymbol(elements);
                  }}
                >
                  转换为 Symbol
                </Button>
              </Space>
            </Col>
          </Row>
        </Col>
        {showJSON ? (
          <Col span={24}>
            <Card>
              <ReactJson name="Sketch JSON" src={sketchJSON || {}} />
            </Card>
          </Col>
        ) : null}
      </Row>
    </div>
  );
}
Example #13
Source File: AppBar.tsx    From next-basics with GNU General Public License v3.0 5 votes vote down vote up
export function AppBar({
  pageTitle,
  breadcrumb,
  documentId,
  noCurrentApp,
}: AppBarProps): React.ReactElement {
  const hideLaunchpadButton = React.useMemo(
    () => getRuntime().getFeatureFlags()["hide-launchpad-button"],
    []
  );

  const licenseInfoEnabled = React.useMemo(
    () => getRuntime().getFeatureFlags()["license-expires-detection"],
    []
  );

  React.useEffect(() => {
    const baseTitle = getRuntime().getBrandSettings().base_title;
    document.title = pageTitle ? `${pageTitle} - ${baseTitle}` : baseTitle;
  }, [pageTitle]);

  const username = getAuth().username;

  React.useEffect(() => {
    (async () => {
      if (licenseInfoEnabled && username) {
        try {
          const { expires, updating } = await CustomerApi_getExpiration();
          // org 为延期中的不提示
          !updating && processLiscenseExpires(expires);
        } catch (error) {
          // eslint-disable-next-line no-empty
        }
      }
    })();
  }, [username]);

  return (
    <div className={styles.appBar} id="app-bar">
      <div className={styles.titleContainer}>
        {!hideLaunchpadButton && (
          <>
            <LaunchpadButton />
            <Divider
              type="vertical"
              style={{ height: 24, margin: "0 16px", top: 0 }}
            />
          </>
        )}

        <AppBarBreadcrumb breadcrumb={breadcrumb} noCurrentApp={noCurrentApp} />
      </div>
      <div className={styles.actionsContainer}>
        <AppDocumentLink documentId={documentId} />
        <AppSetting />
      </div>
    </div>
  );
}
Example #14
Source File: index.tsx    From erda-ui with GNU Affero General Public License v3.0 5 votes vote down vote up
function renderActions<T extends object = any>(actions?: IActions<T>): Array<ColumnProps<T>> {
  if (actions) {
    const { width, render, limitNum } = actions;
    return [
      {
        title: i18n.t('Operations'),
        width,
        dataIndex: 'operation',
        ellipsis: true,
        fixed: 'right',
        render: (_: any, record: T) => {
          const list = render(record);

          const menu = (limitNum || limitNum === 0) && (
            <Menu>
              {list.slice(limitNum).map((item) => (
                <Menu.Item key={item.title} onClick={item.onClick}>
                  <span className="fake-link mr-1">{item.title}</span>
                </Menu.Item>
              ))}
            </Menu>
          );

          return (
            <span className="operate-list">
              {list.slice(0, limitNum).map((item, index: number) => (
                <>
                  {index !== 0 && <Divider type="vertical" />}
                  <span className="fake-link mr-1 align-middle" key={item.title} onClick={item.onClick}>
                    {item.title}
                  </span>
                </>
              ))}
              {menu && (
                <Dropdown overlay={menu} align={{ offset: [0, 5] }}>
                  <Icon />
                </Dropdown>
              )}
            </span>
          );
        },
      },
    ];
  } else {
    return [];
  }
}
Example #15
Source File: Button.tsx    From slim with Apache License 2.0 5 votes vote down vote up
render (): React.ReactNode {
    const Icon = this.props.icon
    if (Icon === undefined) {
      return null
    }

    let text
    if (this.props.label != null) {
      text = (
        <>
          <Divider type='vertical' />
          {this.props.label}
        </>
      )
    }

    let button
    if (this.props.isSelected ?? false) {
      button = (
        <Btn
          onClick={this.handleClick}
          icon={<Icon />}
          type='primary'
          style={{ lineHeight: '1.0' }}
        >
          {text}
        </Btn>
      )
    } else {
      button = (
        <Btn
          onClick={this.handleClick}
          icon={<Icon />}
          type='default'
          style={{ lineHeight: '1.0' }}
        >
          {text}
        </Btn>
      )
    }

    if (this.props.tooltip !== undefined) {
      return (
        <Tooltip title={this.props.tooltip}>
          {button}
        </Tooltip>
      )
    } else {
      return button
    }
  }
Example #16
Source File: index.tsx    From jetlinks-ui-antd with MIT License 5 votes vote down vote up
FunctionDebug: React.FC<Props> = props => {
  const { item } = props;
  const initState: State = {
    debugData: "",
    logs: "",
  };

  const [debugData, setDebugData] = useState(initState.debugData);
  const [logs, setLogs] = useState(initState.logs);

  const debugMqttClient = () => {
    apis.deviceInstance
      .invokedFunction(props.deviceId, props.type,JSON.parse(debugData))
      .then(response => {
        const tempResult = response?.result;
        if (response.status === 200) {
          setLogs(tempResult);
        }else{
          setLogs("调试错误");
        }
      }).catch(() => {
        setLogs(`调试错误`);
    });
  };

  return (
    <Modal
      visible
      width={840}
      title={item.name}
      onCancel={() => props.close()}
      footer={
        <Fragment>
          <Button
            type="primary"
            onClick={() => {
              debugMqttClient();
            }}
          >
            执行
          </Button>
          <Divider type="vertical" />
          <Button type="ghost" onClick={() => setLogs('')}>
            清空
          </Button>
        </Fragment>
      }
    >
      <Form labelCol={{ span: 2 }} wrapperCol={{ span: 22 }}>
        <Form.Item label="参数:">
          <Input.TextArea
            rows={4}
            value={debugData}
            onChange={e => {
              setDebugData(e.target.value);
            }}
            placeholder="参数必须JSON格式"
          />
        </Form.Item>

        <Divider>调试日志</Divider>
        <Input.TextArea rows={4} value={logs} />
      </Form>
    </Modal>
  );
}
Example #17
Source File: index.tsx    From tinyhouse with MIT License 5 votes vote down vote up
export function ListingBookings({
    listingBookings,
    bookingsPage,
    limit,
    setBookingsPage,
}: ListingBookingsProps) {
    const total = listingBookings ? listingBookings.total : null;
    const result = listingBookings ? listingBookings.result : null;

    const listingBookingsList = listingBookings ? (
        <List
            grid={{
                gutter: 8,
                xs: 1,
                sm: 2,
                lg: 3,
            }}
            dataSource={result ? result : undefined}
            locale={{ emptyText: "No bookings have been made yet!" }}
            pagination={{
                current: bookingsPage,
                total: total ? total : undefined,
                defaultPageSize: limit,
                hideOnSinglePage: true,
                showLessItems: true,
                onChange: (page: number) => setBookingsPage(page),
            }}
            renderItem={(listingBooking) => {
                const bookingHistory = (
                    <div className="listing-bookings__history">
                        <div>
                            Check in:{" "}
                            <Text strong>{listingBooking.checkIn}</Text>
                        </div>
                        <div>
                            Check out:{" "}
                            <Text strong>{listingBooking.checkOut}</Text>
                        </div>
                    </div>
                );

                return (
                    <List.Item className="listing-bookings__item">
                        {bookingHistory}
                        <Link to={`/user/${listingBooking.tenant.id}`}>
                            <Avatar
                                src={listingBooking.tenant.avatar}
                                size={64}
                                shape="square"
                            />
                        </Link>
                    </List.Item>
                );
            }}
        />
    ) : null;

    const listingBookingsElement = listingBookingsList ? (
        <div className="listing-bookings">
            <Divider />
            <div className="listing-bookings__section">
                <Title level={4}>Bookings</Title>
            </div>
            {listingBookingsList}
        </div>
    ) : null;

    return listingBookingsElement;
}
Example #18
Source File: index.tsx    From metaplex with Apache License 2.0 5 votes vote down vote up
AdminView = () => {
  const { store, whitelistedCreatorsByCreator, isLoading } = useMeta();
  const connection = useConnection();
  const wallet = useWallet();
  const { setVisible } = useWalletModal();
  const connect = useCallback(
    () => (wallet.wallet ? wallet.connect().catch() : setVisible(true)),
    [wallet.wallet, wallet.connect, setVisible],
  );
  const { storeAddress, setStoreForOwner, isConfigured } = useStore();

  useEffect(() => {
    if (
      !store &&
      !storeAddress &&
      wallet.publicKey &&
      !process.env.NEXT_PUBLIC_STORE_OWNER_ADDRESS
    ) {
      setStoreForOwner(wallet.publicKey.toBase58());
    }
  }, [store, storeAddress, wallet.publicKey]);
  console.log('@admin', wallet.connected, storeAddress, isLoading, store);

  return (
    <>
      {!wallet.connected ? (
        <p>
          <Button type="primary" className="app-btn" onClick={connect}>
            Connect
          </Button>{' '}
          to admin store.
        </p>
      ) : !storeAddress || isLoading ? (
        <Spin />
      ) : store && wallet ? (
        <>
          <InnerAdminView
            store={store}
            whitelistedCreatorsByCreator={whitelistedCreatorsByCreator}
            connection={connection}
            wallet={wallet}
            connected={wallet.connected}
          />
          {!isConfigured && (
            <>
              <Divider />
              <Divider />
              <p>
                To finish initialization please copy config below into{' '}
                <b>packages/web/.env</b> and restart yarn or redeploy
              </p>
              <SetupVariables
                storeAddress={storeAddress}
                storeOwnerAddress={wallet.publicKey?.toBase58()}
              />
            </>
          )}
        </>
      ) : (
        <>
          <p>Store is not initialized</p>
          <Link to={`/`}>Go to initialize</Link>
        </>
      )}
    </>
  );
}
Example #19
Source File: Item.tsx    From tailchat with GNU General Public License v3.0 5 votes vote down vote up
/**
 * 构造聊天项
 */
export function buildMessageItemRow(
  messages: ChatMessage[],
  messageId: string
) {
  const index = findMessageIndexWithId(messages, messageId); // TODO: 这里是因为mattermost的动态列表传的id因此只能这边再用id找回,可以看看是否可以优化
  if (index === -1) {
    return <div />;
  }

  const message = messages[index];

  let showDate = true;
  let showAvatar = true;
  const messageCreatedAt = new Date(message.createdAt ?? '');
  if (index > 0) {
    // 当不是第一条数据时

    // 进行时间合并
    const prevMessage = messages[index - 1];
    if (
      !shouldShowMessageTime(
        new Date(prevMessage.createdAt ?? ''),
        messageCreatedAt
      )
    ) {
      showDate = false;
    }

    // 进行头像合并(在同一时间块下 且发送者为同一人)
    if (showDate === false) {
      showAvatar =
        prevMessage.author !== message.author || prevMessage.hasRecall === true;
    }
  }

  return (
    <div key={message._id}>
      {showDate && (
        <Divider className="text-sm opacity-40 px-6 font-normal select-text">
          {getMessageTimeDiff(messageCreatedAt)}
        </Divider>
      )}
      <ChatMessageItem showAvatar={showAvatar} payload={message} />
    </div>
  );
}
Example #20
Source File: index.tsx    From fe-v5 with Apache License 2.0 5 votes vote down vote up
index = (_props: any) => {
  const history = useHistory();
  const { t, i18n } = useTranslation();
  const [query, setQuery] = useState('');
  const [mine, setMine] = useState(true);
  const [days, setDays] = useState(7);
  const { curBusiItem } = useSelector<RootState, CommonStoreState>((state) => state.common);
  const { tableProps } = useAntdTable((options) => getTableData(options, curBusiItem.id, query, mine, days), { refreshDeps: [curBusiItem.id, query, mine, days] });
  const columns: ColumnProps<DataItem>[] = [
    {
      title: 'ID',
      dataIndex: 'id',
      width: 100,
    },
    {
      title: t('task.title'),
      dataIndex: 'title',
      width: 200,
      render: (text, record) => {
        return <Link to={{ pathname: `/job-tasks/${record.id}/result` }}>{text}</Link>;
      },
    },
    {
      title: t('table.operations'),
      width: 150,
      render: (_text, record) => {
        return (
          <span>
            <Link to={{ pathname: '/job-tasks/add', search: `task=${record.id}` }}>{t('task.clone')}</Link>
            <Divider type='vertical' />
            <Link to={{ pathname: `/job-tasks/${record.id}/detail` }}>{t('task.meta')}</Link>
          </span>
        );
      },
    },
    {
      title: t('task.creator'),
      dataIndex: 'create_by',
      width: 100,
    },
    {
      title: t('task.created'),
      dataIndex: 'create_at',
      width: 160,
      render: (text) => {
        return moment.unix(text).format('YYYY-MM-DD HH:mm:ss');
      },
    },
  ];
  return (
    <PageLayout
      hideCluster
      title={
        <>
          <CodeOutlined />
          {t('执行历史')}
        </>
      }
    >
      <div style={{ display: 'flex' }}>
        <LeftTree></LeftTree>
        {curBusiItem.id ? (
          <div style={{ flex: 1, padding: 10 }}>
            <Row>
              <Col span={16} className='mb10'>
                <Input
                  style={{ width: 200, marginRight: 10 }}
                  prefix={<SearchOutlined />}
                  defaultValue={query}
                  onPressEnter={(e) => {
                    setQuery(e.currentTarget.value);
                  }}
                  placeholder='搜索标题'
                />
                <Select
                  style={{ marginRight: 10 }}
                  value={days}
                  onChange={(val: number) => {
                    setDays(val);
                  }}
                >
                  <Select.Option value={7}>{t('last.7.days')}</Select.Option>
                  <Select.Option value={15}>{t('last.15.days')}</Select.Option>
                  <Select.Option value={30}>{t('last.30.days')}</Select.Option>
                  <Select.Option value={60}>{t('last.60.days')}</Select.Option>
                  <Select.Option value={90}>{t('last.90.days')}</Select.Option>
                </Select>
                <Checkbox
                  checked={mine}
                  onChange={(e) => {
                    setMine(e.target.checked);
                  }}
                >
                  {t('task.only.mine')}
                </Checkbox>
              </Col>
              <Col span={8} style={{ textAlign: 'right' }}>
                <Button
                  type='primary'
                  ghost
                  onClick={() => {
                    history.push('/job-tasks/add');
                  }}
                >
                  {t('task.temporary.create')}
                </Button>
              </Col>
            </Row>
            <Table
              rowKey='id'
              columns={columns as any}
              {...(tableProps as any)}
              pagination={
                {
                  ...tableProps.pagination,
                  showSizeChanger: true,
                  pageSizeOptions: ['10', '50', '100', '500', '1000'],
                  showTotal: (total) => {
                    return i18n.language == 'en' ? `Total ${total} items` : `共 ${total} 条`;
                  },
                } as any
              }
            />
          </div>
        ) : (
          <BlankBusinessPlaceholder text={t('执行历史')}></BlankBusinessPlaceholder>
        )}
      </div>
    </PageLayout>
  );
}
Example #21
Source File: index.tsx    From Aragorn with MIT License 5 votes vote down vote up
Profile = () => {
  const {
    state: {
      uploaderProfiles,
      configuration: { defaultUploaderProfileId }
    }
  } = useAppContext();

  const { id } = useParams<{ id: string }>();

  const [curUploaderProfileId, setCurUploaderProfileId] = useState('');

  const uploaderProfileFormRef = useRef({} as UploaderProfileFormHandle);

  useEffect(() => {
    const currentId = id || (defaultUploaderProfileId as string);
    handleUploaderProfileChange(currentId);
  }, []);

  const handleUploaderProfileChange = (id: string) => {
    setCurUploaderProfileId(id);
    uploaderProfileFormRef.current.handleUploaderProfilesSelect(id);
  };

  const handleSubmit = () => {
    uploaderProfileFormRef.current.handleSubmit();
  };

  const handleDelete = () => {
    uploaderProfileFormRef.current.handleDelete();
  };

  const handleTest = () => {
    uploaderProfileFormRef.current.handleTest();
  };

  return (
    <div className="profile-page">
      <header>
        <span>上传器配置</span>
        <Divider />
      </header>
      <div className="header-menu">
        <Select
          style={{ minWidth: 120 }}
          value={curUploaderProfileId || '请选择'}
          onChange={handleUploaderProfileChange}
        >
          {uploaderProfiles.map(item => (
            <Select.Option key={item.name} value={item.id}>
              {item.name}
            </Select.Option>
          ))}
        </Select>
      </div>
      <main>
        <UploaderProfileForm ref={uploaderProfileFormRef} />
      </main>
      <footer>
        <Divider />
        <Space>
          <Button type="primary" onClick={handleSubmit}>
            更新配置
          </Button>
          <Button danger onClick={handleDelete}>
            删除
          </Button>
          <Button onClick={handleTest}>测试</Button>
        </Space>
      </footer>
    </div>
  );
}
Example #22
Source File: palette.tsx    From jmix-frontend with Apache License 2.0 4 votes vote down vote up
palette = () => (
  <Palette>
    <Category name="Text">
      <Component name="Formatted Message">
        <Variant>
          <FormattedMessage />
        </Variant>
      </Component>
      <Component name="Heading">
        <Variant name="h1">
          <Typography.Title></Typography.Title>
        </Variant>
        <Variant name="h2">
          <Typography.Title level={2}></Typography.Title>
        </Variant>
        <Variant name="h3">
          <Typography.Title level={3}></Typography.Title>
        </Variant>
        <Variant name="h4">
          <Typography.Title level={4}></Typography.Title>
        </Variant>
        <Variant name="h5">
          <Typography.Title level={5}></Typography.Title>
        </Variant>
      </Component>
      <Component name="Text">
        <Variant>
          <Typography.Text></Typography.Text>
        </Variant>
        <Variant name="Secondary">
          <Typography.Text type="secondary"></Typography.Text>
        </Variant>
        <Variant name="Success">
          <Typography.Text type="success"></Typography.Text>
        </Variant>
        <Variant name="Warning">
          <Typography.Text type="warning"></Typography.Text>
        </Variant>
        <Variant name="Danger">
          <Typography.Text type="danger"></Typography.Text>
        </Variant>
        <Variant name="Disabled">
          <Typography.Text disabled></Typography.Text>
        </Variant>
      </Component>
    </Category>
    <Category name="Layout">
      <Component name="Divider">
        <Variant>
          <Divider />
        </Variant>
      </Component>

      <Component name="Grid">
        <Variant name="Simple Row">
          <Row></Row>
        </Variant>
        <Variant name="Two columns">
          <Row>
            <Col span={12}></Col>
            <Col span={12}></Col>
          </Row>
        </Variant>
        <Variant name="Three columns">
          <Row>
            <Col span={8}></Col>
            <Col span={8}></Col>
            <Col span={8}></Col>
          </Row>
        </Variant>
      </Component>

      <Component name="Space">
        <Variant>
          <Space />
        </Variant>
        <Variant name="Small">
          <Space size={"small"} />
        </Variant>
        <Variant name="Large">
          <Space size={"large"} />
        </Variant>
      </Component>
    </Category>
    <Category name="Controls">
      <Component name="Autocomplete">
        <Variant>
          <AutoComplete placeholder="input here" />
        </Variant>
      </Component>

      <Component name="Button">
        <Variant>
          <Button></Button>
        </Variant>
        <Variant name="Primary">
          <Button type="primary"></Button>
        </Variant>
        <Variant name="Link">
          <Button type="link"></Button>
        </Variant>
        <Variant name="Dropdown">
          <Dropdown
            trigger={["click"]}
            overlay={
              <Menu>
                <Menu.Item></Menu.Item>
                <Menu.Item></Menu.Item>
                <Menu.Item></Menu.Item>
              </Menu>
            }
          >
            <Button></Button>
          </Dropdown>
        </Variant>
      </Component>

      <Component name="Checkbox">
        <Variant>
          <Checkbox />
        </Variant>
      </Component>

      <Component name="Switch">
        <Variant>
          <Switch />
        </Variant>
      </Component>

      <Component name="Radio Group">
        <Variant>
          <Radio.Group>
            <Radio value={1}>A</Radio>
            <Radio value={2}>B</Radio>
            <Radio value={3}>C</Radio>
            <Radio value={4}>D</Radio>
          </Radio.Group>
        </Variant>
        <Variant name="Button">
          <Radio.Group>
            <Radio.Button value={1}>A</Radio.Button>
            <Radio.Button value={2}>B</Radio.Button>
            <Radio.Button value={3}>C</Radio.Button>
            <Radio.Button value={4}>D</Radio.Button>
          </Radio.Group>
        </Variant>
      </Component>

      <Component name="DatePicker">
        <Variant>
          <DatePicker />
        </Variant>
        <Variant name="Range">
          <DatePicker.RangePicker />
        </Variant>
      </Component>

      <Component name="TimePicker">
        <Variant>
          <TimePicker />
        </Variant>
        <Variant name="Range">
          <TimePicker.RangePicker />
        </Variant>
      </Component>

      <Component name="Input">
        <Variant>
          <Input />
        </Variant>
        <Variant name="Number">
          <InputNumber />
        </Variant>
      </Component>

      <Component name="Select">
        <Variant>
          <Select defaultValue="1">
            <Select.Option value="1">1</Select.Option>
            <Select.Option value="2">2</Select.Option>
          </Select>
        </Variant>
        <Variant name="Multiple">
          <Select defaultValue={["1"]} mode="multiple" allowClear>
            <Select.Option value="1">1</Select.Option>
            <Select.Option value="2">2</Select.Option>
          </Select>
        </Variant>
      </Component>

      <Component name="Link">
        <Variant>
          <Typography.Link href="" target="_blank"></Typography.Link>
        </Variant>
      </Component>

      <Component name="Slider">
        <Variant>
          <Slider defaultValue={30} />
        </Variant>
        <Variant name="Range">
          <Slider range defaultValue={[20, 50]} />
        </Variant>
      </Component>
    </Category>
    <Category name="Data Display">
      <Component name="Field">
        <Variant>
          <Field
            entityName={ENTITY_NAME}
            disabled={readOnlyMode}
            propertyName=""
            formItemProps={{
              style: { marginBottom: "12px" }
            }}
          />
        </Variant>
      </Component>
      <Component name="Card">
        <Variant>
          <Card />
        </Variant>
        <Variant name="With Title">
          <Card>
            <Card title="Card title">
              <p>Card content</p>
            </Card>
          </Card>
        </Variant>
        <Variant name="My custom card">
          <Card>
            <Card title="Card title">
              <p>Card content</p>
              <Avatar />
            </Card>
          </Card>
        </Variant>
      </Component>
      <Component name="Tabs">
        <Variant>
          <Tabs defaultActiveKey="1">
            <Tabs.TabPane tab="Tab 1" key="1">
              Content of Tab Pane 1
            </Tabs.TabPane>
            <Tabs.TabPane tab="Tab 2" key="2">
              Content of Tab Pane 2
            </Tabs.TabPane>
            <Tabs.TabPane tab="Tab 3" key="3">
              Content of Tab Pane 3
            </Tabs.TabPane>
          </Tabs>
        </Variant>
        <Variant name="Tab Pane">
          <Tabs.TabPane></Tabs.TabPane>
        </Variant>
      </Component>
      <Component name="Collapse">
        <Variant>
          <Collapse defaultActiveKey="1">
            <Collapse.Panel
              header="This is panel header 1"
              key="1"
            ></Collapse.Panel>
            <Collapse.Panel
              header="This is panel header 2"
              key="2"
            ></Collapse.Panel>
            <Collapse.Panel
              header="This is panel header 3"
              key="3"
            ></Collapse.Panel>
          </Collapse>
        </Variant>
      </Component>
      <Component name="Image">
        <Variant>
          <Image width={200} src="" />
        </Variant>
      </Component>
      <Component name="Avatar">
        <Variant>
          <Avatar icon={<UserOutlined />} />
        </Variant>
        <Variant name="Image">
          <Avatar src="https://joeschmoe.io/api/v1/random" />
        </Variant>
      </Component>
      <Component name="Badge">
        <Variant>
          <Badge count={1}></Badge>
        </Variant>
      </Component>
      <Component name="Statistic">
        <Variant>
          <Statistic title="Title" value={112893} />
        </Variant>
      </Component>
      <Component name="Alert">
        <Variant name="Success">
          <Alert message="Text" type="success" />
        </Variant>
        <Variant name="Info">
          <Alert message="Text" type="info" />
        </Variant>
        <Variant name="Warning">
          <Alert message="Text" type="warning" />
        </Variant>
        <Variant name="Error">
          <Alert message="Text" type="error" />
        </Variant>
      </Component>
      <Component name="List">
        <Variant>
          <List
            bordered
            dataSource={[]}
            renderItem={item => <List.Item></List.Item>}
          />
        </Variant>
      </Component>
    </Category>
    <Category name="Icons">
      <Component name="Arrow">
        <Variant name="Up">
          <ArrowUpOutlined />
        </Variant>
        <Variant name="Down">
          <ArrowDownOutlined />
        </Variant>
        <Variant name="Left">
          <ArrowLeftOutlined />
        </Variant>
        <Variant name="Right">
          <ArrowRightOutlined />
        </Variant>
      </Component>
      <Component name="Question">
        <Variant>
          <QuestionOutlined />
        </Variant>
        <Variant name="Circle">
          <QuestionCircleOutlined />
        </Variant>
      </Component>
      <Component name="Plus">
        <Variant>
          <PlusOutlined />
        </Variant>
        <Variant name="Circle">
          <PlusCircleOutlined />
        </Variant>
      </Component>
      <Component name="Info">
        <Variant>
          <InfoOutlined />
        </Variant>
        <Variant name="Circle">
          <InfoCircleOutlined />
        </Variant>
      </Component>
      <Component name="Exclamation">
        <Variant>
          <ExclamationOutlined />
        </Variant>
        <Variant name="Circle">
          <ExclamationCircleOutlined />
        </Variant>
      </Component>
      <Component name="Close">
        <Variant>
          <CloseOutlined />
        </Variant>
        <Variant name="Circle">
          <CloseCircleOutlined />
        </Variant>
      </Component>
      <Component name="Check">
        <Variant>
          <CheckOutlined />
        </Variant>
        <Variant name="Circle">
          <CheckCircleOutlined />
        </Variant>
      </Component>
      <Component name="Edit">
        <Variant>
          <EditOutlined />
        </Variant>
      </Component>
      <Component name="Copy">
        <Variant>
          <CopyOutlined />
        </Variant>
      </Component>
      <Component name="Delete">
        <Variant>
          <DeleteOutlined />
        </Variant>
      </Component>
      <Component name="Bars">
        <Variant>
          <BarsOutlined />
        </Variant>
      </Component>
      <Component name="Bell">
        <Variant>
          <BellOutlined />
        </Variant>
      </Component>
      <Component name="Clear">
        <Variant>
          <ClearOutlined />
        </Variant>
      </Component>
      <Component name="Download">
        <Variant>
          <DownloadOutlined />
        </Variant>
      </Component>
      <Component name="Upload">
        <Variant>
          <UploadOutlined />
        </Variant>
      </Component>
      <Component name="Sync">
        <Variant>
          <SyncOutlined />
        </Variant>
      </Component>
      <Component name="Save">
        <Variant>
          <SaveOutlined />
        </Variant>
      </Component>
      <Component name="Search">
        <Variant>
          <SearchOutlined />
        </Variant>
      </Component>
      <Component name="Settings">
        <Variant>
          <SettingOutlined />
        </Variant>
      </Component>
      <Component name="Paperclip">
        <Variant>
          <PaperClipOutlined />
        </Variant>
      </Component>
      <Component name="Phone">
        <Variant>
          <PhoneOutlined />
        </Variant>
      </Component>
      <Component name="Mail">
        <Variant>
          <MailOutlined />
        </Variant>
      </Component>
      <Component name="Home">
        <Variant>
          <HomeOutlined />
        </Variant>
      </Component>
      <Component name="Contacts">
        <Variant>
          <ContactsOutlined />
        </Variant>
      </Component>
      <Component name="User">
        <Variant>
          <UserOutlined />
        </Variant>
        <Variant name="Add">
          <UserAddOutlined />
        </Variant>
        <Variant name="Remove">
          <UserDeleteOutlined />
        </Variant>
      </Component>
      <Component name="Team">
        <Variant>
          <TeamOutlined />
        </Variant>
      </Component>
    </Category>
    <Category name="Screens">
      <Component name="ExampleCustomScreen">
        <Variant>
          <ExampleCustomScreen />
        </Variant>
      </Component>
      <Component name="CustomEntityFilterTest">
        <Variant>
          <CustomEntityFilterTest />
        </Variant>
      </Component>
      <Component name="CustomFormControls">
        <Variant>
          <CustomFormControls />
        </Variant>
      </Component>
      <Component name="CustomDataDisplayComponents">
        <Variant>
          <CustomDataDisplayComponents />
        </Variant>
      </Component>
      <Component name="CustomAppLayouts">
        <Variant>
          <CustomAppLayouts />
        </Variant>
      </Component>
      <Component name="CustomControls">
        <Variant>
          <CustomControls />
        </Variant>
      </Component>
      <Component name="ErrorBoundaryTests">
        <Variant>
          <ErrorBoundaryTests />
        </Variant>
      </Component>
      <Component name="TestBlankScreen">
        <Variant>
          <TestBlankScreen />
        </Variant>
      </Component>
      <Component name="CarEditor">
        <Variant>
          <CarEditor />
        </Variant>
      </Component>
      <Component name="CarBrowserCards">
        <Variant>
          <CarBrowserCards />
        </Variant>
      </Component>
      <Component name="CarBrowserList">
        <Variant>
          <CarBrowserList />
        </Variant>
      </Component>
      <Component name="CarBrowserTable">
        <Variant>
          <CarBrowserTable />
        </Variant>
      </Component>
      <Component name="CarCardsGrid">
        <Variant>
          <CarCardsGrid />
        </Variant>
      </Component>
      <Component name="FavoriteCars">
        <Variant>
          <FavoriteCars />
        </Variant>
      </Component>
      <Component name="CarCardsWithDetails">
        <Variant>
          <CarCardsWithDetails />
        </Variant>
      </Component>
      <Component name="CarTableWithFilters">
        <Variant>
          <CarTableWithFilters />
        </Variant>
      </Component>
      <Component name="CarMasterDetail">
        <Variant>
          <CarMasterDetail />
        </Variant>
      </Component>
      <Component name="FormWizardCompositionO2O">
        <Variant>
          <FormWizardCompositionO2O />
        </Variant>
      </Component>
      <Component name="FormWizardEditor">
        <Variant>
          <FormWizardEditor />
        </Variant>
      </Component>
      <Component name="FormWizardBrowserTable">
        <Variant>
          <FormWizardBrowserTable />
        </Variant>
      </Component>
      <Component name="CarMultiSelectionTable">
        <Variant>
          <CarMultiSelectionTable />
        </Variant>
      </Component>
      <Component name="DatatypesTestEditor">
        <Variant>
          <DatatypesTestEditor />
        </Variant>
      </Component>
      <Component name="DatatypesTestBrowserCards">
        <Variant>
          <DatatypesTestBrowserCards />
        </Variant>
      </Component>
      <Component name="DatatypesTestBrowserList">
        <Variant>
          <DatatypesTestBrowserList />
        </Variant>
      </Component>
      <Component name="DatatypesTestBrowserTable">
        <Variant>
          <DatatypesTestBrowserTable />
        </Variant>
      </Component>
      <Component name="DatatypesTestCards">
        <Variant>
          <DatatypesTestCards />
        </Variant>
      </Component>
      <Component name="AssociationO2OEditor">
        <Variant>
          <AssociationO2OEditor />
        </Variant>
      </Component>
      <Component name="AssociationO2OBrowserTable">
        <Variant>
          <AssociationO2OBrowserTable />
        </Variant>
      </Component>
      <Component name="AssociationO2MEditor">
        <Variant>
          <AssociationO2MEditor />
        </Variant>
      </Component>
      <Component name="AssociationO2MBrowserTable">
        <Variant>
          <AssociationO2MBrowserTable />
        </Variant>
      </Component>
      <Component name="AssociationM2OEditor">
        <Variant>
          <AssociationM2OEditor />
        </Variant>
      </Component>
      <Component name="AssociationM2OBrowserTable">
        <Variant>
          <AssociationM2OBrowserTable />
        </Variant>
      </Component>
      <Component name="AssociationM2MEditor">
        <Variant>
          <AssociationM2MEditor />
        </Variant>
      </Component>
      <Component name="AssociationM2MBrowserTable">
        <Variant>
          <AssociationM2MBrowserTable />
        </Variant>
      </Component>
      <Component name="CompositionO2OEditor">
        <Variant>
          <CompositionO2OEditor />
        </Variant>
      </Component>
      <Component name="CompositionO2OBrowserTable">
        <Variant>
          <CompositionO2OBrowserTable />
        </Variant>
      </Component>
      <Component name="CompositionO2MEditor">
        <Variant>
          <CompositionO2MEditor />
        </Variant>
      </Component>
      <Component name="CompositionO2MBrowserTable">
        <Variant>
          <CompositionO2MBrowserTable />
        </Variant>
      </Component>
      <Component name="DeeplyNestedTestEntityEditor">
        <Variant>
          <DeeplyNestedTestEntityEditor />
        </Variant>
      </Component>
      <Component name="DeeplyNestedO2MTestEntityTable">
        <Variant>
          <DeeplyNestedO2MTestEntityTable />
        </Variant>
      </Component>
      <Component name="DeeplyNestedO2MTestEntityEditor">
        <Variant>
          <DeeplyNestedO2MTestEntityEditor />
        </Variant>
      </Component>
      <Component name="IntIdEditor">
        <Variant>
          <IntIdEditor />
        </Variant>
      </Component>
      <Component name="IntIdBrowserTable">
        <Variant>
          <IntIdBrowserTable />
        </Variant>
      </Component>
      <Component name="IntIdBrowserCards">
        <Variant>
          <IntIdBrowserCards />
        </Variant>
      </Component>
      <Component name="IntIdBrowserList">
        <Variant>
          <IntIdBrowserList />
        </Variant>
      </Component>
      <Component name="IntIdentityIdCards">
        <Variant>
          <IntIdentityIdCards />
        </Variant>
      </Component>
      <Component name="IntIdentityIdEditor">
        <Variant>
          <IntIdentityIdEditor />
        </Variant>
      </Component>
      <Component name="IntIdentityIdBrowserTable">
        <Variant>
          <IntIdentityIdBrowserTable />
        </Variant>
      </Component>
      <Component name="IntIdentityIdBrowserCards">
        <Variant>
          <IntIdentityIdBrowserCards />
        </Variant>
      </Component>
      <Component name="IntIdentityIdBrowserList">
        <Variant>
          <IntIdentityIdBrowserList />
        </Variant>
      </Component>
      <Component name="StringIdCards">
        <Variant>
          <StringIdCards />
        </Variant>
      </Component>
      <Component name="StringIdMgtCardsEdit">
        <Variant>
          <StringIdMgtCardsEdit />
        </Variant>
      </Component>
      <Component name="StringIdBrowserCards">
        <Variant>
          <StringIdBrowserCards />
        </Variant>
      </Component>
      <Component name="StringIdBrowserList">
        <Variant>
          <StringIdBrowserList />
        </Variant>
      </Component>
      <Component name="StringIdBrowserTable">
        <Variant>
          <StringIdBrowserTable />
        </Variant>
      </Component>
      <Component name="WeirdStringIdEditor">
        <Variant>
          <WeirdStringIdEditor />
        </Variant>
      </Component>
      <Component name="WeirdStringIdBrowserCards">
        <Variant>
          <WeirdStringIdBrowserCards />
        </Variant>
      </Component>
      <Component name="WeirdStringIdBrowserList">
        <Variant>
          <WeirdStringIdBrowserList />
        </Variant>
      </Component>
      <Component name="WeirdStringIdBrowserTable">
        <Variant>
          <WeirdStringIdBrowserTable />
        </Variant>
      </Component>
      <Component name="BoringStringIdEditor">
        <Variant>
          <BoringStringIdEditor />
        </Variant>
      </Component>
      <Component name="BoringStringIdBrowserTable">
        <Variant>
          <BoringStringIdBrowserTable />
        </Variant>
      </Component>
      <Component name="TrickyIdEditor">
        <Variant>
          <TrickyIdEditor />
        </Variant>
      </Component>
      <Component name="TrickyIdBrowserTable">
        <Variant>
          <TrickyIdBrowserTable />
        </Variant>
      </Component>
    </Category>
  </Palette>
)
Example #23
Source File: Cart.tsx    From Shopping-Cart with MIT License 4 votes vote down vote up
Cart = () => {
  const dispatch = useDispatch();
  const { isLoading, items } = useSelector(cartedProductSelector);
  const { tableDataSource, recommend } = useSelector(
    paymentCartedProductSelector,
  );

  useEffect(() => {
    if (storageService.getItem('cart-class101')) {
      dispatch(
        fetchCartedProductListAsync.request({
          productIdList: JSON.parse(
            storageService.getItem('cart-class101') as string,
          ),
        }),
      );
      dispatch(fetchPaymentCartedProductListAsync.request({ id: [] }));
    }
  }, [storageService.getItem]);

  const handleCartTableClick = useCallback(() => {
    storageService.removeItem('cart-class101');
    dispatch(fetchCartedProductListAsync.request({}));
  }, [storageService.removeItem]);

  const handleCartTableChange = useCallback(
    (id: ProductModel['id'], quantity: number) => {
      dispatch(fetchCartedProductListEditAsync.request({ id, quantity }));
    },
    [dispatch],
  );

  const handleSelectChange = useCallback(
    (selectedRowKeys: any, selectedRows: any) => {
      // antd에서 타입을 any로 해놔서 일단, any로 받음. 나머지 로직에서 타입 체크를 차라리 제대로 하자.
      dispatch(
        fetchPaymentCartedProductListAsync.request({
          id: selectedRowKeys as ProductModel['id'][], // 다른 곳에서라도 타입을 정확하게 판단하기 위해 강제 어썰션
          ProductModelList: selectedRows as ProductModel[],
        }),
      );
    },
    [dispatch],
  );

  const handlePaymentClick = useCallback(() => {
    InfoModal('error', '경고', '결제는 안되요~');
  }, [InfoModal]);

  if (isLoading && !items) {
    return <LoadingSpin />;
  }

  return (
    <>
      <Row>
        <Col span={24}>
          <PageTitle title="장바구니" />
        </Col>
      </Row>
      <Row style={{ marginBottom: 50 }}>
        <CartTable
          dataSource={items}
          onClick={handleCartTableClick}
          onChange={handleCartTableChange}
          onSelectChange={handleSelectChange}
        />
      </Row>
      <Row>
        <Divider orientation="left">최종 결제 금액</Divider>
        <CartFinalPriceTable
          dataSource={tableDataSource}
          recommend={recommend}
        />
        <Divider />
      </Row>
      <Row style={{ textAlign: 'right' }}>
        <NavLink to={PRODUCTS_LIST_PATH}>
          <Button size="large" style={{ marginRight: 8 }}>
            뒤로 가기
          </Button>
        </NavLink>
        <Button
          type="danger"
          size="large"
          style={{ marginRight: 6 }}
          disabled={!tableDataSource.totalPrice}
          onClick={handlePaymentClick}
        >
          결제하기
        </Button>
      </Row>
    </>
  );
}
Example #24
Source File: Cohort.tsx    From posthog-foss with MIT License 4 votes vote down vote up
export function Cohort(props: { cohort: CohortType }): JSX.Element {
    const logic = cohortLogic(props)
    const { setCohort } = useActions(logic)
    const { cohort, submitted } = useValues(logic)
    const { hasAvailableFeature } = useValues(userLogic)

    const onDescriptionChange = (description: string): void => {
        setCohort({
            ...cohort,
            description,
        })
    }

    const onTypeChange = (type: string): void => {
        if (type === COHORT_STATIC) {
            setCohort({
                ...cohort,
                is_static: true,
            })
        } else if (type === COHORT_DYNAMIC) {
            setCohort({
                ...cohort,
                is_static: false,
            })
        }
    }

    const staticCSVDraggerProps = {
        name: 'file',
        multiple: false,
        fileList: cohort.csv ? [cohort.csv] : [],
        beforeUpload(file: UploadFile) {
            setCohort({ ...cohort, csv: file })

            return false
        },
        accept: '.csv',
    }

    const COHORT_TYPE_OPTIONS = [
        {
            key: COHORT_STATIC,
            label: 'Static',
            description: 'Upload a list of users. Updates manually',
            icon: <OrderedListOutlined />,
        },
        {
            key: COHORT_DYNAMIC,
            label: 'Dynamic',
            description: 'Cohort updates dynamically based on properties',
            icon: <CalculatorOutlined />,
        },
    ]

    const cohortTypeDropdown = (): JSX.Element => (
        <DropdownSelector
            options={COHORT_TYPE_OPTIONS}
            disabled={cohort.id !== 'new'}
            value={cohort.is_static ? COHORT_STATIC : COHORT_DYNAMIC}
            onValueChange={onTypeChange}
        />
    )

    return (
        <div className="mb">
            <Row gutter={16}>
                <Col>
                    <h3 className="l3">General</h3>
                </Col>
            </Row>
            <Row gutter={16}>
                <Col md={14}>
                    <CohortNameInput input={cohort.name} onChange={(name: string) => setCohort({ ...cohort, name })} />
                </Col>
                <Col md={10}>
                    {cohort.id === 'new' ? (
                        cohortTypeDropdown()
                    ) : (
                        <Tooltip title="Create a new cohort to use a different type of cohort.">
                            <div>{cohortTypeDropdown()}</div>
                        </Tooltip>
                    )}
                </Col>
            </Row>
            {hasAvailableFeature(AvailableFeature.DASHBOARD_COLLABORATION) && (
                <Row gutter={16} className="mt">
                    <Col span={24}>
                        <CohortDescriptionInput description={cohort.description} onChange={onDescriptionChange} />
                    </Col>
                </Row>
            )}
            {cohort.id && cohort.id !== 'new' && <CohortDetailsRow cohort={cohort} />}
            <Divider />
            {cohort.is_static ? (
                <div>
                    <h3 className="l3">Add Users</h3>
                    <span>
                        Drop a <pre style={{ display: 'inline' }}>.csv</pre> file here to add users to your cohort
                    </span>
                    <Dragger {...staticCSVDraggerProps} className="cohort-csv-dragger">
                        <p className="ant-upload-drag-icon">
                            <InboxOutlined />
                        </p>
                        <div>
                            <p className="ant-upload-text">Click or drag file to this area to upload</p>
                            <p className="ant-upload-hint">
                                The CSV file only requires a single column with the user’s distinct ID.
                            </p>

                            {submitted && !cohort.csv && (
                                <p style={{ color: 'var(--danger)', marginTop: 16 }}>You need to upload a CSV file.</p>
                            )}
                        </div>
                    </Dragger>
                </div>
            ) : (
                <CohortMatchingCriteriaSection logic={logic} />
            )}

            {cohort.id !== 'new' && (
                <>
                    <Divider />
                    <div>
                        <h3 className="l3">Matched Users</h3>
                        <span>List of users that currently match the criteria defined</span>
                        {cohort.is_calculating ? (
                            <div className="cohort-recalculating flex-center">
                                <Spinner size="sm" style={{ marginRight: 4 }} />
                                We're recalculating who belongs to this cohort. This could take up to a couple of
                                minutes.
                            </div>
                        ) : (
                            <div style={{ marginTop: 15 }}>
                                <Persons cohort={cohort} />
                            </div>
                        )}
                    </div>
                </>
            )}
        </div>
    )
}
Example #25
Source File: Button.tsx    From html2sketch with MIT License 4 votes vote down vote up
ButtonSymbolDemo: FC = () => {
  const [json, setJSON] = useState<object>();
  const groupLayout = 'LEFT_TO_RIGHT';
  const typeList = [
    { type: 'default' },
    { type: 'primary' },
    { type: 'disabled' },
    { type: 'dashed' },
    { type: 'ghost' },
    { type: 'default', icon: <StepForwardOutlined /> },
    { type: 'primary', icon: <UpCircleOutlined /> },
    { type: 'text' },
    { type: 'link' },
    { type: 'primary', danger: true },
    { type: 'default', danger: true },
    { type: 'dashed', danger: true },
    { type: 'text', danger: true },
  ];

  const buttonList = [
    typeList.map((i) => ({ ...i, size: 'default' })),
    typeList.map((i) => ({ ...i, size: 'small' })),
    typeList.map((i) => ({ ...i, size: 'large' })),
  ];

  const transformFunc = async (
    transferFn: (node: Element) => Promise<Object>,
  ) => {
    try {
      const els = document.getElementsByClassName('button');
      const buttons: Object[] = [];

      const list = Array.from(els);

      for (let i = 0; i < list.length; i++) {
        const sketchBtn = await transferFn(list[i]);
        buttons.push(sketchBtn);
      }

      console.log('-------转换结束--------');
      console.log(buttons);

      copy(JSON.stringify(buttons));
      message.success('转换成功?已复制到剪切板');
      setJSON(buttons);
    } catch (e) {
      message.error('解析失败,配置项可能存在错误!');
      console.error(e);
    }
  };

  const actionList: ActionType[] = [
    {
      text: '转换为 Group',
      type: 'default',
      onClick: () => {
        transformFunc(async (node) => {
          return (await nodeToGroup(node)).toSketchJSON();
        });
      },
    },
    {
      text: '转换为 Symbol',
      type: 'primary',
      onClick: () => {
        transformFunc(async (node) => {
          const symbolLayout = node.getAttribute('layout') as GroupLayoutType;

          const symbol = await nodeToSketchSymbol(node, {
            symbolLayout: symbolLayout || undefined,
            handleSymbol: (symbol) => {
              symbol.name = node.getAttribute('symbol-name') || 'symbol';
              const renameBG = (layer: AnyLayer) => {
                if (layer.layers) {
                  layer.layers.forEach(renameBG);
                }

                if (layer?.name?.includes('ant-btn')) {
                  layer.name = '背景';
                }
              };
              symbol.layers.forEach(renameBG);
            },
          });

          return symbol.toSketchJSON();
        });
      },
    },
  ];

  const group = ['默认', '小', '大'];
  return (
    <div>
      <Row>
        {buttonList.map((list, sizeIndex) => {
          return (
            <Fragment key={sizeIndex}>
              <Col key={sizeIndex}>
                <Space align="start">
                  <div style={{ width: 32 }}>{group[sizeIndex]}</div>
                  <Row gutter={[8, 12]}>
                    {list.map((button, index) => {
                      const { type, size, danger, icon } = button;
                      return (
                        <Col key={index}>
                          <Button
                            className="button"
                            icon={icon}
                            symbol-name={generateSymbolName({
                              type,
                              size,
                              typeIndex: index + 1,
                              sizeIndex: sizeIndex + 1,
                              component: 'button',
                              componentIndex: 1,
                              content: 'general',
                              contentIndex: 1,
                              suffix: danger ? '-Danger' : undefined,
                            })}
                            layout={groupLayout}
                            // @ts-ignore
                            type={type}
                            danger={danger}
                            disabled={type === 'disabled'}
                            // @ts-ignore
                            size={size}
                          >
                            文本
                          </Button>
                        </Col>
                      );
                    })}
                  </Row>
                </Space>
              </Col>
              {sizeIndex === buttonList.length - 1 ? null : <Divider dashed />}
            </Fragment>
          );
        })}
      </Row>
      <Footer json={json} actions={actionList} />
    </div>
  );
}
Example #26
Source File: index.tsx    From antdp with MIT License 4 votes vote down vote up
QuickForm: QuickFormComponent = (props, ref) => {
  const {
    collapseAttributes,
    panelAttributes,
    visible = false,
    type = 'cardform',
    extra,
    formDatas,
    colspan = 3,
    header,
    defaultFormLayout = 'vertical',
    defaultFormItemLayout = formDefaultFormItemLayout,
    size = 'default',
    formHide,
    initialHide,
    ...otherProps
  } = props;

  const [hide] = useFormItemHide(formHide)
  hide.setInitialValues(initialHide || {}, true)

  const HideFormItemDoM = []; // 隐藏的表单
  const FormItemDoM = [];
  let rowcolspan: string | any; // col 里的布局
  let formitemlayout: string | any; // formitem 的布局

  for (var i = 0; i < formDatas.length; i++) {
    if (formDatas[i].hideInForm) {
      HideFormItemDoM.push(formDatas[i]);
    } else {
      FormItemDoM.push(formDatas[i]);
    }
  }
  // 计算一个row里排几个表单;
  const result = [];
  for (let i = 0, j = FormItemDoM.length; i < j; i++) {
    if (FormItemDoM[i].full) {
      result.push(FormItemDoM.slice(i, i + 1));
    } else {
      if (FormItemDoM[i + 1] && FormItemDoM[i + 1].full) {
        result.push(FormItemDoM.slice(i, i + 1));
      } else if (FormItemDoM[i].defaultcolspan) {
        result.push(FormItemDoM.slice(i, i + FormItemDoM[i].defaultcolspan));
        i = i + FormItemDoM[i].defaultcolspan - 1;
      } else {
        result.push(FormItemDoM.slice(i, i + colspan));
        i = i + colspan - 1;
      }
    }
  }
  // 渲染成表单;
  const CollapseFormDoM = (item: any, idx: React.Key | null | undefined) => {
    const {
      label,
      name,
      attributes,
      type,
      options,
      onlyimg,
      defaultFormItemLayout,
      full,
      defaultRowColspan,
      hideInForm,
      descItem,
      render,
      // 用于判断是否需要进行隐藏显示 (在组件外层包裹一层组件用于控制item显示和隐藏)
      isHide,
      ...otherts
    } = item;
    const dataList = options || [];
    const optionDatas =
      dataList &&
      dataList.length > 0 &&
      dataList.map(
        (
          { value, label, ...others }: any,
          _idx: React.Key | null | undefined,
        ) => {
          if (type === 'select' || type === 'Select') {
            return (
              <Option value={value} key={_idx} {...others}>
                {label}
              </Option>
            );
          } else if (type === 'radio' || type === 'Radio') {
            return (
              <Radio.Button value={value} key={_idx} {...others}>
                {label}
              </Radio.Button>
            );
          }
        },
      );
    const selectOption = optionDatas ? optionDatas : [];
    const rowcolspan_num = [
      colLayout_one,
      colLayout_two,
      colLayout_third,
      colLayout_fourth,
    ];
    const formitemlayout_num = [
      fromItemLayout_conspan_one,
      fromItemLayout_conspan_two,
      fromItemLayout_conspan_third,
      fromItemLayout_conspan_fourth,
    ];
    if (colspan && full) {
      rowcolspan = colLayout_one;
      if (colspan === 3 || colspan === 4) {
        if (props.defaultFormItemLayout) {
          // 如果FormCollapse组件上带有defaulFormItemLayout参数
          formitemlayout = props.defaultFormItemLayout;
          // eslint-disable-next-line max-depth
          if (item.defaultFormItemLayout || item.defaultRowColspan) {
            // 如果FormCollapse组件内部的某个小组件带有defaulFormItemLayout参数
            formitemlayout = item.defaultFormItemLayout;
            rowcolspan = item.defaultRowColspan; // 单独的表单col 布局
          }
        } else if (item.defaultFormItemLayout || item.defaultRowColspan) {
          //FormCollapse组件内部只有某个小组件带了defaulFormItemLayout参数
          formitemlayout = item.defaultFormItemLayout;
          rowcolspan = item.defaultRowColspan; // 单独的表单col 布局
        } else {
          formitemlayout = fromItemLayout_third_row;
        }
      } else {
        formitemlayout = fromItemLayout_two_row;
      }
    } else {
      rowcolspan = rowcolspan_num[colspan - 1];
      if (props.defaultFormItemLayout) {
        formitemlayout = props.defaultFormItemLayout;
        if (item.defaultFormItemLayout || item.defaultRowColspan) {
          // 如果FormCollapse组件内部的某个小组件带有defaultFormItemLayout参数
          formitemlayout = item.defaultFormItemLayout;
          rowcolspan = item.defaultRowColspan; // 单独的表单col 布局
        }
      } else if (item.defaultFormItemLayout || item.defaultRowColspan) {
        formitemlayout =
          item.defaultFormItemLayout || formitemlayout_num[colspan - 1];
        rowcolspan = item.defaultRowColspan; // 单独的表单col 布局
      } else {
        formitemlayout = formitemlayout_num[colspan - 1];
      }
    }

    // 上传图片的按钮展示
    const uploadButtonDom = () => {
      if (item.attributes.listType === 'picture-card') {
        if (item.attributes.imageUrl && item.attributes.imageUrl !== '') {
          return (
            <img
              src={item.attributes.imageUrl}
              alt="avatar"
              style={{ width: '100%' }}
            />
          );
        } else if (item.attributes.fileList) {
          // 上传的图片大于或等于8张时 并且 没有onlyimg参数,显示icon上传按钮
          if (item.attributes.fileList.length >= 8 && !onlyimg) {
            return (
              <div>
                {item.attributes.loading === 'loading' ? (
                  <LoadingOutlined />
                ) : (
                  <PlusOutlined />
                )}
                <div className="ant-upload-text">上传</div>
              </div>
            );
            // 上传的图片大于或等于maxCount张时 并且 有onlyimg参数,不显示上传按钮
          } else if (item.attributes.maxCount && item.attributes.fileList.length >= item.attributes.maxCount && onlyimg) {
            return null;
          }
          return (
            <div>
              {item.attributes.loading === 'loading' ? (
                <LoadingOutlined />
              ) : (
                <PlusOutlined />
              )}
              <div className="ant-upload-text">上传</div>
            </div>
          );
        }
      } else {
        return (
          <div>
            <Button>
              <UploadOutlined />
              上传
            </Button>
          </div>
        );
      }
    };
    let renderItem = (
      <Col
        key={idx}
        style={{
          display: item.hideInForm ? 'none' : 'block',
          padding:
            defaultFormLayout && defaultFormLayout === 'vertical'
              ? '0px 12px 8px 12px'
              : '0',
        }}
        className={
          defaultFormLayout && defaultFormLayout === 'vertical'
            ? 'antdp-FormCol'
            : ''
        }
        {...rowcolspan}
      >
        <FormItem
          className="antdp-FormItem"
          colon={false}
          label={label}
          name={name}
          {...(defaultFormLayout && defaultFormLayout === 'vertical'
            ? null
            : formitemlayout)}
          {...otherts}
        >
          {name ? (
            (() => {
              // 组件基础参数
              const componentprams = {
                size: size ? size : 'small',
                ...attributes,
              };
              if (type === 'select' || type === 'Select') {
                return (
                  <Select
                    dropdownMatchSelectWidth={false}
                    allowClear
                    placeholder={
                      attributes && attributes.disabled ? '' : `请选择${label} `
                    }
                    {...componentprams}
                  >
                    {selectOption}
                  </Select>
                );
              } else if (type === 'radio' || type === 'Radio') {
                return (
                  <Radio.Group size={size ? size : 'small'} {...attributes}>
                    {selectOption}
                  </Radio.Group>
                );
              } else if (type === 'datePicker' || type === 'DatePicker') {
                return (
                  <DatePicker
                    locale={locale}
                    style={{ width: '100%' }}
                    placeholder={
                      attributes && attributes.disabled ? '' : `请选择${label} `
                    }
                    {...componentprams}
                  />
                );
              } else if (type === 'monthPicker' || type === 'MonthPicker') {
                return (
                  <MonthPicker
                    locale={locale}
                    style={{ width: '100%' }}
                    placeholder={
                      attributes && attributes.disabled ? '' : `请选择${label} `
                    }
                    {...componentprams}
                  />
                );
              } else if (type === 'rangePicker' || type === 'RangePicker') {
                return (
                  <RangePicker
                    locale={locale}
                    style={{ width: '100%' }}
                    {...componentprams}
                  />
                );
              } else if (
                type === 'timepicker' ||
                type === 'timePicker' ||
                type === 'TimePicker'
              ) {
                return (
                  <TimePicker
                    locale={locale}
                    style={{ width: '100%' }}
                    placeholder={
                      attributes && attributes.disabled ? '' : `请选择${label} `
                    }
                    {...componentprams}
                  />
                );
              } else if (type === 'cascader' || type === 'Cascader') {
                return (
                  <Cascader
                    placeholder={
                      attributes && attributes.disabled ? '' : `请选择${label} `
                    }
                    {...componentprams}
                  />
                );
              } else if (type === 'textarea' || type === 'TextArea') {
                return (
                  <Input.TextArea
                    placeholder={
                      attributes && attributes.disabled ? '' : `请输入${label} `
                    }
                    {...componentprams}
                  />
                );
              } else if (type === 'inputNumber' || type === 'InputNumber') {
                return (
                  <InputNumber
                    placeholder={
                      attributes && attributes.disabled ? '' : `请输入${label} `
                    }
                    style={{ width: '100%' }}
                    {...componentprams}
                  />
                );
              } else if (type === 'treeSelect' || type === 'TreeSelect') {
                return (
                  <TreeSelect
                    placeholder={
                      attributes && attributes.disabled ? '' : `请选择${label} `
                    }
                    {...componentprams}
                  />
                );
              } else if (type === 'checkbox' || type === 'Checkbox') {
                if (
                  (item.options && item.options.length > 0) ||
                  (item.option && item.option.length > 0)
                ) {
                  return (
                    <Checkbox.Group
                      options={item.options || item.option}
                      {...attributes}
                    />
                  );
                }
                return (
                  <Checkbox {...attributes}>
                    {label || item.checkboxLable}
                  </Checkbox>
                );
              } else if (type === 'UploadGrid' || type === 'uploadGrid') {
                return (
                  <UploadGrid {...attributes}>{uploadButtonDom()}</UploadGrid>
                );
              } else if (type === 'autoComplete' || type === 'AutoComplete') {
                return (
                  <AutoComplete
                    placeholder={
                      attributes && attributes.disabled ? '' : `请输入${label} `
                    }
                    {...componentprams}
                  />
                );
              } else if (type === 'Password') {
                return (
                  <Input.Password
                    placeholder={
                      attributes && attributes.disabled ? '' : `请输入${label} `
                    }
                    {...componentprams}
                  />
                );
              } else if (type === 'inputCount' || type === 'InputCount') {
                return (
                  <InputCount
                    placeholder={
                      attributes && attributes.disabled ? '' : `请输入${label} `
                    }
                    {...attributes}
                  />
                );
              } else if (type === 'render') {
                return render && render
              } else {
                if (
                  (attributes && attributes.type === 'Search') ||
                  type === 'InputSearch'
                ) {
                  const suffix = (
                    <AudioOutlined
                      style={{
                        fontSize: 16,
                        color: '#fff',
                      }}
                    />
                  );
                  return (
                    <Search
                      suffix={suffix}
                      placeholder={
                        attributes && attributes.disabled
                          ? ''
                          : `请输入${label} `
                      }
                      {...componentprams}
                    />
                  );
                }
                return (
                  <Input
                    placeholder={
                      attributes && attributes.disabled ? '' : `请输入${label} `
                    }
                    {...componentprams}
                  />
                );
              }
            })()
          ) : (
            <Input
              placeholder={
                attributes && attributes.disabled ? '' : `请输入${label} `
              }
              size={size}
              {...attributes}
            />
          )}
        </FormItem>
      </Col>
    )

    if (isHide && name) {
      return (
        <Hide key={idx} name={name}>
          {renderItem}
        </Hide>
      );
    }


    return renderItem;
  };
  // 隐藏的表单集合
  const hideCollapseForm = HideFormItemDoM.map((item, idx) =>
    CollapseFormDoM(item, idx),
  );
  // 表单集合
  const CollapseForm = result.map((it, indix) => {
    return (
      <Row key={indix}>
        {it.map((item, idx) => {
          return CollapseFormDoM(item, idx);
        })}
      </Row>
    );
  });
  // Form+表单集合
  const FormDom = (
    <HideContext.Provider value={hide} >
      <ConfigProvider locale={zhCN}>
        <Form
          layout={defaultFormLayout ? defaultFormLayout : 'horizontal'}
          ref={ref}
          {...(defaultFormLayout && defaultFormLayout === 'vertical'
            ? null
            : formitemlayout)}
          {...otherProps}
        >
          <Row>{hideCollapseForm}</Row>
          <div>{CollapseForm}</div>
        </Form>
      </ConfigProvider>
    </HideContext.Provider>
  );
  // type 为 modal时没有折叠,没有标题,直接显示form表单内容
  if (type === 'modal') {
    return <div style={{ margin: -10 }}>{FormDom}</div>
  }
  // type 为CardPro  带标题
  if (type === 'CardPro') {
    return (
      <CardPro title={header}>
        <div className="antdp-FormBox">{FormDom}</div>
      </CardPro>
    );
  }
  // type 为cardform 时 显示表单,分割线 分离每个表单
  if (type === 'cardform') {
    return (
      <div>
        <h3 className="antdp-FormTitle">{header}</h3>
        {FormDom}
        <Divider type="horizontal" className="antdp-FormDivider" />
      </div>
    );
  }
  return (
    <Collapse
      defaultActiveKey={!visible ? ['1'] : ''}
      {...collapseAttributes}
      className="antdp-mb10"
    >
      <Panel header={header} key="1" {...panelAttributes} extra={extra}>
        {FormDom}
      </Panel>
    </Collapse>
  );
}
Example #27
Source File: index.tsx    From S2 with MIT License 4 votes vote down vote up
App = ({ data }) => {
  const onIconClick = ({ meta }) => {
    setInteractedCol(meta.value);
    setColModalVisible(!colModalVisible);
  };
  const s2Ref = useRef(null);
  const [columns, setColumns] = React.useState(initColumns);

  const [interactedCol, setInteractedCol] = useState('');
  const modalCallbackRef = useRef((e) => {});

  const [options, setOptions] = useState({
    width: 600,
    height: 400,
    showSeriesNumber: true,
    interaction: {
      enableCopy: true,
      autoResetSheetStyle: false,
      hoverFocus: false,
    },
    colCell: (item, spreadsheet, headerConfig) => {
      if (item.colIndex === 0) {
        return new CustomCornerCell(item, spreadsheet, headerConfig);
      }
      return new CustomTableColCell(
        item,
        spreadsheet,
        headerConfig,
        onIconClick,
      );
    },
    customSVGIcons: [
      {
        name: 'Filter',
        svg: filterIcon,
      },
      {
        name: 'SortUp',
        svg: sortUp,
      },
      {
        name: 'SortDown',
        svg: sortDown,
      },
    ],
    tooltip: {
      operation: {
        hiddenColumns: true,
      },
    },
    showDefaultHeaderActionIcon: false,
  });
  const [dataCfg, setDataCfg] = useState({
    fields: {
      columns,
    },
    data,
    sortParams: [],
    filterParams: [],
  });

  useEffect(() => {
    setDataCfg((cfg) => ({
      ...cfg,
      fields: { columns },
    }));
    s2Ref.current.render(true);
  }, [columns.length]);

  const [searchKey, setSearchKey] = useState('');
  const [searchResult, setSearchResult] = useState([]);
  const [colModalVisible, setColModalVisible] = useState(false);
  const [searchResultActiveIndex, setSearchResultActiveIndex] = useState(-1);
  const [form] = Form.useForm();

  const allChecked = columns.length === initColumns.length;

  const focusNext = (results, currentIndex) => {
    const length = results.length;
    let nextIndex = currentIndex + 1;
    if (nextIndex >= length) {
      nextIndex = 0;
    }
    setSearchResultActiveIndex(nextIndex);
    const current = results[nextIndex];
    scrollToCell(
      current.row,
      current.col,
      s2Ref.current.options,
      s2Ref.current.facet,
      s2Ref.current.interaction,
    );
  };

  const focusPrev = (results) => {
    const length = results.length;
    let nextIndex = searchResultActiveIndex - 1;
    if (nextIndex < 0) {
      nextIndex = length - 1;
    }
    setSearchResultActiveIndex(nextIndex);
    const current = results[nextIndex];
    scrollToCell(
      current.row,
      current.col,
      s2Ref.current.options,
      s2Ref.current.facet,
      s2Ref.current.interaction,
    );
  };

  const search = (key) => {
    let searchData = [];
    if (s2Ref.current) {
      searchData = s2Ref.current.dataSet.getDisplayDataSet();
    }
    const results = getSearchResult(key, searchData, columns);
    setSearchResult(results);
    setSearchResultActiveIndex(-1);
    if (results.length > 0) {
      focusNext(results, -1);
    }
  };

  return (
    <div>
      <Space>
        <ShowList
          columns={columns}
          allChecked={allChecked}
          setColumns={setColumns}
        />
        <Search
          placeholder="输入关键词搜索"
          allowClear
          enterButton="Search"
          value={searchKey}
          onChange={(e) => {
            setSearchKey(e.target.value);
          }}
          onSearch={(key) => {
            search(key);
          }}
        />

        {searchResult.length ? (
          <>
            <div>{`${searchResultActiveIndex + 1}/${
              searchResult.length + 1
            }`}</div>
            <Button
              shape="circle"
              icon={<antdIcons.ArrowLeftOutlined />}
              onClick={() => {
                if (searchResult.length > 0) {
                  focusPrev(searchResult, searchResultActiveIndex);
                }
              }}
            />
            <Button
              shape="circle"
              icon={<antdIcons.ArrowRightOutlined />}
              onClick={() => {
                if (searchResult.length > 0) {
                  focusNext(searchResult, searchResultActiveIndex);
                }
              }}
            />
          </>
        ) : null}
      </Space>

      <Divider />
      <SheetComponent
        ref={s2Ref}
        dataCfg={dataCfg}
        options={options}
        sheetType="table"
        onColCellClick={(e) => {
          // 最左侧列的格子点击后全选
          if (e.viewMeta.colIndex === 0) {
            s2Ref.current?.interaction.selectAll();
          }
        }}
        onCopied={() => {
          message.success('复制成功');
        }}
      />
      <Modal
        title="列设置"
        visible={colModalVisible}
        className="antv-s2-data-preview-demo-modal"
        onCancel={() => {
          setColModalVisible(false);
          form.resetFields();
        }}
        onOk={() => {
          modalCallbackRef.current();
          setColModalVisible(false);
        }}
      >
        <SortPopover
          spreadsheet={s2Ref.current}
          fieldName={interactedCol}
          modalCallbackRef={modalCallbackRef}
        />
      </Modal>
    </div>
  );
}
Example #28
Source File: DashboardPage.tsx    From iot-center-v2 with MIT License 4 votes vote down vote up
DashboardPage: FunctionComponent<
  RouteComponentProps<PropsRoute> & Props
> = ({match, history, helpCollapsed}) => {
  const deviceId = match.params.deviceId ?? VIRTUAL_DEVICE
  const [loading, setLoading] = useState(true)
  const [message, setMessage] = useState<Message | undefined>()
  const [deviceData, setDeviceData] = useState<DeviceData | undefined>()
  const [dataStamp, setDataStamp] = useState(0)
  const [devices, setDevices] = useState<DeviceInfo[] | undefined>(undefined)
  const [timeStart, setTimeStart] = useState('-1d')
  const [xDomain, setXDomain] = useState<number[] | undefined>(undefined)

  const resetXDomain = () =>
    setXDomain(getXDomainFromTable(deviceData?.measurementsTable))

  const isVirtualDevice = deviceId === VIRTUAL_DEVICE
  const measurementsTable = deviceData?.measurementsTable

  // fetch device configuration and data
  useEffect(() => {
    const fetchDeviceLastValues = async (
      config: DeviceConfig,
      timeStart: string
    ) => {
      return Promise.all(
        measurementsDefinitions.map(async ({column}) => ({
          column,
          table: await fetchDeviceDataFieldLast(config, column, timeStart),
        }))
      )
    }

    const fetchData = async () => {
      setLoading(true)
      try {
        const config = await fetchDeviceConfig(deviceId)
        const deviceData: DeviceData = {config}
        const [table, lastValues] = await Promise.all([
          fetchDeviceMeasurements(config, timeStart),
          fetchDeviceLastValues(config, timeStart),
        ])
        deviceData.measurementsTable = table
        deviceData.measurementsLastValues = lastValues
        setDeviceData(deviceData)
      } catch (e) {
        console.error(e)
        setMessage({
          title: 'Cannot load device data',
          description: String(e),
          type: 'error',
        })
      }
      setLoading(false)
    }

    fetchData()
  }, [dataStamp, deviceId, timeStart])

  useEffect(() => {
    resetXDomain()
    // eslint-disable-next-line
  }, [deviceData])

  useEffect(() => {
    const fetchDevices = async () => {
      try {
        const response = await fetch('/api/devices')
        if (response.status >= 300) {
          const text = await response.text()
          throw new Error(`${response.status} ${text}`)
        }
        const data = await response.json()
        setDevices(data)
      } catch (e) {
        setMessage({
          title: 'Cannot fetch data',
          description: String(e),
          type: 'error',
        })
      }
    }

    fetchDevices()
  }, [])

  const renderGauge = (
    gaugeDefinition: Partial<GaugeLayerConfig>,
    table: GiraffeTable
  ) => {
    const gaugeDefaults: GaugeLayerConfig = {
      type: 'gauge',
      gaugeColors: [],
      gaugeSize: 4,
      gaugeTheme: {
        ...GAUGE_THEME_LIGHT,
        valuePositionYOffset: 1,
      },
    }

    return (
      <div style={{width: '100%', height: 150}}>
        <Plot
          config={{
            showAxes: false,
            layers: [{...gaugeDefaults, ...gaugeDefinition}],
            table,
          }}
        />
      </div>
    )
  }

  const gaugeLastTimeMessage = (time: number) => {
    const now = Date.now()
    const diff = now - time

    if (diff < 60_000) return 'just now'
    if (diff < 300_000) return 'less than 5 min ago'
    if (diff < 900_000) return 'more than 5 min ago'
    return 'long time ago'
  }

  const gaugeMissingValues: string[] = []
  const gauges = deviceData?.measurementsLastValues?.length ? (
    <>
      <Row gutter={[22, 22]}>
        {measurementsDefinitions.map(({gauge, title, column}) => {
          const lastValueTable = deviceData?.measurementsLastValues?.find(
            (x) => x.column === column
          )?.table

          if (!lastValueTable?.length) {
            gaugeMissingValues.push(title)
            return undefined
          }

          const [time] = lastValueTable.getColumn('_time') as number[]

          return (
            <Col
              sm={helpCollapsed ? 24 : 24}
              md={helpCollapsed ? 12 : 24}
              xl={helpCollapsed ? 6 : 12}
            >
              <Card
                title={title}
                extra={
                  <Tooltip title={new Date(time).toISOString()}>
                    <div style={{color: COLOR_TEXT}}>
                      {gaugeLastTimeMessage(time)}
                    </div>
                  </Tooltip>
                }
              >
                {renderGauge(gauge, lastValueTable)}
              </Card>
            </Col>
          )
        })}
      </Row>
      <Divider style={{color: 'rgba(0, 0, 0, .2)'}} orientation="right">
        {gaugeMissingValues.length
          ? `Gauge missing values: ${gaugeMissingValues.join(', ')}`
          : undefined}
      </Divider>
    </>
  ) : undefined

  const renderPlot = (
    lineDefinition: Partial<LineLayerConfig> | undefined,
    table: GiraffeTable,
    column: string
  ) => {
    const lineDefaults: LineLayerConfig = {
      type: 'line',
      x: '_time',
      y: column,
      interpolation: 'linear',
      colors: [COLOR_PRIMARY],
    }

    return (
      <div style={{width: '100%', height: 200}}>
        <Plot
          config={{
            xDomain: xDomain,
            onSetXDomain: setXDomain,
            onResetXDomain: resetXDomain,
            layers: [{...lineDefaults, ...lineDefinition}],
            table,
            valueFormatters: {
              _time: timeFormatter({
                timeZone: 'UTC',
                format: 'YYYY-MM-DD HH:mm:ss ZZ',
              }),
            },
          }}
        />
      </div>
    )
  }

  const plots =
    measurementsTable && measurementsTable?.length
      ? (() => {
          const measurementsWithValues = measurementsDefinitions.filter(
            ({column}) => measurementsTable.getColumn(column)
          )
          const measurementsNoValues = measurementsDefinitions.filter(
            ({column}) => !measurementsTable.getColumn(column)
          )

          return (
            <>
              <Row gutter={[0, 24]}>
                {measurementsWithValues.map(({line, title, column}, i) => (
                  <Col xs={24}>
                    <Collapse
                      defaultActiveKey={measurementsWithValues.map((_, i) => i)}
                    >
                      <CollapsePanel key={i} header={title}>
                        {renderPlot(line, measurementsTable, column)}
                      </CollapsePanel>
                    </Collapse>
                  </Col>
                ))}
              </Row>
              {measurementsNoValues.length ? (
                <Collapse>
                  {measurementsNoValues.map(({title}, i) => (
                    <CollapsePanel
                      key={i}
                      disabled={true}
                      header={`${title} - No data`}
                    />
                  ))}
                </Collapse>
              ) : undefined}
            </>
          )
        })()
      : undefined

  const timeOptions: {label: string; value: string}[] = [
    {label: 'Past 5m', value: '-5m'},
    {label: 'Past 15m', value: '-15m'},
    {label: 'Past 1h', value: '-1h'},
    {label: 'Past 6h', value: '-6h'},
    {label: 'Past 1d', value: '-1d'},
    {label: 'Past 3d', value: '-3d'},
    {label: 'Past 7d', value: '-7d'},
    {label: 'Past 30d', value: '-30d'},
  ]

  const pageControls = (
    <>
      <Tooltip title="Choose device" placement="left">
        <Select
          showSearch
          value={deviceId}
          placeholder={'select device to show'}
          showArrow={true}
          filterOption={true}
          onChange={(key) => history.push(`/dashboard/${key}`)}
          style={{minWidth: 200, width: 350, marginRight: 10}}
          loading={!devices}
          disabled={!devices}
        >
          {devices &&
            devices.map(({deviceId}) => (
              <Select.Option key={deviceId} value={deviceId}>
                {deviceId}
              </Select.Option>
            ))}
        </Select>
      </Tooltip>

      <Tooltip title="Choose time" placement="left">
        <Select
          value={timeStart}
          onChange={setTimeStart}
          style={{minWidth: 100}}
          loading={loading}
          disabled={loading}
        >
          {timeOptions.map(({label, value}) => (
            <Select.Option key={value} value={value}>
              {label}
            </Select.Option>
          ))}
        </Select>
      </Tooltip>

      <Tooltip title="Reload Device Data">
        <Button
          disabled={loading}
          loading={loading}
          onClick={() => setDataStamp(dataStamp + 1)}
          style={{marginLeft: 10}}
          icon={<IconRefresh />}
        />
      </Tooltip>
      <Tooltip title="Go to device settings" placement="topRight">
        <Button
          type="primary"
          icon={<IconSettings />}
          style={{marginLeft: 10}}
          href={`/devices/${deviceId}`}
        ></Button>
      </Tooltip>
    </>
  )

  return (
    <PageContent
      title={
        <>
          Dashboard
          {isVirtualDevice ? (
            <Tooltip title="This page writes temperature measurements for the last 7 days from an emulated device, the temperature is reported every minute.">
              <InfoCircleFilled style={{fontSize: '1em', marginLeft: 5}} />
            </Tooltip>
          ) : undefined}
        </>
      }
      titleExtra={pageControls}
      message={message}
      spin={loading}
      forceShowScroll={true}
    >
      {deviceData?.measurementsTable?.length ? (
        <>
          {gauges}
          {plots}
        </>
      ) : (
        <Card>
          <Empty />
        </Card>
      )}
    </PageContent>
  )
}
Example #29
Source File: DendronCalendarPanel.tsx    From dendron with GNU Affero General Public License v3.0 4 votes vote down vote up
export default function DendronCalendarPanel({ ide, engine }: DendronProps) {
  // --- init
  const ctx = "CalendarView";
  const logger = createLogger("calendarView");

  logger.info({
    ctx,
    state: "enter",
  });
  const { getPrefixCls } = React.useContext(ConfigProvider.ConfigContext);

  const [activeMode, setActiveMode] = useState<CalendarProps["mode"]>("month");
  const { notes, config } = engine;
  const { noteActive } = ide;
  const currentVault = noteActive?.vault;

  logger.info({
    activeNoteFname: noteActive ? noteActive.fname : "no active note found",
  });
  const maxDots: number = 5;
  const wordsPerDot: number = 250;

  const defaultConfig = ConfigUtils.genDefaultConfig();
  const journalConfig = ConfigUtils.getJournal(config || defaultConfig);
  const journalDailyDomain = journalConfig.dailyDomain;
  const journalName = journalConfig.name;

  // Load up the full engine state as all notes are needed for the Tree View
  const [workspace] = useWorkspaceProps();
  useEngine({ engineState: engine, opts: workspace });

  // luxon token format lookup https://github.com/moment/luxon/blob/master/docs/formatting.md#table-of-tokens
  let journalDateFormat = journalConfig.dateFormat;
  const journalMonthDateFormat = "y.MM"; // TODO compute format for currentMode="year" from config

  // Currently luxon does not support setting first day of the week (https://github.com/moment/luxon/issues/373)
  // const dayOfWeek = config?.journal.firstDayOfWeek;
  // const locale = "en-us";

  if (journalDateFormat) {
    // correct possible user mistake that very likely is meant to be day of the month, padded to 2 (dd) and not localized date with abbreviated month (DD)
    journalDateFormat = journalDateFormat.replace(/DD/, "dd");
  }

  const groupedDailyNotes = useMemo(() => {
    const vaultNotes = _.values(notes).filter((notes) => {
      if (currentVault) {
        return VaultUtils.isEqualV2(notes.vault, currentVault);
      }
      return true;
    });

    const dailyNotes = vaultNotes.filter((note) =>
      note.fname.startsWith(`${journalDailyDomain}.${journalName}`)
    );
    const result = _.groupBy(dailyNotes, (note) => {
      return journalName ? getMaybeDatePortion(note, journalName) : undefined;
    });
    return result;
  }, [notes, journalName, journalDailyDomain, currentVault?.fsPath]);

  const activeDate = useMemo(() => {
    if (noteActive && journalName && journalDateFormat) {
      const maybeDatePortion = getMaybeDatePortion(noteActive, journalName);

      if (maybeDatePortion && _.first(groupedDailyNotes[maybeDatePortion])) {
        const dailyDate = Time.DateTime.fromFormat(
          maybeDatePortion,
          journalDateFormat
        );

        const monthlyDate = Time.DateTime.fromFormat(
          maybeDatePortion,
          journalMonthDateFormat
        );

        return dailyDate.isValid
          ? dailyDate
          : monthlyDate.isValid
          ? monthlyDate
          : undefined;
      }

      return undefined;
    }
  }, [noteActive, groupedDailyNotes, journalName, journalDateFormat]);

  const getDateKey = useCallback<
    (date: DateTime, mode?: CalendarProps["mode"]) => string | undefined
  >(
    (date, mode) => {
      const format =
        (mode || activeMode) === "month"
          ? journalDateFormat
          : journalMonthDateFormat;
      return format ? date.toFormat(format) : undefined;
    },
    [activeMode, journalDateFormat]
  );

  const onSelect = useCallback<
    (date: DateTime, mode?: CalendarProps["mode"]) => void
  >(
    (date, mode) => {
      logger.info({ ctx: "onSelect", date });
      const dateKey = getDateKey(date, mode);
      const selectedNote = dateKey
        ? _.first(groupedDailyNotes[dateKey])
        : undefined;

      postVSCodeMessage({
        type: CalendarViewMessageType.onSelect,
        data: {
          id: selectedNote?.id,
          fname: `${journalDailyDomain}.${journalName}.${dateKey}`,
        },
        source: DMessageSource.webClient,
      });
    },
    [groupedDailyNotes, getDateKey, journalDailyDomain, journalName]
  );

  const onPanelChange = useCallback<
    Exclude<CalendarProps["onPanelChange"], undefined>
  >((date, mode) => {
    logger.info({ ctx: "onPanelChange", date, mode });
    setActiveMode(mode);
  }, []);

  const onClickToday = useCallback(() => {
    const mode = "month";
    setActiveMode(mode);
    onSelect(Time.now(), mode);
  }, [onSelect]);

  const dateFullCellRender = useCallback<
    Exclude<CalendarProps["dateFullCellRender"], undefined>
  >(
    (date) => {
      const dateKey = getDateKey(date);
      const dailyNote = dateKey
        ? _.first(groupedDailyNotes[dateKey])
        : undefined;
      const dailyNotes = dailyNote ? [dailyNote] : []; // keeping for case of showing all dailyNotes of day in multi-vault

      const dateCell =
        // multiple daily notes can exist for that day in a mulit-vault setup
        // will only show up when `noteActive` is `undefined`. this happens when opening vscode with no document open
        dailyNotes.map((note, index) => {
          const amount = _.clamp(
            wordsPerDot
              ? Math.floor(note.body.split(/\n| /).length / wordsPerDot) // TODO create test
              : 0,
            0,
            maxDots
          );

          return (
            <div
              key={note.id}
              style={{
                position: "relative",
                top: index * 2 - 6, // space between the day and dots boxes
                // left: index * 1,
              }}
            >
              {_.times(amount, (index) => (
                <div
                  key={index}
                  style={{
                    position: "absolute",
                    left: index * 7, // 7 resutls in a nice visible space between the dots
                  }}
                >
                  <Badge
                    className={`${note.fname}`}
                    dot
                    color={
                      "#00adb5" /* color copied from packages/dendron-next-server/assets/themes/dark-theme.less TODO make dependent on active theme */
                    }
                  />
                </div>
              ))}
            </div>
          );
        });

      const prefixCls = getPrefixCls("picker");
      const calendarPrefixCls = `${prefixCls}-calendar`;

      return (
        <div
          className={classNames(
            `${prefixCls}-cell-inner`,
            `${calendarPrefixCls}-date`,
            {
              [`${calendarPrefixCls}-date-today`]: isSameDate(today, date),
            }
          )}
        >
          <div
            className={`${calendarPrefixCls}-date-value`}
            style={{ color: !dailyNote ? "gray" : undefined }}
          >
            {_.padStart(String(luxonGenerateConfig.getDate(date)), 2, "0")}
          </div>
          <div className={`${calendarPrefixCls}-date-content`}>{dateCell}</div>
        </div>
      );
    },
    [getDateKey, groupedDailyNotes]
  );

  return (
    <>
      <div className="calendar">
        <Calendar
          mode={activeMode}
          onSelect={onSelect}
          onPanelChange={onPanelChange}
          /*
          // @ts-ignore -- `null` initializes ant Calendar into a controlled component whereby it does not render an selected/visible date (today) when `activeDate` is `undefined`*/
          value={activeDate || null}
          dateFullCellRender={dateFullCellRender}
          fullscreen={false}
        />
      </div>
      <Divider plain style={{ marginTop: 0 }}>
        <Button type="primary" onClick={onClickToday}>
          Today
        </Button>
      </Divider>
    </>
  );
}