Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

780 user ssh key #403

Merged
merged 2 commits into from
Jun 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions src/api/repository/sshKey.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// ref: https://github.com/machbase/neo-server/blob/31b78eb95325d4690d178f9a56da2df396d4d5a9/mods/service/httpd/httpd.go#L211
import request from '@/api/core';

export interface SSHKEY_ITEM_TYPE {
keyType: string;
fingerprint: string;
comment: string;
}
interface RES_COMMON {
elapse: string;
reason: string;
success: string;
}
interface RES_SSHKEY extends RES_COMMON {
data: SSHKEY_ITEM_TYPE[];
}

/**
* Get ssh key list
* @returns ssh key list
*/
export const getSSHKeys = (): Promise<RES_SSHKEY> => {
return request({
method: 'GET',
url: `/api/sshkeys`,
});
};

/**
* Add ssh key
* @SSHKeyPub string
*/
export const addSSHKey = (aSSHKeyPub: string): Promise<RES_COMMON> => {
return request({
method: 'POST',
url: `/api/sshkeys`,
data: { key: aSSHKeyPub },
});
};

/**
* Delete ssh key
* @FingerPrt string
* @return status
*/
export const delSSHKey = (aFingerPrt: string): Promise<RES_COMMON> => {
return request({
method: 'DELETE',
url: `/api/sshkeys/${aFingerPrt}`,
});
};
2 changes: 2 additions & 0 deletions src/components/editor/Body.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { Timer } from '../timer';
import { ShellManage } from '@/components/ShellManage';
import { Bridge } from '../bridge';
import { useNavigate } from 'react-router-dom';
import { SSHKey } from '../sshkey';

