mirror of
https://github.com/labring/sealos.git
synced 2026-10-28 02:27:18 +08:00
styles(desktop):modify namespace styles (#3997)
This commit is contained in:
@@ -56,6 +56,7 @@
|
||||
"Dissolve Team": "Dissovle Team",
|
||||
"Invaild Name of Team": "Dissovle Team",
|
||||
"Manage Team": "Manage Team",
|
||||
"Default Team": "Default",
|
||||
"private team ID of user": "private team ID of user",
|
||||
"Invite Member": "Invite Member",
|
||||
"Handle": "Handle",
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
"Dissolve Team": "解散",
|
||||
"Invaild Name of Team": "不合法的团队名称",
|
||||
"Manage Team": "管理团队",
|
||||
"Default Team": "默认",
|
||||
"private team ID of user": "用户的 private team 的团队ID",
|
||||
"Invite Member": "邀请成员",
|
||||
"Handle": "操作",
|
||||
|
||||
@@ -63,9 +63,19 @@ describe('Login create', () => {
|
||||
['team5', 4],
|
||||
['team6', 5]
|
||||
])(
|
||||
'limit 5 team',
|
||||
'limit 4 team',
|
||||
async (teamName: string, idx: number) => {
|
||||
if (idx === 0) {
|
||||
const res = await _passwordLoginRequest(request)({
|
||||
user: 'createTest5',
|
||||
password: 'testtest'
|
||||
});
|
||||
expect(res.data?.user).toBeDefined();
|
||||
session = res.data!;
|
||||
setAuth(session);
|
||||
}
|
||||
const res = await createRequest({ teamName });
|
||||
console.log('curIdx', idx, 'code', res.code);
|
||||
if (idx > 3) expect(res.code).toBe(403);
|
||||
else expect(res.code).toBe(200);
|
||||
},
|
||||
|
||||
@@ -12,30 +12,29 @@ import {
|
||||
PopoverTrigger,
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverBody,
|
||||
PopoverHeader
|
||||
PopoverBody
|
||||
} from '@chakra-ui/react';
|
||||
import { useMutation, useQuery } from '@tanstack/react-query';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useContext, useMemo } from 'react';
|
||||
import { useContext, useEffect, useMemo } from 'react';
|
||||
import Iconfont from '../iconfont';
|
||||
import useAppStore from '@/stores/app';
|
||||
|
||||
import { ApiResp, Session } from '@/types';
|
||||
import { ApiResp } from '@/types';
|
||||
import { formatMoney } from '@/utils/format';
|
||||
import { RechargeEnabledContext } from '@/pages';
|
||||
import TeamCenter from '@/components/team/TeamCenter';
|
||||
import NsList from '@/components/team/NsList';
|
||||
import CreateTeam from '../team/CreateTeam';
|
||||
import { NamespaceDto } from '@/types/team';
|
||||
import { switchRequest } from '@/api/namespace';
|
||||
import { nsListRequest, switchRequest } from '@/api/namespace';
|
||||
import RightIcon from '../icons/RightArrow';
|
||||
import { NSType } from '@/types/team';
|
||||
|
||||
const NsMenu = () => {
|
||||
const { t } = useTranslation();
|
||||
const session = useSessionStore((s) => s.session);
|
||||
const setSession = useSessionStore((s) => s.setSession);
|
||||
const { ns_uid } = session.user;
|
||||
const { ns_uid, k8s_username } = session.user;
|
||||
const router = useRouter();
|
||||
const mutation = useMutation({
|
||||
mutationFn: switchRequest,
|
||||
@@ -46,25 +45,49 @@ const NsMenu = () => {
|
||||
}
|
||||
}
|
||||
});
|
||||
const switchTeam = async ({ uid }: NamespaceDto) => {
|
||||
const switchTeam = async ({ uid }: { uid: string }) => {
|
||||
if (ns_uid !== uid) mutation.mutate(uid);
|
||||
};
|
||||
const { data } = useQuery({
|
||||
queryKey: ['teamList', 'teamGroup'],
|
||||
queryFn: nsListRequest
|
||||
});
|
||||
const namespaces = data?.data?.namespaces || [];
|
||||
const namespace = namespaces.find((x) => x.uid === ns_uid);
|
||||
const defaultNamespace = namespaces.find((x) => x.nstype === NSType.Private);
|
||||
if (!namespace && defaultNamespace && namespaces.length > 0) {
|
||||
// 被删了
|
||||
switchTeam({ uid: defaultNamespace.uid });
|
||||
}
|
||||
return (
|
||||
<Popover placement="left">
|
||||
<PopoverTrigger>
|
||||
{
|
||||
// !todo 颜色可以改变
|
||||
<Box pl="12px" cursor={'pointer'}>
|
||||
<Image
|
||||
pr="4px"
|
||||
borderRight={'1px'}
|
||||
borderColor={'#BDC1C5'}
|
||||
color={'#fff'}
|
||||
mr="10px"
|
||||
src="/images/allVector.svg"
|
||||
w="16px"
|
||||
h="16px"
|
||||
/>
|
||||
<Box
|
||||
px="16px"
|
||||
cursor={'pointer'}
|
||||
py="10px"
|
||||
bgColor={'rgba(255, 255, 255, 0.6)'}
|
||||
borderRadius={'8px'}
|
||||
width={'full'}
|
||||
>
|
||||
<Text color="#7B838B" fontSize={'11px'} p="4px">
|
||||
{t('Team')}
|
||||
</Text>
|
||||
<Flex
|
||||
justify={'space-between'}
|
||||
align={'center'}
|
||||
_hover={{
|
||||
bgColor: 'rgba(0, 0, 0, 0.03)'
|
||||
}}
|
||||
transition={'0.3s'}
|
||||
p="4px"
|
||||
>
|
||||
<Text fontSize="14px" fontWeight={'500'} color={'#363C42'}>
|
||||
{namespace?.nstype === NSType.Private ? t('Default Team') : namespace?.teamName}
|
||||
</Text>
|
||||
<RightIcon w="16px" h="16px" />
|
||||
</Flex>
|
||||
</Box>
|
||||
}
|
||||
</PopoverTrigger>
|
||||
@@ -75,21 +98,12 @@ const NsMenu = () => {
|
||||
w="250px"
|
||||
background="linear-gradient(270deg, #F1F1F1 0%, #EEE 43.75%, #ECECEC 100%)"
|
||||
>
|
||||
<PopoverHeader p="0">
|
||||
<Flex w="100%" align={'center'}>
|
||||
<Text fontSize="16px" fontWeight={'600'} py="8px" pl="4px" color={'#363C42'}>
|
||||
{t('Team')}
|
||||
</Text>
|
||||
<TeamCenter />
|
||||
<CreateTeam />
|
||||
</Flex>
|
||||
</PopoverHeader>
|
||||
<PopoverBody px="0" pb="0" pt="4px">
|
||||
<NsList
|
||||
displayPoint={true}
|
||||
selected_ns_uid={ns_uid}
|
||||
click={switchTeam}
|
||||
nullNs={switchTeam}
|
||||
namespaces={namespaces}
|
||||
/>
|
||||
</PopoverBody>
|
||||
</PopoverContent>
|
||||
@@ -157,27 +171,10 @@ export default function Index({ disclosure }: { disclosure: UseDisclosureReturn
|
||||
fallbackSrc="/images/sealos.svg"
|
||||
alt="user avator"
|
||||
/>
|
||||
<Text color={'#24282C'} fontSize={'20px'} fontWeight={600}>
|
||||
<Text color={'#24282C'} fontSize={'20px'} fontWeight={600} mb="22px">
|
||||
{user?.name}
|
||||
</Text>
|
||||
<Flex
|
||||
alignItems={'center'}
|
||||
mt="8px"
|
||||
bg={'rgba(255, 255, 255, 0.50)'}
|
||||
py="6px"
|
||||
color="#5A646E"
|
||||
borderRadius={'50px'}
|
||||
border="1.5px solid rgba(0,0,0,0)"
|
||||
_hover={{
|
||||
borderColor: '#36ADEF'
|
||||
}}
|
||||
>
|
||||
<NsMenu />
|
||||
<Text fontSize={'12px'}>{nsid}</Text>
|
||||
<Box mr="12px" onClick={() => copyData(nsid)} ml="8px" cursor={'pointer'}>
|
||||
<Iconfont iconName="icon-copy2" width={14} height={14} color="#7B838B"></Iconfont>
|
||||
</Box>
|
||||
</Flex>
|
||||
<NsMenu />
|
||||
<Stack
|
||||
direction={'column'}
|
||||
width={'100%'}
|
||||
@@ -186,6 +183,10 @@ export default function Index({ disclosure }: { disclosure: UseDisclosureReturn
|
||||
borderRadius={'8px'}
|
||||
gap={'0px'}
|
||||
>
|
||||
<Flex alignItems={'center'} borderBottom={'1px solid #0000001A'} p="16px">
|
||||
<Text>{t('Manage Team')}</Text>
|
||||
<TeamCenter mr="0" />
|
||||
</Flex>
|
||||
<Flex alignItems={'center'} borderBottom={'1px solid #0000001A'} p="16px">
|
||||
<Text>
|
||||
{t('Balance')}: {formatMoney(balance).toFixed(2)}
|
||||
@@ -203,6 +204,11 @@ export default function Index({ disclosure }: { disclosure: UseDisclosureReturn
|
||||
});
|
||||
disclosure.onClose();
|
||||
}}
|
||||
_hover={{
|
||||
bgColor: 'rgba(0, 0, 0, 0.03)'
|
||||
}}
|
||||
transition={'0.3s'}
|
||||
p="4px"
|
||||
color={'#219BF4'}
|
||||
fontWeight="500"
|
||||
fontSize="12px"
|
||||
@@ -214,7 +220,15 @@ export default function Index({ disclosure }: { disclosure: UseDisclosureReturn
|
||||
{
|
||||
<Flex alignItems={'center'} py="16px">
|
||||
<Text ml="16px">kubeconfig</Text>
|
||||
<Box ml="auto" onClick={() => download('kubeconfig.yaml', kubeconfig)}>
|
||||
<Box
|
||||
_hover={{
|
||||
bgColor: 'rgba(0, 0, 0, 0.03)'
|
||||
}}
|
||||
transition={'0.3s'}
|
||||
p="4px"
|
||||
ml="auto"
|
||||
onClick={() => download('kubeconfig.yaml', kubeconfig)}
|
||||
>
|
||||
<Iconfont
|
||||
iconName="icon-download"
|
||||
width={16}
|
||||
@@ -222,7 +236,16 @@ export default function Index({ disclosure }: { disclosure: UseDisclosureReturn
|
||||
color="#219BF4"
|
||||
></Iconfont>
|
||||
</Box>
|
||||
<Box ml="8px" mr="20px" onClick={() => copyData(kubeconfig)} cursor={'pointer'}>
|
||||
<Box
|
||||
_hover={{
|
||||
bgColor: 'rgba(0, 0, 0, 0.03)'
|
||||
}}
|
||||
p="4px"
|
||||
ml="8px"
|
||||
mr="20px"
|
||||
onClick={() => copyData(kubeconfig)}
|
||||
cursor={'pointer'}
|
||||
>
|
||||
<Iconfont iconName="icon-copy2" width={16} height={16} color="#219BF4"></Iconfont>
|
||||
</Box>
|
||||
</Flex>
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import { Icon, IconProps } from '@chakra-ui/react';
|
||||
|
||||
export default function RightIcon(props: IconProps) {
|
||||
return (
|
||||
<Icon
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M4.7666 14.075C4.59993 13.9083 4.5166 13.711 4.5166 13.483C4.5166 13.2554 4.59993 13.0583 4.7666 12.8917L9.64994 8.00832L4.74993 3.10832C4.59438 2.95277 4.5166 2.75832 4.5166 2.52499C4.5166 2.29165 4.59993 2.09165 4.7666 1.92499C4.93327 1.75832 5.1306 1.67499 5.3586 1.67499C5.58616 1.67499 5.78327 1.75832 5.94993 1.92499L11.5499 7.54165C11.6166 7.60832 11.6639 7.68054 11.6919 7.75832C11.7195 7.8361 11.7333 7.91943 11.7333 8.00832C11.7333 8.09721 11.7195 8.18054 11.6919 8.25832C11.6639 8.3361 11.6166 8.40832 11.5499 8.47499L5.93327 14.0917C5.77771 14.2472 5.58616 14.325 5.3586 14.325C5.1306 14.325 4.93327 14.2417 4.7666 14.075Z"
|
||||
fill="#219BF4"
|
||||
/>
|
||||
</Icon>
|
||||
);
|
||||
}
|
||||
@@ -1,39 +1,25 @@
|
||||
import { useCopyData } from '@/hooks/useCopyData';
|
||||
import request from '@/services/request';
|
||||
import { Box, Flex, Text } from '@chakra-ui/react';
|
||||
import { useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import Iconfont from '../iconfont';
|
||||
import { ApiResp } from '@/types';
|
||||
import InviteMember from './InviteMember';
|
||||
import { NSType, NamespaceDto, UserRole } from '@/types/team';
|
||||
import { NSType, NamespaceDto } from '@/types/team';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
const NsList = ({
|
||||
click,
|
||||
selected_ns_uid,
|
||||
nullNs,
|
||||
namespaces,
|
||||
displayPoint = false,
|
||||
...boxprop
|
||||
}: {
|
||||
displayPoint: boolean;
|
||||
click?: (ns: NamespaceDto) => void;
|
||||
selected_ns_uid: string;
|
||||
nullNs?: (privateNamespace: NamespaceDto) => void;
|
||||
namespaces: NamespaceDto[];
|
||||
} & Parameters<typeof Box>[0]) => {
|
||||
const queryClient = useQueryClient();
|
||||
const { data } = useQuery({
|
||||
queryKey: ['teamList', 'teamGroup'],
|
||||
queryFn: () =>
|
||||
request<any, ApiResp<{ namespaces: (NamespaceDto & { role: UserRole })[] }>>(
|
||||
'/api/auth/namespace/list'
|
||||
)
|
||||
});
|
||||
const { copyData } = useCopyData();
|
||||
const namespaces = data?.data?.namespaces || [];
|
||||
const namespace = namespaces.find((x) => x.uid === selected_ns_uid);
|
||||
const privateNamespace = namespaces.find((x) => x.nstype === NSType.Private);
|
||||
if (!namespace && namespaces.length > 0 && privateNamespace) {
|
||||
// 被删了
|
||||
nullNs && nullNs(privateNamespace);
|
||||
}
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Box {...boxprop}>
|
||||
{namespaces.length > 0 &&
|
||||
@@ -83,34 +69,9 @@ const NsList = ({
|
||||
: {})}
|
||||
textTransform={'capitalize'}
|
||||
>
|
||||
{ns.teamName}
|
||||
{ns.nstype === NSType.Private ? t('Default Team') : ns.teamName}
|
||||
</Text>
|
||||
</Flex>
|
||||
<Flex
|
||||
ml="auto"
|
||||
className="namespace-option"
|
||||
display={ns.uid === selected_ns_uid ? 'flex' : 'none'}
|
||||
position={'absolute'}
|
||||
right={'0'}
|
||||
>
|
||||
{ns.nstype === NSType.Team && (
|
||||
<InviteMember ownRole={ns.role} mr="6px" ns_uid={ns.uid} />
|
||||
)}
|
||||
<Flex
|
||||
onClick={() => copyData(ns.id)}
|
||||
justify={'center'}
|
||||
alignItems={'center'}
|
||||
cursor={'pointer'}
|
||||
mr="6px"
|
||||
w="24px"
|
||||
h="24px"
|
||||
_hover={{
|
||||
bgColor: 'rgba(0, 0, 0, 0.03)'
|
||||
}}
|
||||
>
|
||||
<Iconfont iconName="icon-copy2" width={18} height={18} color="#7B838B"></Iconfont>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Flex>
|
||||
))}
|
||||
</Box>
|
||||
|
||||
@@ -10,7 +10,8 @@ import {
|
||||
ModalOverlay,
|
||||
useDisclosure,
|
||||
Divider,
|
||||
Stack
|
||||
Stack,
|
||||
FlexProps
|
||||
} from '@chakra-ui/react';
|
||||
import NsList from './NsList';
|
||||
import { useState } from 'react';
|
||||
@@ -26,11 +27,11 @@ import useSessionStore from '@/stores/session';
|
||||
import { InvitedStatus, NSType, UserRole, teamMessageDto } from '@/types/team';
|
||||
import { TeamUserDto } from '@/types/user';
|
||||
import ReciveMessage from './ReciveMessage';
|
||||
import { reciveMessageRequest, teamDetailsRequest } from '@/api/namespace';
|
||||
import { nsListRequest, reciveMessageRequest, teamDetailsRequest } from '@/api/namespace';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
export default function TeamCenter() {
|
||||
export default function TeamCenter(props: FlexProps) {
|
||||
const session = useSessionStore((s) => s.session);
|
||||
const { ns_uid: default_ns_uid, nsid: default_nsid, userId } = session.user;
|
||||
const { ns_uid: default_ns_uid, nsid: default_nsid, userId, k8s_username } = session.user;
|
||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||
const [nsid, setNsid] = useState(default_nsid);
|
||||
const [messageFilter, setMessageFilter] = useState<string[]>([]);
|
||||
@@ -40,7 +41,7 @@ export default function TeamCenter() {
|
||||
() => teamDetailsRequest(ns_uid),
|
||||
{
|
||||
refetchInterval(data) {
|
||||
if (data?.data?.users.some((x) => x.status === InvitedStatus.Inviting)) {
|
||||
if (data?.data?.users?.some((x) => x.status === InvitedStatus.Inviting)) {
|
||||
return 2000;
|
||||
} else {
|
||||
return false;
|
||||
@@ -57,10 +58,23 @@ export default function TeamCenter() {
|
||||
const messages: teamMessageDto[] = reciveMessage.data?.data?.messages || [];
|
||||
const users: TeamUserDto[] = [...(data?.data?.users || [])];
|
||||
const curTeamUser = users.find((user) => user.uid === userId);
|
||||
const teamName = data?.data?.namespace.teamName || '';
|
||||
const namespace = data?.data?.namespace;
|
||||
const teamName =
|
||||
namespace?.nstype === NSType.Private ? t('Default Team') : namespace?.teamName || '';
|
||||
const createTime = data?.data?.namespace.createTime || '';
|
||||
const isTeam = data?.data?.namespace.nstype === NSType.Team;
|
||||
const { copyData } = useCopyData();
|
||||
const { data: teamListData } = useQuery({
|
||||
queryKey: ['teamList', 'teamGroup'],
|
||||
queryFn: nsListRequest
|
||||
});
|
||||
const namespaces = teamListData?.data?.namespaces || [];
|
||||
const defaultNamespace = namespaces.find((ns) => ns.nstype === NSType.Private);
|
||||
if (defaultNamespace && !namespaces.find((ns) => ns.uid === ns_uid)) {
|
||||
// 空了
|
||||
setNs_uid(defaultNamespace.uid);
|
||||
setNsid(defaultNamespace.id);
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<Flex
|
||||
@@ -74,6 +88,7 @@ export default function TeamCenter() {
|
||||
transition={'all 0.3s'}
|
||||
justify={'center'}
|
||||
align={'center'}
|
||||
{...props}
|
||||
>
|
||||
<Image
|
||||
cursor={'pointer'}
|
||||
@@ -87,7 +102,7 @@ export default function TeamCenter() {
|
||||
w="20px"
|
||||
/>
|
||||
</Flex>
|
||||
<Modal isOpen={isOpen} onClose={onClose} isCentered>
|
||||
<Modal isOpen={isOpen} onClose={onClose} isCentered closeOnOverlayClick={false}>
|
||||
<ModalOverlay />
|
||||
<ModalContent
|
||||
borderRadius={'8px'}
|
||||
@@ -135,10 +150,7 @@ export default function TeamCenter() {
|
||||
setNs_uid(ns.uid);
|
||||
setNsid(ns.id);
|
||||
}}
|
||||
nullNs={(ns) => {
|
||||
setNs_uid(ns.uid);
|
||||
setNsid(ns.id);
|
||||
}}
|
||||
namespaces={teamListData?.data?.namespaces || []}
|
||||
/>
|
||||
</Box>
|
||||
</Stack>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { authSession } from '@/services/backend/auth';
|
||||
import { createNS, queryNSByUid } from '@/services/backend/db/namespace';
|
||||
import { createNS } from '@/services/backend/db/namespace';
|
||||
import { get_k8s_username, queryUser } from '@/services/backend/db/user';
|
||||
import { queryNamespacesByUser } from '@/services/backend/db/userToNamespace';
|
||||
import { getUserKubeconfig, setUserTeamCreate } from '@/services/backend/kubernetes/admin';
|
||||
import { getTeamKubeconfig } from '@/services/backend/kubernetes/admin';
|
||||
import { GetUserDefaultNameSpace } from '@/services/backend/kubernetes/user';
|
||||
import { jsonRes } from '@/services/backend/response';
|
||||
import { bindingRole, modifyTeamRole } from '@/services/backend/team';
|
||||
@@ -34,8 +34,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
if (!ns_creater) throw new Error('fail to get ns_creater');
|
||||
const nsid = GetUserDefaultNameSpace(ns_creater);
|
||||
// 创建伪user
|
||||
await getUserKubeconfig(user.uid, ns_creater);
|
||||
const creater_kc_str = await setUserTeamCreate(ns_creater);
|
||||
const creater_kc_str = await getTeamKubeconfig(ns_creater, tokenUser.k8s_username);
|
||||
if (!creater_kc_str) throw new Error('fail to get kubeconfig');
|
||||
const namespace = await createNS({
|
||||
namespace: nsid,
|
||||
@@ -65,6 +64,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
message: 'Successfully',
|
||||
data: {
|
||||
namespace: {
|
||||
role: UserRole.Owner,
|
||||
createTime: namespace.createTime,
|
||||
uid: namespace.uid,
|
||||
id: namespace.id,
|
||||
|
||||
@@ -14,10 +14,16 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
|
||||
if (utnWithUser.length <= 0)
|
||||
return jsonRes(res, { code: 404, message: 'namespace not founded!' });
|
||||
|
||||
const rawNamespace = utnWithUser[0].namespace;
|
||||
const selfUtn = utnWithUser.find(
|
||||
(utn) => utn.userId === payload.user.uid && utn.k8s_username === payload.user.k8s_username
|
||||
);
|
||||
if (!selfUtn) return jsonRes(res, { code: 404, message: 'You are not in the namespace' });
|
||||
const namespace: NamespaceDto = {
|
||||
uid: rawNamespace.uid,
|
||||
id: rawNamespace.id,
|
||||
role: selfUtn.role,
|
||||
createTime: rawNamespace.createTime,
|
||||
teamName: rawNamespace.teamName,
|
||||
nstype: rawNamespace.nstype
|
||||
|
||||
@@ -11,12 +11,13 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
const ns = await queryNamespacesByUser({ userId: payload.user.uid, k8s_username });
|
||||
// 没接受应该不能查看消息
|
||||
const namespaces = ns
|
||||
.filter((x) => x.status === InvitedStatus.Accepted)
|
||||
.map<
|
||||
NamespaceDto & {
|
||||
role: UserRole;
|
||||
}
|
||||
>((x) => ({
|
||||
.filter(
|
||||
(x) =>
|
||||
x.status === InvitedStatus.Accepted &&
|
||||
x.k8s_username === payload.user.k8s_username &&
|
||||
x.userId === payload.user.uid
|
||||
)
|
||||
.map<NamespaceDto>((x) => ({
|
||||
id: x.namespace.id,
|
||||
uid: x.namespace.uid,
|
||||
createTime: x.namespace.createTime,
|
||||
|
||||
@@ -159,31 +159,28 @@ async function setUserKubeconfig(kc: k8s.KubeConfig, uid: string, k8s_username:
|
||||
return k8s_username;
|
||||
}
|
||||
|
||||
async function setUserTeam(kc: k8s.KubeConfig, k8s_username: string) {
|
||||
async function setUserTeamCreate(kc: k8s.KubeConfig, k8s_username: string, owner: string) {
|
||||
const group = 'user.sealos.io';
|
||||
const resourceKind = 'User';
|
||||
const version = 'v1';
|
||||
const plural = 'users';
|
||||
const updateTime = k8sFormatTime(new Date());
|
||||
const client = kc.makeApiClient(k8s.CustomObjectsApi);
|
||||
const patchs = [
|
||||
{ op: 'add', path: '/metadata/labels/user.sealos.io~1type', value: 'Group' },
|
||||
{ op: 'replace', path: '/metadata/labels/updateTime', value: updateTime }
|
||||
];
|
||||
await client.patchClusterCustomObject(
|
||||
group,
|
||||
version,
|
||||
plural,
|
||||
k8s_username,
|
||||
patchs,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json-patch+json'
|
||||
const resourceObj = {
|
||||
apiVersion: 'user.sealos.io/v1',
|
||||
kind: resourceKind,
|
||||
metadata: {
|
||||
annotations: {
|
||||
'user.sealos.io/owner': owner
|
||||
},
|
||||
name: k8s_username,
|
||||
labels: {
|
||||
'user.sealos.io/type': 'Group',
|
||||
owner: updateTime
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
await client.createClusterCustomObject(group, version, plural, resourceObj);
|
||||
return k8s_username;
|
||||
}
|
||||
async function removeUserTeam(kc: k8s.KubeConfig, k8s_username: string) {
|
||||
@@ -263,12 +260,13 @@ export const getUserKubeconfig = async (uid: string, k8s_username: string) => {
|
||||
});
|
||||
return kubeconfig;
|
||||
};
|
||||
export const setUserTeamCreate = async (k8s_username: string) => {
|
||||
// 创建Team用的伪user
|
||||
export const getTeamKubeconfig = async (k8s_username: string, owner: string) => {
|
||||
const kc = K8sApiDefault();
|
||||
const group = 'user.sealos.io';
|
||||
const version = 'v1';
|
||||
const plural = 'users';
|
||||
await setUserTeam(kc, k8s_username);
|
||||
await setUserTeamCreate(kc, k8s_username, owner);
|
||||
|
||||
let body = await watchCustomClusterObject({
|
||||
kc,
|
||||
@@ -276,12 +274,16 @@ export const setUserTeamCreate = async (k8s_username: string) => {
|
||||
version,
|
||||
plural,
|
||||
fn(_, cur) {
|
||||
return cur?.metadata?.labels?.['user.sealos.io/type'] === 'Group';
|
||||
return (
|
||||
cur?.metadata?.labels?.['user.sealos.io/type'] === 'Group' &&
|
||||
cur?.metadata?.annotations?.['user.sealos.io/owner'] === owner
|
||||
);
|
||||
},
|
||||
name: k8s_username
|
||||
});
|
||||
return body;
|
||||
};
|
||||
|
||||
export const setUserTeamDelete = async (k8s_username: string) => {
|
||||
const kc = K8sApiDefault();
|
||||
const group = 'user.sealos.io';
|
||||
@@ -296,7 +298,6 @@ export const setUserTeamDelete = async (k8s_username: string) => {
|
||||
version,
|
||||
plural,
|
||||
fn(_, cur) {
|
||||
console.log(cur?.metadata?.labels?.['user.sealos.io/status']);
|
||||
return cur?.metadata?.labels?.['user.sealos.io/status'] === 'Deleted';
|
||||
},
|
||||
name: k8s_username
|
||||
|
||||
@@ -110,7 +110,7 @@ export type NamespaceDto = {
|
||||
createTime: Date;
|
||||
// 展示到前端的名字
|
||||
teamName: string;
|
||||
// role: UserRole;
|
||||
role: UserRole;
|
||||
readonly nstype: NSType;
|
||||
};
|
||||
export enum UserRole {
|
||||
|
||||
@@ -246,7 +246,8 @@ const EditApp = ({ appName, tabType }: { appName?: string; tabType: string }) =>
|
||||
justifyContent={'start'}
|
||||
alignItems={'center'}
|
||||
backgroundColor={'rgba(255, 255, 255)'}
|
||||
backdropBlur={'100px'}>
|
||||
backdropBlur={'100px'}
|
||||
>
|
||||
<Box cursor={'pointer'} onClick={() => router.push('/')}>
|
||||
<MyIcon ml={'46px'} name="arrowLeft" color={'#24282C'} w={'16px'} h={'16px'}></MyIcon>
|
||||
</Box>
|
||||
@@ -255,7 +256,8 @@ const EditApp = ({ appName, tabType }: { appName?: string; tabType: string }) =>
|
||||
fontWeight={500}
|
||||
fontSize={16}
|
||||
textDecoration={'none'}
|
||||
color={'#7B838B'}>
|
||||
color={'#7B838B'}
|
||||
>
|
||||
<BreadcrumbItem textDecoration={'none'}>
|
||||
<BreadcrumbLink _hover={{ color: '#219BF4', textDecoration: 'none' }} href="/">
|
||||
{t('Template List')}
|
||||
@@ -274,7 +276,8 @@ const EditApp = ({ appName, tabType }: { appName?: string; tabType: string }) =>
|
||||
flexDirection={'column'}
|
||||
width={'100%'}
|
||||
flexGrow={1}
|
||||
backgroundColor={'rgba(255, 255, 255, 0.90)'}>
|
||||
backgroundColor={'rgba(255, 255, 255, 0.90)'}
|
||||
>
|
||||
<Header
|
||||
templateDetail={templateDetail}
|
||||
appName={''}
|
||||
|
||||
@@ -182,7 +182,8 @@ export default function Develop() {
|
||||
borderRadius={'8px'}
|
||||
overflowY={'hidden'}
|
||||
overflowX={'scroll'}
|
||||
flex={1}>
|
||||
flex={1}
|
||||
>
|
||||
{/* left */}
|
||||
<Flex flexDirection={'column'} w="50%" borderRight={'1px solid #EFF0F1'}>
|
||||
<Flex
|
||||
@@ -192,7 +193,8 @@ export default function Develop() {
|
||||
alignItems={'center'}
|
||||
backgroundColor={'#F8FAFB'}
|
||||
px="36px"
|
||||
borderRadius={'8px 8px 0px 0px '}>
|
||||
borderRadius={'8px 8px 0px 0px '}
|
||||
>
|
||||
<MyIcon name="dev" color={'#24282C'} w={'24px'} h={'24px'}></MyIcon>
|
||||
<Text fontWeight={'500'} fontSize={'16px'} color={'#24282C'} ml="8px">
|
||||
{t('develop.Development')}
|
||||
@@ -220,7 +222,8 @@ export default function Develop() {
|
||||
alignItems={'center'}
|
||||
backgroundColor={'#F8FAFB'}
|
||||
pl="42px"
|
||||
borderRadius={'8px 8px 0px 0px '}>
|
||||
borderRadius={'8px 8px 0px 0px '}
|
||||
>
|
||||
<MyIcon name="eyeShow" color={'#24282C'} w={'24px'} h={'24px'}></MyIcon>
|
||||
<Text fontWeight={'500'} fontSize={'16px'} color={'#24282C'} ml="8px">
|
||||
{t('develop.Preview')}
|
||||
@@ -232,7 +235,8 @@ export default function Develop() {
|
||||
pt="26px"
|
||||
pr={{ sm: '20px', md: '60px' }}
|
||||
borderBottom={'1px solid #EFF0F1'}
|
||||
flexDirection={'column'}>
|
||||
flexDirection={'column'}
|
||||
>
|
||||
<Text fontWeight={'500'} fontSize={'18px'} color={'#24282C'}>
|
||||
{t('develop.Configure Form')}
|
||||
</Text>
|
||||
@@ -248,7 +252,8 @@ export default function Develop() {
|
||||
minW={'100px'}
|
||||
h={'34px'}
|
||||
variant={'link'}
|
||||
onClick={handleExportYaml}>
|
||||
onClick={handleExportYaml}
|
||||
>
|
||||
{t('Export')} Yaml
|
||||
</Button>
|
||||
</Flex>
|
||||
|
||||
@@ -89,7 +89,8 @@ function Index() {
|
||||
height={'100%'}
|
||||
overflow={'auto'}
|
||||
backgroundColor={'#edeff0'}
|
||||
position={'relative'}>
|
||||
position={'relative'}
|
||||
>
|
||||
<Flex justifyContent={'center'} flexDirection={'column'} alignItems={'center'} pt={'24px'}>
|
||||
<Text color={'24282C'} fontSize={'48px'} fontWeight={500}>
|
||||
{t('Templates')}
|
||||
@@ -107,7 +108,8 @@ function Index() {
|
||||
top={'26px'}
|
||||
backgroundColor={'#FFF'}
|
||||
borderRadius={'40px'}
|
||||
onClick={() => router.push('/develop')}>
|
||||
onClick={() => router.push('/develop')}
|
||||
>
|
||||
<MyIcon name="tool" fill={'transparent'} />
|
||||
<Text ml="8px" color={'#485058'} fontWeight={500} cursor={'pointer'} fontSize={'12px'}>
|
||||
{t('develop.YAML Detection Tool')}
|
||||
@@ -122,7 +124,8 @@ function Index() {
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none">
|
||||
fill="none"
|
||||
>
|
||||
<path
|
||||
d="M21.71 20.29L18 16.61C19.4401 14.8144 20.1375 12.5353 19.9488 10.2413C19.7601 7.9473 18.6997 5.81278 16.9855 4.27664C15.2714 2.7405 13.0338 1.91951 10.7329 1.98247C8.43204 2.04543 6.24273 2.98756 4.61515 4.61514C2.98757 6.24272 2.04543 8.43203 1.98247 10.7329C1.91951 13.0338 2.74051 15.2714 4.27665 16.9855C5.81279 18.6997 7.94731 19.7601 10.2413 19.9488C12.5353 20.1375 14.8144 19.4401 16.61 18L20.29 21.68C20.383 21.7737 20.4936 21.8481 20.6154 21.8989C20.7373 21.9497 20.868 21.9758 21 21.9758C21.132 21.9758 21.2627 21.9497 21.3846 21.8989C21.5064 21.8481 21.617 21.7737 21.71 21.68C21.8902 21.4935 21.991 21.2443 21.991 20.985C21.991 20.7257 21.8902 20.4765 21.71 20.29ZM11 18C9.61553 18 8.26216 17.5895 7.11101 16.8203C5.95987 16.0511 5.06266 14.9579 4.53285 13.6788C4.00303 12.3997 3.86441 10.9922 4.13451 9.63436C4.4046 8.2765 5.07129 7.02922 6.05026 6.05025C7.02922 5.07128 8.2765 4.4046 9.63437 4.1345C10.9922 3.8644 12.3997 4.00303 13.6788 4.53284C14.9579 5.06265 16.0511 5.95986 16.8203 7.111C17.5895 8.26215 18 9.61553 18 11C18 12.8565 17.2625 14.637 15.9498 15.9497C14.637 17.2625 12.8565 18 11 18Z"
|
||||
fill="#24282C"
|
||||
@@ -144,7 +147,8 @@ function Index() {
|
||||
justifyContent={'center'}
|
||||
w={'100%'}
|
||||
gridTemplateColumns="repeat(auto-fit, minmax(328px, 328px))"
|
||||
gridGap={'24px'}>
|
||||
gridGap={'24px'}
|
||||
>
|
||||
{filterData &&
|
||||
filterData?.map((item: TemplateType) => {
|
||||
return (
|
||||
@@ -164,14 +168,16 @@ function Index() {
|
||||
p={'24px'}
|
||||
borderRadius={'6px'}
|
||||
backgroundColor={'#fff'}
|
||||
border={'1px solid #DEE0E2'}>
|
||||
border={'1px solid #DEE0E2'}
|
||||
>
|
||||
<Box
|
||||
p={'6px'}
|
||||
w={'48px'}
|
||||
h={'48px'}
|
||||
borderRadius={'4px'}
|
||||
backgroundColor={'#fff'}
|
||||
border={' 1px solid #DEE0E2'}>
|
||||
border={' 1px solid #DEE0E2'}
|
||||
>
|
||||
<Image src={item?.spec?.icon} alt="" width={'36px'} height={'36px'} />
|
||||
</Box>
|
||||
<Flex mt={'12px'} alignItems={'center'} justifyContent="space-between">
|
||||
@@ -187,7 +193,8 @@ function Index() {
|
||||
h={'28px'}
|
||||
borderRadius={'4px'}
|
||||
border={'1px solid #DEE0E2'}
|
||||
backgroundColor={'#F4F6F8'}>
|
||||
backgroundColor={'#F4F6F8'}
|
||||
>
|
||||
Deploy
|
||||
</Flex>
|
||||
</Flex>
|
||||
@@ -203,7 +210,8 @@ function Index() {
|
||||
mt={'8px'}
|
||||
fontSize={'12px'}
|
||||
color={'5A646E'}
|
||||
fontWeight={400}>
|
||||
fontWeight={400}
|
||||
>
|
||||
{item?.spec?.description}
|
||||
</Text>
|
||||
<Flex mt={'auto'} justifyContent={'space-between'} alignItems={'center'}>
|
||||
|
||||
Reference in New Issue
Block a user