antd#Steps TypeScript Examples

The following examples show how to use antd#Steps. 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: FormWizardStepStatus.tsx    From jmix-frontend with Apache License 2.0 7 votes vote down vote up
FormWizardStepStatus = observer(({onSelectStep}: FormWizardStepStatusProps) => {
    const {formWizardStore} = useFormWizard();
    const {formatMessage} = useIntl()

    return (
        <Steps
            style={{marginBottom: 12}}
            size="small"
            current={formWizardStore.stepIndex}
            onChange={onSelectStep}
        >
            {formWizardStore.steps.map((step, index) => (
                <Steps.Step
                    disabled={step.status === 'wait'}
                    key={step.name}
                    title={formatMessage({id: 'formWizard.stepTitle'}, {index: index + 1})}
                    status={step.status}
                />
            ))}
        </Steps>
    );
})
Example #2
Source File: index.tsx    From posthog-foss with MIT License 5 votes vote down vote up
{ Step } = Steps
Example #3
Source File: index.tsx    From metaplex with Apache License 2.0 5 votes vote down vote up
Sidebar = ({
  step,
  setStep,
  submit,
  isValidStep,
  buttonLoading,
}: SidebarProps) => {
  const { connected } = useWallet();
  const { isLoading } = useMeta();
  const { width } = useWindowDimensions();

  const isFinalStep = step === CreatePackSteps.ReviewAndMint;
  const shouldDisable =
    !isValidStep || !connected || isLoading || buttonLoading;

  const handleContinue = (): void => {
    if (isFinalStep) {
      return submit();
    }

    setStep(step + 1);
  };

  return (
    <div className="sidebar-wrapper">
      <Steps
        className="sidebar-steps"
        direction={width < 768 ? 'horizontal' : 'vertical'}
        current={step}
      >
        {Object.entries(STEPS_TITLES).map(([step, title]) => (
          <Step title={title} key={step} />
        ))}
      </Steps>

      <Button
        className="sidebar-btn secondary-btn"
        onClick={handleContinue}
        disabled={shouldDisable}
      >
        {buttonLoading ? <Spin /> : CONTINUE_TITLES[step]}
      </Button>

      {step !== CreatePackSteps.SelectItems && (
        <Button
          type="text"
          className="sidebar-btn"
          onClick={() => setStep(step - 1)}
        >
          Back
        </Button>
      )}
    </div>
  );
}
Example #4
Source File: questionnaire.tsx    From RareCamp with Apache License 2.0 5 votes vote down vote up
{ Step } = Steps
Example #5
Source File: index.tsx    From metaplex with Apache License 2.0 5 votes vote down vote up
{ Step } = Steps
Example #6
Source File: index.tsx    From metaplex with Apache License 2.0 5 votes vote down vote up
{ Step } = Steps
Example #7
Source File: UpdateForm.tsx    From ui-visualization with MIT License 5 votes vote down vote up
{ Step } = Steps
Example #8
Source File: SourceEditorViewSteps.tsx    From jitsu with MIT License 5 votes vote down vote up
SourceEditorViewSteps: React.FC<SourceEditorTabsViewProps> = ({
  steps,
  controlsDisabled,
  handleBringSourceData,
  setInitialSourceData,
  handleLeaveEditor,
}) => {
  const [currentStep, setCurrentStep] = useState<number>(0)
  const [currentStepIsLoading, setCurrentStepIsLoading] = useState<boolean>(false)

  const proceedButtonTitle = steps[currentStep].proceedButtonTitle ?? "Next"

  const handleCompleteStep = () => {
    setInitialSourceData(handleBringSourceData())
  }

  const handleGoToNextStep: AsyncUnknownFunction = async () => {
    handleCompleteStep()
    setCurrentStepIsLoading(true)
    try {
      await steps[currentStep].proceedAction?.()
      setCurrentStep(step => step + 1)
    } catch (error) {
      actionNotification.error(`${error}`)
    } finally {
      setCurrentStepIsLoading(false)
    }
  }

  const handleStepBack: AsyncUnknownFunction = async () => {
    handleCompleteStep()
    setCurrentStep(step => step - 1)
  }

  return (
    <>
      <div className={cn("flex flex-col items-stretch flex-grow-0 flex-shrink h-full min-h-0")}>
        <div className="flex-shrink-0 flex-grow-0 mb-4">
          <Steps current={currentStep}>
            {steps.map(({ key, title, description }, idx) => (
              <Steps.Step
                key={key}
                title={title}
                description={description}
                icon={idx === currentStep && currentStepIsLoading ? <LoadingOutlined spin /> : undefined}
              />
            ))}
          </Steps>
        </div>

        <div className={cn("flex-grow flex-shrink min-h-0 overflow-y-auto pr-4")}>
          <fieldset disabled={currentStepIsLoading}>{steps[currentStep]?.render}</fieldset>
        </div>

        <div className="flex items-center flex-shrink flex-grow-0 border-t py-2">
          <SourceEditorViewControls
            mainButton={{
              title: proceedButtonTitle,
              loading: currentStepIsLoading,
              handleClick: handleGoToNextStep,
            }}
            secondaryButton={{
              title: "Back",
              hide: currentStep === 0,
              handleClick: handleStepBack,
            }}
            dangerButton={{
              title: "Cancel",
              handleClick: handleLeaveEditor,
            }}
            controlsDisabled={controlsDisabled}
          />
        </div>
      </div>
    </>
  )
}
Example #9
Source File: control.tsx    From leek with Apache License 2.0 5 votes vote down vote up
{ Step } = Steps
Example #10
Source File: index.tsx    From metaplex with Apache License 2.0 5 votes vote down vote up
{ Step } = Steps
Example #11
Source File: index.tsx    From amiya with MIT License 4 votes vote down vote up
export default function Demo() {
  // 商品选择是否可见
  const [currStep, setCurrStep] = useState(0)
  // 提交的数据
  const [submitValues, setSubmitValues] = useState<AnyKeyProps>({})
  // 提交的数据
  const [submitTagValues, setSubmitTagValues] = useState<AnyKeyProps>({})

  return (
    <Card className="step-form">
      <Steps current={currStep} className="steps">
        <Steps.Step title="基础信息" />
        <Steps.Step title="能力选择" />
        <Steps.Step title="录入完成" />
      </Steps>
      {currStep === 0 && (
        <AyForm
          formLayout="vertical"
          onConfirm={values => {
            setSubmitValues(values)
            setCurrStep(1)
          }}
        >
          <AyFields>
            <AyField title="昵称" key="nickname" required help="你在平台展示的名称。" defaultValue="一只兔子" />
            <AyField title="真实姓名" key="name" required help="仅用于认证,不会在界面展示。" defaultValue="阿米娅" />
            <AyField title="证件信息" key="__card" type="input-group" required>
              <AyField
                type="select"
                key="cardType"
                style={{ width: 130 }}
                defaultValue={2}
                required
                options={[
                  { label: '居民身份证', value: 1 },
                  { label: '出生证', value: 2 },
                  { label: '护照', value: 3 }
                ]}
              />
              <AyField
                title="证件号码"
                key="cardNo"
                required
                style={{ width: 370 }}
                defaultValue="A1R2K3N4I5G6H7T8S9"
              />
            </AyField>
            <AyField
              title="简介"
              key="memo"
              type="textarea"
              placeholder="介绍一下自己"
              defaultValue="正在努力奋斗中..."
            />
          </AyFields>
          <AyButton htmlType="submit" type="primary">
            下一步
          </AyButton>
        </AyForm>
      )}
      {currStep === 1 && (
        <AyForm
          formLayout="vertical"
          onConfirm={values => {
            setSubmitTagValues(values)
            setCurrStep(2)
          }}
        >
          <AyFields>
            <AyField
              title="资质"
              key="type"
              type="card-group"
              options={[
                { label: '高级资深干员', value: 3 },
                { label: '资深干员', value: 2 },
                { label: '新手', value: 1 }
              ]}
              required
              defaultValue={1}
            />
            <AyField title="星级" key="level" type="rate" count={6} required defaultValue={5} />
            <AyField
              title="能力"
              key="tags"
              type="checkbox-group"
              options={[
                { label: '控场', value: 1 },
                { label: '爆发', value: 2 },
                { label: '治疗', value: 3 },
                { label: '支援', value: 4 },
                { label: '费用回复', value: 5 },
                { label: '输出', value: 6 }
              ]}
              required
              defaultValue={[2, 6]}
            />
          </AyFields>
          <Space>
            <AyButton onClick={() => setCurrStep(currStep - 1)}>上一步</AyButton>
            <AyButton htmlType="submit" type="primary">
              下一步
            </AyButton>
          </Space>
        </AyForm>
      )}
      {currStep == 2 && (
        <Result
          status="success"
          title="录入完成"
          subTitle="信息录入已完成,可以选择再次录入。"
          extra={[
            <AyButton
              type="primary"
              onClick={() => {
                setCurrStep(0)
                setSubmitValues({})
                setSubmitTagValues({})
              }}
            >
              再次录入
            </AyButton>
          ]}
        />
      )}
      {submitValues.name && <pre>{JSON.stringify(submitValues, null, 2)}</pre>}
      {submitTagValues.type && <pre>{JSON.stringify(submitTagValues, null, 2)}</pre>}
    </Card>
  )
}
Example #12
Source File: index.tsx    From metaplex with Apache License 2.0 4 votes vote down vote up
AuctionCreateView = () => {
  const connection = useConnection();
  const wallet = useWallet();
  const { whitelistedCreatorsByCreator, storeIndexer } = useMeta();
  const { step_param }: { step_param: string } = useParams();
  const history = useHistory();
  const mint = useMint(QUOTE_MINT);
  const { width } = useWindowDimensions();

  const [step, setStep] = useState<number>(0);
  const [stepsVisible, setStepsVisible] = useState<boolean>(true);
  const [auctionObj, setAuctionObj] = useState<
    | {
        vault: StringPublicKey;
        auction: StringPublicKey;
        auctionManager: StringPublicKey;
      }
    | undefined
  >(undefined);
  const [attributes, setAttributes] = useState<AuctionState>({
    reservationPrice: 0,
    items: [],
    category: AuctionCategory.Open,
    auctionDurationType: 'minutes',
    gapTimeType: 'minutes',
    winnersCount: 1,
    startSaleTS: undefined,
    startListTS: undefined,
    quoteMintAddress: '',
    //@ts-ignore
    quoteMintInfo: undefined,
    //@ts-ignore
    quoteMintInfoExtended: undefined,
  });

  const [tieredAttributes, setTieredAttributes] = useState<TieredAuctionState>({
    items: [],
    tiers: [],
  });

  useEffect(() => {
    if (step_param) setStep(parseInt(step_param));
    else gotoNextStep(0);
  }, [step_param]);

  const gotoNextStep = (_step?: number) => {
    const nextStep = _step === undefined ? step + 1 : _step;
    history.push(`/auction/create/${nextStep.toString()}`);
  };

  const createAuction = async () => {
    let winnerLimit: WinnerLimit;
    //const mint = attributes.quoteMintInfo
    if (
      attributes.category === AuctionCategory.InstantSale &&
      attributes.instantSaleType === InstantSaleType.Open
    ) {
      const { items, instantSalePrice } = attributes;

      if (items.length > 0 && items[0].participationConfig) {
        items[0].participationConfig.fixedPrice = new BN(
          toLamports(instantSalePrice, mint) || 0,
        );
      }

      winnerLimit = new WinnerLimit({
        type: WinnerLimitType.Unlimited,
        usize: ZERO,
      });
    } else if (attributes.category === AuctionCategory.InstantSale) {
      const { items, editions } = attributes;

      if (items.length > 0) {
        const item = items[0];
        if (!editions) {
          item.winningConfigType = WinningConfigType.TokenOnlyTransfer;
        }

        item.amountRanges = [
          new AmountRange({
            amount: new BN(1),
            length: new BN(editions || 1),
          }),
        ];
      }

      winnerLimit = new WinnerLimit({
        type: WinnerLimitType.Capped,
        usize: new BN(editions || 1),
      });
    } else if (attributes.category === AuctionCategory.Open) {
      if (
        attributes.items.length > 0 &&
        attributes.items[0].participationConfig
      ) {
        attributes.items[0].participationConfig.fixedPrice = new BN(
          toLamports(attributes.participationFixedPrice, mint) || 0,
        );
      }
      winnerLimit = new WinnerLimit({
        type: WinnerLimitType.Unlimited,
        usize: ZERO,
      });
    } else if (
      attributes.category === AuctionCategory.Limited ||
      attributes.category === AuctionCategory.Single
    ) {
      if (attributes.items.length > 0) {
        const item = attributes.items[0];
        if (
          attributes.category == AuctionCategory.Single &&
          item.masterEdition
        ) {
          item.winningConfigType = WinningConfigType.TokenOnlyTransfer;
        }
        item.amountRanges = [
          new AmountRange({
            amount: new BN(1),
            length:
              attributes.category === AuctionCategory.Single
                ? new BN(1)
                : new BN(attributes.editions || 1),
          }),
        ];
      }
      winnerLimit = new WinnerLimit({
        type: WinnerLimitType.Capped,
        usize:
          attributes.category === AuctionCategory.Single
            ? new BN(1)
            : new BN(attributes.editions || 1),
      });

      if (
        attributes.participationNFT &&
        attributes.participationNFT.participationConfig
      ) {
        attributes.participationNFT.participationConfig.fixedPrice = new BN(
          toLamports(attributes.participationFixedPrice, mint) || 0,
        );
      }
    } else {
      const tiers = tieredAttributes.tiers;
      tiers.forEach(
        c =>
          (c.items = c.items.filter(
            i => (i as TierDummyEntry).winningConfigType !== undefined,
          )),
      );
      const filteredTiers = tiers.filter(
        i => i.items.length > 0 && i.winningSpots.length > 0,
      );

      tieredAttributes.items.forEach((config, index) => {
        let ranges: AmountRange[] = [];
        filteredTiers.forEach(tier => {
          const tierRangeLookup: Record<number, AmountRange> = {};
          const tierRanges: AmountRange[] = [];
          const item = tier.items.find(
            i => (i as TierDummyEntry).safetyDepositBoxIndex == index,
          );

          if (item) {
            config.winningConfigType = (
              item as TierDummyEntry
            ).winningConfigType;
            const sorted = tier.winningSpots.sort();
            sorted.forEach((spot, i) => {
              if (tierRangeLookup[spot - 1]) {
                tierRangeLookup[spot] = tierRangeLookup[spot - 1];
                tierRangeLookup[spot].length = tierRangeLookup[spot].length.add(
                  new BN(1),
                );
              } else {
                tierRangeLookup[spot] = new AmountRange({
                  amount: new BN((item as TierDummyEntry).amount),
                  length: new BN(1),
                });
                // If the first spot with anything is winner spot 1, you want a section of 0 covering winning
                // spot 0.
                // If we have a gap, we want a gap area covered with zeroes.
                const zeroLength = i - 1 > 0 ? spot - sorted[i - 1] - 1 : spot;
                if (zeroLength > 0) {
                  tierRanges.push(
                    new AmountRange({
                      amount: new BN(0),
                      length: new BN(zeroLength),
                    }),
                  );
                }
                tierRanges.push(tierRangeLookup[spot]);
              }
            });
            // Ok now we have combined ranges from this tier range. Now we merge them into the ranges
            // at the top level.
            const oldRanges = ranges;
            ranges = [];
            let oldRangeCtr = 0,
              tierRangeCtr = 0;

            while (
              oldRangeCtr < oldRanges.length ||
              tierRangeCtr < tierRanges.length
            ) {
              let toAdd = new BN(0);
              if (
                tierRangeCtr < tierRanges.length &&
                tierRanges[tierRangeCtr].amount.gt(new BN(0))
              ) {
                toAdd = tierRanges[tierRangeCtr].amount;
              }

              if (oldRangeCtr == oldRanges.length) {
                ranges.push(
                  new AmountRange({
                    amount: toAdd,
                    length: tierRanges[tierRangeCtr].length,
                  }),
                );
                tierRangeCtr++;
              } else if (tierRangeCtr == tierRanges.length) {
                ranges.push(oldRanges[oldRangeCtr]);
                oldRangeCtr++;
              } else if (
                oldRanges[oldRangeCtr].length.gt(
                  tierRanges[tierRangeCtr].length,
                )
              ) {
                oldRanges[oldRangeCtr].length = oldRanges[
                  oldRangeCtr
                ].length.sub(tierRanges[tierRangeCtr].length);

                ranges.push(
                  new AmountRange({
                    amount: oldRanges[oldRangeCtr].amount.add(toAdd),
                    length: tierRanges[tierRangeCtr].length,
                  }),
                );

                tierRangeCtr += 1;
                // dont increment oldRangeCtr since i still have length to give
              } else if (
                tierRanges[tierRangeCtr].length.gt(
                  oldRanges[oldRangeCtr].length,
                )
              ) {
                tierRanges[tierRangeCtr].length = tierRanges[
                  tierRangeCtr
                ].length.sub(oldRanges[oldRangeCtr].length);

                ranges.push(
                  new AmountRange({
                    amount: oldRanges[oldRangeCtr].amount.add(toAdd),
                    length: oldRanges[oldRangeCtr].length,
                  }),
                );

                oldRangeCtr += 1;
                // dont increment tierRangeCtr since they still have length to give
              } else if (
                tierRanges[tierRangeCtr].length.eq(
                  oldRanges[oldRangeCtr].length,
                )
              ) {
                ranges.push(
                  new AmountRange({
                    amount: oldRanges[oldRangeCtr].amount.add(toAdd),
                    length: oldRanges[oldRangeCtr].length,
                  }),
                );
                // Move them both in this degen case
                oldRangeCtr++;
                tierRangeCtr++;
              }
            }
          }
        });
        console.log('Ranges');
        config.amountRanges = ranges;
      });

      winnerLimit = new WinnerLimit({
        type: WinnerLimitType.Capped,
        usize: new BN(attributes.winnersCount),
      });
      if (
        attributes.participationNFT &&
        attributes.participationNFT.participationConfig
      ) {
        attributes.participationNFT.participationConfig.fixedPrice = new BN(
          toLamports(attributes.participationFixedPrice, mint) || 0,
        );
      }
      console.log('Tiered settings', tieredAttributes.items);
    }

    const isInstantSale =
      attributes.instantSalePrice &&
      attributes.priceFloor === attributes.instantSalePrice;

    const LAMPORTS_PER_TOKEN =
      attributes.quoteMintAddress == WRAPPED_SOL_MINT.toBase58()
        ? LAMPORTS_PER_SOL
        : Math.pow(10, attributes.quoteMintInfo.decimals || 0);

    const auctionSettings: IPartialCreateAuctionArgs = {
      winners: winnerLimit,
      endAuctionAt: isInstantSale
        ? null
        : new BN(
            (attributes.auctionDuration || 0) *
              (attributes.auctionDurationType == 'days'
                ? 60 * 60 * 24 // 1 day in seconds
                : attributes.auctionDurationType == 'hours'
                ? 60 * 60 // 1 hour in seconds
                : 60), // 1 minute in seconds
          ), // endAuctionAt is actually auction duration, poorly named, in seconds
      auctionGap: isInstantSale
        ? null
        : new BN(
            (attributes.gapTime || 0) *
              (attributes.gapTimeType == 'days'
                ? 60 * 60 * 24 // 1 day in seconds
                : attributes.gapTimeType == 'hours'
                ? 60 * 60 // 1 hour in seconds
                : 60), // 1 minute in seconds
          ),
      priceFloor: new PriceFloor({
        type: attributes.priceFloor
          ? PriceFloorType.Minimum
          : PriceFloorType.None,
        minPrice: new BN((attributes.priceFloor || 0) * LAMPORTS_PER_TOKEN),
      }),
      tokenMint: attributes.quoteMintAddress,
      gapTickSizePercentage: attributes.tickSizeEndingPhase || null,
      tickSize: attributes.priceTick
        ? new BN(attributes.priceTick * LAMPORTS_PER_TOKEN)
        : null,
      instantSalePrice: attributes.instantSalePrice
        ? new BN((attributes.instantSalePrice || 0) * LAMPORTS_PER_TOKEN)
        : null,
      name: null,
    };

    const isOpenEdition =
      attributes.category === AuctionCategory.Open ||
      attributes.instantSaleType === InstantSaleType.Open;
    const safetyDepositDrafts = isOpenEdition
      ? []
      : attributes.category !== AuctionCategory.Tiered
      ? attributes.items
      : tieredAttributes.items;
    const participationSafetyDepositDraft = isOpenEdition
      ? attributes.items[0]
      : attributes.participationNFT;

    const _auctionObj = await createAuctionManager(
      connection,
      wallet,
      whitelistedCreatorsByCreator,
      auctionSettings,
      safetyDepositDrafts,
      participationSafetyDepositDraft,
      attributes.quoteMintAddress,
      storeIndexer,
    );
    setAuctionObj(_auctionObj);
  };

  const categoryStep = (
    <CategoryStep
      confirm={(category: AuctionCategory) => {
        setAttributes({
          ...attributes,
          category,
        });
        gotoNextStep();
      }}
    />
  );

  const instantSaleStep = (
    <InstantSaleStep
      attributes={attributes}
      setAttributes={setAttributes}
      confirm={() => gotoNextStep()}
    />
  );

  const copiesStep = (
    <CopiesStep
      attributes={attributes}
      setAttributes={setAttributes}
      confirm={() => gotoNextStep()}
    />
  );

  const winnersStep = (
    <NumberOfWinnersStep
      attributes={attributes}
      setAttributes={setAttributes}
      confirm={() => gotoNextStep()}
    />
  );

  const priceAuction = (
    <PriceAuction
      attributes={attributes}
      setAttributes={setAttributes}
      confirm={() => gotoNextStep()}
    />
  );

  const initialStep = (
    <InitialPhaseStep
      attributes={attributes}
      setAttributes={setAttributes}
      confirm={() => gotoNextStep()}
    />
  );

  const endingStep = (
    <EndingPhaseAuction
      attributes={attributes}
      setAttributes={setAttributes}
      confirm={() => gotoNextStep()}
    />
  );

  const participationStep = (
    <ParticipationStep
      attributes={attributes}
      setAttributes={setAttributes}
      confirm={() => gotoNextStep()}
    />
  );

  const tierTableStep = (
    <TierTableStep
      attributes={tieredAttributes}
      setAttributes={setTieredAttributes}
      maxWinners={attributes.winnersCount}
      confirm={() => gotoNextStep()}
    />
  );

  const reviewStep = (
    <ReviewStep
      attributes={attributes}
      setAttributes={setAttributes}
      confirm={() => {
        setStepsVisible(false);
        gotoNextStep();
      }}
      connection={connection}
    />
  );

  const waitStep = (
    <WaitingStep createAuction={createAuction} confirm={() => gotoNextStep()} />
  );

  const congratsStep = <Congrats auction={auctionObj} />;

  const stepsByCategory = {
    [AuctionCategory.InstantSale]: [
      ['Category', categoryStep],
      ['Instant Sale', instantSaleStep],
      ['Review', reviewStep],
      ['Publish', waitStep],
      [undefined, congratsStep],
    ],
    [AuctionCategory.Limited]: [
      ['Category', categoryStep],
      ['Copies', copiesStep],
      ['Price', priceAuction],
      ['Initial Phase', initialStep],
      ['Ending Phase', endingStep],
      ['Participation NFT', participationStep],
      ['Review', reviewStep],
      ['Publish', waitStep],
      [undefined, congratsStep],
    ],
    [AuctionCategory.Single]: [
      ['Category', categoryStep],
      ['Copies', copiesStep],
      ['Price', priceAuction],
      ['Initial Phase', initialStep],
      ['Ending Phase', endingStep],
      ['Participation NFT', participationStep],
      ['Review', reviewStep],
      ['Publish', waitStep],
      [undefined, congratsStep],
    ],
    [AuctionCategory.Open]: [
      ['Category', categoryStep],
      ['Copies', copiesStep],
      ['Price', priceAuction],
      ['Initial Phase', initialStep],
      ['Ending Phase', endingStep],
      ['Review', reviewStep],
      ['Publish', waitStep],
      [undefined, congratsStep],
    ],
    [AuctionCategory.Tiered]: [
      ['Category', categoryStep],
      ['Winners', winnersStep],
      ['Tiers', tierTableStep],
      ['Price', priceAuction],
      ['Initial Phase', initialStep],
      ['Ending Phase', endingStep],
      ['Participation NFT', participationStep],
      ['Review', reviewStep],
      ['Publish', waitStep],
      [undefined, congratsStep],
    ],
  };

  return (
    <>
      <Row className="creator-base-page" style={{ paddingTop: 50 }}>
        {stepsVisible && (
          <Col span={24} md={4}>
            <Steps
              progressDot
              direction={width < 768 ? 'horizontal' : 'vertical'}
              current={step}
              style={{
                width: 'fit-content',
                margin: '0 auto 30px auto',
                overflowX: 'auto',
                maxWidth: '100%',
              }}
            >
              {stepsByCategory[attributes.category]
                .filter(_ => !!_[0])
                .map((step, idx) => (
                  <Step title={step[0]} key={idx} />
                ))}
            </Steps>
          </Col>
        )}
        <Col span={24} {...(stepsVisible ? { md: 20 } : { md: 24 })}>
          {stepsByCategory[attributes.category][step][1]}
          {0 < step && stepsVisible && (
            <div style={{ margin: 'auto', width: 'fit-content' }}>
              <Button onClick={() => gotoNextStep(step - 1)}>Back</Button>
            </div>
          )}
        </Col>
      </Row>
    </>
  );
}
Example #13
Source File: index.tsx    From metaplex with Apache License 2.0 4 votes vote down vote up
WaitingStep = (props: {
  mint: Function;
  minting: boolean;
  confirm: Function;
  step: number;
}) => {
  useEffect(() => {
    const func = async () => {
      await props.mint();
      props.confirm();
    };
    func();
  }, []);

  const setIconForStep = (currentStep: number, componentStep) => {
    if (currentStep === componentStep) {
      return <LoadingOutlined />;
    }
    return null;
  };

  return (
    <div
      style={{
        marginTop: 70,
        display: 'flex',
        flexDirection: 'column',
        alignItems: 'center',
      }}
    >
      <Spin size="large" />
      <Card>
        <Steps direction="vertical" current={props.step}>
          <Step
            className={'white-description'}
            title="Minting"
            description="Starting Mint Process"
            icon={setIconForStep(props.step, 0)}
          />
          <Step
            className={'white-description'}
            title="Preparing Assets"
            icon={setIconForStep(props.step, 1)}
          />
          <Step
            className={'white-description'}
            title="Signing Metadata Transaction"
            description="Approve the transaction from your wallet"
            icon={setIconForStep(props.step, 2)}
          />
          <Step
            className={'white-description'}
            title="Sending Transaction to Solana"
            description="This will take a few seconds."
            icon={setIconForStep(props.step, 3)}
          />
          <Step
            className={'white-description'}
            title="Waiting for Initial Confirmation"
            icon={setIconForStep(props.step, 4)}
          />
          <Step
            className={'white-description'}
            title="Waiting for Final Confirmation"
            icon={setIconForStep(props.step, 5)}
          />
          <Step
            className={'white-description'}
            title="Uploading to Arweave"
            icon={setIconForStep(props.step, 6)}
          />
          <Step
            className={'white-description'}
            title="Updating Metadata"
            icon={setIconForStep(props.step, 7)}
          />
          <Step
            className={'white-description'}
            title="Signing Token Transaction"
            description="Approve the final transaction from your wallet"
            icon={setIconForStep(props.step, 8)}
          />
        </Steps>
      </Card>
    </div>
  );
}
Example #14
Source File: index.tsx    From metaplex with Apache License 2.0 4 votes vote down vote up
ArtCreateView = () => {
  const connection = useConnection();
  const { endpoint } = useConnectionConfig();
  const wallet = useWallet();
  const [alertMessage, setAlertMessage] = useState<string>();
  const { step_param }: { step_param: string } = useParams();
  const history = useHistory();
  const { width } = useWindowDimensions();
  const [nftCreateProgress, setNFTcreateProgress] = useState<number>(0);

  const [step, setStep] = useState<number>(0);
  const [stepsVisible, setStepsVisible] = useState<boolean>(true);
  const [isMinting, setMinting] = useState<boolean>(false);
  const [nft, setNft] = useState<
    { metadataAccount: StringPublicKey } | undefined
  >(undefined);
  const [files, setFiles] = useState<File[]>([]);
  const [isCollection, setIsCollection] = useState<boolean>(false);
  const [attributes, setAttributes] = useState<IMetadataExtension>({
    name: '',
    symbol: '',
    collection: '',
    description: '',
    external_url: '',
    image: '',
    animation_url: undefined,
    attributes: undefined,
    seller_fee_basis_points: 0,
    creators: [],
    properties: {
      files: [],
      category: MetadataCategory.Image,
    },
  });

  const gotoStep = useCallback(
    (_step: number) => {
      history.push(`/art/create/${_step.toString()}`);
      if (_step === 0) setStepsVisible(true);
    },
    [history],
  );

  useEffect(() => {
    if (step_param) setStep(parseInt(step_param));
    else gotoStep(0);
  }, [step_param, gotoStep]);

  // store files
  const mint = async () => {
    const metadata = {
      name: attributes.name,
      symbol: attributes.symbol,
      creators: attributes.creators,
      collection: attributes.collection,
      description: attributes.description,
      sellerFeeBasisPoints: attributes.seller_fee_basis_points,
      image: attributes.image,
      animation_url: attributes.animation_url,
      attributes: attributes.attributes,
      external_url: attributes.external_url,
      properties: {
        files: attributes.properties.files,
        category: attributes.properties?.category,
      },
    };
    setStepsVisible(false);
    setMinting(true);

    try {
      const _nft = await mintNFT(
        connection,
        wallet,
        endpoint.name,
        files,
        metadata,
        setNFTcreateProgress,
        attributes.properties?.maxSupply,
      );

      if (_nft) setNft(_nft);
      setAlertMessage('');
    } catch (e: any) {
      setAlertMessage(e.message);
    } finally {
      setMinting(false);
    }
  };

  return (
    <>
      <Row className={'creator-base-page'} style={{ paddingTop: 50 }}>
        {stepsVisible && (
          <Col span={24} md={4}>
            <Steps
              progressDot
              direction={width < 768 ? 'horizontal' : 'vertical'}
              current={step}
              style={{
                width: 'fit-content',
                margin: '0 auto 30px auto',
                overflowX: 'auto',
                maxWidth: '100%',
              }}
            >
              <Step title="Category" />
              <Step title="Upload" />
              <Step title="Info" />
              <Step title="Royalties" />
              <Step title="Launch" />
            </Steps>
          </Col>
        )}
        <Col span={24} {...(stepsVisible ? { md: 20 } : { md: 24 })}>
          {step === 0 && (
            <CategoryStep
              confirm={(category: MetadataCategory) => {
                setAttributes({
                  ...attributes,
                  properties: {
                    ...attributes.properties,
                    category,
                  },
                });
                gotoStep(1);
              }}
            />
          )}
          {step === 1 && (
            <UploadStep
              attributes={attributes}
              setAttributes={setAttributes}
              files={files}
              setFiles={setFiles}
              confirm={() => gotoStep(2)}
            />
          )}

          {step === 2 && (
            <InfoStep
              attributes={attributes}
              files={files}
              isCollection={isCollection}
              setIsCollection={setIsCollection}
              setAttributes={setAttributes}
              confirm={() => gotoStep(3)}
            />
          )}
          {step === 3 && (
            <RoyaltiesStep
              attributes={attributes}
              confirm={() => gotoStep(4)}
              setAttributes={setAttributes}
            />
          )}
          {step === 4 && (
            <LaunchStep
              attributes={attributes}
              files={files}
              confirm={() => gotoStep(5)}
              connection={connection}
            />
          )}
          {step === 5 && (
            <WaitingStep
              mint={mint}
              minting={isMinting}
              step={nftCreateProgress}
              confirm={() => gotoStep(6)}
            />
          )}
          {0 < step && step < 5 && (
            <div style={{ margin: 'auto', width: 'fit-content' }}>
              <Button onClick={() => gotoStep(step - 1)}>Back</Button>
            </div>
          )}
        </Col>
      </Row>
      <MetaplexOverlay visible={step === 6}>
        <Congrats nft={nft} alert={alertMessage} />
      </MetaplexOverlay>
    </>
  );
}
Example #15
Source File: control.tsx    From leek with Apache License 2.0 4 votes vote down vote up
ControlPage = () => {
  const [current, setCurrent] = useState(0);
  const [command, setCommand] = useState<string>("revoke");
  const { currentApp, currentEnv } = useApplication();

  const service = new ControlService();
  const metricsService = new MetricsService();
  const [broadcasting, setBroadcasting] = useState<boolean>();

  const [seenTasks, setSeenTasks] = useState([]);
  const [taskName, setTaskName] = useState<string>();
  const [terminate, setTerminate] = useState<boolean>(false);
  const [signal, setSignal] = useState<string>("SIGTERM");
  const [revocationCount, setRevocationCount] = useState<number>(0);

  const [seenTasksFetching, setSeenTasksFetching] = useState<boolean>();

  const next = () => {
    if (command === "revoke" && current === 1)
      revoke("true").then(() => {
        setCurrent(current + 1);
      });
    else setCurrent(current + 1);
  };

  const prev = () => {
    setCurrent(current - 1);
  };

  const memoizedTaskNameOptions = useMemo(() => {
    // memoize this because it's common to have many different task names, which causes the dropdown to be very laggy.
    // This is a known problem in Ant Design
    return seenTasks.map((task, key) => badgedOption(task));
  }, [seenTasks]);

  function revoke(dry_run) {
    if (!currentApp || !currentEnv || !taskName) return;
    setBroadcasting(true);
    return service
      .revokeTasksByName(
        currentApp,
        currentEnv,
        taskName,
        terminate,
        signal,
        dry_run
      )
      .then(handleAPIResponse)
      .then((result: any) => {
        setRevocationCount(result.revocation_count);
        if (dry_run !== "true") {
          setCurrent(0);
          pendingRevocation(result);
        }
      }, handleAPIError)
      .catch(handleAPIError)
      .finally(() => setBroadcasting(false));
  }

  function broadcastCommand() {
    if (command === "revoke") revoke("false");
  }

  function pendingRevocation(result) {
    confirm({
      title: "Tasks pending revocation!",
      icon: <CheckCircleOutlined style={{ color: "#00BFA6" }} />,
      content: (
        <>
          <Typography.Paragraph>
            Revocation command queued for {result.revocation_count} tasks!
          </Typography.Paragraph>
        </>
      ),
      okText: "Ok",
      cancelButtonProps: { style: { display: "none" } },
    });
  }

  function getSeenTasks(open) {
    if (!currentApp || !open) return;
    setSeenTasksFetching(true);
    metricsService
      .getSeenTasks(currentApp, currentEnv, {})
      .then(handleAPIResponse)
      .then((result: any) => {
        setSeenTasks(result.aggregations.seen_tasks.buckets);
      }, handleAPIError)
      .catch(handleAPIError)
      .finally(() => setSeenTasksFetching(false));
  }

  return (
    <>
      <Helmet>
        <html lang="en" />
        <title>Control</title>
        <meta name="description" content="Control commands" />
        <meta name="keywords" content="celery, commands" />
      </Helmet>

      {/* Steps */}
      <Row style={{ marginTop: 20 }}>
        <Card style={{ width: "100%" }}>
          <Steps current={current}>
            <Step title="Command" description="Choose command" />
            <Step title="Setup" description="Setup command args" />
            <Step title="Broadcast" description="Broadcast command" />
          </Steps>
        </Card>
      </Row>

      {/* Tabs Containers */}
      <Row style={{ marginTop: 20, marginBottom: 20 }}>
        <Card style={{ width: "100%", alignItems: "center" }}>
          {current == 0 && (
            <Row justify="center" style={{ width: "100%" }}>
              <Row style={{ width: "100%" }} justify="center">
                <Typography.Title level={5}>
                  What control command you want to broadcast?
                </Typography.Title>
              </Row>

              <Row style={{ width: "100%" }} justify="center">
                <Select
                  style={{ width: "200" }}
                  defaultValue="revoke"
                  onSelect={(value) => setCommand(value)}
                >
                  <Option value="revoke">Revoke</Option>
                </Select>
              </Row>
            </Row>
          )}

          {current == 1 && command === "revoke" && (
            <Row justify="center" style={{ width: "100%" }}>
              <Typography.Paragraph>
                Revoking tasks works by sending a broadcast message to all the
                workers, the workers then keep a list of revoked tasks in
                memory. When a worker receives a task in the list, it will skip
                executing the task.
              </Typography.Paragraph>

              <Select
                placeholder="Task name"
                style={{ width: "100%" }}
                allowClear
                showSearch
                dropdownMatchSelectWidth={false}
                onDropdownVisibleChange={getSeenTasks}
                notFoundContent={seenTasksFetching ? loadingIndicator : null}
                // @ts-ignore
                onSelect={(value) => setTaskName(value)}
              >
                {memoizedTaskNameOptions}
              </Select>

              <Row align="middle" style={{ marginTop: 16, width: "100%" }}>
                <Checkbox onChange={(e) => setTerminate(e.target.checked)}>
                  {" "}
                  Terminate already started tasks with
                </Checkbox>
                <Select
                  style={{ width: 90 }}
                  // @ts-ignore
                  onSelect={(value) => setSignal(value)}
                  defaultValue="SIGTERM"
                >
                  <Option value="SIGTERM">SIGTERM</Option>
                  <Option value="SIGKILL">SIGKILL</Option>
                </Select>
              </Row>

              <Row justify="start" style={{ width: "100%", marginTop: 10 }}>
                <Typography.Paragraph type="secondary">
                  The worker won’t terminate an already executing task unless
                  the terminate option is set.
                </Typography.Paragraph>
              </Row>

              <Divider />

              <Row justify="start" style={{ width: "100%" }}>
                <Typography.Text type="secondary">
                  <Typography.Text strong type="warning">
                    Caveats:
                  </Typography.Text>
                  <ul>
                    <li>
                      When a worker starts up it will synchronize revoked tasks
                      with other workers in the cluster unless you have disabled
                      synchronization using worker arg
                      <Typography.Text code>--without-mingle</Typography.Text>.
                    </li>
                    <li>
                      If The list of revoked tasks is in-memory and if all
                      workers restart the list of revoked ids will also vanish.
                      If you want to preserve this list between restarts you
                      need to specify a file for these to be stored in by using
                      the <Typography.Text code>–statedb</Typography.Text>{" "}
                      argument to celery worker.
                    </li>
                  </ul>
                </Typography.Text>
              </Row>
            </Row>
          )}

          {current == 2 && command === "revoke" && (
            <>
              <Row justify="center" style={{ width: "100%" }}>
                <Typography.Paragraph>
                  Found{" "}
                  <Typography.Text code>{revocationCount}</Typography.Text>{" "}
                  pending ( <TaskState state="QUEUED" />{" "}
                  <TaskState state="RECEIVED" /> <TaskState state="STARTED" />)
                  instances of task{" "}
                  <Typography.Text code>{taskName}</Typography.Text>. Are you
                  sure you want to revoke them all?
                </Typography.Paragraph>
              </Row>
              {terminate && (
                <Row justify="center" style={{ width: "100%" }}>
                  <Typography.Paragraph type="secondary">
                    If an instance is already <TaskState state="STARTED" /> it
                    will be terminated using{" "}
                    <Typography.Text code>{signal}</Typography.Text> signal!
                  </Typography.Paragraph>
                </Row>
              )}
            </>
          )}
        </Card>
      </Row>

      {/* Controls */}
      <Row justify="end">
        {current > 0 && (
          <Button style={{ margin: "0 8px" }} onClick={() => prev()}>
            Previous
          </Button>
        )}
        {current < 2 && (
          <Button type="primary" onClick={() => next()}>
            Next
          </Button>
        )}
        {current === 2 && (
          <Button
            type="primary"
            onClick={broadcastCommand}
            loading={broadcasting}
          >
            Broadcast
          </Button>
        )}
      </Row>
    </>
  );
}
Example #16
Source File: UpdateForm.tsx    From ui-visualization with MIT License 4 votes vote down vote up
UpdateForm: React.FC<UpdateFormProps> = (props) => {
  const [formVals, setFormVals] = useState<FormValueType>({
    name: props.values.name,
    desc: props.values.desc,
    key: props.values.key,
    target: '0',
    template: '0',
    type: '1',
    time: '',
    frequency: 'month',
  });

  const [currentStep, setCurrentStep] = useState<number>(0);

  const [form] = Form.useForm();

  const {
    onSubmit: handleUpdate,
    onCancel: handleUpdateModalVisible,
    updateModalVisible,
    values,
  } = props;

  const forward = () => setCurrentStep(currentStep + 1);

  const backward = () => setCurrentStep(currentStep - 1);

  const handleNext = async () => {
    const fieldsValue = await form.validateFields();

    setFormVals({ ...formVals, ...fieldsValue });

    if (currentStep < 2) {
      forward();
    } else {
      handleUpdate({ ...formVals, ...fieldsValue });
    }
  };

  const renderContent = () => {
    if (currentStep === 1) {
      return (
        <>
          <FormItem name="target" label="监控对象">
            <Select style={{ width: '100%' }}>
              <Option value="0">表一</Option>
              <Option value="1">表二</Option>
            </Select>
          </FormItem>
          <FormItem name="template" label="规则模板">
            <Select style={{ width: '100%' }}>
              <Option value="0">规则模板一</Option>
              <Option value="1">规则模板二</Option>
            </Select>
          </FormItem>
          <FormItem name="type" label="规则类型">
            <RadioGroup>
              <Radio value="0">强</Radio>
              <Radio value="1">弱</Radio>
            </RadioGroup>
          </FormItem>
        </>
      );
    }
    if (currentStep === 2) {
      return (
        <>
          <FormItem
            name="time"
            label="开始时间"
            rules={[{ required: true, message: '请选择开始时间!' }]}
          >
            <DatePicker
              style={{ width: '100%' }}
              showTime
              format="YYYY-MM-DD HH:mm:ss"
              placeholder="选择开始时间"
            />
          </FormItem>
          <FormItem name="frequency" label="调度周期">
            <Select style={{ width: '100%' }}>
              <Option value="month">月</Option>
              <Option value="week">周</Option>
            </Select>
          </FormItem>
        </>
      );
    }
    return (
      <>
        <FormItem
          name="name"
          label="规则名称"
          rules={[{ required: true, message: '请输入规则名称!' }]}
        >
          <Input placeholder="请输入" />
        </FormItem>
        <FormItem
          name="desc"
          label="规则描述"
          rules={[{ required: true, message: '请输入至少五个字符的规则描述!', min: 5 }]}
        >
          <TextArea rows={4} placeholder="请输入至少五个字符" />
        </FormItem>
      </>
    );
  };

  const renderFooter = () => {
    if (currentStep === 1) {
      return (
        <>
          <Button style={{ float: 'left' }} onClick={backward}>
            上一步
          </Button>
          <Button onClick={() => handleUpdateModalVisible(false, values)}>取消</Button>
          <Button type="primary" onClick={() => handleNext()}>
            下一步
          </Button>
        </>
      );
    }
    if (currentStep === 2) {
      return (
        <>
          <Button style={{ float: 'left' }} onClick={backward}>
            上一步
          </Button>
          <Button onClick={() => handleUpdateModalVisible(false, values)}>取消</Button>
          <Button type="primary" onClick={() => handleNext()}>
            完成
          </Button>
        </>
      );
    }
    return (
      <>
        <Button onClick={() => handleUpdateModalVisible(false, values)}>取消</Button>
        <Button type="primary" onClick={() => handleNext()}>
          下一步
        </Button>
      </>
    );
  };

  return (
    <Modal
      width={640}
      bodyStyle={{ padding: '32px 40px 48px' }}
      destroyOnClose
      title="规则配置"
      visible={updateModalVisible}
      footer={renderFooter()}
      onCancel={() => handleUpdateModalVisible()}
    >
      <Steps style={{ marginBottom: 28 }} size="small" current={currentStep}>
        <Step title="基本信息" />
        <Step title="配置规则属性" />
        <Step title="设定调度周期" />
      </Steps>
      <Form
        {...formLayout}
        form={form}
        initialValues={{
          target: formVals.target,
          template: formVals.template,
          type: formVals.type,
          frequency: formVals.frequency,
          name: formVals.name,
          desc: formVals.desc,
        }}
      >
        {renderContent()}
      </Form>
    </Modal>
  );
}
Example #17
Source File: groupSave.tsx    From jetlinks-ui-antd with MIT License 4 votes vote down vote up
groupSave: React.FC<Props> = props => {

  const {
    form: {getFieldDecorator},
    form,
  } = props;

  const initState: State = {
    currentStep: 0,
    deviceId: [],
    groupData: props.data
  };

  const [currentStep, setCurrentStep] = useState<number>(initState.currentStep);
  const [deviceId, setDeviceId] = useState(initState.deviceId);
  const [groupData, setGroupData] = useState(initState.groupData);

  let taskByIdPush: any;

  useEffect(() => {
    props.data.devices?.map((item: any) => {
      deviceId.push(item.id);
    });

    return () => {
      taskByIdPush && taskByIdPush.unsubscribe();
    };
  }, []);

  const submitData = () => {
    form.validateFields((err, fileValue) => {
      if (err) return;

      if (props.data.id) {
        apis.deviceGroup.saveOrUpdate(fileValue)
          .then((response: any) => {
            if (response.status === 200) {
              message.success("保存成功");
              setCurrentStep(Number(currentStep + 1));
            }
          }).catch(() => {
        })
      } else {
        apis.deviceGroup.save(fileValue)
          .then((response: any) => {
            if (response.status === 200) {
              message.success("保存成功");
              setCurrentStep(Number(currentStep + 1));
              setGroupData(response.result);
            }
          }).catch(() => {
        })
      }
    });
  };

  const groupBindDevice = () => {

    apis.deviceGroup._bind(groupData.id, deviceId)
      .then((response: any) => {
        if (response.status === 200) {
          message.success('绑定成功');
          setCurrentStep(Number(currentStep + 1));
        }
      }).catch(() => {
    });
  };

  return (

    <Modal
      title={`${props.data?.id ? '编辑' : '新建'}设备分组`}
      visible
      okText={currentStep === 2 ? '完成' : '下一步'}
      cancelText={currentStep === 0 ? '取消' : '上一步'}
      onOk={() => {
        if (currentStep === 2) {
          props.close();
        } else if (currentStep === 1) {
          groupBindDevice();
        } else {
          submitData();
        }
      }}
      width='50%'
      onCancel={(event) => {
        if (event.target.tagName === 'BUTTON') {
          if (currentStep === 0) {
            props.close();
          } else {
            setCurrentStep(Number(currentStep - 1));
          }
        } else {
          props.close();
        }
      }}
    >

      <Steps current={currentStep} size="small" className={styles.steps} style={{paddingBottom: 24}}>
        <Steps.Step title="基本信息"/>
        <Steps.Step title="绑定设备"/>
        <Steps.Step title="完成"/>
      </Steps>
      <div>
        {currentStep === 0 && (
          <Form labelCol={{span: 5}} wrapperCol={{span: 15}} key="groupForm">
            <Form.Item key="id" label="分组标识">
              {getFieldDecorator('id', {
                rules: [
                  {required: true, message: '请输入分组标识'},
                  {max: 64, message: '分组标识不超过64个字符'},
                  {pattern: new RegExp(/^[0-9a-zA-Z_\-]+$/, "g"), message: '分组标识只能由数字、字母、下划线、中划线组成'}
                ],
                initialValue: props.data?.id,
              })(<Input placeholder="输入分组ID" disabled={!!props.data.id}/>)}
            </Form.Item>
            <Form.Item key="name" label="分组名称">
              {getFieldDecorator('name', {
                rules: [
                  {required: true, message: '请输入分组名称'},
                  {max: 200, message: '分组名称不超过200个字符'}
                ],
                initialValue: props.data?.name,
              })(<Input placeholder="输入分组名称"/>)}
            </Form.Item>
            <Form.Item key='description' label="描述">
              {getFieldDecorator('description', {
                initialValue: props.data?.description,
              })(<Input.TextArea rows={4}/>)}
            </Form.Item>
          </Form>
        )}

        {/* {currentStep === 1 && (
          <div>
            <Card style={{maxHeight: 500, overflowY: 'auto', overflowX: 'hidden'}}>
              <ChoiceDevice deviceList={deviceId} save={(item: any[]) => {
                setDeviceId(item);
              }}/>
            </Card>
          </div>
        )} */}

        {currentStep === 2 && (
          <Result
            status="success"
            title="操作成功"
            className={styles.result}
          >
          </Result>
        )}
      </div>
    </Modal>
  );
}
Example #18
Source File: index.tsx    From jetlinks-ui-antd with MIT License 4 votes vote down vote up
Save: React.FC<Props> = props => {

  const {
    form: { getFieldDecorator },
    form,
  } = props;

  const initState: State = {
    currentStep: 0,
    upgradeData: props.data,
    releaseType: '',
    deviceId: [],
    speedProgress: {
      waiting: 0,
      processing: 0,
    },
  };

  const [currentStep, setCurrentStep] = useState<number>(initState.currentStep);
  const [upgradeData, setUpgradeData] = useState(initState.upgradeData);
  const [releaseType, setReleaseType] = useState(initState.releaseType);
  const [deviceId, setDeviceId] = useState(initState.deviceId);
  const [speedProgress, setSpeedProgress] = useState(initState.speedProgress);
  const [progressConditions, setProgressConditions] = useState(false);
  const [resultSpinning, setResultSpinning] = useState(false);

  let taskByIdPush: any;

  const historyCount = () => {
    apis.firmware._count(
      encodeQueryParam({ terms: { taskId: upgradeData.id, state: 'waiting' } }),
    ).then((response: any) => {
      if (response.status === 200) {
        speedProgress.waiting = response.result;
        setSpeedProgress({ ...speedProgress });
        apis.firmware._count(
          encodeQueryParam({ terms: { taskId: upgradeData.id, state: 'processing' } }),
        ).then((response: any) => {
          if (response.status === 200) {
            speedProgress.processing = response.result;
            setSpeedProgress({ ...speedProgress });
            setProgressConditions(true);
            taskPush();
          } else {
            setResultSpinning(false);
          }
        }).catch(() => {
        });
      } else {
        setResultSpinning(false);
      }
    }).catch(() => {
    });
  };

  useEffect(() => {
    return () => {
      taskByIdPush && taskByIdPush.unsubscribe();
    };
  }, []);

  const submitData = () => {
    form.validateFields((err, fileValue) => {
      if (err) return;

      let params = {
        ...fileValue,
        id: props.data.id,
        productId: props.productId,
        firmwareId: props.firmwareId,
      };
      if (upgradeData.id) {
        apis.firmware.updateUpgrade(params)
          .then((response: any) => {
            if (response.status === 200) {
              message.success('保存成功');
              if (props.data.id) {
                setCurrentStep(2);
              } else {
                setCurrentStep(Number(currentStep + 1));
              }
            }
          }).catch(() => {
        });
      } else {
        apis.firmware.saveUpgrade(params)
          .then((response: any) => {
            if (response.status === 200) {
              message.success('保存成功');
              setUpgradeData(response.result);
              setCurrentStep(Number(currentStep + 1));
            }
          }).catch(() => {
        });
      }
    });
  };

  const taskRelease = () => {

    if (releaseType === '' || releaseType === null) {
      message.error('请选择发布方式');
      return;
    }
    if (releaseType === 'all') {
      apis.firmware._deployAll(upgradeData.id)
        .then((response: any) => {
          if (response.status === 200) {
            message.success('任务发布成功');
            setCurrentStep(Number(currentStep + 1));
          }
        }).catch(() => {
      });
    } else {
      apis.firmware._deploy(deviceId, upgradeData.id)
        .then((response: any) => {
          if (response.status === 200) {
            message.success('任务发布成功');
            setCurrentStep(Number(currentStep + 1));
          }
        }).catch(() => {
      });
    }
  };

  const taskPush = () => {
    if (taskByIdPush) {
      taskByIdPush.unsubscribe();
    }
    setResultSpinning(false);
    taskByIdPush = getWebsocket(
      `firmware-push-upgrade-by-taskId`,
      `/device-firmware/publish`,
      {
        taskId: upgradeData.id,
      },
    ).subscribe((resp: any) => {
      const { payload } = resp;
      if (payload.success) {
        speedProgress.processing = (speedProgress.processing + 1);
        speedProgress.waiting = (speedProgress.waiting - 1);
        setSpeedProgress({ ...speedProgress });
      }
    });
  };

  const extra = (
    <>
      {upgradeData.mode?.value === 'push' && (
        <Button type="primary" onClick={() => {
          setResultSpinning(false);
          historyCount();
        }}>
          推送升级
        </Button>
      )}
    </>
  );

  const progressDisplay = (
    <div className={styles.information} style={{ textAlign: 'center' }}>
      <Descriptions column={1}>
        <Descriptions.Item label="等待升级">{speedProgress.waiting}</Descriptions.Item>
        <Descriptions.Item label="升级中"> {speedProgress.processing}</Descriptions.Item>
      </Descriptions>
    </div>
  );

  return (
    <Modal
      title={`${props.data?.id ? '编辑' : '新建'}固件版本`}
      visible
      okText={currentStep === 2 ? '完成' : '下一步'}
      cancelText={currentStep === 0 ? '取消' : '上一步'}
      onOk={() => {
        if (currentStep === 2) {
          props.close();
        } else if (currentStep === 1) {
          taskRelease();
        } else {
          submitData();
        }
      }}
      /*cancelButtonProps={currentStep === 2 ? { disabled: true } : { disabled: false }}*/
      width='60%'
      onCancel={(event) => {
        if (event.target.tagName === 'BUTTON') {
          if (currentStep === 0) {
            props.close();
          } else {
            setCurrentStep(Number(currentStep - 1));
          }
        } else {
          props.close();
        }
      }}
    >
      <Steps current={currentStep} className={styles.steps}>
        <Steps.Step title="任务信息"/>
        <Steps.Step title="发布任务"/>
        <Steps.Step title="完成"/>
      </Steps>
      {currentStep === 0 && (
        <Form labelCol={{ span: 3 }} wrapperCol={{ span: 20 }} key="firmwareForm">
          <Form.Item key="name" label="任务名称">
            {getFieldDecorator('name', {
              rules: [{ required: true, message: '任务名称必填' }],
              initialValue: props.data.name,
            })(<Input placeholder="输入任务名称"/>)}
          </Form.Item>
          <Form.Item key="timeoutSeconds" label="超时时间">
            {getFieldDecorator('timeoutSeconds', {
              rules: [{ required: true, message: '超时时间必填' }],
              initialValue: props.data.timeoutSeconds,
            })(<Input placeholder="输入超时时间/秒"/>)}
          </Form.Item>
          <Form.Item key="mode" label="推送方式">
            {getFieldDecorator('mode', {
              rules: [{ required: true, message: '推送方式必填' }],
              initialValue: props.data.mode?.value,
            })(<Select placeholder="选择推送方式">
              <Select.Option value='push'>平台推送</Select.Option>
              <Select.Option value='pull'>设备拉取</Select.Option>
            </Select>)}
          </Form.Item>
          <Form.Item label="描述">
            {getFieldDecorator('description', {
              initialValue: props.data.description,
            })(<Input.TextArea rows={4}/>)}
          </Form.Item>
        </Form>
      )}

      {currentStep === 1 && (
        <div>
          <Form labelCol={{ span: 3 }} wrapperCol={{ span: 20 }} key="releaseForm">
            <Form.Item key="releaseType" label="发布方式">
              {getFieldDecorator('releaseType', {
                rules: [{ required: true, message: '选择发布方式' }],
              })(<Select placeholder="选择发布方式" onChange={(value: string) => {
                setReleaseType(value);
              }}>
                <Select.Option value='all'>所有设备</Select.Option>
                <Select.Option value='part'>选择设备</Select.Option>
              </Select>)}
            </Form.Item>
          </Form>
          {releaseType === 'part' && (
            <Form.Item wrapperCol={{ span: 20 }} labelCol={{ span: 3 }} label='选择设备'>
              <Card style={{ maxHeight: 500, overflowY: 'auto', overflowX: 'hidden' }}>
                <ChoiceDevice productId={props.productId} save={(item: any[]) => {
                  setDeviceId(item);
                }}/>
              </Card>
            </Form.Item>
          )}
        </div>
      )}
      {currentStep === 2 && (
        <Spin spinning={resultSpinning} tip="加载中...">
          <Result status="success" title="操作成功" extra={extra} className={styles.result}>
            {progressConditions && (progressDisplay)}
          </Result>
        </Spin>
      )}
    </Modal>
  );
}
Example #19
Source File: SaveTask.tsx    From jetlinks-ui-antd with MIT License 4 votes vote down vote up
Save: React.FC<Props> = props => {

  const {
    form: {getFieldDecorator},
    form,
  } = props;

  const initState: State = {
    currentStep: props.appointStep,
    upgradeData: props.data,
    releaseType: 'all',
    deviceId: [],
    taskStatus: {
      waiting: 0,
      waitingSpinning: true,
      processing: 0,
      processingSpinning: true,
      success: 0,
      successSpinning: true,
      failed: 0,
      failedSpinning: true,
    },
  };

  const [currentStep, setCurrentStep] = useState<number>(initState.currentStep);
  const [upgradeData, setUpgradeData] = useState(initState.upgradeData);
  const [releaseType, setReleaseType] = useState(initState.releaseType);
  const [deviceId, setDeviceId] = useState(initState.deviceId);
  const [taskStatus, setTaskStatus] = useState(initState.taskStatus);
  const [spinning, setSpinning] = useState(false);
  const [pushOrSuspend, setPushOrSuspend] = useState(false);
  const [taskByIdPush, setTaskByIdPush] = useState<any>();

  useEffect(() => {
    return () => {
      taskByIdPush && taskByIdPush.unsubscribe();
    };
  }, [taskByIdPush]);

  const taskStatusProcessing = () => {
    apis.firmware._count(
      encodeQueryParam({terms: {taskId: upgradeData.id, state: 'processing'}}),
    ).then((response: any) => {
      if (response.status === 200) {
        taskStatus.processing = response.result;
        taskStatus.processingSpinning = false;
        setTaskStatus({...taskStatus});
      }
    }).catch(() => {
    });
  };

  const taskStatusWaiting = () => {
    apis.firmware._count(
      encodeQueryParam({terms: {taskId: upgradeData.id, state: 'waiting'}}),
    ).then((response: any) => {
      if (response.status === 200) {
        taskStatus.waiting = response.result;
        taskStatus.waitingSpinning = false;
        setTaskStatus({...taskStatus});
      }
    }).catch(() => {
    });
  };

  const taskStatusFailed = () => {
    apis.firmware._count(
      encodeQueryParam({terms: {taskId: upgradeData.id, state: 'failed'}}),
    ).then((response: any) => {
      if (response.status === 200) {
        taskStatus.failed = response.result;
        taskStatus.failedSpinning = false;
        setTaskStatus({...taskStatus});
      }
    }).catch(() => {
    });
  };

  const taskStatusSuccess = () => {
    apis.firmware._count(
      encodeQueryParam({terms: {taskId: upgradeData.id, state: 'success'}}),
    ).then((response: any) => {
      if (response.status === 200) {
        taskStatus.success = response.result;
        taskStatus.successSpinning = false;
        setTaskStatus({...taskStatus});
      }
    }).catch(() => {
    });
  };

  useEffect(() => {
    if (currentStep === 2) {
      taskStatusWaiting();
      taskStatusProcessing();
      taskStatusSuccess();
      taskStatusFailed();
    }
  }, [currentStep]);

  const submitData = () => {
    form.validateFields((err, fileValue) => {
      if (err) return;

      let params = {
        ...fileValue,
        id: upgradeData.id,
        productId: props.productId,
        firmwareId: props.firmwareId,
      };
      if (upgradeData.id) {
        apis.firmware.updateUpgrade(params)
          .then((response: any) => {
            if (response.status === 200) {
              message.success('保存成功');
              setSpinning(false);
              if (props.data.id) {
                setCurrentStep(2);
              } else {
                setCurrentStep(Number(currentStep + 1));
              }
            }
          }).catch(() => {
        });
      } else {
        apis.firmware.saveUpgrade(params)
          .then((response: any) => {
            if (response.status === 200) {
              message.success('保存成功');
              setUpgradeData(response.result);
              setSpinning(false);
              setCurrentStep(Number(currentStep + 1));
            }
          }).catch(() => {
        });
      }
    });
  };

  const taskRelease = () => {

    if (releaseType === '' || releaseType === null) {
      message.error('请选择发布方式');
      setSpinning(false);
      return;
    }
    if (releaseType === 'all') {
      apis.firmware._deployAll(upgradeData.id)
        .then((response: any) => {
          if (response.status === 200) {
            message.success('任务发布成功');
            setSpinning(false);
            setCurrentStep(Number(currentStep + 1));
          }
        }).catch(() => {
      });
    } else {
      apis.firmware._deploy(deviceId, upgradeData.id)
        .then((response: any) => {
          if (response.status === 200) {
            message.success('任务发布成功');
            setSpinning(false);
            setCurrentStep(Number(currentStep + 1));
          }
        }).catch(() => {
      });
    }
  };

  const taskPush = () => {
    if (taskByIdPush) {
      taskByIdPush.unsubscribe();
    }
    let taskPush = getWebsocket(
      `firmware-push-upgrade-by-taskId`,
      `/device-firmware/publish`,
      {
        taskId: upgradeData.id,
      },
    ).subscribe(() => {
      taskStatus.processing = (taskStatus.processing + 1);
      taskStatus.waiting = (taskStatus.waiting - 1);
      setTaskStatus({...taskStatus});
    });
    setTaskByIdPush(taskPush);
  };

  return (
    <Card style={{padding: 5}}>
      <Steps current={currentStep} size="small" className={styles.steps} style={{paddingBottom: 24}}>
        <Steps.Step title="任务信息"/>
        <Steps.Step title="发布任务"/>
        <Steps.Step title="完成"/>
      </Steps>
      <Spin spinning={spinning}>
        <div>
          {currentStep === 0 && (
            <Form labelCol={{span: 9}} wrapperCol={{span: 7}} key="firmwareForm">
              <Form.Item key="name" label="任务名称">
                {getFieldDecorator('name', {
                  rules: [
                    {required: true, message: '请输入任务名称'},
                    {max: 200, message: '任务名称不超过200个字符'}
                  ],
                  initialValue: upgradeData.name,
                })(<Input placeholder="输入任务名称"/>)}
              </Form.Item>
              <Form.Item key="timeoutSeconds" label="超时时间">
                {getFieldDecorator('timeoutSeconds', {
                  rules: [{required: true, message: '请输入超时时间'}],
                  initialValue: upgradeData.timeoutSeconds,
                })(<InputNumber min={0} step={1} style={{width:'100%'}} placeholder="请输入超时时间"/>)}
              </Form.Item>
              <Form.Item key="mode" label="推送方式">
                {getFieldDecorator('mode', {
                  rules: [{required: true, message: '推送方式必填'}],
                  initialValue: upgradeData.mode?.value,
                })(<Select placeholder="选择推送方式">
                  <Select.Option value='push'>平台推送</Select.Option>
                  <Select.Option value='pull'>设备拉取</Select.Option>
                </Select>)}
              </Form.Item>
              <Form.Item label="描述">
                {getFieldDecorator('description', {
                  initialValue: upgradeData.description,
                })(<Input.TextArea rows={4}/>)}
              </Form.Item>
            </Form>
          )}

          {currentStep === 1 && (
            <div>
              <Form labelCol={{span: 4}} wrapperCol={{span: 17}} key="releaseForm">
                <Form.Item key="releaseType" label="发布方式">
                  {getFieldDecorator('releaseType', {
                    rules: [{required: true, message: '选择发布方式'}],
                    initialValue: releaseType,
                  })(
                    <Radio.Group buttonStyle="solid" onChange={(event) => {
                      setReleaseType(event.target.value);
                    }}>
                      <Radio.Button value="all">所有设备</Radio.Button>
                      <Radio.Button value="part">选择设备</Radio.Button>
                    </Radio.Group>,
                  )}
                </Form.Item>
              </Form>
              {releaseType === 'part' && (
                <Form.Item labelCol={{span: 4}} wrapperCol={{span: 17}} label='选择设备'>
                  <Card style={{maxHeight: 500, overflowY: 'auto', overflowX: 'hidden'}}>
                    <ChoiceDevice productId={props.productId} save={(item: any[]) => {
                      setDeviceId(item);
                    }}/>
                  </Card>
                </Form.Item>
              )}
            </div>
          )}
          {currentStep === 2 && (
            <div style={{padding: '0 15% 0 15%'}}>
              <Row gutter={24}>
                <Col {...topColResponsiveProps}>
                  <Spin spinning={taskStatus.waitingSpinning}>
                    <ChartCard title={<Badge status="warning" text='等待升级'/>}
                               total={<AutoHide title={taskStatus.waiting} style={{width: '313%'}}/>}
                               action={
                                 <div>
                                   <Icon title='刷新' type="sync" onClick={() => {
                                     taskStatus.waitingSpinning = true;
                                     setTaskStatus({...taskStatus});
                                     taskStatusWaiting();
                                   }}/>
                                 </div>
                               }
                    >
                      <a style={{float: 'right', marginLeft: 8}}
                         onClick={() => {
                           props.close({type: 'history', taskId: props.data.id, state: 'waiting'});
                         }}>
                        查看
                      </a>
                      {upgradeData.mode?.value === 'push' && (
                        <>
                          {pushOrSuspend ? (
                            <Popconfirm title="确定暂停此次推送任务?请谨慎操作" onConfirm={() => {
                              taskByIdPush && taskByIdPush.unsubscribe();
                              setPushOrSuspend(false);
                              message.success('已暂停');
                            }}>
                              <a style={{float: 'right'}}>
                                暂停推送
                              </a>
                            </Popconfirm>
                          ) : (
                            <Popconfirm title="确定推送此升级任务至设备?请谨慎操作" onConfirm={() => {
                              setPushOrSuspend(true);
                              taskPush();
                            }}>
                              <a style={{float: 'right'}}>
                                推送升级
                              </a>
                            </Popconfirm>
                          )}
                        </>
                      )}
                    </ChartCard>
                  </Spin>
                </Col>
                <Col {...topColResponsiveProps}>
                  <Spin spinning={taskStatus.processingSpinning}>
                    <ChartCard title={<Badge status="processing" text='升级中'/>}
                               total={<AutoHide title={taskStatus.processing} style={{width: '313%'}}/>}
                               action={
                                 <div>
                                   <Icon title='刷新' type="sync" onClick={() => {
                                     taskStatus.processingSpinning = true;
                                     setTaskStatus({...taskStatus});
                                     taskStatusProcessing();
                                   }}/>
                                 </div>
                               }
                    >
                      <a style={{float: 'right'}}
                         onClick={() => {
                           props.close({type: 'history', taskId: props.data.id, state: 'processing'});
                         }}>
                        查看
                      </a>
                    </ChartCard>
                  </Spin>
                </Col>
                <Col {...topColResponsiveProps}>
                  <Spin spinning={taskStatus.successSpinning}>
                    <ChartCard title={<Badge status="success" text='升级完成'/>}
                               total={<AutoHide title={taskStatus.success} style={{width: '313%'}}/>}
                               action={
                                 <div>
                                   <Icon title='刷新' type="sync" onClick={() => {
                                     taskStatus.successSpinning = true;
                                     setTaskStatus({...taskStatus});
                                     taskStatusSuccess();
                                   }}/>
                                 </div>
                               }
                    >
                      <a style={{float: 'right'}}
                         onClick={() => {
                           props.close({type: 'history', taskId: props.data.id, state: 'success'});
                         }}>
                        查看
                      </a>
                    </ChartCard>
                  </Spin>
                </Col>
                <Col {...topColResponsiveProps}>
                  <Spin spinning={taskStatus.failedSpinning}>
                    <ChartCard title={<Badge status="error" text='升级失败'/>}
                               total={<AutoHide title={taskStatus.failed} style={{width: '313%'}}/>}
                               action={
                                 <div>
                                   <Icon title='刷新' type="sync" onClick={() => {
                                     taskStatus.failedSpinning = true;
                                     setTaskStatus({...taskStatus});
                                     taskStatusFailed();
                                   }}/>
                                 </div>
                               }
                    >
                      <a style={{float: 'right'}}
                         onClick={() => {
                           props.close({type: 'history', taskId: props.data.id, state: 'failed'});
                         }}>
                        查看
                      </a>
                    </ChartCard>
                  </Spin>
                </Col>
              </Row>
            </div>
          )}

          <div style={{textAlign: 'center'}}>
            {currentStep === 0 ? (<Button onClick={() => {
              props.close({type: 'task'});
            }}>
              返回
            </Button>) : (<Button onClick={() => {
                setCurrentStep(Number(currentStep - 1));
              }}>
                上一步
              </Button>
            )}
            {currentStep === 2 ? (
              <Button type="primary" style={{marginLeft: 8}} onClick={() => {
                props.close({type: 'task'});
              }}>
                完成
              </Button>
            ) : (<Button type="primary" style={{marginLeft: 8}} onClick={() => {
              setSpinning(true);
              if (currentStep === 0) {
                submitData();
              } else {
                taskRelease();
              }
            }}>
              下一步
            </Button>)}
          </div>
        </div>
      </Spin>
    </Card>
  );
}
Example #20
Source File: questionnaire.tsx    From RareCamp with Apache License 2.0 4 votes vote down vote up
export default function questionnaire() {
  const [current, setCurrent] = React.useState(0)
  const [formValues, setFormValues] = React.useState({})
  const [feasibility, setFeasibility] = React.useState({
    isFeasible: false,
    assessmentFinished: false,
    answers: {},
  })
  const [content, setContent] = React.useState({
    imgURL: '/eligibility_2.png',
    description:
      "Lorem ipsum, or lipsum as it is sometimes known, is dummy text used in laying out print, graphic or web designs. The passage is attributed to an unknown typesetter in the 15th century who is thought to have scrambled parts of Cicero's De",
  })

  React.useEffect(() => {
    if (current === 0)
      setContent({
        imgURL: '/eligibility_2.png',
        description:
          "Lorem ipsum, or lipsum as it is sometimes known, is dummy text used in laying out print, graphic or web designs. The passage is attributed to an unknown typesetter in the 15th century who is thought to have scrambled parts of Cicero's De",
      })
    else if (current === 1)
      setContent({
        imgURL: '/eligibility_4.png',
        description:
          "Lorem ipsum, or lipsum as it is sometimes known, is dummy text used in laying out print, graphic or web designs. The passage is attributed to an unknown typesetter in the 15th century who is thought to have scrambled parts of Cicero's De",
      })
    else
      setContent({
        imgURL: '/eligibility_3.png',
        description:
          "Lorem ipsum, or lipsum as it is sometimes known, is dummy text used in laying out print, graphic or web designs. The passage is attributed to an unknown typesetter in the 15th century who is thought to have scrambled parts of Cicero's De",
      })
  }, [current])

  const [form] = Form.useForm()
  useEffect(() => {
    setFormValues({ ...formValues, ...form.getFieldsValue() })
  }, [form])
  async function handleFormSubmit(values: Questionnaire) {
    const isFeasible = isGeneTherapyFeasible(values)
    setFeasibility({
      isFeasible,
      assessmentFinished: true,
      answers: values,
    })
  }

  const nextStep = () =>
    form.validateFields().then(() => setCurrent(current + 1))
  const title = 'Determine eligibility for AAV-based gene therapy'
  const subTitle =
    'Complete this short questionnaire to help our team determine your eligibility.'
  return (
    <AppLayout title="" selectedKey="programs">
      <SubHeader title={<h3>{title}</h3>} subTitle={subTitle} />
      <QuestionnaireContainer>
        <div className="questionnaire-form">
          {feasibility.assessmentFinished ? (
            <QuestionnaireResult
              isFeasible={feasibility.isFeasible}
              answers={feasibility.answers as Questionnaire}
            />
          ) : (
            <>
              <Steps current={current}>
                {steps.map((item, index) => (
                  <Step
                    className={index === 0 ? 'first-step' : ''}
                    key={item.title}
                    title={item.title}
                  />
                ))}
              </Steps>
              <OFForm
                onFinish={handleFormSubmit}
                initialValues={{
                  proteinSize: ProteinSize.LESS_THAN_1100,
                  mutationType: MutationType.LEADS_TO_LOSS,
                }}
                layout="vertical"
                form={form}
              >
                <div className="steps-content">
                  {steps.map((item, index) => (
                    <div
                      key={item.title}
                      style={{
                        display: index === current ? 'block' : 'none',
                      }}
                    >
                      {item.content}
                    </div>
                  ))}
                </div>
                <div className="steps-action">
                  {current > 0 && (
                    <Button
                      style={{ margin: '0 8px' }}
                      onClick={() => setCurrent(current - 1)}
                    >
                      Back
                    </Button>
                  )}

                  {current < steps.length - 1 && (
                    <Button type="primary" onClick={nextStep}>
                      Next
                    </Button>
                  )}
                  {current === steps.length - 1 && (
                    <Button type="primary" htmlType="submit">
                      Check Eligibility
                    </Button>
                  )}
                </div>
              </OFForm>
            </>
          )}
        </div>
        <QuestionnaireIllustration
          feasibility={feasibility}
          className="questionnaire-illustration"
          imgURL={content.imgURL}
          description={content.description}
        />
      </QuestionnaireContainer>
    </AppLayout>
  )
}
Example #21
Source File: index.tsx    From posthog-foss with MIT License 4 votes vote down vote up
export function PreflightCheck(): JSX.Element {
    const { preflight, preflightLoading, preflightMode } = useValues(preflightLogic)
    const { setPreflightMode } = useActions(preflightLogic)
    const isReady =
        preflight &&
        preflight.django &&
        preflight.db &&
        preflight.redis &&
        preflight.celery &&
        (preflightMode === 'experimentation' || preflight.plugins)

    const checks = [
        {
            id: 'database',
            name: 'Database (Postgres)',
            status: preflight?.db,
        },
        {
            id: 'backend',
            name: 'Backend server (Django)',
            status: preflight?.django,
        },
        {
            id: 'redis',
            name: 'Cache & queue (Redis)',
            status: preflight?.redis,
        },
        {
            id: 'celery',
            name: 'Background jobs (Celery)',
            status: preflight?.celery,
        },
        {
            id: 'plugins',
            name: 'Plugin server (Node)',
            status: preflight?.plugins,
            caption: preflightMode === 'experimentation' ? 'Required in production environments' : '',
            failedState: preflightMode === 'experimentation' ? 'warning' : 'error',
        },
        {
            id: 'frontend',
            name: 'Frontend build (Webpack)',
            status: true, // If this code is ran, the front-end is already built
        },
        {
            id: 'tls',
            name: 'SSL/TLS certificate',
            status: window.location.protocol === 'https:',
            caption:
                preflightMode === 'experimentation'
                    ? 'Not required for development or testing'
                    : 'Install before ingesting real user data',
            failedState: preflightMode === 'experimentation' ? 'not-required' : 'warning',
        },
    ] as CheckInterface[]

    const handlePreflightFinished = (): void => {
        router.actions.push(urls.signup())
    }

    return (
        <div style={{ minHeight: '100vh' }}>
            <Row
                style={{
                    display: 'flex',
                    justifyContent: 'center',
                    paddingTop: 32,
                    paddingBottom: 32,
                    backgroundColor: '#eeefe9',
                }}
            >
                <img src={posthogLogo} style={{ width: 157, height: 30 }} />
            </Row>
            <Row style={{ display: 'flex', justifyContent: 'center', paddingBottom: 16 }}>
                <PageHeader title="Lets get started..." />
            </Row>
            <Row style={{ display: 'flex', justifyContent: 'center' }}>
                <div style={{ width: 960 }}>
                    <Steps current={0}>
                        <Step title="Preflight check" subTitle="1 min" description="Prepare your instance" />
                        <Step
                            title="Event capture"
                            subTitle="15 mins"
                            description="Set up your app to capture events"
                        />
                        <Step
                            title="Setup your team"
                            subTitle="5 mins"
                            description="Invite your team and start discovering insights"
                        />
                    </Steps>
                </div>
            </Row>
            <Row style={{ display: 'flex', justifyContent: 'center' }}>
                <div style={{ display: 'flex', alignItems: 'center', flexDirection: 'column' }}>
                    <img src={suprisedHog} style={{ maxHeight: '100%', width: 320 }} />
                    <p>Any questions?</p>
                    <Button type="default" data-attr="support" data-source="preflight">
                        <a href="https://posthog.com/support" target="_blank" rel="noreferrer">
                            Get support
                        </a>
                    </Button>
                </div>
                <div
                    style={{
                        display: 'flex',
                        justifyContent: 'flex-start',
                        margin: '0 32px',
                        flexDirection: 'column',
                        paddingTop: 32,
                    }}
                >
                    <Card style={{ width: '100%' }}>
                        <Row style={{ display: 'flex', justifyContent: 'space-between', lineHeight: '32px' }}>
                            {!preflightMode ? (
                                <b style={{ fontSize: 16 }}>Select launch mode</b>
                            ) : (
                                <>
                                    <b style={{ fontSize: 16 }}>
                                        <span>
                                            <span
                                                style={{ color: blue.primary, cursor: 'pointer' }}
                                                onClick={() => setPreflightMode(null)}
                                            >
                                                Select launch mode
                                            </span>{' '}
                                            &gt; {capitalizeFirstLetter(preflightMode)}
                                        </span>
                                    </b>
                                    <Button
                                        type="default"
                                        data-attr="preflight-refresh"
                                        icon={<SyncOutlined />}
                                        onClick={() => window.location.reload()}
                                        disabled={preflightLoading || !preflight}
                                    >
                                        Refresh
                                    </Button>
                                </>
                            )}
                        </Row>
                        {!preflightMode && (
                            <div>We're excited to have you here. What's your plan for this installation?</div>
                        )}
                        <div
                            className="text-center"
                            style={{ padding: '24px 0', display: 'flex', justifyContent: 'center', maxWidth: 533 }}
                        >
                            {!preflightMode && (
                                <>
                                    <Button
                                        type="default"
                                        data-attr="preflight-experimentation"
                                        size="large"
                                        onClick={() => setPreflightMode('experimentation')}
                                        icon={<ApiTwoTone />}
                                    >
                                        Just playing
                                    </Button>
                                    <Button
                                        type="primary"
                                        style={{ marginLeft: 16 }}
                                        size="large"
                                        data-attr="preflight-live"
                                        onClick={() => setPreflightMode('live')}
                                        icon={<RocketFilled />}
                                    >
                                        Live implementation
                                    </Button>
                                </>
                            )}

                            {preflightMode && (
                                <>
                                    <Row>
                                        {checks.map((item) => (
                                            <PreflightItem key={item.id} {...item} />
                                        ))}
                                    </Row>
                                </>
                            )}
                        </div>
                    </Card>
                    {preflightMode && (
                        <>
                            <div className="space-top text-center" data-attr="preflightStatus">
                                {isReady ? (
                                    <b style={{ color: green.primary }}>All systems go!</b>
                                ) : (
                                    <b>Checks in progress…</b>
                                )}
                            </div>
                            <div className="text-center" style={{ marginBottom: 64 }}>
                                <Button
                                    type="primary"
                                    data-attr="preflight-complete"
                                    data-source={preflightMode}
                                    disabled={!isReady}
                                    onClick={handlePreflightFinished}
                                >
                                    Continue
                                </Button>
                            </div>
                        </>
                    )}
                </div>
            </Row>
        </div>
    )
}