aboutsummaryrefslogtreecommitdiff
path: root/Timeline/ClientApp/src/app/views/common
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2020-09-03 18:10:02 +0800
committercrupest <crupest@outlook.com>2020-09-03 18:10:02 +0800
commitac40d9c18e2ac7b4995dac38d5da04a3ea7f1559 (patch)
treeed843d6075b8c7667f1a402dfddf3f892fba3ffa /Timeline/ClientApp/src/app/views/common
parentb027f7d2793999159b362041b2f697df74e4b1b9 (diff)
downloadtimeline-ac40d9c18e2ac7b4995dac38d5da04a3ea7f1559.tar.gz
timeline-ac40d9c18e2ac7b4995dac38d5da04a3ea7f1559.tar.bz2
timeline-ac40d9c18e2ac7b4995dac38d5da04a3ea7f1559.zip
Migrate to react-bootstrap.
Diffstat (limited to 'Timeline/ClientApp/src/app/views/common')
-rw-r--r--Timeline/ClientApp/src/app/views/common/AppBar.tsx2
-rw-r--r--Timeline/ClientApp/src/app/views/common/FileInput.tsx36
-rw-r--r--Timeline/ClientApp/src/app/views/common/OperationDialog.tsx93
-rw-r--r--Timeline/ClientApp/src/app/views/common/alert/AlertHost.tsx9
4 files changed, 48 insertions, 92 deletions
diff --git a/Timeline/ClientApp/src/app/views/common/AppBar.tsx b/Timeline/ClientApp/src/app/views/common/AppBar.tsx
index 464747c0..ee4ead8f 100644
--- a/Timeline/ClientApp/src/app/views/common/AppBar.tsx
+++ b/Timeline/ClientApp/src/app/views/common/AppBar.tsx
@@ -17,7 +17,7 @@ const AppBar: React.FC = (_) => {
const isAdministrator = user && user.administrator;
return (
- <Navbar bg="primary" variant="dark" expand="md">
+ <Navbar bg="primary" variant="dark" expand="md" sticky="top">
<LinkContainer to="/">
<Navbar.Brand className="d-flex align-items-center">
<TimelineLogo style={{ height: "1em" }} />
diff --git a/Timeline/ClientApp/src/app/views/common/FileInput.tsx b/Timeline/ClientApp/src/app/views/common/FileInput.tsx
deleted file mode 100644
index 7b053d5c..00000000
--- a/Timeline/ClientApp/src/app/views/common/FileInput.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-import React from "react";
-import clsx from "clsx";
-
-export interface FileInputProps
- extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "type" | "id"> {
- inputId?: string;
- labelText: string;
- color?: string;
- className?: string;
-}
-
-const FileInput: React.FC<FileInputProps> = (props) => {
- const { inputId, labelText, color, className, ...otherProps } = props;
-
- const realInputId = React.useMemo<string>(() => {
- if (inputId != null) return inputId;
- return (
- "file-input-" +
- (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1)
- );
- }, [inputId]);
-
- return (
- <>
- <input className="d-none" type="file" id={realInputId} {...otherProps} />
- <label
- htmlFor={realInputId}
- className={clsx("btn", "btn-" + (color ?? "primary"), className)}
- >
- {labelText}
- </label>
- </>
- );
-};
-
-export default FileInput;
diff --git a/Timeline/ClientApp/src/app/views/common/OperationDialog.tsx b/Timeline/ClientApp/src/app/views/common/OperationDialog.tsx
index 402ffbec..6f97eb15 100644
--- a/Timeline/ClientApp/src/app/views/common/OperationDialog.tsx
+++ b/Timeline/ClientApp/src/app/views/common/OperationDialog.tsx
@@ -1,26 +1,13 @@
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
-import {
- Spinner,
- Container,
- ModalBody,
- Label,
- Input,
- FormGroup,
- FormFeedback,
- ModalFooter,
- Button,
- Modal,
- ModalHeader,
- FormText,
-} from "reactstrap";
+import { Spinner, Container, Form, Button, Modal } from "react-bootstrap";
import { UiLogicError } from "@/common";
const DefaultProcessPrompt: React.FC = (_) => {
return (
<Container className="justify-content-center align-items-center">
- <Spinner />
+ <Spinner animation="border" variant="success" />
</Container>
);
};
@@ -233,7 +220,7 @@ const OperationDialog: React.FC<OperationDialogProps> = (props) => {
body = (
<>
- <ModalBody>
+ <Modal.Body>
{inputPrompt}
{inputScheme.map((item, index) => {
const value = values[index];
@@ -242,9 +229,9 @@ const OperationDialog: React.FC<OperationDialogProps> = (props) => {
if (item.type === "text") {
return (
- <FormGroup key={index}>
- {item.label && <Label>{t(item.label)}</Label>}
- <Input
+ <Form.Group key={index}>
+ {item.label && <Form.Label>{t(item.label)}</Form.Label>}
+ <Form.Control
type={item.password === true ? "password" : "text"}
value={value as string}
onChange={(e) => {
@@ -258,35 +245,35 @@ const OperationDialog: React.FC<OperationDialogProps> = (props) => {
)
);
}}
- invalid={error != null}
- {...item.textFieldProps}
+ isInvalid={error != null}
/>
- {error != null && <FormFeedback>{error}</FormFeedback>}
- {item.helperText && <FormText>{t(item.helperText)}</FormText>}
- </FormGroup>
+ {error != null && (
+ <Form.Control.Feedback>{error}</Form.Control.Feedback>
+ )}
+ {item.helperText && (
+ <Form.Text>{t(item.helperText)}</Form.Text>
+ )}
+ </Form.Group>
);
} else if (item.type === "bool") {
return (
- <FormGroup check key={index}>
- <Input
+ <Form.Group key={index}>
+ <Form.Check<"input">
type="checkbox"
- value={value as string}
- onChange={(e) => {
- updateValue(
- index,
- (e.target as HTMLInputElement).checked
- );
+ checked={value as boolean}
+ onChange={(event) => {
+ updateValue(index, event.currentTarget.checked);
}}
+ label={t(item.label)}
/>
- <Label check>{t(item.label)}</Label>
- </FormGroup>
+ </Form.Group>
);
} else if (item.type === "select") {
return (
- <FormGroup key={index}>
- <Label>{t(item.label)}</Label>
- <Input
- type="select"
+ <Form.Group key={index}>
+ <Form.Label>{t(item.label)}</Form.Label>
+ <Form.Control
+ as="select"
value={value as string}
onChange={(event) => {
updateValue(index, event.target.value);
@@ -300,18 +287,18 @@ const OperationDialog: React.FC<OperationDialogProps> = (props) => {
</option>
);
})}
- </Input>
- </FormGroup>
+ </Form.Control>
+ </Form.Group>
);
}
})}
- </ModalBody>
- <ModalFooter>
- <Button color="secondary" onClick={close}>
+ </Modal.Body>
+ <Modal.Footer>
+ <Button variant="secondary" onClick={close}>
{t("operationDialog.cancel")}
</Button>
<Button
- color="primary"
+ variant="primary"
disabled={testErrorInfo(inputError)}
onClick={() => {
if (validateAll()) {
@@ -321,14 +308,14 @@ const OperationDialog: React.FC<OperationDialogProps> = (props) => {
>
{t("operationDialog.confirm")}
</Button>
- </ModalFooter>
+ </Modal.Footer>
</>
);
} else if (step === "process") {
body = (
- <ModalBody>
+ <Modal.Body>
{props.processPrompt?.() ?? <DefaultProcessPrompt />}
- </ModalBody>
+ </Modal.Body>
);
} else {
let content: React.ReactNode;
@@ -345,12 +332,12 @@ const OperationDialog: React.FC<OperationDialogProps> = (props) => {
}
body = (
<>
- <ModalBody>{content}</ModalBody>
- <ModalFooter>
- <Button color="primary" onClick={close}>
+ <Modal.Body>{content}</Modal.Body>
+ <Modal.Footer>
+ <Button variant="primary" onClick={close}>
{t("operationDialog.ok")}
</Button>
- </ModalFooter>
+ </Modal.Footer>
</>
);
}
@@ -359,7 +346,7 @@ const OperationDialog: React.FC<OperationDialogProps> = (props) => {
return (
<Modal isOpen={props.open} toggle={close}>
- <ModalHeader
+ <Modal.Header
className={
props.titleColor != null
? "text-" +
@@ -372,7 +359,7 @@ const OperationDialog: React.FC<OperationDialogProps> = (props) => {
}
>
{title}
- </ModalHeader>
+ </Modal.Header>
{body}
</Modal>
);
diff --git a/Timeline/ClientApp/src/app/views/common/alert/AlertHost.tsx b/Timeline/ClientApp/src/app/views/common/alert/AlertHost.tsx
index 31c0fb86..c74f18e2 100644
--- a/Timeline/ClientApp/src/app/views/common/alert/AlertHost.tsx
+++ b/Timeline/ClientApp/src/app/views/common/alert/AlertHost.tsx
@@ -1,8 +1,8 @@
import React, { useCallback } from "react";
-import { Alert } from "reactstrap";
import without from "lodash/without";
import concat from "lodash/concat";
import { useTranslation } from "react-i18next";
+import { Alert } from "react-bootstrap";
import {
alertService,
@@ -37,7 +37,12 @@ export const AutoCloseAlert: React.FC<AutoCloseAlertProps> = (props) => {
}, [dismissTime, props.close]);
return (
- <Alert className="m-3" color={alert.type ?? "primary"} toggle={props.close}>
+ <Alert
+ className="m-3"
+ variant={alert.type ?? "primary"}
+ onClose={props.close}
+ dismissible
+ >
{(() => {
const { message } = alert;
if (typeof message === "function") {