const Body = ({ pExtentionList, pSideSizes, pDraged, pGetInfo, pGetPath, pSetDragStat, pDragStat }: any) => {
const [sBoardList, setBoardList] = useRecoilState<any[]>(gBoardList);
Expand Down Expand Up @@ -254,6 +255,7 @@ const Body = ({ pExtentionList, pSideSizes, pDraged, pGetInfo, pGetPath, pSetDra
{aItem.type === 'timer' && <Timer pCode={aItem.code} />}
{aItem.type === 'shell-manage' && <ShellManage pCode={aItem.code} />}
{aItem.type === 'bridge' && <Bridge pCode={aItem.code} />}
{aItem.type === 'ssh-key' && <SSHKey />}
{isImage(aItem.name) && <ImageBox pBase64Code={aItem.code} pType={aItem.type} />}
</div>
);
Expand Down
39 changes: 35 additions & 4 deletions src/components/extension/ExtensionTab/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,39 @@
font-family: initial;
font-size: 13px;
}
.extension-tab-copy-block-wrapper {
display: flex;
margin: 8px 0px 8px 0px;

.extension-tab-copy-block {
overflow-x: scroll;
width: 100%;
display: flex;
justify-content: space-between;

flex-direction: row;
align-items: flex-start;
padding: 8px;
border-radius: 3px;
border: solid 1px #f1f1f125;
background-color: rgba(255, 255, 255, 0.13);
color: #f1f1f1;
text-align: start;

&-text {
width: auto;
}
&-btn {
margin-left: 24px;
}
}
}

.extension-tab-hover-bg-wrapper {
&:hover {
background-color: rgba(255, 255, 255, 0.13);
}
}

.extension-tab-switch-wrapper {
display: flex;
Expand Down Expand Up @@ -195,7 +228,6 @@
border-radius: 2px;
font-size: 13px;
padding: 4px;
margin-right: 16px;

&:hover {
border: 1px solid rgba(255, 255, 255, 0.13);
Expand Down Expand Up @@ -496,17 +528,16 @@
text-transform: capitalize;
}
&-desc {
color: #aaaaaa;
color: #a3a3a3;
font-size: 14px;
// margin: 4px 0;
}
&-text {
margin-top: 4px;
width: 100%;
font-size: 13px;
white-space: break-spaces;
overflow-wrap: break-word;
color: #c5c4c4;
color: #dfdfdf;
overflow: hidden;
}

Expand Down
72 changes: 69 additions & 3 deletions src/components/extension/ExtensionTab/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import './index.scss';
import { VscCheck, VscCircleFilled, VscPass } from 'react-icons/vsc';
import { generateUUID } from '@/utils';
import { MdKeyboardArrowRight, MdOutlineKeyboardArrowDown } from 'react-icons/md';
import { ClipboardCopy } from '@/utils/ClipboardCopy';

export const ExtensionTab = ({ children, pRef }: { children: React.ReactNode; pRef?: React.MutableRefObject<any> }) => {
return (
Expand Down Expand Up @@ -70,12 +71,16 @@ const TextButton = ({
pCallback,
pWidth,
pIsDisable = false,
onMouseOut = () => {},
mr = '16px',
}: {
pText: string;
pType: string;
pCallback: (e: React.MouseEvent) => void;
pWidth?: string;
pIsDisable?: boolean;
onMouseOut?: (e: React.MouseEvent) => void;
mr?: string;
}) => {
const getColor = () => {
switch (pType) {
Expand All @@ -88,7 +93,12 @@ const TextButton = ({
}
};
return (
<button className="extension-tab-text-button" style={{ backgroundColor: pIsDisable ? '#6f7173' : getColor(), width: pWidth }} onClick={pCallback}>
<button
className="extension-tab-text-button"
style={{ backgroundColor: pIsDisable ? '#6f7173' : getColor(), width: pWidth, marginRight: mr }}
onClick={pCallback}
onMouseOut={onMouseOut}
>
{pText}
</button>
);
Expand All @@ -100,7 +110,17 @@ const IconBtn = ({ children, pCallback, pActive }: { children: React.ReactNode;
</div>
);
};
const Input = ({ pAutoFocus, pCallback, pValue, pWidth }: { pAutoFocus?: boolean; pCallback?: (e: React.FormEvent<HTMLInputElement>) => void; pValue?: any; pWidth?: any }) => {
const Input = ({
pAutoFocus,
pCallback = () => {},
pValue,
pWidth,
}: {
pAutoFocus?: boolean;
pCallback?: (e: React.FormEvent<HTMLInputElement>) => void;
pValue?: any;
pWidth?: any;
}) => {
return (
<div className="extension-tab-input-wrapper" style={{ width: pWidth }}>
<input autoFocus={pAutoFocus} onChange={pCallback} value={pValue} />
Expand All @@ -111,16 +131,18 @@ const TextArea = ({
pAutoFocus = false,
pContent,
pHeight,
pPlaceHolder = '',
pCallback,
}: {
pAutoFocus?: boolean;
pContent: string;
pHeight: number;
pPlaceHolder?: string;
pCallback?: (e: React.FormEvent<HTMLTextAreaElement>) => void;
}) => {
return (
<div className="extension-tab-text-area-wrapper">
<textarea autoFocus={pAutoFocus} defaultValue={pContent} onChange={pCallback} style={{ height: pHeight + 'px' }} />
<textarea placeholder={pPlaceHolder} autoFocus={pAutoFocus} defaultValue={pContent} onChange={pCallback} style={{ height: pHeight + 'px' }} />
</div>
);
};
Expand Down Expand Up @@ -478,6 +500,46 @@ const Collapse = ({ pInitOpen = false, pTrigger, pChildren }: { pInitOpen?: bool
);
};

const CopyBlock = ({ pContent }: { pContent: string }) => {
return (
<div className="extension-tab-copy-block-wrapper">
<div className="extension-tab-copy-block">
<div className="extension-tab-copy-block-text">
<ContentText pContent={pContent} />
</div>
<div className="extension-tab-copy-block-btn">
<CopyButton pContent={pContent} />
</div>
</div>
</div>
);
};

const CopyButton = ({ pContent }: { pContent: string }) => {
const [sTooltipTxt, setTooltipTxt] = useState<string>('Copy');

/** copy clipboard */
const handleCopy = () => {
setTooltipTxt('Copied!');
ClipboardCopy(pContent);
};
const handleMouseout = () => {
sTooltipTxt === 'Copied!' && setTooltipTxt('Copy');
};

return (
<div className="extension-tab-copy-warpper">
<TextButton pText={sTooltipTxt} pType="COPY" pWidth="60px" pCallback={handleCopy} onMouseOut={handleMouseout} mr="0px" />
</div>
);
};
const Space = ({ pHeight = '8px' }: { pHeight?: string }) => {
return <div style={{ width: '100%', height: pHeight }} />;
};
const HoverBg = ({ children }: { children: React.ReactNode }) => {
return <div className="extension-tab-hover-bg-wrapper">{children}</div>;
};

ExtensionTab.Checkbox = Checkbox;
ExtensionTab.Group = Group;
ExtensionTab.Header = Header;
Expand All @@ -503,3 +565,7 @@ ExtensionTab.TextResErr = TextResErr;
ExtensionTab.StatusCircle = StatusCircle;
ExtensionTab.Collapse = Collapse;
ExtensionTab.TextResSuccess = TextResSuccess;
ExtensionTab.CopyButton = CopyButton;
ExtensionTab.CopyBlock = CopyBlock;
ExtensionTab.Space = Space;
ExtensionTab.HoverBg = HoverBg;
52 changes: 48 additions & 4 deletions src/components/extension/index.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import { useState, useRef, useEffect } from 'react';
import { Cmd, VscSymbolFile, VscThreeBars, VscNote, VscGraphLine, Gear, VscFiles, Logout, Key, VscLibrary, GoDatabase, VscKey, GoTerminal } from '@/assets/icons/Icon';
import ExtensionBtn from '@/components/extension/ExtensionBtn';
import { useRecoilState } from 'recoil';
import { gExtensionList, gSelectedExtension } from '@/recoil/recoil';
import { useRecoilState, useSetRecoilState } from 'recoil';
import { gBoardList, gExtensionList, gSelectedExtension, gSelectedTab } from '@/recoil/recoil';
import Menu from '../contextMenu/Menu';
import useOutsideClick from '@/hooks/useOutsideClick';
import { LicenseModal } from '@/components/modal/LicenseModal';
import { logOut } from '@/api/repository/login';
import { useNavigate } from 'react-router-dom';
import { RxLapTimer } from 'react-icons/rx';
import { VscTypeHierarchy } from 'react-icons/vsc';
import { generateUUID } from '@/utils';
import './index.scss';

const Extension = ({ pHandleSideBar, pSetSideSizes, pIsSidebar }: any) => {
Expand All @@ -19,6 +20,8 @@ const Extension = ({ pHandleSideBar, pSetSideSizes, pIsSidebar }: any) => {
const [sExtensionList] = useRecoilState<any>(gExtensionList);
const [sSelectedExtension, setSelectedExtension] = useRecoilState<string>(gSelectedExtension);
const [sIsLicenseModal, setIsLicenseModal] = useState<boolean>(false);
const setSelectedTab = useSetRecoilState<any>(gSelectedTab);
const [sBoardList, setBoardList] = useRecoilState<any[]>(gBoardList);

const selectExtension = (aItem: any) => {
if (aItem.label === sSelectedExtension) {
Expand All @@ -33,7 +36,6 @@ const Extension = ({ pHandleSideBar, pSetSideSizes, pIsSidebar }: any) => {
setSelectedExtension(aItem.id);
}
};

const logout = async () => {
const sLogout: any = await logOut();
if (sLogout.success) {
Expand All @@ -42,7 +44,6 @@ const Extension = ({ pHandleSideBar, pSetSideSizes, pIsSidebar }: any) => {
sNavigate('/login');
}
};

const setIcon = (aId: any) => {
switch (aId) {
case 'SQL':
Expand Down Expand Up @@ -73,6 +74,45 @@ const Extension = ({ pHandleSideBar, pSetSideSizes, pIsSidebar }: any) => {
return <Cmd />;
}
};
const handleSSHKeys = () => {
setIsOpen(false);
const sExistKeyTab = sBoardList.reduce((prev: boolean, cur: any) => {
return prev || cur.type === 'ssh-key';
}, false);

if (sExistKeyTab) {
const aTarget = sBoardList.find((aBoard: any) => aBoard.type === 'ssh-key');
setBoardList((aBoardList: any) => {
return aBoardList.map((aBoard: any) => {
if (aBoard.id === aTarget.id) {
return {
...aTarget,
name: `SSH KEYS`,
code: '',
savedCode: '',
};
}
return aBoard;
});
});
setSelectedTab(aTarget.id);
return;
} else {
const sId = generateUUID();
setBoardList([
...sBoardList,
{
id: sId,
type: 'ssh-key',
name: `SSH KEYS`,
code: '',
savedCode: '',
},
]);
setSelectedTab(sId);
return;
}
};

useOutsideClick(MenuRef, () => setIsOpen(false));

Expand Down Expand Up @@ -122,6 +162,10 @@ const Extension = ({ pHandleSideBar, pSetSideSizes, pIsSidebar }: any) => {
<Key />
<span>License</span>
</Menu.Item>
<Menu.Item onClick={handleSSHKeys}>
<VscKey />
<span>SSH Keys</span>
</Menu.Item>
<Menu.Item onClick={logout}>
<Logout />
<span>Logout</span>
Expand Down
Loading
Loading