diff --git a/pages/admin/navbar.tsx b/pages/admin/navbar.tsx
index a3298309..68bfed1b 100644
--- a/pages/admin/navbar.tsx
+++ b/pages/admin/navbar.tsx
@@ -1,4 +1,4 @@
-import { Text, Box, Heading, Image, Center, Button, Flex, VStack, Divider, useToast, FormControl, FormLabel, FormHelperText, Input, FormErrorMessage, HStack, Wrap, useMediaQuery, Avatar, Textarea, Table, Thead, Tr, Th, Tbody, Td, IconButton, useDisclosure, Modal, ModalOverlay, ModalContent, ModalHeader, ModalBody, ModalFooter, Select, NumberInput, NumberInputField, NumberInputStepper, NumberIncrementStepper, NumberDecrementStepper } from "@chakra-ui/react"
+import { Text, Box, Heading, Image, Center, Button, Flex, VStack, Divider, useToast, FormControl, FormLabel, FormHelperText, Input, FormErrorMessage, HStack, Wrap, useMediaQuery, Avatar, Textarea, Table, Thead, Tr, Th, Tbody, Td, IconButton, useDisclosure, Modal, ModalOverlay, ModalContent, ModalHeader, ModalBody, ModalFooter, Select, NumberInput, NumberInputField, NumberInputStepper, NumberIncrementStepper, NumberDecrementStepper ,AlertDialog, AlertDialogOverlay, AlertDialogContent, AlertDialogHeader, AlertDialogBody, AlertDialogFooter} from "@chakra-ui/react"
import Card from "components/card"
import PageContainer from "layouts/page-container"
import Sidebar from "layouts/sidebar/sidebar"
@@ -103,15 +103,7 @@ const UserNavbarPage = () => {
{
- navbars.map((nv,i) =>
- | {nv.label} |
- {nv.value} |
- {nv.weight} |
-
- onEditNavbar(nv)}/>
- onDeleteNavbar(nv.id)} />
- |
-
)
+ navbars.map((nv,i) => )
}
@@ -133,7 +125,7 @@ const UserNavbarPage = () => {
Value
- { currentNavbar.value = e.currentTarget.value; onNavbarChange() }} placeholder="enter a url, e.g /search"/>
+ { currentNavbar.value = e.currentTarget.value; onNavbarChange() }} placeholder="enter a url, e.g /search/posts"/>
@@ -156,3 +148,49 @@ const UserNavbarPage = () => {
}
export default UserNavbarPage
+
+const NV = ({ nv, onEdit, onDelete }) => {
+ const [isOpen, setIsOpen] = React.useState(false)
+ const onClose = () => setIsOpen(false)
+ const cancelRef = React.useRef()
+
+ return (
+ <>
+
+ | {nv.label} |
+ {nv.value} |
+ {nv.weight} |
+
+ onEdit(nv)}/>
+ setIsOpen(true)} />
+ |
+
+
+
+
+
+ 删除菜单 - {nv.label}
+
+
+
+ Are you sure? You can't undo this action afterwards.
+
+
+
+
+
+
+
+
+
+ >
+ )
+}
\ No newline at end of file
diff --git a/pages/admin/tag/[id].tsx b/pages/admin/tag/[id].tsx
index 0a599970..9948559f 100644
--- a/pages/admin/tag/[id].tsx
+++ b/pages/admin/tag/[id].tsx
@@ -1,4 +1,4 @@
-import { Box, Button, Flex, useColorMode, useColorModeValue, useDisclosure, useRadioGroup, useToast, chakra, Input, HStack, IconButton, Heading, Divider } from '@chakra-ui/react';
+import { Box, Button, Flex, useColorMode, useColorModeValue, useDisclosure, useRadioGroup, useToast, chakra, Input, HStack, IconButton, Heading, Divider, AlertDialog, AlertDialogOverlay, AlertDialogContent, AlertDialogHeader, AlertDialogBody, AlertDialogFooter, Text } from '@chakra-ui/react';
import React, { useEffect, useState } from 'react';
import { MarkdownEditor } from 'components/markdown-editor/editor';
import PageContainer from 'layouts/page-container';
@@ -16,13 +16,14 @@ import RadioCard from 'components/radio-card';
import { useViewportScroll } from 'framer-motion';
import Card from 'components/card';
import { Tag } from 'src/types/tag';
+import { ReserveUrls } from 'src/data/reserve-urls';
function PostEditPage() {
const router = useRouter()
const { id } = router.query
const [editMode, setEditMode] = useState(EditMode.Edit)
- const [tag, setTag]:[Tag,any] = useState({
+ const [tag, setTag]: [Tag, any] = useState({
md: `标签介绍,支持markdown`,
title: ''
})
@@ -84,26 +85,26 @@ function PostEditPage() {
}
-
-
- Title
+
+
+ Title
- { tag.title = e.target.value; onChange()}} mt="4" variant="flushed" size="sm" placeholder="Tag title..." focusBorderColor="teal.400" />
+ { tag.title = e.target.value; onChange() }} mt="4" variant="flushed" size="sm" placeholder="Tag title..." focusBorderColor="teal.400" />
-
- Name
+
+ Name
- { tag.name = e.target.value; onChange()}} mt="4" variant="flushed" size="sm" placeholder="Tag name..." focusBorderColor="teal.400" />
+ { tag.name = e.target.value; onChange() }} mt="4" variant="flushed" size="sm" placeholder="Tag name..." focusBorderColor="teal.400" />
-
- 封面
+
+ 封面
- { tag.cover = e.target.value; onChange()}} mt="4" variant="flushed" size="sm" placeholder="图片链接,你可以用github当图片存储服务" focusBorderColor="teal.400" />
+ { tag.cover = e.target.value; onChange() }} mt="4" variant="flushed" size="sm" placeholder="图片链接,你可以用github当图片存储服务" focusBorderColor="teal.400" />
-
- 图标
+
+ 图标
- { tag.icon = e.target.value; onChange()}} mt="4" variant="flushed" size="sm" placeholder="图片链接" focusBorderColor="teal.400" />
+ { tag.icon = e.target.value; onChange() }} mt="4" variant="flushed" size="sm" placeholder="图片链接" focusBorderColor="teal.400" />
@@ -113,10 +114,12 @@ function PostEditPage() {
export default PostEditPage
function HeaderContent(props: any) {
+ const [delOpen, setDelOpen] = React.useState(false)
+ const cancelRef = React.useRef()
const { toggleColorMode: toggleMode } = useColorMode()
const text = useColorModeValue("dark", "light")
const SwitchIcon = useColorModeValue(FaMoon, FaSun)
-
+ const router = useRouter()
const editOptions = [EditMode.Edit, EditMode.Preview]
const { getRootProps, getRadioProps } = useRadioGroup({
name: "framework",
@@ -128,8 +131,10 @@ function HeaderContent(props: any) {
const group = getRootProps()
const onDelete = async () => {
await requestApi.delete(`/tag/${props.tagID}`)
+ setDelOpen(false)
+ router.push(`${ReserveUrls.Admin}/tags`)
}
-
+
return (
<>
@@ -171,9 +176,35 @@ function HeaderContent(props: any) {
icon={}
/>
-
+
+ setDelOpen(false)}
+ >
+
+
+
+ Delete Tag
+
+
+
+ 删除Tag将删除所有相关的信息,同时该操作不可逆,请慎重
+
+
+
+
+
+
+
+
+
>
)
}
diff --git a/pages/settings/navbar.tsx b/pages/settings/navbar.tsx
index 830195d3..f172163d 100644
--- a/pages/settings/navbar.tsx
+++ b/pages/settings/navbar.tsx
@@ -1,4 +1,4 @@
-import { Text, Box, Heading, Image, Center, Button, Flex, VStack, Divider, useToast, FormControl, FormLabel, FormHelperText, Input, FormErrorMessage, HStack, Wrap, useMediaQuery, Avatar, Textarea, Table, Thead, Tr, Th, Tbody, Td, IconButton, useDisclosure, Modal, ModalOverlay, ModalContent, ModalHeader, ModalBody, ModalFooter, Select, NumberInput, NumberInputField, NumberInputStepper, NumberIncrementStepper, NumberDecrementStepper } from "@chakra-ui/react"
+import { Text, Box, Heading, Image, Center, Button, Flex, VStack, Divider, useToast, FormControl, FormLabel, FormHelperText, Input, FormErrorMessage, HStack, Wrap, useMediaQuery, Avatar, Textarea, Table, Thead, Tr, Th, Tbody, Td, IconButton, useDisclosure, Modal, ModalOverlay, ModalContent, ModalHeader, ModalBody, ModalFooter, Select, NumberInput, NumberInputField, NumberInputStepper, NumberIncrementStepper, NumberDecrementStepper,AlertDialog, AlertDialogOverlay, AlertDialogContent, AlertDialogHeader, AlertDialogBody, AlertDialogFooter } from "@chakra-ui/react"
import Card from "components/card"
import PageContainer from "layouts/page-container"
import Sidebar from "layouts/sidebar/sidebar"
@@ -39,7 +39,7 @@ export const NavbarEditor = ({ orgID = "" }) => {
}, [])
const getNavbars = async () => {
- const res = await requestApi.get(`/user/navbars/${orgID ? orgID : 0}`)
+ const res = await requestApi.get(`/user/navbars/${orgID ? orgID : 0}`)
setNavbars(res.data)
}
@@ -76,7 +76,7 @@ export const NavbarEditor = ({ orgID = "" }) => {
}
if (orgID) {
- await requestApi.post(`/org/navbar/${orgID}`,currentNavbar)
+ await requestApi.post(`/org/navbar/${orgID}`, currentNavbar)
} else {
await requestApi.post(`/user/navbar`, currentNavbar)
}
@@ -122,7 +122,7 @@ export const NavbarEditor = ({ orgID = "" }) => {
}
const onDeleteNavbar = async id => {
- await requestApi.delete(`/${orgID?'org':'user'}/navbar/${id}`)
+ await requestApi.delete(`/${orgID ? 'org' : 'user'}/navbar/${id}`)
getNavbars()
}
@@ -145,16 +145,7 @@ export const NavbarEditor = ({ orgID = "" }) => {
{
- navbars.map((nv, i) =>
- | {nv.label} |
- {nv.type === NavbarType.Link ? "link" : "series"} |
- {nv.type === NavbarType.Link ? nv.value : getSeriesTitle(nv.value)} |
- {nv.weight} |
-
- onEditNavbar(nv)} />
- onDeleteNavbar(nv.id)} />
- |
-
)
+ navbars.map((nv, i) => )
}
@@ -204,4 +195,51 @@ export const NavbarEditor = ({ orgID = "" }) => {
>
)
+}
+
+const NV = ({ nv, onEdit, onDelete, getSeriesTitle }) => {
+ const [isOpen, setIsOpen] = React.useState(false)
+ const onClose = () => setIsOpen(false)
+ const cancelRef = React.useRef()
+
+ return (
+ <>
+
+ | {nv.label} |
+ {nv.type === NavbarType.Link ? "link" : "series"} |
+ {nv.type === NavbarType.Link ? nv.value : getSeriesTitle(nv.value)} |
+ {nv.weight} |
+
+ onEdit(nv)} />
+ setIsOpen(true)} />
+ |
+
+
+
+
+
+ 删除菜单 - {nv.label}
+
+
+
+ Are you sure? You can't undo this action afterwards.
+
+
+
+
+
+
+
+
+
+ >
+ )
}
\ No newline at end of file
diff --git a/server/internal/api/tag.go b/server/internal/api/tag.go
index 718a31e5..a4f71812 100644
--- a/server/internal/api/tag.go
+++ b/server/internal/api/tag.go
@@ -94,7 +94,7 @@ func DeleteTag(c *gin.Context) {
}
user := user.CurrentUser(c)
- if !user.Role.IsAdmin() {
+ if !user.Role.IsSuperAdmin() {
c.JSON(http.StatusForbidden, common.RespError(e.NoPermission))
}
diff --git a/server/pkg/models/role.go b/server/pkg/models/role.go
index 16170d4c..5bc122e8 100644
--- a/server/pkg/models/role.go
+++ b/server/pkg/models/role.go
@@ -14,6 +14,10 @@ func (r RoleType) IsValid() bool {
return r == ROLE_NORMAL || r == ROLE_EDITOR || r == ROLE_ADMIN || r == ROLE_SUPER_ADMIN
}
+func (r RoleType) IsSuperAdmin() bool {
+ return r == ROLE_SUPER_ADMIN
+}
+
func (r RoleType) IsAdmin() bool {
return r == ROLE_ADMIN || r == ROLE_SUPER_ADMIN
}
diff --git a/src/components/story/manage-story-card.tsx b/src/components/story/manage-story-card.tsx
index 471bab94..08285bc0 100644
--- a/src/components/story/manage-story-card.tsx
+++ b/src/components/story/manage-story-card.tsx
@@ -1,5 +1,5 @@
import React from "react"
-import { chakra, Heading, VStack, Text, HStack, Button, Flex, PropsOf, Tag, useMediaQuery, IconButton, Tooltip } from "@chakra-ui/react"
+import { chakra, Heading, VStack, Text, HStack, Button, Flex, PropsOf, Tag, useMediaQuery, IconButton, Tooltip, AlertDialog, AlertDialogOverlay, AlertDialogContent, AlertDialogHeader, AlertDialogBody, AlertDialogFooter } from "@chakra-ui/react"
import { Story } from "src/types/story"
import moment from 'moment'
import { IDType } from "src/types/id"
@@ -17,11 +17,15 @@ type Props = PropsOf & {
// 文章卡片,展示需要被管理的文章
export const ManageStoryCard = (props: Props) => {
- const { story, onEdit, onDelete, showSource = true,onPin, ...rest } = props
+ const { story, onEdit, onDelete, showSource = true, onPin, ...rest } = props
const [isSmallScreen] = useMediaQuery("(max-width: 768px)")
const Lay = isSmallScreen ? VStack : Flex
const gap = moment(story.created).fromNow()
+ const [isOpen, setIsOpen] = React.useState(false)
+ const onClose = () => setIsOpen(false)
+ const cancelRef = React.useRef()
+
const showActions = onEdit || onDelete || onPin
return (
//@ts-ignore
@@ -34,18 +38,18 @@ export const ManageStoryCard = (props: Props) => {
发布于{gap}
{showActions &&
- {onPin &&
+ {onPin &&
}
onClick={() => onPin(story.id)}
- color={story.pinned? "teal" : null}
+ color={story.pinned ? "teal" : null}
/>
}
- {onEdit&&
+ {onEdit &&
{
/>
}
- {onDelete&&
+ {onDelete &&
}
- onClick={() => props.onDelete(story.id)}
+ onClick={() => setIsOpen(true)}
/>
}
}
+
+
+
+
+ 删除文章 - {story.title}
+
+
+
+ Are you sure? You can't undo this action afterwards.
+
+
+
+
+
+
+
+
+
)
}