profile-new.tsx 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. import { useRef, useState } from "react";
  2. import { mutate } from "swr";
  3. import { useTranslation } from "react-i18next";
  4. import { useLockFn, useSetState } from "ahooks";
  5. import {
  6. Button,
  7. Dialog,
  8. DialogActions,
  9. DialogContent,
  10. DialogTitle,
  11. FormControl,
  12. IconButton,
  13. InputLabel,
  14. MenuItem,
  15. Select,
  16. TextField,
  17. } from "@mui/material";
  18. import { Settings } from "@mui/icons-material";
  19. import { createProfile } from "@/services/cmds";
  20. import Notice from "../base/base-notice";
  21. import FileInput from "./file-input";
  22. interface Props {
  23. open: boolean;
  24. onClose: () => void;
  25. }
  26. // create a new profile
  27. // remote / local file / merge / script
  28. const ProfileNew = (props: Props) => {
  29. const { open, onClose } = props;
  30. const { t } = useTranslation();
  31. const [form, setForm] = useSetState({
  32. type: "remote",
  33. name: "",
  34. desc: "",
  35. url: "",
  36. });
  37. const [showOpt, setShowOpt] = useState(false);
  38. // can add more option
  39. const [option, setOption] = useSetState({ user_agent: "" });
  40. // file input
  41. const fileDataRef = useRef<string | null>(null);
  42. const onCreate = useLockFn(async () => {
  43. if (!form.type) {
  44. Notice.error("`Type` should not be null");
  45. return;
  46. }
  47. try {
  48. const name = form.name || `${form.type} file`;
  49. if (form.type === "remote" && !form.url) {
  50. throw new Error("The URL should not be null");
  51. }
  52. const option_ = form.type === "remote" ? option : undefined;
  53. const item = { ...form, name, option: option_ };
  54. const fileData = form.type === "local" ? fileDataRef.current : null;
  55. await createProfile(item, fileData);
  56. setForm({ type: "remote", name: "", desc: "", url: "" });
  57. setOption({ user_agent: "" });
  58. setShowOpt(false);
  59. fileDataRef.current = null;
  60. mutate("getProfiles");
  61. onClose();
  62. } catch (err: any) {
  63. Notice.error(err.message || err.toString());
  64. }
  65. });
  66. const textFieldProps = {
  67. fullWidth: true,
  68. size: "small",
  69. margin: "normal",
  70. variant: "outlined",
  71. } as const;
  72. return (
  73. <Dialog open={open} onClose={onClose}>
  74. <DialogTitle sx={{ pb: 0.5 }}>{t("Create Profile")}</DialogTitle>
  75. <DialogContent sx={{ width: 336, pb: 1 }}>
  76. <FormControl size="small" fullWidth sx={{ mt: 2, mb: 1 }}>
  77. <InputLabel>Type</InputLabel>
  78. <Select
  79. autoFocus
  80. label={t("Type")}
  81. value={form.type}
  82. onChange={(e) => setForm({ type: e.target.value })}
  83. >
  84. <MenuItem value="remote">Remote</MenuItem>
  85. <MenuItem value="local">Local</MenuItem>
  86. <MenuItem value="script">Script</MenuItem>
  87. <MenuItem value="merge">Merge</MenuItem>
  88. </Select>
  89. </FormControl>
  90. <TextField
  91. {...textFieldProps}
  92. label={t("Name")}
  93. autoComplete="off"
  94. value={form.name}
  95. onChange={(e) => setForm({ name: e.target.value })}
  96. />
  97. <TextField
  98. {...textFieldProps}
  99. label={t("Descriptions")}
  100. autoComplete="off"
  101. value={form.desc}
  102. onChange={(e) => setForm({ desc: e.target.value })}
  103. />
  104. {form.type === "remote" && (
  105. <TextField
  106. {...textFieldProps}
  107. label={t("Subscription URL")}
  108. autoComplete="off"
  109. value={form.url}
  110. onChange={(e) => setForm({ url: e.target.value })}
  111. />
  112. )}
  113. {form.type === "local" && (
  114. <FileInput onChange={(val) => (fileDataRef.current = val)} />
  115. )}
  116. {showOpt && (
  117. <TextField
  118. {...textFieldProps}
  119. label="User Agent"
  120. autoComplete="off"
  121. value={option.user_agent}
  122. onChange={(e) => setOption({ user_agent: e.target.value })}
  123. />
  124. )}
  125. </DialogContent>
  126. <DialogActions sx={{ px: 2, pb: 2, position: "relative" }}>
  127. {form.type === "remote" && (
  128. <IconButton
  129. size="small"
  130. color="inherit"
  131. sx={{ position: "absolute", left: 18 }}
  132. onClick={() => setShowOpt((o) => !o)}
  133. >
  134. <Settings />
  135. </IconButton>
  136. )}
  137. <Button onClick={onClose} variant="outlined">
  138. {t("Cancel")}
  139. </Button>
  140. <Button onClick={onCreate} variant="contained">
  141. {t("Save")}
  142. </Button>
  143. </DialogActions>
  144. </Dialog>
  145. );
  146. };
  147. export default ProfileNew;