mirror of
https://github.com/LukeHagar/firecamp.git
synced 2025-12-10 20:37:47 +00:00
Merge branch 'main' into test/rest-playground
This commit is contained in:
16
package.json
16
package.json
@@ -1,17 +1,20 @@
|
|||||||
{
|
{
|
||||||
"name": "firecamp",
|
"name": "firecamp",
|
||||||
"version": "3.0.0",
|
"version": "3.2.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "Universal API testing and collaboration platform",
|
"description": "Universal API testing and collaboration platform",
|
||||||
"main": "packages/firecamp-desktop-app/dist/services/Main",
|
"main": "packages/firecamp-desktop-app/dist/services/Main",
|
||||||
"homepage": "./dev",
|
"homepage": "./dev",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build:workspace": "pnpm --filter=@firecamp/scripts --filter=@firecamp/rest-executor --filter=@firecamp/ws-executor --filter=@firecamp/socket.io-executor build",
|
|
||||||
"boot": "pnpm install --shamefully-hoist",
|
"boot": "pnpm install --shamefully-hoist",
|
||||||
"bootstrap": "pnpm install --shamefully-hoist",
|
"bootstrap": "pnpm install --shamefully-hoist",
|
||||||
"start": "npx webpack serve --config ./webpack.dev.js",
|
"dev": "run-p build:workspace webpack:dev",
|
||||||
"dev": "APP_VERSION=$npm_package_version AppFormat=webapp && node scripts/build && pnpm build:workspace && pnpm start",
|
"build": "run-s validate:release build:workspace webpack:prod",
|
||||||
"release:web": "AppFormat=webapp && pnpm build:workspace && node scripts/release",
|
"build:workspace": "pnpm --filter=@firecamp/scripts --filter=@firecamp/rest-executor --filter=@firecamp/ws-executor --filter=@firecamp/socket.io-executor build",
|
||||||
|
"webpack:dev": "webpack serve --config ./webpack.dev.js",
|
||||||
|
"webpack:prod": "webpack --config ./webpack.prod.js",
|
||||||
|
"validate:release": "node scripts/release",
|
||||||
|
"release:web": "pnpm build",
|
||||||
"lint": "eslint packages/firecamp-rest/src/**/*.{ts|tsx} packages/*.js packages-clients/*.js scripts webpack/*.js",
|
"lint": "eslint packages/firecamp-rest/src/**/*.{ts|tsx} packages/*.js packages-clients/*.js scripts webpack/*.js",
|
||||||
"test": "jest",
|
"test": "jest",
|
||||||
"prettify": "prettier --write \"platform/firecamp-platform/src/**/*.(ts|tsx)\" \"packages/firecamp-rest/src/**/*.(ts|tsx)\" \"packages/firecamp-graphql/src/**/*.(ts|tsx)\"",
|
"prettify": "prettier --write \"platform/firecamp-platform/src/**/*.(ts|tsx)\" \"packages/firecamp-rest/src/**/*.(ts|tsx)\" \"packages/firecamp-graphql/src/**/*.(ts|tsx)\"",
|
||||||
@@ -76,6 +79,7 @@
|
|||||||
"jest-css-modules-transform": "^4.4.2",
|
"jest-css-modules-transform": "^4.4.2",
|
||||||
"lint-staged": "^13.1.2",
|
"lint-staged": "^13.1.2",
|
||||||
"node-polyfill-webpack-plugin": "^2.0.0",
|
"node-polyfill-webpack-plugin": "^2.0.0",
|
||||||
|
"npm-run-all": "^4.1.5",
|
||||||
"postcss-loader": "^7.0.2",
|
"postcss-loader": "^7.0.2",
|
||||||
"prettier": "^2.6.2",
|
"prettier": "^2.6.2",
|
||||||
"react-addons-test-utils": "^15.0.2",
|
"react-addons-test-utils": "^15.0.2",
|
||||||
@@ -85,6 +89,7 @@
|
|||||||
"semver": "^7.3.5",
|
"semver": "^7.3.5",
|
||||||
"shelljs": "^0.8.5",
|
"shelljs": "^0.8.5",
|
||||||
"style-loader": "^3.3.1",
|
"style-loader": "^3.3.1",
|
||||||
|
"terser-webpack-plugin": "^5.3.9",
|
||||||
"ts-loader": "^9.2.8",
|
"ts-loader": "^9.2.8",
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
"typescript": "^5.0.2",
|
"typescript": "^5.0.2",
|
||||||
@@ -95,6 +100,7 @@
|
|||||||
"webpack-hot-middleware": "^2.25.1",
|
"webpack-hot-middleware": "^2.25.1",
|
||||||
"webpack-html-plugin": "^0.1.1",
|
"webpack-html-plugin": "^0.1.1",
|
||||||
"webpack-httpolyglot-server": "^0.3.0",
|
"webpack-httpolyglot-server": "^0.3.0",
|
||||||
|
"webpack-merge": "^5.9.0",
|
||||||
"worker-loader": "^3.0.8"
|
"worker-loader": "^3.0.8"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -50,7 +50,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@firecamp/agent-manager": "workspace:*",
|
"@firecamp/agent-manager": "workspace:*",
|
||||||
"@firecamp/cloud-apis": "^0.2.8",
|
"@firecamp/cloud-apis": "0.2.10",
|
||||||
"@firecamp/cookie-manager": "^0.0.0",
|
"@firecamp/cookie-manager": "^0.0.0",
|
||||||
"@firecamp/graphql": "workspace:*",
|
"@firecamp/graphql": "workspace:*",
|
||||||
"@firecamp/rest": "workspace:*",
|
"@firecamp/rest": "workspace:*",
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 7.5 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.5 KiB |
@@ -26,6 +26,7 @@ import { useTabStore } from '../../../store/tab';
|
|||||||
import { ETabEntityTypes } from '../../tabs/types';
|
import { ETabEntityTypes } from '../../tabs/types';
|
||||||
import platformContext from '../../../services/platform-context';
|
import platformContext from '../../../services/platform-context';
|
||||||
import { useExplorerStore } from '../../../store/explorer';
|
import { useExplorerStore } from '../../../store/explorer';
|
||||||
|
import useExplorerFacade from './useExplorerFacade';
|
||||||
|
|
||||||
const Explorer: FC<any> = () => {
|
const Explorer: FC<any> = () => {
|
||||||
const explorerTreeRef = useRef();
|
const explorerTreeRef = useRef();
|
||||||
@@ -43,29 +44,14 @@ const Explorer: FC<any> = () => {
|
|||||||
fetchExplorer,
|
fetchExplorer,
|
||||||
updateCollection,
|
updateCollection,
|
||||||
updateFolder,
|
updateFolder,
|
||||||
moveRequest,
|
// moveRequest,
|
||||||
moveFolder,
|
// moveFolder,
|
||||||
changeCollectionChildrenPosition,
|
changeCollectionChildrenPosition,
|
||||||
changeFolderChildrenPosition,
|
changeFolderChildrenPosition,
|
||||||
deleteCollection,
|
// deleteCollection,
|
||||||
deleteFolder,
|
// deleteFolder,
|
||||||
deleteRequest,
|
// deleteRequest,
|
||||||
} = useExplorerStore(
|
} = useExplorerFacade();
|
||||||
(s) => ({
|
|
||||||
explorer: s.explorer,
|
|
||||||
fetchExplorer: s.fetchExplorer,
|
|
||||||
updateCollection: s.updateCollection,
|
|
||||||
updateFolder: s.updateFolder,
|
|
||||||
moveRequest: s.moveRequest,
|
|
||||||
moveFolder: s.moveFolder,
|
|
||||||
changeCollectionChildrenPosition: s.changeCollectionChildrenPosition,
|
|
||||||
changeFolderChildrenPosition: s.changeFolderChildrenPosition,
|
|
||||||
deleteCollection: s.deleteCollection,
|
|
||||||
deleteFolder: s.deleteFolder,
|
|
||||||
deleteRequest: s.deleteRequest,
|
|
||||||
}),
|
|
||||||
shallow
|
|
||||||
);
|
|
||||||
|
|
||||||
const { isProgressing, collections, folders, requests } = explorer;
|
const { isProgressing, collections, folders, requests } = explorer;
|
||||||
|
|
||||||
@@ -457,31 +443,6 @@ const Explorer: FC<any> = () => {
|
|||||||
</Container>
|
</Container>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="w-full h-full flex flex-row">
|
|
||||||
<Container>
|
|
||||||
<Container.Body>
|
|
||||||
<div className="flex flex-col mt-8 p-4 items-center justify-center mt-2">
|
|
||||||
<div className="fc-sidebar-noproject-icon text-5xl opacity-20 mb-2"></div>
|
|
||||||
{!!searchString ? (
|
|
||||||
<div className="text-sm text-app-foreground-inactive text-center mb-1">
|
|
||||||
<span className="text-base block mb-2">No search found...</span>
|
|
||||||
Your search is not found within this workspace.
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div className="text-sm text-app-foreground-inactive text-center mb-1">
|
|
||||||
<span className="text-app-foreground text-base block mb-2">
|
|
||||||
Create your first API collection!
|
|
||||||
</span>
|
|
||||||
You don't have any API collection in this workspace.
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</Container.Body>
|
|
||||||
</Container>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Explorer;
|
export default Explorer;
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import shallow from 'zustand/shallow';
|
||||||
|
import { useExplorerStore } from '../../../store/explorer';
|
||||||
|
|
||||||
|
const useExplorerFacade = () => {
|
||||||
|
return useExplorerStore(
|
||||||
|
(s) => ({
|
||||||
|
explorer: s.explorer,
|
||||||
|
fetchExplorer: s.fetchExplorer,
|
||||||
|
updateCollection: s.updateCollection,
|
||||||
|
updateFolder: s.updateFolder,
|
||||||
|
// moveRequest: s.moveRequest,
|
||||||
|
// moveFolder: s.moveFolder,
|
||||||
|
changeCollectionChildrenPosition: s.changeCollectionChildrenPosition,
|
||||||
|
changeFolderChildrenPosition: s.changeFolderChildrenPosition,
|
||||||
|
// deleteCollection: s.deleteCollection,
|
||||||
|
// deleteFolder: s.deleteFolder,
|
||||||
|
// deleteRequest: s.deleteRequest,
|
||||||
|
}),
|
||||||
|
shallow
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useExplorerFacade;
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
import { useState } from 'react';
|
|
||||||
import classnames from 'classnames';
|
|
||||||
|
|
||||||
import { RiBracesLine } from '@react-icons/all-files/ri/RiBracesLine';
|
|
||||||
import { VscArrowDown } from '@react-icons/all-files/vsc/VscArrowDown';
|
|
||||||
import { VscFolder } from '@react-icons/all-files/vsc/VscFolder';
|
|
||||||
import { VscOrganization } from '@react-icons/all-files/vsc/VscOrganization';
|
import { VscOrganization } from '@react-icons/all-files/vsc/VscOrganization';
|
||||||
import { AiOutlineUserAdd } from '@react-icons/all-files/ai/AiOutlineUserAdd';
|
|
||||||
import { AiOutlineUserSwitch } from '@react-icons/all-files/ai/AiOutlineUserSwitch';
|
import { AiOutlineUserSwitch } from '@react-icons/all-files/ai/AiOutlineUserSwitch';
|
||||||
import { VscMultipleWindows } from '@react-icons/all-files/vsc/VscMultipleWindows';
|
import { VscMultipleWindows } from '@react-icons/all-files/vsc/VscMultipleWindows';
|
||||||
import { VscWindow } from '@react-icons/all-files/vsc/VscWindow';
|
import {
|
||||||
import { VscTriangleDown } from '@react-icons/all-files/vsc/VscTriangleDown';
|
Triangle,
|
||||||
|
MailOpen,
|
||||||
|
FolderClosed,
|
||||||
|
Braces,
|
||||||
|
ArrowDown,
|
||||||
|
AppWindow,
|
||||||
|
UserPlus2,
|
||||||
|
} from 'lucide-react';
|
||||||
|
|
||||||
import { Button, DropdownMenu, FcIconGetSquare } from '@firecamp/ui';
|
import { Button, DropdownMenu, FcIconGetSquare } from '@firecamp/ui';
|
||||||
import platformContext from '../../services/platform-context';
|
import platformContext from '../../services/platform-context';
|
||||||
@@ -27,61 +27,83 @@ enum EMenuOptions {
|
|||||||
InviteMembers = 'invite-members',
|
InviteMembers = 'invite-members',
|
||||||
SwitchOrg = 'switch-org',
|
SwitchOrg = 'switch-org',
|
||||||
SwitchWorkspace = 'switch-workspace',
|
SwitchWorkspace = 'switch-workspace',
|
||||||
|
AllInvitation = 'all-invitation',
|
||||||
}
|
}
|
||||||
|
|
||||||
const options = [
|
const options = [
|
||||||
{
|
{
|
||||||
id: EMenuOptions.Request,
|
id: EMenuOptions.Request,
|
||||||
name: 'New request',
|
name: 'New request',
|
||||||
prefix: () => <FcIconGetSquare size={16} className='text-app-foreground-active' />,
|
prefix: () => (
|
||||||
|
<FcIconGetSquare size={16} className="text-app-foreground-active" />
|
||||||
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: EMenuOptions.Collection,
|
id: EMenuOptions.Collection,
|
||||||
name: 'New collection',
|
name: 'New collection',
|
||||||
prefix: () => <VscFolder size={16} className='text-app-foreground-active' />,
|
prefix: () => (
|
||||||
|
<FolderClosed size={16} className="text-app-foreground-active" />
|
||||||
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: EMenuOptions.Environment,
|
id: EMenuOptions.Environment,
|
||||||
name: 'New environment',
|
name: 'New environment',
|
||||||
prefix: () => <RiBracesLine size={16} className='text-app-foreground-active' />,
|
prefix: () => <Braces size={16} className="text-app-foreground-active" />,
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
id: EMenuOptions.ImportCollection,
|
id: EMenuOptions.ImportCollection,
|
||||||
name: 'Import collection',
|
name: 'Import collection',
|
||||||
showSeparator: true,
|
showSeparator: true,
|
||||||
prefix: () => <VscArrowDown size={16} className='text-app-foreground-active' />,
|
prefix: () => (
|
||||||
|
<ArrowDown size={16} className="text-app-foreground-active" />
|
||||||
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: EMenuOptions.Workspace,
|
id: EMenuOptions.Workspace,
|
||||||
name: 'New workspace',
|
name: 'New workspace',
|
||||||
prefix: () => <VscWindow size={16} className='text-app-foreground-active' />,
|
prefix: () => (
|
||||||
|
<AppWindow size={16} className="text-app-foreground-active" />
|
||||||
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: EMenuOptions.Organization,
|
id: EMenuOptions.Organization,
|
||||||
name: 'New organization',
|
name: 'New organization',
|
||||||
prefix: () => <VscOrganization size={16} className='text-app-foreground-active' />,
|
prefix: () => (
|
||||||
|
<VscOrganization size={16} className="text-app-foreground-active" />
|
||||||
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: EMenuOptions.InviteMembers,
|
id: EMenuOptions.InviteMembers,
|
||||||
name: 'Invite members',
|
name: 'Invite members',
|
||||||
showSeparator: true,
|
showSeparator: true,
|
||||||
prefix: () => <AiOutlineUserAdd size={16} className='text-app-foreground-active' />,
|
prefix: () => (
|
||||||
|
<UserPlus2 size={16} className="text-app-foreground-active" />
|
||||||
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: EMenuOptions.SwitchOrg,
|
id: EMenuOptions.SwitchOrg,
|
||||||
name: 'Switch organization',
|
name: 'Switch organization',
|
||||||
prefix: () => <AiOutlineUserSwitch size={16} className='text-app-foreground-active' />,
|
prefix: () => (
|
||||||
|
<AiOutlineUserSwitch size={16} className="text-app-foreground-active" />
|
||||||
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: EMenuOptions.SwitchWorkspace,
|
id: EMenuOptions.SwitchWorkspace,
|
||||||
name: 'Switch workspace',
|
name: 'Switch workspace',
|
||||||
prefix: () => <VscMultipleWindows size={16} className='text-app-foreground-active' />,
|
prefix: () => (
|
||||||
|
<VscMultipleWindows size={16} className="text-app-foreground-active" />
|
||||||
|
),
|
||||||
|
showSeparator: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: EMenuOptions.AllInvitation,
|
||||||
|
name: 'View invitation',
|
||||||
|
prefix: () => <MailOpen size={16} className="text-app-foreground-active" />,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const GlobalCreateDD = ({}) => {
|
const GlobalCreateDD = ({}) => {
|
||||||
const [isOpen, toggleOpen] = useState(false);
|
|
||||||
const { open } = useTabStore.getState();
|
const { open } = useTabStore.getState();
|
||||||
const onSelect = (option) => {
|
const onSelect = (option) => {
|
||||||
switch (option.id) {
|
switch (option.id) {
|
||||||
@@ -113,17 +135,19 @@ const GlobalCreateDD = ({}) => {
|
|||||||
case EMenuOptions.SwitchWorkspace:
|
case EMenuOptions.SwitchWorkspace:
|
||||||
platformContext.app.modals.openSwitchWorkspace();
|
platformContext.app.modals.openSwitchWorkspace();
|
||||||
break;
|
break;
|
||||||
|
case EMenuOptions.AllInvitation:
|
||||||
|
platformContext.app.modals.openAllInvitation();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="border-l border-b border-tab-border flex items-center pl-1">
|
<div className="border-l border-b border-tab-border flex items-center pl-1">
|
||||||
<DropdownMenu
|
<DropdownMenu
|
||||||
onOpenChange={(v) => toggleOpen(v)}
|
|
||||||
handler={() => (
|
handler={() => (
|
||||||
<Button
|
<Button
|
||||||
text={'Create'}
|
leftIcon={<Triangle size={20} />}
|
||||||
rightIcon={<VscTriangleDown size={12} className={classnames({'transform rotate-180': isOpen})}/>}
|
animate={false}
|
||||||
transparent
|
transparent
|
||||||
primary
|
primary
|
||||||
compact
|
compact
|
||||||
@@ -131,9 +155,10 @@ const GlobalCreateDD = ({}) => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
options={options}
|
options={options}
|
||||||
|
footer={<div className="mt-1">v{process.env.APP_VERSION}</div>}
|
||||||
onSelect={onSelect}
|
onSelect={onSelect}
|
||||||
classNames={{
|
classNames={{
|
||||||
dropdown: '-ml-[2px]',
|
dropdown: '-ml-[2px] pb-0',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,12 +5,6 @@ import { Modal } from '@firecamp/ui';
|
|||||||
import './ErrorPopup.sass';
|
import './ErrorPopup.sass';
|
||||||
|
|
||||||
const ErrorPopup: FC<FallbackProps> = ({ error }) => {
|
const ErrorPopup: FC<FallbackProps> = ({ error }) => {
|
||||||
const bg = {
|
|
||||||
modal: {
|
|
||||||
background: '#c84a1782',
|
|
||||||
color: '#e3dfdf',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let [isOpen, toggleOpen] = useState(true);
|
let [isOpen, toggleOpen] = useState(true);
|
||||||
|
|
||||||
@@ -24,7 +18,6 @@ const ErrorPopup: FC<FallbackProps> = ({ error }) => {
|
|||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
opened={isOpen}
|
opened={isOpen}
|
||||||
styles={{ content: bg.modal }}
|
|
||||||
onClose={_onClose}
|
onClose={_onClose}
|
||||||
className="fc-error-popup"
|
className="fc-error-popup"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -240,8 +240,7 @@ const SidebarContainer: FC<any> = () => {
|
|||||||
const _setActiveItem = async (selected) => {
|
const _setActiveItem = async (selected) => {
|
||||||
if (!selected?.id) return;
|
if (!selected?.id) return;
|
||||||
else if (selected.item == EActivityBarItems.User) {
|
else if (selected.item == EActivityBarItems.User) {
|
||||||
window.open('https://app.firecamp.dev/profile/info');
|
platformContext.app.modals.openUserProfile();
|
||||||
platformContext.app.modals.openSaveRequest(); // openUserProfile();
|
|
||||||
} else if (selected.item == EActivityBarItems.Settings)
|
} else if (selected.item == EActivityBarItems.Settings)
|
||||||
platformContext.app.modals.openWorkspaceManagement();
|
platformContext.app.modals.openWorkspaceManagement();
|
||||||
else if (selected.item == EActivityBarItems.SslNProxy)
|
else if (selected.item == EActivityBarItems.SslNProxy)
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ import WorkspaceManagement from './workspace/WorkspaceManagement';
|
|||||||
import SwitchWorkspace from './workspace/SwitchWorkspace';
|
import SwitchWorkspace from './workspace/SwitchWorkspace';
|
||||||
import CloneEnvironment from './environment/CloneEnvironment';
|
import CloneEnvironment from './environment/CloneEnvironment';
|
||||||
import EditRequest from './request/edit-request/EditRequest';
|
import EditRequest from './request/edit-request/EditRequest';
|
||||||
|
import ProfileManagement from './profile/ProfileManagement';
|
||||||
|
import AllInvitation from './invitation/AllInvitation';
|
||||||
|
|
||||||
export const ModalContainer = () => {
|
export const ModalContainer = () => {
|
||||||
const { currentOpenModal, isOpen, close } = useModalStore(
|
const { currentOpenModal, isOpen, close } = useModalStore(
|
||||||
@@ -58,7 +60,8 @@ export const ModalContainer = () => {
|
|||||||
return <CloneEnvironment opened={isOpen} onClose={close} />;
|
return <CloneEnvironment opened={isOpen} onClose={close} />;
|
||||||
|
|
||||||
// User
|
// User
|
||||||
// case EPlatformModalTypes.UserProfile: return <UserProfile isOpen={isOpen} onClose={close} />;
|
case EPlatformModalTypes.UserProfile:
|
||||||
|
return <ProfileManagement opened={isOpen} onClose={close} />;
|
||||||
|
|
||||||
// Auth
|
// Auth
|
||||||
case EPlatformModalTypes.SignIn:
|
case EPlatformModalTypes.SignIn:
|
||||||
@@ -73,6 +76,8 @@ export const ModalContainer = () => {
|
|||||||
return <ResetPassword opened={isOpen} onClose={close} />;
|
return <ResetPassword opened={isOpen} onClose={close} />;
|
||||||
case EPlatformModalTypes.RefreshToken:
|
case EPlatformModalTypes.RefreshToken:
|
||||||
return <RefreshToken opened={isOpen} onClose={close} />;
|
return <RefreshToken opened={isOpen} onClose={close} />;
|
||||||
|
case EPlatformModalTypes.AllInvitation:
|
||||||
|
return <AllInvitation opened={isOpen} onClose={close} />;
|
||||||
default:
|
default:
|
||||||
return <></>;
|
return <></>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ const ForgotPassword: FC<IModal> = ({ opened = false, onClose = () => {} }) => {
|
|||||||
const _onKeyDown = (e: any) => e.key === 'Enter' && handleSubmit(_onSubmit);
|
const _onKeyDown = (e: any) => e.key === 'Enter' && handleSubmit(_onSubmit);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Drawer opened={opened} onClose={onClose} size={440}>
|
<Drawer opened={opened} onClose={onClose} size={440} classNames={{body: 'mt-[10vh]'}}>
|
||||||
<Mail
|
<Mail
|
||||||
size="48"
|
size="48"
|
||||||
className="mb-6 mx-auto text-activityBar-foreground-inactive"
|
className="mb-6 mx-auto text-activityBar-foreground-inactive"
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import platformContext from '../../../services/platform-context';
|
|||||||
*/
|
*/
|
||||||
const SignIn: FC<IModal> = ({ opened, onClose }) => {
|
const SignIn: FC<IModal> = ({ opened, onClose }) => {
|
||||||
return (
|
return (
|
||||||
<Drawer opened={opened} onClose={onClose} size={440}>
|
<Drawer opened={opened} onClose={onClose} size={440} classNames={{body: 'mt-[10vh]'}}>
|
||||||
{/* <img className="mx-auto w-12 mb-6" src={'img/firecamp-logo.svg'} /> */}
|
{/* <img className="mx-auto w-12 mb-6" src={'img/firecamp-logo.svg'} /> */}
|
||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
<FcLogo className="mx-auto w-14" size={80} />
|
<FcLogo className="mx-auto w-14" size={80} />
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ const SignInWithEmail: FC<IModal> = ({ opened, onClose }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Drawer opened={opened} onClose={onClose} size={440}>
|
<Drawer opened={opened} onClose={onClose} size={440} classNames={{body: 'mt-[10vh]'}}>
|
||||||
<div className="mb-2">
|
<div className="mb-2">
|
||||||
<FcLogo className="mx-auto w-14" size={80} />
|
<FcLogo className="mx-auto w-14" size={80} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ const SignUp: FC<IModal> = ({ opened, onClose }) => {
|
|||||||
const _onKeyDown = (e) => e.key === 'Enter' && handleSubmit(_onSignUp);
|
const _onKeyDown = (e) => e.key === 'Enter' && handleSubmit(_onSignUp);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Drawer opened={opened} onClose={onClose} size={440}>
|
<Drawer opened={opened} onClose={onClose} size={440} classNames={{body: 'mt-[10vh]'}}>
|
||||||
{/* <img className="mx-auto w-12 mb-6" src={'img/firecamp-logo.svg'} /> */}
|
{/* <img className="mx-auto w-12 mb-6" src={'img/firecamp-logo.svg'} /> */}
|
||||||
<div className="-mt-4">
|
<div className="-mt-4">
|
||||||
<FcLogo className="mx-auto w-14" size={80} />
|
<FcLogo className="mx-auto w-14" size={80} />
|
||||||
@@ -101,7 +101,10 @@ const SignUp: FC<IModal> = ({ opened, onClose }) => {
|
|||||||
required: true,
|
required: true,
|
||||||
maxLength: 50,
|
maxLength: 50,
|
||||||
minLength: 1,
|
minLength: 1,
|
||||||
pattern: /^[0-9a-zA-Z ]+$/,
|
pattern: {
|
||||||
|
value: /^[0-9a-zA-Z ]+$/,
|
||||||
|
message: "The username should not have any special characters"
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
useformRef={form}
|
useformRef={form}
|
||||||
onKeyDown={_onKeyDown}
|
onKeyDown={_onKeyDown}
|
||||||
@@ -110,7 +113,7 @@ const SignUp: FC<IModal> = ({ opened, onClose }) => {
|
|||||||
? errors?.username?.message || 'Please enter username'
|
? errors?.username?.message || 'Please enter username'
|
||||||
: ''
|
: ''
|
||||||
}
|
}
|
||||||
wrapperClassName="!mb-2"
|
wrapperClassName="!mb-4"
|
||||||
/>
|
/>
|
||||||
<Input
|
<Input
|
||||||
placeholder="Enter your email"
|
placeholder="Enter your email"
|
||||||
@@ -132,7 +135,7 @@ const SignUp: FC<IModal> = ({ opened, onClose }) => {
|
|||||||
'Please enter valid username or password'
|
'Please enter valid username or password'
|
||||||
: ''
|
: ''
|
||||||
}
|
}
|
||||||
wrapperClassName="!mb-2"
|
wrapperClassName="!mb-4"
|
||||||
/>
|
/>
|
||||||
<Input
|
<Input
|
||||||
placeholder="Enter password"
|
placeholder="Enter password"
|
||||||
@@ -163,7 +166,7 @@ const SignUp: FC<IModal> = ({ opened, onClose }) => {
|
|||||||
? errors?.password?.message || 'Please enter valid password'
|
? errors?.password?.message || 'Please enter valid password'
|
||||||
: ''
|
: ''
|
||||||
}
|
}
|
||||||
wrapperClassName="!mb-3"
|
wrapperClassName="!mb-4"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -118,9 +118,6 @@ const CloneEnvironment: FC<IModal> = ({ opened, onClose = () => {} }) => {
|
|||||||
opened={opened}
|
opened={opened}
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
size={500}
|
size={500}
|
||||||
classNames={{
|
|
||||||
content: 'h-[750px]'
|
|
||||||
}}
|
|
||||||
title={
|
title={
|
||||||
!isFetching ? (
|
!isFetching ? (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -0,0 +1,134 @@
|
|||||||
|
import { FC, useEffect, useState } from 'react';
|
||||||
|
import { _array } from '@firecamp/utils';
|
||||||
|
import { Container, Drawer, IModal, ProgressBar } from '@firecamp/ui';
|
||||||
|
import InvitationCard from './InvitationCard';
|
||||||
|
import platformContext from '../../../services/platform-context';
|
||||||
|
import { IInvite } from './InvitationCard.interface';
|
||||||
|
import { Rest } from '@firecamp/cloud-apis';
|
||||||
|
|
||||||
|
const AllInvitation: FC<IModal> = ({ opened, onClose }) => {
|
||||||
|
const [list, updateList] = useState<Array<IInvite> | []>([]);
|
||||||
|
const [inviteId, updateInviteId] = useState('');
|
||||||
|
const [isRequesting, setIsRequesting] = useState(false);
|
||||||
|
const [isFetching, setIsFetching] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setIsFetching(true);
|
||||||
|
|
||||||
|
Rest.invitation
|
||||||
|
.getMyPendingInvitations()
|
||||||
|
.then((res) => res.data)
|
||||||
|
.then((res) => {
|
||||||
|
const { error } = res;
|
||||||
|
if (!error) {
|
||||||
|
updateList(res);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => setIsFetching(false));
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const switchToWrs = async (wrs: any, org: any) => {
|
||||||
|
await platformContext.app.switchWorkspace(wrs, org);
|
||||||
|
platformContext.app.modals.close();
|
||||||
|
};
|
||||||
|
|
||||||
|
const _handleInvitation = async (invite: IInvite) => {
|
||||||
|
if (isRequesting) return;
|
||||||
|
|
||||||
|
setIsRequesting(true);
|
||||||
|
updateInviteId(invite.token);
|
||||||
|
|
||||||
|
Rest.invitation
|
||||||
|
.accept(invite.token)
|
||||||
|
.then((res) => res.data)
|
||||||
|
.then(({ flag, data, message }) => {
|
||||||
|
if (flag) {
|
||||||
|
const { org, workspace } = data;
|
||||||
|
platformContext.app.notify.success(
|
||||||
|
'You have successfully joined the invitation'
|
||||||
|
);
|
||||||
|
|
||||||
|
platformContext.window.confirm({
|
||||||
|
message:
|
||||||
|
'Congratulations on joining the invitation! Are you interested in switching workspaces and start collaboration?',
|
||||||
|
labels: { confirm: 'Yes, switch workspace.' },
|
||||||
|
onConfirm: () => switchToWrs(workspace, org),
|
||||||
|
onCancel: () => {
|
||||||
|
setIsRequesting(false);
|
||||||
|
updateInviteId('');
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
let Index = list.findIndex((i) => i.token === invite.token);
|
||||||
|
updateList((list) => [
|
||||||
|
...list.slice(0, Index),
|
||||||
|
...list.slice(Index + 1),
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
platformContext.app.notify.alert(message);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
platformContext.app.notify.alert(e.response?.data.message || e.message);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
setIsRequesting(false);
|
||||||
|
updateInviteId('');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Drawer
|
||||||
|
opened={opened}
|
||||||
|
onClose={onClose}
|
||||||
|
size={600}
|
||||||
|
title={
|
||||||
|
<div className="text-lg leading-5 px-3 flex items-center font-medium">
|
||||||
|
All Invitation
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Container className="py-4">
|
||||||
|
<ProgressBar active={isFetching} />
|
||||||
|
{!isFetching ? (
|
||||||
|
<Container.Body>
|
||||||
|
{!_array.isEmpty(list) ? (
|
||||||
|
list.map((invite, index) => (
|
||||||
|
<InvitationCard
|
||||||
|
key={index}
|
||||||
|
inviterName={invite.inviterName}
|
||||||
|
orgName={invite.orgName}
|
||||||
|
workspaceName={invite.workspaceName}
|
||||||
|
role={invite.role}
|
||||||
|
isRequesting={isRequesting}
|
||||||
|
disabled={inviteId.length > 0 && inviteId === invite.token}
|
||||||
|
onAccept={() => _handleInvitation(invite)}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<NoInvitationFound />
|
||||||
|
)}
|
||||||
|
</Container.Body>
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
)}
|
||||||
|
</Container>
|
||||||
|
</Drawer>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default AllInvitation;
|
||||||
|
|
||||||
|
const NoInvitationFound = () => {
|
||||||
|
return (
|
||||||
|
<div className="p-8 flex flex-col justify-center items-center">
|
||||||
|
<div className="text-sm max-w-xs mx-auto text-center px-10">
|
||||||
|
<label className="font-semibold text-app-foreground uppercase">
|
||||||
|
No Invitation Found
|
||||||
|
</label>
|
||||||
|
<span className="block font-normal text-app-foreground-inactive">
|
||||||
|
You do not have any new invitations at this time.
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
export interface IInvite {
|
||||||
|
inviterName: string;
|
||||||
|
orgName: string;
|
||||||
|
workspaceName: string;
|
||||||
|
role: number;
|
||||||
|
token?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type IInvitationCard = IInvite & {
|
||||||
|
disabled: boolean;
|
||||||
|
onAccept: () => void;
|
||||||
|
isRequesting: boolean;
|
||||||
|
};
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
import { FC } from 'react';
|
||||||
|
import { Button, TabHeader } from '@firecamp/ui';
|
||||||
|
import { EUserRolesWorkspace } from '../../../types';
|
||||||
|
import { IInvitationCard } from './InvitationCard.interface';
|
||||||
|
|
||||||
|
const RoleOptions = [
|
||||||
|
{
|
||||||
|
id: EUserRolesWorkspace.Owner,
|
||||||
|
name: 'Owner',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: EUserRolesWorkspace.Admin,
|
||||||
|
name: 'Admin',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: EUserRolesWorkspace.Collaborator,
|
||||||
|
name: 'Collaborator',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: EUserRolesWorkspace.Viewer,
|
||||||
|
name: 'Viewer',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const InvitationCard: FC<IInvitationCard> = ({
|
||||||
|
inviterName,
|
||||||
|
workspaceName,
|
||||||
|
orgName,
|
||||||
|
role,
|
||||||
|
disabled = false,
|
||||||
|
isRequesting = false,
|
||||||
|
onAccept,
|
||||||
|
}) => {
|
||||||
|
const userRole = RoleOptions.find((r) => r.id == role);
|
||||||
|
// console.log(`user.role`, userRole, role);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="bg-app-background p-4 shadow-sm rounded border mb-4">
|
||||||
|
{/* <label className="text-sm font-semibold leading-3 block text-app-foreground-inactive uppercase w-full relative py-4">
|
||||||
|
NEW INVITATION
|
||||||
|
</label> */}
|
||||||
|
<div className="my-4">
|
||||||
|
<span className="font-semibold">{inviterName}</span>
|
||||||
|
<span> has invited you to collaborate on the </span>
|
||||||
|
<span className="font-semibold">{orgName}</span>
|
||||||
|
<span>/</span>
|
||||||
|
<span className="font-semibold">{workspaceName}</span>
|
||||||
|
<span> as </span>
|
||||||
|
<span className="font-semibold">{userRole?.name}</span>
|
||||||
|
</div>
|
||||||
|
<TabHeader className="!px-0">
|
||||||
|
<TabHeader.Right>
|
||||||
|
<Button
|
||||||
|
text={isRequesting ? 'Accepting...': 'Accept Invitation'}
|
||||||
|
disabled={disabled}
|
||||||
|
onClick={() => onAccept()}
|
||||||
|
primary
|
||||||
|
xs
|
||||||
|
/>
|
||||||
|
</TabHeader.Right>
|
||||||
|
</TabHeader>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default InvitationCard;
|
||||||
@@ -1,36 +1,175 @@
|
|||||||
import { FC, useState } from 'react';
|
import { FC, useEffect, useState } from 'react';
|
||||||
import {
|
import { Rest } from '@firecamp/cloud-apis';
|
||||||
Input,
|
|
||||||
TextArea,
|
|
||||||
TabHeader,
|
|
||||||
Button,
|
|
||||||
Modal,
|
|
||||||
IModal,
|
|
||||||
SecondaryTab,
|
|
||||||
} from '@firecamp/ui';
|
|
||||||
import { _misc } from '@firecamp/utils';
|
import { _misc } from '@firecamp/utils';
|
||||||
import { VscEdit } from '@react-icons/all-files/vsc/VscEdit';
|
import { IModal, SecondaryTab, Drawer, ProgressBar } from '@firecamp/ui';
|
||||||
|
import EditOrganization from './tabs/EditOrganization';
|
||||||
|
import Members from './tabs/Members';
|
||||||
|
import BillingTab from './tabs/Billing';
|
||||||
|
import Workspaces from './tabs/Workspaces';
|
||||||
|
import { usePlatformStore } from '../../../store/platform';
|
||||||
|
import platformContext from '../../../services/platform-context';
|
||||||
|
import { Regex } from '../../../constants';
|
||||||
|
|
||||||
const OrgManagement: FC<IModal> = ({ opened = false, onClose = () => {} }) => {
|
enum ETabTypes {
|
||||||
// let { create, checkNameAvailability } = useWorkspaceStore((s: IWorkspaceStore)=>({
|
Overview = 'overview',
|
||||||
// create: s.create,
|
Workspaces = 'workspaces',
|
||||||
// checkNameAvailability: s.checkNameAvailability
|
Members = 'members',
|
||||||
// }))
|
Billing = 'billing',
|
||||||
|
}
|
||||||
|
const tabs = [
|
||||||
|
{ name: 'Overview', id: ETabTypes.Overview },
|
||||||
|
{ name: 'Workspaces', id: ETabTypes.Workspaces },
|
||||||
|
{ name: 'Members', id: ETabTypes.Members },
|
||||||
|
{ name: 'Billing', id: ETabTypes.Billing },
|
||||||
|
];
|
||||||
|
|
||||||
const tabs = [
|
// to convert date into readable date
|
||||||
{ name: 'Edit', id: 'edit' },
|
export const getFormalDate = (convertDate: string) => {
|
||||||
{ name: 'Members', id: 'members' },
|
let date = new Date(convertDate);
|
||||||
{ name: 'Billing', id: 'billing' },
|
if (date.toString() === 'Invalid Date') return 'N/A';
|
||||||
];
|
|
||||||
let [activeTab, setActiveTab] = useState<string>(tabs[0].id);
|
let dateString = date.toLocaleDateString('en-US', {
|
||||||
|
month: 'long',
|
||||||
|
day: 'numeric',
|
||||||
|
year: 'numeric',
|
||||||
|
});
|
||||||
|
return dateString;
|
||||||
|
};
|
||||||
|
|
||||||
|
const OrgManagement: FC<IModal> = ({ opened = false, onClose = () => { } }) => {
|
||||||
|
const { organization, setOrg } = usePlatformStore((s) => ({
|
||||||
|
organization: s.organization,
|
||||||
|
setOrg: s.setOrg,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const [activeTab, setActiveTab] = useState<string>(tabs[0].id);
|
||||||
|
const [isFetching, setIsFetching] = useState(false);
|
||||||
|
const [workspaces, updateWorkspaces] = useState([]);
|
||||||
|
const [members, updateMembers] = useState([]);
|
||||||
|
|
||||||
|
const [org, updOrg] = useState(organization);
|
||||||
|
const [error, setError] = useState({ name: '' });
|
||||||
|
const [isRequesting, setIsRequesting] = useState(false);
|
||||||
|
|
||||||
|
// getting organization's workspaces / members listing once
|
||||||
|
useEffect(() => {
|
||||||
|
if (activeTab === ETabTypes.Workspaces && workspaces.length === 0) {
|
||||||
|
setIsFetching(true);
|
||||||
|
|
||||||
|
Rest.organization
|
||||||
|
.getMyWorkspacesOfOrg(organization.__ref.id)
|
||||||
|
.then((res) => res.data)
|
||||||
|
.then((list) => {
|
||||||
|
updateWorkspaces(list);
|
||||||
|
})
|
||||||
|
.finally(() => setIsFetching(false));
|
||||||
|
} else if (activeTab === ETabTypes.Members && members.length === 0) {
|
||||||
|
setIsFetching(true);
|
||||||
|
|
||||||
|
Rest.organization
|
||||||
|
.getMembers(organization.__ref.id)
|
||||||
|
.then((res) => res.data)
|
||||||
|
.then((list) => {
|
||||||
|
updateMembers(list);
|
||||||
|
})
|
||||||
|
.finally(() => setIsFetching(false));
|
||||||
|
}
|
||||||
|
}, [activeTab]);
|
||||||
|
|
||||||
|
const onChange = (e, reset) => {
|
||||||
|
if (reset) {
|
||||||
|
updOrg(organization);
|
||||||
|
if (error.name) setError({ name: '' });
|
||||||
|
} else {
|
||||||
|
const { name, value } = e.target;
|
||||||
|
if (error.name) setError({ name: '' });
|
||||||
|
updOrg((o) => ({ ...o, [name]: value }));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onUpdate = () => {
|
||||||
|
if (isRequesting) return;
|
||||||
|
const name = org.name.trim();
|
||||||
|
const description = org.description?.trim();
|
||||||
|
if (!name || name.length < 4) {
|
||||||
|
setError({
|
||||||
|
name: 'The organization name must have minimum 4 characters',
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const isValid = Regex.OrgName.test(name);
|
||||||
|
if (!isValid) {
|
||||||
|
setError({
|
||||||
|
name: 'The org name must not contain any spaces or special characters.',
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
organization.name === org.name &&
|
||||||
|
organization.description === org.description
|
||||||
|
)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const _org: { name?: string; description?: string } = {};
|
||||||
|
if (organization.name !== name) {
|
||||||
|
_org.name = name;
|
||||||
|
}
|
||||||
|
if (organization.description !== description) {
|
||||||
|
_org.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
setIsRequesting(true);
|
||||||
|
Rest.organization
|
||||||
|
.update(organization.__ref.id, _org)
|
||||||
|
.then((res) => res.data)
|
||||||
|
.then(({ error, message }) => {
|
||||||
|
if (!error) {
|
||||||
|
platformContext.app.notify.success(
|
||||||
|
"The organization's detail has been updated successfully."
|
||||||
|
);
|
||||||
|
setOrg({ ...organization, ..._org });
|
||||||
|
} else {
|
||||||
|
platformContext.app.notify.alert(message);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
platformContext.app.notify.alert(e.response?.data.message || e.message);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
setIsRequesting(false);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const renderTab = (tabId: string) => {
|
const renderTab = (tabId: string) => {
|
||||||
switch (tabId) {
|
switch (tabId) {
|
||||||
case 'edit':
|
case ETabTypes.Overview:
|
||||||
return <EditInfoTab />;
|
return (
|
||||||
case 'members':
|
<EditOrganization
|
||||||
return <MembersTab />;
|
organization={org}
|
||||||
case 'billing':
|
error={error}
|
||||||
|
isRequesting={isRequesting}
|
||||||
|
onSubmit={onUpdate}
|
||||||
|
onChange={onChange}
|
||||||
|
enableReset={
|
||||||
|
organization.name !== org.name ||
|
||||||
|
organization.description !== org.description
|
||||||
|
}
|
||||||
|
// disabled={true} // TODO: only allow owner
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
case ETabTypes.Workspaces:
|
||||||
|
return <Workspaces workspaces={workspaces} isFetching={isFetching} />;
|
||||||
|
case ETabTypes.Members:
|
||||||
|
return (
|
||||||
|
<Members
|
||||||
|
members={members}
|
||||||
|
updateMembers={updateMembers}
|
||||||
|
isFetching={isFetching}
|
||||||
|
organizationId={organization.__ref.id}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
case ETabTypes.Billing:
|
||||||
return <BillingTab />;
|
return <BillingTab />;
|
||||||
default:
|
default:
|
||||||
return <></>;
|
return <></>;
|
||||||
@@ -38,128 +177,25 @@ const OrgManagement: FC<IModal> = ({ opened = false, onClose = () => {} }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Drawer
|
||||||
opened={opened}
|
opened={opened}
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
size={600}
|
size={600}
|
||||||
classNames={{
|
|
||||||
body: 'h-[80vh]',
|
|
||||||
}}
|
|
||||||
title={
|
title={
|
||||||
<div className="text-lg leading-5 px-6 flex items-center font-medium">
|
<div className="text-lg leading-5 px-3 flex items-center font-medium">
|
||||||
Organization Management
|
Organization Management
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<>
|
<ProgressBar active={isFetching} />
|
||||||
<SecondaryTab
|
<SecondaryTab
|
||||||
className="flex items-center p-4 pb-0"
|
className="pt-4"
|
||||||
list={tabs}
|
list={tabs}
|
||||||
activeTab={'edit'}
|
activeTab={activeTab}
|
||||||
onSelect={setActiveTab}
|
onSelect={setActiveTab}
|
||||||
/>
|
/>
|
||||||
{renderTab(activeTab)}
|
{renderTab(activeTab)}
|
||||||
</>
|
</Drawer>
|
||||||
<div className="!py-3 border-t border-app-border ">
|
|
||||||
<TabHeader>
|
|
||||||
<TabHeader.Right>
|
|
||||||
<Button text="Cancel" onClick={(e) => onClose(e)} ghost xs />
|
|
||||||
<Button
|
|
||||||
text={false ? 'Creating...' : 'Create'}
|
|
||||||
onClick={() => {}}
|
|
||||||
disabled={false}
|
|
||||||
primary
|
|
||||||
xs
|
|
||||||
/>
|
|
||||||
</TabHeader.Right>
|
|
||||||
</TabHeader>
|
|
||||||
</div>
|
|
||||||
</Modal>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
export default OrgManagement;
|
export default OrgManagement;
|
||||||
|
|
||||||
const EditInfoTab: FC<any> = () => {
|
|
||||||
let [org, setOrg] = useState({
|
|
||||||
name: '',
|
|
||||||
description: '',
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="px-6 py-3">
|
|
||||||
<label className="text-sm font-semibold leading-3 block text-app-foreground-inactive uppercase w-full relative mb-2">
|
|
||||||
ADD NEW WORKSPACE INFO
|
|
||||||
</label>
|
|
||||||
<div className="mt-4">
|
|
||||||
<Input
|
|
||||||
autoFocus={true}
|
|
||||||
label="Name"
|
|
||||||
placeholder="Organization name"
|
|
||||||
name={'name'}
|
|
||||||
value={org.name || ''}
|
|
||||||
onChange={() => {}}
|
|
||||||
onKeyDown={() => {}}
|
|
||||||
onBlur={() => {}}
|
|
||||||
disabled={true}
|
|
||||||
iconPosition="right"
|
|
||||||
icon={<VscEdit />}
|
|
||||||
// error={error.name}
|
|
||||||
/>
|
|
||||||
{/* {
|
|
||||||
flag_wrsNameCheckInProgress === false && flag_isWrsNameAvailable === undefined
|
|
||||||
? <Alert withBorder text="please type the workspace name to check its availability" info/>: <></>
|
|
||||||
}
|
|
||||||
{
|
|
||||||
flag_wrsNameCheckInProgress === true? <Alert withBorder text={`checking workspace name availability - ${workspace?.name}`} warning/>: <></>
|
|
||||||
}
|
|
||||||
{
|
|
||||||
flag_wrsNameCheckInProgress === false && flag_isWrsNameAvailable === true
|
|
||||||
? <Alert withBorder text={`the workspace name is available - ${workspace?.name}`} success/>: <></>
|
|
||||||
}
|
|
||||||
{
|
|
||||||
flag_wrsNameCheckInProgress === false && flag_isWrsNameAvailable === false
|
|
||||||
? <Alert withBorder text={`the workspace name is not available - ${workspace?.name}`} error/>: <></>
|
|
||||||
}
|
|
||||||
{
|
|
||||||
error.name?.length
|
|
||||||
? <Alert withBorder text={error.name} error/>: <></>
|
|
||||||
} */}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<TextArea
|
|
||||||
type="text"
|
|
||||||
minHeight="200px"
|
|
||||||
label="Description (optional)"
|
|
||||||
labelClassName="fc-input-label"
|
|
||||||
placeholder="Description"
|
|
||||||
note="Markdown supported in description"
|
|
||||||
name={'description'}
|
|
||||||
value={org.description || ''}
|
|
||||||
onChange={() => {}}
|
|
||||||
disabled={true}
|
|
||||||
iconPosition="right"
|
|
||||||
icon={<VscEdit />}
|
|
||||||
/>
|
|
||||||
{/* {error.global?.length ? (
|
|
||||||
<TabHeader.Left>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
fontSize: '12px',
|
|
||||||
color: 'red' //'green'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{error.global}
|
|
||||||
</div>
|
|
||||||
</TabHeader.Left>
|
|
||||||
) : <></>} */}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const MembersTab = () => {
|
|
||||||
return <div className="p-6"> Members Tab</div>;
|
|
||||||
};
|
|
||||||
|
|
||||||
const BillingTab = () => {
|
|
||||||
return <div className="p-6"> Billing Tab</div>;
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
|
||||||
|
const BillingTab = () => {
|
||||||
|
return <div className="p-4 text-activityBar-foreground-inactive">
|
||||||
|
<span className="my-4">
|
||||||
|
Coming soon...
|
||||||
|
</span>
|
||||||
|
</div>;
|
||||||
|
};
|
||||||
|
export default BillingTab;
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
import { FC } from 'react';
|
||||||
|
import { Button, Container, Input, TabHeader, TextArea } from '@firecamp/ui';
|
||||||
|
|
||||||
|
const EditOrganization: FC<any> = ({
|
||||||
|
organization,
|
||||||
|
error,
|
||||||
|
isRequesting,
|
||||||
|
onSubmit,
|
||||||
|
onChange,
|
||||||
|
enableReset = true,
|
||||||
|
disabled = false
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<Container className="py-6 px-3 flex-1 flex flex-col h-full">
|
||||||
|
<Container.Body>
|
||||||
|
<label className="text-sm font-semibold leading-3 block text-app-foreground-inactive uppercase w-full relative mb-4">
|
||||||
|
UPDATE ORGANIZATION INFO
|
||||||
|
</label>
|
||||||
|
<div>
|
||||||
|
<Input
|
||||||
|
autoFocus={true}
|
||||||
|
label="Name"
|
||||||
|
placeholder="Organization name"
|
||||||
|
name={'name'}
|
||||||
|
defaultValue={organization.name || ''}
|
||||||
|
onChange={onChange}
|
||||||
|
onKeyDown={() => {}}
|
||||||
|
onBlur={() => {}}
|
||||||
|
error={error.name}
|
||||||
|
wrapperClassName="!mb-3"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<TextArea
|
||||||
|
type="text"
|
||||||
|
minHeight="240px"
|
||||||
|
label="Description (optional)"
|
||||||
|
labelClassName="fc-input-label"
|
||||||
|
placeholder="Description"
|
||||||
|
note="Markdown supported in description"
|
||||||
|
name={'description'}
|
||||||
|
defaultValue={organization.description || ''}
|
||||||
|
onChange={onChange}
|
||||||
|
/>
|
||||||
|
</Container.Body>
|
||||||
|
<Container.Footer>
|
||||||
|
<TabHeader className="!px-0">
|
||||||
|
<TabHeader.Left></TabHeader.Left>
|
||||||
|
<TabHeader.Right>
|
||||||
|
|
||||||
|
{/* {enableReset ? <Button text="Undo" onClick={(e) => onChange(e, true)} ghost xs /> : <></>} */}
|
||||||
|
<Button
|
||||||
|
text={isRequesting ? 'Updating...' : 'Update'}
|
||||||
|
onClick={onSubmit}
|
||||||
|
disabled={isRequesting || disabled || !enableReset}
|
||||||
|
primary
|
||||||
|
xs
|
||||||
|
/>
|
||||||
|
</TabHeader.Right>
|
||||||
|
</TabHeader>
|
||||||
|
</Container.Footer>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default EditOrganization;
|
||||||
@@ -0,0 +1,196 @@
|
|||||||
|
import { FC, useEffect, useRef, useState } from 'react';
|
||||||
|
import { ChevronDown } from 'lucide-react';
|
||||||
|
import cx from 'classnames';
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Container,
|
||||||
|
DropdownMenu,
|
||||||
|
PrimitiveTable,
|
||||||
|
TTableApi,
|
||||||
|
} from '@firecamp/ui';
|
||||||
|
import { _array } from '@firecamp/utils';
|
||||||
|
import { Rest } from '@firecamp/cloud-apis';
|
||||||
|
import platformContext from '../../../../services/platform-context';
|
||||||
|
import { EUserRolesWorkspace } from '../../../../types';
|
||||||
|
import { getFormalDate } from '../OrgManagement';
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{ id: 'index', name: 'No.', key: 'index', width: '35px', fixedWidth: true },
|
||||||
|
{
|
||||||
|
id: 'name',
|
||||||
|
name: 'Name',
|
||||||
|
key: 'name',
|
||||||
|
width: '100px',
|
||||||
|
resizeWithContainer: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'role',
|
||||||
|
name: 'Role',
|
||||||
|
key: 'role',
|
||||||
|
width: '100px',
|
||||||
|
fixedWidth: true,
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// id: 'joinedAt',
|
||||||
|
// name: 'Joined Date',
|
||||||
|
// key: 'joinedAt',
|
||||||
|
// width: '130px',
|
||||||
|
// fixedWidth: true,
|
||||||
|
// },
|
||||||
|
];
|
||||||
|
|
||||||
|
const RoleOptions = [
|
||||||
|
{
|
||||||
|
id: EUserRolesWorkspace.Owner,
|
||||||
|
name: 'Owner',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: EUserRolesWorkspace.Admin,
|
||||||
|
name: 'Admin',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: EUserRolesWorkspace.Collaborator,
|
||||||
|
name: 'Collaborator',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const Members = ({
|
||||||
|
organizationId = '',
|
||||||
|
members = [],
|
||||||
|
updateMembers,
|
||||||
|
isFetching = false,
|
||||||
|
}) => {
|
||||||
|
const tableApi = useRef<TTableApi>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!_array.isEmpty(members)) {
|
||||||
|
const memberList = members.map((m, i) => {
|
||||||
|
return {
|
||||||
|
id: m.id,
|
||||||
|
name: m.username,
|
||||||
|
role: m.role,
|
||||||
|
joinedAt: getFormalDate(m.__ref.joinedAt),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
tableApi.current.initialize(memberList);
|
||||||
|
}
|
||||||
|
}, [members]);
|
||||||
|
|
||||||
|
const onChangeRole = (row) => {
|
||||||
|
platformContext.window.confirm({
|
||||||
|
message: `Please confirm, You're assigning ${row.role.name} role to ${row.name}, right?`,
|
||||||
|
labels: {
|
||||||
|
cancel: 'Cancel',
|
||||||
|
confirm: 'Yes, change the role.',
|
||||||
|
},
|
||||||
|
onConfirm: () => {
|
||||||
|
Rest.organization
|
||||||
|
.changeMemberRole(organizationId, row.id, row.role.id)
|
||||||
|
.then((res) => res.data)
|
||||||
|
.then(({ error, message }) => {
|
||||||
|
if (!error) {
|
||||||
|
tableApi.current.setRow({ ...row, role: row.role.id });
|
||||||
|
|
||||||
|
// update the member listing after update
|
||||||
|
let Index = members.findIndex((m) => m.id == row.id);
|
||||||
|
updateMembers([
|
||||||
|
...members.slice(0, Index),
|
||||||
|
{ ...members[Index], role: row.role.id },
|
||||||
|
...members.slice(Index + 1),
|
||||||
|
]);
|
||||||
|
|
||||||
|
platformContext.app.notify.success(
|
||||||
|
"The member's role has been changed successfully."
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
platformContext.app.notify.alert(message);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
platformContext.app.notify.alert(
|
||||||
|
e.response?.data.message || e.message
|
||||||
|
);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderCell = (column, cellValue, rowIndex, row, tableApi, onChange) => {
|
||||||
|
switch (column.id) {
|
||||||
|
case 'index':
|
||||||
|
return <div className="px-2 text-base"> {rowIndex + 1} </div>;
|
||||||
|
break;
|
||||||
|
case 'name':
|
||||||
|
case 'joinedAt':
|
||||||
|
return <div className="p-1 text-base">{cellValue}</div>;
|
||||||
|
break;
|
||||||
|
case 'role':
|
||||||
|
return (
|
||||||
|
<div className="p-1 text-center">
|
||||||
|
<RoleDD
|
||||||
|
role={row.role}
|
||||||
|
onSelect={(role) => onChangeRole({ ...row, role })}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return <></>;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container className="gap-2 pt-2 !h-[80vh]">
|
||||||
|
<Container.Body>
|
||||||
|
<PrimitiveTable
|
||||||
|
classes={{
|
||||||
|
container: 'h-full',
|
||||||
|
}}
|
||||||
|
columns={columns}
|
||||||
|
rows={[]}
|
||||||
|
showDefaultEmptyRows={false}
|
||||||
|
renderColumn={(c) => c.name}
|
||||||
|
renderCell={renderCell}
|
||||||
|
onChange={console.log}
|
||||||
|
onMount={(api) => (tableApi.current = api)}
|
||||||
|
/>
|
||||||
|
</Container.Body>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default Members;
|
||||||
|
|
||||||
|
const RoleDD: FC<{
|
||||||
|
role: number;
|
||||||
|
onSelect: (role: { name: string; id: number }) => void;
|
||||||
|
}> = ({ role, onSelect }) => {
|
||||||
|
const [isOpen, toggleOpen] = useState(false);
|
||||||
|
|
||||||
|
const _role = RoleOptions.find((r) => r.id == role);
|
||||||
|
if (!_role) return <></>;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DropdownMenu
|
||||||
|
onOpenChange={(v) => toggleOpen(v)}
|
||||||
|
handler={() => (
|
||||||
|
<Button
|
||||||
|
text={_role.name}
|
||||||
|
rightIcon={
|
||||||
|
<ChevronDown
|
||||||
|
size={12}
|
||||||
|
className={cx({ 'transform rotate-180': isOpen })}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
compact
|
||||||
|
ghost
|
||||||
|
sm
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
options={RoleOptions}
|
||||||
|
onSelect={onSelect}
|
||||||
|
disabled={role === EUserRolesWorkspace.Owner}
|
||||||
|
width={115}
|
||||||
|
sm
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
import { FC, useEffect, useRef } from 'react';
|
||||||
|
import {
|
||||||
|
Container,
|
||||||
|
PrimitiveTable,
|
||||||
|
TTableApi,
|
||||||
|
} from '@firecamp/ui';
|
||||||
|
import { _array } from '@firecamp/utils';
|
||||||
|
import { getFormalDate } from '../OrgManagement';
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{ id: 'index', name: 'No.', key: 'index', width: '35px', fixedWidth: true },
|
||||||
|
{
|
||||||
|
id: 'name',
|
||||||
|
name: 'Name',
|
||||||
|
key: 'name',
|
||||||
|
width: '100px',
|
||||||
|
resizeWithContainer: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'created',
|
||||||
|
name: 'Created Date',
|
||||||
|
key: 'created',
|
||||||
|
width: '130px',
|
||||||
|
fixedWidth: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'members',
|
||||||
|
name: 'Members',
|
||||||
|
key: 'members',
|
||||||
|
width: '100px',
|
||||||
|
fixedWidth: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const Workspaces: FC<{workspaces: Array<any>, isFetching: boolean}> = ({ workspaces = [], isFetching = false }) => {
|
||||||
|
const tableApi = useRef<TTableApi>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!_array.isEmpty(workspaces)) {
|
||||||
|
const workspaceList = workspaces.map((m, i) => {
|
||||||
|
return {
|
||||||
|
id: m.__ref?.id,
|
||||||
|
name: m.name,
|
||||||
|
created: getFormalDate(m.__ref.createdAt),
|
||||||
|
members: m.members.length,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
tableApi.current.initialize(workspaceList);
|
||||||
|
}
|
||||||
|
}, [workspaces]);
|
||||||
|
|
||||||
|
const renderCell = (column, cellValue, rowIndex, row, tableApi, onChange) => {
|
||||||
|
switch (column.id) {
|
||||||
|
case 'index':
|
||||||
|
return <div className="px-2"> {rowIndex + 1} </div>;
|
||||||
|
break;
|
||||||
|
case 'name':
|
||||||
|
case 'members':
|
||||||
|
case 'created':
|
||||||
|
return <div className="p-1 text-base">{cellValue}</div>;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return <></>;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container className="gap-2 pt-2 !h-[80vh]">
|
||||||
|
<Container.Body>
|
||||||
|
<PrimitiveTable
|
||||||
|
classes={{
|
||||||
|
container: 'h-full',
|
||||||
|
}}
|
||||||
|
columns={columns}
|
||||||
|
rows={[]}
|
||||||
|
showDefaultEmptyRows={false}
|
||||||
|
renderColumn={(c) => c.name}
|
||||||
|
renderCell={renderCell}
|
||||||
|
onChange={console.log}
|
||||||
|
onMount={(api) => (tableApi.current = api)}
|
||||||
|
/>
|
||||||
|
</Container.Body>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default Workspaces;
|
||||||
@@ -0,0 +1,178 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
|
import { useForm } from 'react-hook-form';
|
||||||
|
import { Button, Input } from '@firecamp/ui';
|
||||||
|
import { VscEye } from '@react-icons/all-files/vsc/VscEye';
|
||||||
|
import { Rest } from '@firecamp/cloud-apis';
|
||||||
|
import platformContext from '../../../services/platform-context';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change Password component
|
||||||
|
*/
|
||||||
|
const ChangePassword = () => {
|
||||||
|
const [isRequesting, setFlagIsRequesting] = useState(false);
|
||||||
|
const [oldPassword, toggleOldPassword] = useState(false);
|
||||||
|
const [showPassword, toggleShowPassword] = useState(false);
|
||||||
|
const [confirmPassword, toggleConfirmPassword] = useState(false);
|
||||||
|
|
||||||
|
const form = useForm();
|
||||||
|
const { handleSubmit, errors, getValues, reset } = form;
|
||||||
|
|
||||||
|
const _onSubmit = async (payload: {
|
||||||
|
currentPassword: string;
|
||||||
|
newPassword: string;
|
||||||
|
}) => {
|
||||||
|
if (isRequesting) return;
|
||||||
|
|
||||||
|
setFlagIsRequesting(true);
|
||||||
|
|
||||||
|
await Rest.user
|
||||||
|
.changePassword({
|
||||||
|
currentPassword: payload.currentPassword,
|
||||||
|
newPassword: payload.newPassword,
|
||||||
|
})
|
||||||
|
.then((res) => res.data)
|
||||||
|
.then(({ error, message }) => {
|
||||||
|
if (!error) {
|
||||||
|
reset({ currentPassword: '', newPassword: '', confirmPassword: '' });
|
||||||
|
platformContext.app.notify.success(message);
|
||||||
|
} else {
|
||||||
|
platformContext.app.notify.alert(
|
||||||
|
message ?? `Failed to change password!`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
platformContext.app.notify.alert(
|
||||||
|
e?.response?.data?.message || e.message,
|
||||||
|
{
|
||||||
|
labels: { alert: 'error!' },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
setFlagIsRequesting(false);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const _onKeyDown = (e: any) => e.key === 'Enter' && handleSubmit(_onSubmit);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<form onSubmit={handleSubmit(_onSubmit)} className="mx-2 mt-4">
|
||||||
|
<Input
|
||||||
|
placeholder="Enter old password"
|
||||||
|
key={'currentPassword'}
|
||||||
|
name={'currentPassword'}
|
||||||
|
type={oldPassword ? 'text' : 'password'}
|
||||||
|
label="Old Password"
|
||||||
|
iconPosition="right"
|
||||||
|
icon={
|
||||||
|
<VscEye
|
||||||
|
title="password"
|
||||||
|
size={16}
|
||||||
|
onClick={() => {
|
||||||
|
toggleOldPassword(!oldPassword);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
registerMeta={{
|
||||||
|
required: 'Please enter your current password',
|
||||||
|
minLength: {
|
||||||
|
value: 8,
|
||||||
|
message: 'Password should be at least 8 character',
|
||||||
|
},
|
||||||
|
maxLength: {
|
||||||
|
value: 50,
|
||||||
|
message: 'Password should not exceed 50 character',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
useformRef={form}
|
||||||
|
onKeyDown={_onKeyDown}
|
||||||
|
error={
|
||||||
|
errors?.currentPassword
|
||||||
|
? errors?.currentPassword?.message || 'Invalid password'
|
||||||
|
: ''
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Input
|
||||||
|
placeholder="Enter new password"
|
||||||
|
key={'newPassword'}
|
||||||
|
name={'newPassword'}
|
||||||
|
type={showPassword ? 'text' : 'password'}
|
||||||
|
label="New Password"
|
||||||
|
iconPosition="right"
|
||||||
|
icon={
|
||||||
|
<VscEye
|
||||||
|
title="password"
|
||||||
|
size={16}
|
||||||
|
onClick={() => {
|
||||||
|
toggleShowPassword(!showPassword);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
registerMeta={{
|
||||||
|
required: 'Please enter your new password',
|
||||||
|
minLength: {
|
||||||
|
value: 8,
|
||||||
|
message: 'Password should be at least 8 character',
|
||||||
|
},
|
||||||
|
maxLength: {
|
||||||
|
value: 50,
|
||||||
|
message: 'Password should not exceed 50 character',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
useformRef={form}
|
||||||
|
onKeyDown={_onKeyDown}
|
||||||
|
error={
|
||||||
|
errors?.newPassword
|
||||||
|
? errors?.newPassword?.message || 'Invalid password'
|
||||||
|
: ''
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Input
|
||||||
|
placeholder="Enter password again"
|
||||||
|
key={'confirmPassword'}
|
||||||
|
name={'confirmPassword'}
|
||||||
|
type={confirmPassword ? 'text' : 'password'}
|
||||||
|
label="Confirm Password"
|
||||||
|
iconPosition="right"
|
||||||
|
icon={
|
||||||
|
<VscEye
|
||||||
|
title="password"
|
||||||
|
size={16}
|
||||||
|
onClick={() => {
|
||||||
|
toggleConfirmPassword(!confirmPassword);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
registerMeta={{
|
||||||
|
required: 'Please enter password again',
|
||||||
|
validate: (value) => {
|
||||||
|
const { newPassword } = getValues();
|
||||||
|
return newPassword === value || 'Passwords should match';
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
useformRef={form}
|
||||||
|
onKeyDown={_onKeyDown}
|
||||||
|
error={
|
||||||
|
errors?.confirmPassword
|
||||||
|
? errors?.confirmPassword?.message || 'Invalid password'
|
||||||
|
: ''
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
type="submit"
|
||||||
|
text={isRequesting ? 'Updating Password...' : 'Update Password'}
|
||||||
|
onClick={handleSubmit(_onSubmit)}
|
||||||
|
fullWidth
|
||||||
|
primary
|
||||||
|
sm
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ChangePassword;
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import { FC, useState } from 'react';
|
||||||
|
import { Drawer, IModal, SecondaryTab } from '@firecamp/ui';
|
||||||
|
import ChangePassword from './ChangePassword';
|
||||||
|
import UpdateProfile from './UpdateProfile';
|
||||||
|
const tabs = [
|
||||||
|
{ name: 'Profile', id: 'profile' },
|
||||||
|
{ name: 'Change Password', id: 'password' },
|
||||||
|
];
|
||||||
|
const ProfileManagement: FC<IModal> = ({ opened, onClose }) => {
|
||||||
|
let [activeTab, setActiveTab] = useState<string>(tabs[0].id);
|
||||||
|
|
||||||
|
const renderTab = (tabId: string) => {
|
||||||
|
switch (tabId) {
|
||||||
|
case 'profile':
|
||||||
|
return <UpdateProfile />;
|
||||||
|
case 'password':
|
||||||
|
return <ChangePassword />;
|
||||||
|
default:
|
||||||
|
return <></>;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<Drawer
|
||||||
|
opened={opened}
|
||||||
|
onClose={onClose}
|
||||||
|
size={600}
|
||||||
|
// classNames={{
|
||||||
|
// body: 'h-[80vh]',
|
||||||
|
// }}
|
||||||
|
title={
|
||||||
|
<div className="text-lg leading-5 px-6 flex items-center font-medium">
|
||||||
|
Profile Management
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<SecondaryTab
|
||||||
|
className="py-4"
|
||||||
|
list={tabs}
|
||||||
|
activeTab={activeTab}
|
||||||
|
onSelect={setActiveTab}
|
||||||
|
/>
|
||||||
|
{renderTab(activeTab)}
|
||||||
|
</Drawer>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default ProfileManagement;
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
import { FC, useEffect, useState } from 'react';
|
||||||
|
import { useForm } from 'react-hook-form';
|
||||||
|
import { Button, Input } from '@firecamp/ui';
|
||||||
|
import { Rest } from '@firecamp/cloud-apis';
|
||||||
|
import platformContext from '../../../services/platform-context';
|
||||||
|
import { useUserStore } from '../../../store/user';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update Profile component
|
||||||
|
*/
|
||||||
|
const UpdateProfile = () => {
|
||||||
|
const [isRequesting, setFlagIsRequesting] = useState(false);
|
||||||
|
|
||||||
|
const form = useForm();
|
||||||
|
let { handleSubmit, errors, setValue } = form;
|
||||||
|
|
||||||
|
const { user, setUser } = useUserStore((s) => ({
|
||||||
|
user: s.user,
|
||||||
|
setUser: s.setUser
|
||||||
|
}));
|
||||||
|
|
||||||
|
// set the initial value for the form
|
||||||
|
useEffect(() => {
|
||||||
|
setValue("name", user.name);
|
||||||
|
},[user]);
|
||||||
|
|
||||||
|
const _onSubmit = async (payload: { name: string }) => {
|
||||||
|
let { name } = payload;
|
||||||
|
if (isRequesting || user.name === name) return;
|
||||||
|
|
||||||
|
|
||||||
|
setFlagIsRequesting(true);
|
||||||
|
|
||||||
|
await Rest.user
|
||||||
|
.updateProfile({ name })
|
||||||
|
.then((res) => res.data)
|
||||||
|
.then(({ error, message }) => {
|
||||||
|
if (!error) {
|
||||||
|
platformContext.app.notify.success(
|
||||||
|
`Your profile details are updated`
|
||||||
|
);
|
||||||
|
// update the user store
|
||||||
|
setUser({...user, name})
|
||||||
|
} else {
|
||||||
|
platformContext.app.notify.alert(message);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
platformContext.app.notify.alert(
|
||||||
|
e?.response?.data?.message || e.message,
|
||||||
|
{
|
||||||
|
labels: { alert: 'error!' },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
setFlagIsRequesting(false);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const _onKeyDown = (e: any) => e.key === 'Enter' && handleSubmit(_onSubmit);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<form onSubmit={handleSubmit(_onSubmit)} className="mx-2 mt-4">
|
||||||
|
<Input
|
||||||
|
placeholder="Enter name"
|
||||||
|
key={'name'}
|
||||||
|
name={'name'}
|
||||||
|
type={'text'}
|
||||||
|
label="Name"
|
||||||
|
registerMeta={{
|
||||||
|
required: true,
|
||||||
|
}}
|
||||||
|
useformRef={form}
|
||||||
|
onKeyDown={_onKeyDown}
|
||||||
|
error={
|
||||||
|
errors?.name ? errors?.name?.message || 'Please enter name' : ''
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Input
|
||||||
|
placeholder="Enter Username"
|
||||||
|
key={'username'}
|
||||||
|
name={'username'}
|
||||||
|
label="Username"
|
||||||
|
value={user.username}
|
||||||
|
disabled
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Input
|
||||||
|
placeholder="Enter email"
|
||||||
|
key={'email'}
|
||||||
|
name={'email'}
|
||||||
|
label="Email"
|
||||||
|
value={user.email}
|
||||||
|
disabled
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
type="submit"
|
||||||
|
text={isRequesting ? 'Updating...' : 'Update Name'}
|
||||||
|
onClick={handleSubmit(_onSubmit)}
|
||||||
|
fullWidth
|
||||||
|
primary
|
||||||
|
sm
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default UpdateProfile;
|
||||||
@@ -92,7 +92,6 @@ const EditRequest: FC<IModal> = ({
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
classNames={{
|
classNames={{
|
||||||
content: 'h-[600px]',
|
|
||||||
body: 'p-0',
|
body: 'p-0',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import { FC, useEffect, useState } from 'react';
|
|||||||
import {
|
import {
|
||||||
Container,
|
Container,
|
||||||
Drawer,
|
Drawer,
|
||||||
Modal,
|
|
||||||
IModal,
|
IModal,
|
||||||
SecondaryTab,
|
SecondaryTab,
|
||||||
ProgressBar,
|
ProgressBar,
|
||||||
@@ -12,23 +11,29 @@ import { Rest } from '@firecamp/cloud-apis';
|
|||||||
import { useWorkspaceStore, IWorkspaceStore } from '../../../store/workspace';
|
import { useWorkspaceStore, IWorkspaceStore } from '../../../store/workspace';
|
||||||
import EditInfoTab from './tabs/EditInfoTab';
|
import EditInfoTab from './tabs/EditInfoTab';
|
||||||
import MembersTab from './tabs/MembersTab';
|
import MembersTab from './tabs/MembersTab';
|
||||||
|
import platformContext from '../../../services/platform-context';
|
||||||
import './workspace.scss';
|
import './workspace.scss';
|
||||||
|
import { Regex } from '../../../constants';
|
||||||
|
import PendingInviteMembersTab from './tabs/PendingInviteMembersTab';
|
||||||
|
|
||||||
enum ETabTypes {
|
enum ETabTypes {
|
||||||
Edit = 'edit',
|
Edit = 'edit',
|
||||||
Members = 'members',
|
Members = 'members',
|
||||||
|
PendingInvitation = 'pending_invitation',
|
||||||
}
|
}
|
||||||
const WorkspaceManagement: FC<IModal> = ({
|
const WorkspaceManagement: FC<IModal> = ({
|
||||||
opened = false,
|
opened = false,
|
||||||
onClose = () => {},
|
onClose = () => {},
|
||||||
}) => {
|
}) => {
|
||||||
let { workspace } = useWorkspaceStore((s: IWorkspaceStore) => ({
|
let { workspace, setWorkspace } = useWorkspaceStore((s: IWorkspaceStore) => ({
|
||||||
workspace: s.workspace,
|
workspace: s.workspace,
|
||||||
|
setWorkspace: s.setWorkspace,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const [wrs, setWrs] = useState(workspace);
|
const [wrs, setWrs] = useState(workspace);
|
||||||
const [isRequesting, setIsRequesting] = useState(false);
|
const [isRequesting, setIsRequesting] = useState(false);
|
||||||
const [wrsMembers, setWrsMembers] = useState([]);
|
const [wrsMembers, setWrsMembers] = useState([]);
|
||||||
|
const [wrsInviteMembers, setWrsInviteMembers] = useState([]);
|
||||||
const [isFetchingMembers, setIsFetchingMembers] = useState(false);
|
const [isFetchingMembers, setIsFetchingMembers] = useState(false);
|
||||||
const [error, setError] = useState({ name: '' });
|
const [error, setError] = useState({ name: '' });
|
||||||
const [activeTab, setActiveTab] = useState<ETabTypes>(ETabTypes.Edit);
|
const [activeTab, setActiveTab] = useState<ETabTypes>(ETabTypes.Edit);
|
||||||
@@ -36,16 +41,22 @@ const WorkspaceManagement: FC<IModal> = ({
|
|||||||
const tabs = [
|
const tabs = [
|
||||||
{ name: 'Edit', id: ETabTypes.Edit },
|
{ name: 'Edit', id: ETabTypes.Edit },
|
||||||
{ name: 'Members', id: ETabTypes.Members },
|
{ name: 'Members', id: ETabTypes.Members },
|
||||||
|
{ name: 'Pending Invitation', id: ETabTypes.PendingInvitation },
|
||||||
];
|
];
|
||||||
|
|
||||||
/** fetch wrs members to be shown on second tab activated, only fetch once */
|
/** fetch wrs members to be shown on second tab activated, only fetch once */
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (activeTab === ETabTypes.Members && wrsMembers.length === 0) {
|
if (
|
||||||
|
[ETabTypes.Members, ETabTypes.PendingInvitation].includes(activeTab) &&
|
||||||
|
activeTab === ETabTypes.Members
|
||||||
|
? wrsMembers.length === 0
|
||||||
|
: wrsInviteMembers.length === 0
|
||||||
|
) {
|
||||||
setIsFetchingMembers(true);
|
setIsFetchingMembers(true);
|
||||||
Rest.workspace
|
Rest.workspace
|
||||||
.getMembers(workspace.__ref.id)
|
.getMembers(workspace.__ref.id)
|
||||||
.then((res) => res.data)
|
.then((res) => res.data)
|
||||||
.then(({ members = [], invited }) => {
|
.then(({ members = [], invited = [] }) => {
|
||||||
const memberList = members.map((m, i) => {
|
const memberList = members.map((m, i) => {
|
||||||
return {
|
return {
|
||||||
id: m.__ref?.id ?? i,
|
id: m.__ref?.id ?? i,
|
||||||
@@ -54,51 +65,117 @@ const WorkspaceManagement: FC<IModal> = ({
|
|||||||
role: m.role,
|
role: m.role,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
const invitedMemberList = invited.map((m, i) => {
|
||||||
|
return {
|
||||||
|
id: m.__ref?.id ?? i,
|
||||||
|
name: m.name || m.username,
|
||||||
|
email: m.email,
|
||||||
|
role: m.role,
|
||||||
|
};
|
||||||
|
});
|
||||||
setWrsMembers(memberList);
|
setWrsMembers(memberList);
|
||||||
|
setWrsInviteMembers(invitedMemberList);
|
||||||
})
|
})
|
||||||
.finally(() => setIsFetchingMembers(false));
|
.finally(() => setIsFetchingMembers(false));
|
||||||
}
|
}
|
||||||
}, [activeTab]);
|
}, [activeTab]);
|
||||||
|
|
||||||
const onChange = (e) => {
|
const onChange = (e, reset) => {
|
||||||
const { name, value } = e.target;
|
if (reset) {
|
||||||
if (error.name) setError({ name: '' });
|
if (error.name) setError({ name: '' });
|
||||||
setWrs((w) => ({ ...w, [name]: value }));
|
setWrs(workspace);
|
||||||
|
} else {
|
||||||
|
const { name, value } = e.target;
|
||||||
|
if (error.name) setError({ name: '' });
|
||||||
|
setWrs((w) => ({ ...w, [name]: value }));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onUpdate = () => {
|
const onUpdate = () => {
|
||||||
if (isRequesting) return;
|
if (isRequesting) return;
|
||||||
const name = wrs.name.trim();
|
const name = wrs.name.trim();
|
||||||
|
const description = wrs.description?.trim();
|
||||||
|
|
||||||
if (!name || name.length < 6) {
|
if (!name || name.length < 6) {
|
||||||
setError({ name: 'The workspace name must have minimum 6 characters' });
|
setError({ name: 'The workspace name must have minimum 6 characters' });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const _wrs = { name, description: wrs?.description?.trim() };
|
|
||||||
|
|
||||||
// TODO: workspace update API call
|
const isValid = Regex.WorkspaceName.test(name);
|
||||||
|
if (!isValid) {
|
||||||
|
setError({
|
||||||
|
name: 'The workspace name must not contain any spaces or special characters.',
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
workspace.name === wrs.name &&
|
||||||
|
workspace.description === wrs.description
|
||||||
|
)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const _wrs: { name?: string; description?: string } = {};
|
||||||
|
if (workspace.name !== name) {
|
||||||
|
_wrs.name = name;
|
||||||
|
}
|
||||||
|
if (workspace.description !== description) {
|
||||||
|
_wrs.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
setIsRequesting(true);
|
||||||
|
Rest.workspace
|
||||||
|
.update(workspace.__ref.id, _wrs)
|
||||||
|
.then(({ error, message }) => {
|
||||||
|
if (!error) {
|
||||||
|
platformContext.app.notify.success(
|
||||||
|
"The workspace's detail has been changed successfully."
|
||||||
|
);
|
||||||
|
setWorkspace({ ...workspace, ..._wrs });
|
||||||
|
} else {
|
||||||
|
platformContext.app.notify.alert(message);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
platformContext.app.notify.alert(e.response?.data.message || e.message);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
setIsRequesting(false);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderTab = (tabId: string) => {
|
const renderTab = (tabId: string) => {
|
||||||
// console.log(wrs, "wrs....")
|
// console.log(wrs, "wrs....")
|
||||||
switch (tabId) {
|
switch (tabId) {
|
||||||
case 'edit':
|
case ETabTypes.Edit:
|
||||||
return (
|
return (
|
||||||
<EditInfoTab
|
<EditInfoTab
|
||||||
workspace={wrs}
|
workspace={wrs}
|
||||||
error={error}
|
error={error}
|
||||||
isRequesting={isRequesting}
|
isRequesting={isRequesting}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
close={onClose}
|
|
||||||
onSubmit={onUpdate}
|
onSubmit={onUpdate}
|
||||||
|
enableReset={
|
||||||
|
workspace.name !== wrs.name ||
|
||||||
|
workspace.description !== wrs.description
|
||||||
|
}
|
||||||
|
// disabled={true} // TODO: only allowed for owner & admin
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
case 'members':
|
case ETabTypes.Members:
|
||||||
return (
|
return (
|
||||||
<MembersTab
|
<MembersTab
|
||||||
members={wrsMembers}
|
members={wrsMembers}
|
||||||
isFetchingMembers={isFetchingMembers}
|
isFetchingMembers={isFetchingMembers}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
case ETabTypes.PendingInvitation:
|
||||||
|
return (
|
||||||
|
<PendingInviteMembersTab
|
||||||
|
members={wrsInviteMembers}
|
||||||
|
isFetchingMembers={isFetchingMembers}
|
||||||
|
/>
|
||||||
|
);
|
||||||
default:
|
default:
|
||||||
return <></>;
|
return <></>;
|
||||||
}
|
}
|
||||||
@@ -115,7 +192,7 @@ const WorkspaceManagement: FC<IModal> = ({
|
|||||||
}
|
}
|
||||||
size={550}
|
size={550}
|
||||||
classNames={{
|
classNames={{
|
||||||
body: '!p-4 h-[450px]'
|
body: '!p-4 h-[90vh]',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { FC, useEffect, useState } from 'react';
|
import { FC, useEffect, useState } from 'react';
|
||||||
import { Drawer, IModal, SecondaryTab } from '@firecamp/ui';
|
import { Container, Drawer, IModal, Notes, SecondaryTab } from '@firecamp/ui';
|
||||||
import { _array, _misc } from '@firecamp/utils';
|
import { _array, _misc } from '@firecamp/utils';
|
||||||
import { Rest } from '@firecamp/cloud-apis';
|
import { Rest } from '@firecamp/cloud-apis';
|
||||||
import InviteNonOrgMembers from './tabs/InviteNonOrgMembers';
|
import InviteNonOrgMembers from './tabs/InviteNonOrgMembers';
|
||||||
@@ -13,6 +13,11 @@ enum EInviteMemberTabs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const InviteMembers: FC<IModal> = ({ opened = false, onClose = () => {} }) => {
|
const InviteMembers: FC<IModal> = ({ opened = false, onClose = () => {} }) => {
|
||||||
|
const { scope, organization } = usePlatformStore(s => ({
|
||||||
|
scope: s.scope,
|
||||||
|
organization: s.organization
|
||||||
|
}));
|
||||||
|
|
||||||
const [isFetchingMembers, setIsFetchingMembers] = useState(false);
|
const [isFetchingMembers, setIsFetchingMembers] = useState(false);
|
||||||
const [orgMembers, setOrgMembers] = useState([]);
|
const [orgMembers, setOrgMembers] = useState([]);
|
||||||
|
|
||||||
@@ -24,7 +29,11 @@ const InviteMembers: FC<IModal> = ({ opened = false, onClose = () => {} }) => {
|
|||||||
}>;
|
}>;
|
||||||
}>({
|
}>({
|
||||||
role: EUserRolesWorkspace.Collaborator,
|
role: EUserRolesWorkspace.Collaborator,
|
||||||
usersList: [{ name: '', email: '' }],
|
usersList: [
|
||||||
|
{ name: '', email: '' },
|
||||||
|
{ name: '', email: '' },
|
||||||
|
{ name: '', email: '' },
|
||||||
|
],
|
||||||
});
|
});
|
||||||
const [orgTabState, setOrgTabState] = useState<{
|
const [orgTabState, setOrgTabState] = useState<{
|
||||||
id: string;
|
id: string;
|
||||||
@@ -57,7 +66,7 @@ const InviteMembers: FC<IModal> = ({ opened = false, onClose = () => {} }) => {
|
|||||||
/** fetch org members to be invited on second tab activated, only fetch once */
|
/** fetch org members to be invited on second tab activated, only fetch once */
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (activeTab === EInviteMemberTabs.OrgMembers && orgMembers.length === 0) {
|
if (activeTab === EInviteMemberTabs.OrgMembers && orgMembers.length === 0) {
|
||||||
const { scope, organization } = usePlatformStore.getState();
|
|
||||||
if (scope == EPlatformScope.Person) return;
|
if (scope == EPlatformScope.Person) return;
|
||||||
setIsFetchingMembers(true);
|
setIsFetchingMembers(true);
|
||||||
Rest.organization
|
Rest.organization
|
||||||
@@ -90,38 +99,62 @@ const InviteMembers: FC<IModal> = ({ opened = false, onClose = () => {} }) => {
|
|||||||
opened={opened}
|
opened={opened}
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
size={576}
|
size={576}
|
||||||
classNames={{
|
|
||||||
content: 'h-[700px]',
|
|
||||||
body: 'h-[480px]'
|
|
||||||
}}
|
|
||||||
title={
|
title={
|
||||||
<div className="text-lg leading-5 px-1 flex items-center font-medium">
|
<div className="text-lg leading-5 px-1 flex items-center font-medium">
|
||||||
Invite Members To Join The Workspace
|
Invite Members To Join The Workspace
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
classNames={{
|
||||||
|
body: 'pb-4 h-[90vh]',
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<div className="!pt-4 h-fit flex flex-col">
|
<Container>
|
||||||
<SecondaryTab
|
{(scope == EPlatformScope.Person) ? (
|
||||||
className="flex items-center pb-6 -ml-2"
|
<Container.Body className="mt-8">
|
||||||
list={tabs}
|
<InviteNotAllowed />
|
||||||
activeTab={activeTab}
|
</Container.Body>
|
||||||
onSelect={(tabId: EInviteMemberTabs) => setActiveTab(tabId)}
|
) : (
|
||||||
/>
|
<>
|
||||||
{activeTab == EInviteMemberTabs.NewMembers ? (
|
<Container.Header className="!pt-4">
|
||||||
<InviteNonOrgMembers
|
<SecondaryTab
|
||||||
state={nonOrgTabState}
|
className="flex items-center pb-6 -ml-2"
|
||||||
onChange={changeNonOrgTabState}
|
list={tabs}
|
||||||
/>
|
activeTab={activeTab}
|
||||||
) : (
|
onSelect={(tabId: EInviteMemberTabs) => setActiveTab(tabId)}
|
||||||
<InviteOrgMembers
|
/>
|
||||||
state={orgTabState}
|
</Container.Header>
|
||||||
members={orgMembers}
|
<Container.Body>
|
||||||
isFetchingMembers={isFetchingMembers}
|
{activeTab == EInviteMemberTabs.NewMembers ? (
|
||||||
onChange={changeOrgTabState}
|
<InviteNonOrgMembers
|
||||||
/>
|
state={nonOrgTabState}
|
||||||
)}
|
onChange={changeNonOrgTabState}
|
||||||
</div>
|
/>
|
||||||
|
) : (
|
||||||
|
<InviteOrgMembers
|
||||||
|
state={orgTabState}
|
||||||
|
members={orgMembers}
|
||||||
|
isFetchingMembers={isFetchingMembers}
|
||||||
|
onChange={changeOrgTabState}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Container.Body>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Container>
|
||||||
</Drawer>
|
</Drawer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
export default InviteMembers;
|
export default InviteMembers;
|
||||||
|
|
||||||
|
const InviteNotAllowed = () => {
|
||||||
|
return (
|
||||||
|
<Notes
|
||||||
|
title={
|
||||||
|
'Inviting users to your personal workspace is currently unavailable.'
|
||||||
|
}
|
||||||
|
description={`But don't worry! <br/>
|
||||||
|
You can still collaborate effectively by taking the first step to create an organization. 🤝 <br/>
|
||||||
|
Start working together seamlessly and efficiently with your team in no time!`}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import cx from 'classnames';
|
|||||||
import { VscAdd } from '@react-icons/all-files/vsc/VscAdd';
|
import { VscAdd } from '@react-icons/all-files/vsc/VscAdd';
|
||||||
import { VscClose } from '@react-icons/all-files/vsc/VscClose';
|
import { VscClose } from '@react-icons/all-files/vsc/VscClose';
|
||||||
import { FormField, Input } from '@firecamp/ui';
|
import { FormField, Input } from '@firecamp/ui';
|
||||||
|
import { _array } from '@firecamp/utils';
|
||||||
|
|
||||||
const InviteUsersForm = ({ usersList, onChange, error }) => {
|
const InviteUsersForm = ({ usersList, onChange, error }) => {
|
||||||
const _handleNameChange = (e, position) => {
|
const _handleNameChange = (e, position) => {
|
||||||
@@ -73,14 +74,8 @@ const InviteUsersForm = ({ usersList, onChange, error }) => {
|
|||||||
<VscClose size={20} className="text-error" />
|
<VscClose size={20} className="text-error" />
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
{error[index]?.message.length > 0 ? (
|
{!_array.isEmpty(error) ? (
|
||||||
<div
|
<Error error={error} index={index} />
|
||||||
className={cx(
|
|
||||||
'text-sm font-light text-error absolute left-0 bottom-0'
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{error[index].message}
|
|
||||||
</div>
|
|
||||||
) : (
|
) : (
|
||||||
<></>
|
<></>
|
||||||
)}
|
)}
|
||||||
@@ -91,3 +86,17 @@ const InviteUsersForm = ({ usersList, onChange, error }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default InviteUsersForm;
|
export default InviteUsersForm;
|
||||||
|
|
||||||
|
const Error = ({ error, index }) => {
|
||||||
|
let errorObject = error.find((m) => m.index === index);
|
||||||
|
|
||||||
|
if (errorObject?.message.length > 0)
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={cx('text-sm font-light text-error absolute left-0 bottom-0')}
|
||||||
|
>
|
||||||
|
{errorObject.message}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
return <></>;
|
||||||
|
};
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ const InviteNonOrgMembers = ({ state, onChange }) => {
|
|||||||
const { usersList, role } = state;
|
const { usersList, role } = state;
|
||||||
|
|
||||||
const inviteMembers = useCallback(() => {
|
const inviteMembers = useCallback(() => {
|
||||||
|
setInvitingFlag(true);
|
||||||
const { success, error } = validateMembersDetail(usersList);
|
const { success, error } = validateMembersDetail(usersList);
|
||||||
if (error?.length) {
|
if (error?.length) {
|
||||||
setError(error);
|
setError(error);
|
||||||
@@ -118,17 +119,17 @@ const InviteNonOrgMembers = ({ state, onChange }) => {
|
|||||||
</ScrollBar>
|
</ScrollBar>
|
||||||
</Container.Body>
|
</Container.Body>
|
||||||
<Container.Footer className="flex items-center">
|
<Container.Footer className="flex items-center">
|
||||||
<a
|
<Button
|
||||||
className="!text-link hover:!text-link hover:underline cursor-pointer text-sm px-2 pl-0"
|
onClick={() => {
|
||||||
target="_blank"
|
|
||||||
href="#"
|
|
||||||
onClick={(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
platformContext.app.modals.openWorkspaceManagement();
|
platformContext.app.modals.openWorkspaceManagement();
|
||||||
}}
|
}}
|
||||||
>
|
text='Open Workspace Management'
|
||||||
Open Workspace Management
|
// classNames={{
|
||||||
</a>
|
// root: '!text-link hover:!text-link hover:underline'
|
||||||
|
// }}
|
||||||
|
ghost
|
||||||
|
xs
|
||||||
|
/>
|
||||||
<Button
|
<Button
|
||||||
text={isInvitingMembers ? 'Sending invitation...' : 'Send Invitation'}
|
text={isInvitingMembers ? 'Sending invitation...' : 'Send Invitation'}
|
||||||
classNames={{
|
classNames={{
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ const InviteOrgMembers: FC<IProps> = ({
|
|||||||
onSelect={(m) => onChange({ ...member, ...m })}
|
onSelect={(m) => onChange({ ...member, ...m })}
|
||||||
classNames={{
|
classNames={{
|
||||||
trigger: 'block',
|
trigger: 'block',
|
||||||
dropdown: '-mt-2 overflow-y-scroll invisible-scrollbar h-[200px]',
|
dropdown: '-mt-2 overflow-y-scroll invisible-scrollbar max-h-[200px]',
|
||||||
item: '!px-4',
|
item: '!px-4',
|
||||||
}}
|
}}
|
||||||
width={512}
|
width={512}
|
||||||
@@ -127,17 +127,19 @@ const InviteOrgMembers: FC<IProps> = ({
|
|||||||
<RolesCallout role={_role.id} />
|
<RolesCallout role={_role.id} />
|
||||||
</Container.Body>
|
</Container.Body>
|
||||||
<Container.Footer className="flex items-center">
|
<Container.Footer className="flex items-center">
|
||||||
<a
|
<Button
|
||||||
className="!text-link hover:!text-link hover:underline cursor-pointer text-sm px-2 pl-0"
|
onClick={() => {
|
||||||
target="_blank"
|
|
||||||
href="#"
|
|
||||||
onClick={(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
platformContext.app.modals.openWorkspaceManagement();
|
platformContext.app.modals.openWorkspaceManagement();
|
||||||
}}
|
}}
|
||||||
>
|
// classNames={{
|
||||||
Open Workspace Management
|
// root: '!text-link hover:!text-link hover:underline'
|
||||||
</a>
|
// }}
|
||||||
|
text='Open Workspace Management'
|
||||||
|
ghost
|
||||||
|
xs
|
||||||
|
/>
|
||||||
|
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
text={'Send Invitation'}
|
text={'Send Invitation'}
|
||||||
disabled={!member.name || !member.role || isInvitingMembers}
|
disabled={!member.name || !member.role || isInvitingMembers}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { FC } from 'react';
|
import { FC } from 'react';
|
||||||
import { Button, Input, TabHeader, TextArea } from '@firecamp/ui';
|
import { Button, Container, Input, TabHeader, TextArea } from '@firecamp/ui';
|
||||||
import platformContext from '../../../../services/platform-context';
|
import platformContext from '../../../../services/platform-context';
|
||||||
|
|
||||||
const EditInfoTab: FC<any> = ({
|
const EditInfoTab: FC<any> = ({
|
||||||
@@ -8,76 +8,74 @@ const EditInfoTab: FC<any> = ({
|
|||||||
isRequesting,
|
isRequesting,
|
||||||
onSubmit,
|
onSubmit,
|
||||||
onChange,
|
onChange,
|
||||||
close,
|
disabled = false,
|
||||||
|
enableReset = false,
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<div className="p-3 flex-1 flex flex-col">
|
<Container className="pt-3 px-3 flex-1 flex flex-col h-full">
|
||||||
<label className="text-sm font-semibold leading-3 block text-app-foreground-inactive uppercase w-full relative mb-2">
|
<Container.Body>
|
||||||
UPDATE WORKSPACE INFO
|
<label className="text-sm font-semibold leading-3 block text-app-foreground-inactive uppercase w-full relative mb-2">
|
||||||
</label>
|
UPDATE WORKSPACE INFO
|
||||||
<div>
|
</label>
|
||||||
<Input
|
<div>
|
||||||
autoFocus={true}
|
<Input
|
||||||
label="Name"
|
autoFocus={true}
|
||||||
placeholder="Workspace name"
|
label="Name"
|
||||||
name={'name'}
|
placeholder="Workspace name"
|
||||||
defaultValue={workspace.name || ''}
|
name={'name'}
|
||||||
|
defaultValue={workspace.name || ''}
|
||||||
|
onChange={onChange}
|
||||||
|
onKeyDown={() => {}}
|
||||||
|
onBlur={() => {}}
|
||||||
|
error={error.name}
|
||||||
|
// error={error.name}
|
||||||
|
// iconPosition="right"
|
||||||
|
// icon={<VscEdit />}
|
||||||
|
wrapperClassName="!mb-3"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<TextArea
|
||||||
|
type="text"
|
||||||
|
minHeight="240px"
|
||||||
|
label="Description (optional)"
|
||||||
|
labelClassName="fc-input-label"
|
||||||
|
placeholder="Description"
|
||||||
|
note="Markdown supported in description"
|
||||||
|
name={'description'}
|
||||||
|
defaultValue={workspace.description || ''}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
onKeyDown={() => {}}
|
// disabled={true}
|
||||||
onBlur={() => {}}
|
|
||||||
error={error.name}
|
|
||||||
// error={error.name}
|
|
||||||
// iconPosition="right"
|
// iconPosition="right"
|
||||||
// icon={<VscEdit />}
|
// icon={<VscEdit />}
|
||||||
wrapperClassName='!mb-3'
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</Container.Body>
|
||||||
|
<Container.Footer>
|
||||||
<TextArea
|
<TabHeader className="!px-0">
|
||||||
type="text"
|
<TabHeader.Left>
|
||||||
minHeight="180px"
|
<Button
|
||||||
label="Description (optional)"
|
onClick={() => {
|
||||||
labelClassName="fc-input-label"
|
platformContext.app.modals.openInviteMembers();
|
||||||
placeholder="Description"
|
}}
|
||||||
note="Markdown supported in description"
|
text="Invite New Members"
|
||||||
name={'description'}
|
ghost
|
||||||
defaultValue={workspace.description || ''}
|
xs
|
||||||
onChange={onChange}
|
/>
|
||||||
// disabled={true}
|
</TabHeader.Left>
|
||||||
// iconPosition="right"
|
<TabHeader.Right>
|
||||||
// icon={<VscEdit />}
|
{/* TODO: update details */}
|
||||||
/>
|
{/* {enableReset ? <Button text="Undo" onClick={(e) => onChange(e, true)} ghost xs /> : <></>} */}
|
||||||
<TabHeader className="!px-0">
|
<Button
|
||||||
<TabHeader.Left>
|
text={isRequesting ? 'Updating...' : 'Update'}
|
||||||
<a
|
onClick={onSubmit}
|
||||||
className="!text-link hover:!text-link hover:underline cursor-pointer text-sm px-2 pl-0"
|
disabled={isRequesting || disabled || !enableReset}
|
||||||
target="_blank"
|
primary
|
||||||
href="#"
|
xs
|
||||||
onClick={(e) => {
|
/>
|
||||||
e.preventDefault();
|
</TabHeader.Right>
|
||||||
platformContext.app.modals.openInviteMembers();
|
</TabHeader>
|
||||||
}}
|
</Container.Footer>
|
||||||
>
|
</Container>
|
||||||
Invite New Members
|
|
||||||
</a>
|
|
||||||
</TabHeader.Left>
|
|
||||||
<TabHeader.Right>
|
|
||||||
<Button
|
|
||||||
text="Cancel"
|
|
||||||
onClick={(e) => close(e)}
|
|
||||||
ghost
|
|
||||||
xs
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
text={isRequesting ? 'Updating...' : 'Update'}
|
|
||||||
onClick={onSubmit}
|
|
||||||
disabled={isRequesting}
|
|
||||||
primary
|
|
||||||
xs
|
|
||||||
/>
|
|
||||||
</TabHeader.Right>
|
|
||||||
</TabHeader>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
export default EditInfoTab;
|
export default EditInfoTab;
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ const MembersTab = ({ members = [], isFetchingMembers = false }) => {
|
|||||||
e.response?.data.message || e.message
|
e.response?.data.message || e.message
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -151,8 +151,8 @@ const MembersTab = ({ members = [], isFetchingMembers = false }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container className="gap-2">
|
<Container className="gap-2 pt-2">
|
||||||
<Container.Body className="pt-2 visible-scrollbar">
|
<Container.Body className="visible-scrollbar">
|
||||||
<ProgressBar active={isFetchingMembers} className={'top-auto'} />
|
<ProgressBar active={isFetchingMembers} className={'top-auto'} />
|
||||||
<PrimitiveTable
|
<PrimitiveTable
|
||||||
classes={{
|
classes={{
|
||||||
@@ -167,18 +167,15 @@ const MembersTab = ({ members = [], isFetchingMembers = false }) => {
|
|||||||
onMount={(api) => (tableApi.current = api)}
|
onMount={(api) => (tableApi.current = api)}
|
||||||
/>
|
/>
|
||||||
</Container.Body>
|
</Container.Body>
|
||||||
<Container.Footer className="flex items-center">
|
<Container.Footer className="px-3 h-[34px] flex items-center">
|
||||||
<a
|
<Button
|
||||||
className="!text-link hover:!text-link hover:underline cursor-pointer text-sm px-2 pl-0"
|
onClick={() => {
|
||||||
target="_blank"
|
|
||||||
href="#"
|
|
||||||
onClick={(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
platformContext.app.modals.openInviteMembers();
|
platformContext.app.modals.openInviteMembers();
|
||||||
}}
|
}}
|
||||||
>
|
text="Invite New Members"
|
||||||
Invite New Members
|
ghost
|
||||||
</a>
|
xs
|
||||||
|
/>
|
||||||
</Container.Footer>
|
</Container.Footer>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,219 @@
|
|||||||
|
import { FC, useEffect, useRef, useState } from 'react';
|
||||||
|
import { VscTrash } from '@react-icons/all-files/vsc/VscTrash';
|
||||||
|
import { VscTriangleDown } from '@react-icons/all-files/vsc/VscTriangleDown';
|
||||||
|
import cx from 'classnames';
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Container,
|
||||||
|
DropdownMenu,
|
||||||
|
PrimitiveTable,
|
||||||
|
ProgressBar,
|
||||||
|
TTableApi,
|
||||||
|
} from '@firecamp/ui';
|
||||||
|
import { _array } from '@firecamp/utils';
|
||||||
|
import { Rest } from '@firecamp/cloud-apis';
|
||||||
|
import platformContext from '../../../../services/platform-context';
|
||||||
|
import { useWorkspaceStore } from '../../../../store/workspace';
|
||||||
|
import { EUserRolesWorkspace } from '../../../../types';
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{ id: 'index', name: 'No.', key: 'index', width: '35px', fixedWidth: true },
|
||||||
|
{ id: 'name', name: 'Name', key: 'name', width: '100px' },
|
||||||
|
{
|
||||||
|
id: 'email',
|
||||||
|
name: 'Email',
|
||||||
|
key: 'email',
|
||||||
|
resizeWithContainer: true,
|
||||||
|
width: '180px',
|
||||||
|
},
|
||||||
|
{ id: 'role', name: 'Role', key: 'role', width: '115px', fixedWidth: true },
|
||||||
|
// { id: 'action', name: '', key: '', width: '35px', fixedWidth: true },
|
||||||
|
];
|
||||||
|
|
||||||
|
const RoleOptions = [
|
||||||
|
{
|
||||||
|
id: EUserRolesWorkspace.Owner,
|
||||||
|
name: 'Owner',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: EUserRolesWorkspace.Admin,
|
||||||
|
name: 'Admin',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: EUserRolesWorkspace.Collaborator,
|
||||||
|
name: 'Collaborator',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const PendingInviteMembersTab = ({ members = [], isFetchingMembers = false }) => {
|
||||||
|
const workspace = useWorkspaceStore.getState().workspace;
|
||||||
|
const tableApi = useRef<TTableApi>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!_array.isEmpty(members)) {
|
||||||
|
const memberList = members.map((m, i) => {
|
||||||
|
return {
|
||||||
|
id: m.id,
|
||||||
|
name: m.name || m.username,
|
||||||
|
email: m.email,
|
||||||
|
role: m.role,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
tableApi.current.initialize(memberList);
|
||||||
|
}
|
||||||
|
}, [members]);
|
||||||
|
|
||||||
|
const onRemoveMember = (row) => {
|
||||||
|
|
||||||
|
platformContext.window.confirm({
|
||||||
|
message: `You're sure to remove ${row.name} from the workspace?`,
|
||||||
|
labels: {
|
||||||
|
cancel: 'Cancel',
|
||||||
|
confirm: 'Yes, remove the member.',
|
||||||
|
},
|
||||||
|
onConfirm: () => {
|
||||||
|
Rest.workspace
|
||||||
|
.removeMember(workspace.__ref.id, row.id)
|
||||||
|
.then(() => {
|
||||||
|
tableApi.current.removeRow(row.id);
|
||||||
|
platformContext.app.notify.success(
|
||||||
|
'The member has been removed successfully.'
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
platformContext.app.notify.alert(
|
||||||
|
e.response?.data.message || e.message
|
||||||
|
);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const onChangeRole = (row) => {
|
||||||
|
platformContext.window.confirm({
|
||||||
|
message: `Please confirm, You're assigning ${row.role.name} role to ${row.name}, right?`,
|
||||||
|
labels: {
|
||||||
|
cancel: 'Cancel',
|
||||||
|
confirm: 'Yes, change the role.',
|
||||||
|
},
|
||||||
|
onConfirm: () => {
|
||||||
|
Rest.workspace
|
||||||
|
.changeMemberRole(workspace.__ref.id, row.id, row.role.id)
|
||||||
|
.then(() => {
|
||||||
|
tableApi.current.setRow({ ...row, role: row.role.id });
|
||||||
|
platformContext.app.notify.success(
|
||||||
|
"The member's role has been changed successfully."
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
platformContext.app.notify.alert(
|
||||||
|
e.response?.data.message || e.message
|
||||||
|
);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderCell = (column, cellValue, rowIndex, row, tableApi, onChange) => {
|
||||||
|
switch (column.id) {
|
||||||
|
case 'index':
|
||||||
|
return <div className="px-2"> {rowIndex + 1} </div>;
|
||||||
|
break;
|
||||||
|
case 'name':
|
||||||
|
return <div className="p-1">{cellValue}</div>;
|
||||||
|
break;
|
||||||
|
case 'email':
|
||||||
|
return <div className="p-1">{cellValue}</div>;
|
||||||
|
break;
|
||||||
|
case 'role':
|
||||||
|
return (
|
||||||
|
<div className="p-1 text-center">
|
||||||
|
<RoleDD
|
||||||
|
role={row.role}
|
||||||
|
onSelect={(role) => onChangeRole({ ...row, role })}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
// case 'action':
|
||||||
|
// return (
|
||||||
|
// <div className="px-2">
|
||||||
|
// <VscTrash
|
||||||
|
// size={14}
|
||||||
|
// className="text-error cursor-pointer"
|
||||||
|
// onClick={() => onRemoveMember(row)}
|
||||||
|
// />
|
||||||
|
// </div>
|
||||||
|
// );
|
||||||
|
// break;
|
||||||
|
default:
|
||||||
|
return column.key;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container className="gap-2 pt-2">
|
||||||
|
<Container.Body className="visible-scrollbar">
|
||||||
|
<ProgressBar active={isFetchingMembers} className={'top-auto'} />
|
||||||
|
<PrimitiveTable
|
||||||
|
classes={{
|
||||||
|
container: 'h-full',
|
||||||
|
}}
|
||||||
|
columns={columns}
|
||||||
|
rows={[]}
|
||||||
|
showDefaultEmptyRows={false}
|
||||||
|
renderColumn={(c) => c.name}
|
||||||
|
renderCell={renderCell}
|
||||||
|
onChange={console.log}
|
||||||
|
onMount={(api) => (tableApi.current = api)}
|
||||||
|
/>
|
||||||
|
</Container.Body>
|
||||||
|
<Container.Footer className="px-3 h-[34px] flex items-center">
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
platformContext.app.modals.openInviteMembers();
|
||||||
|
}}
|
||||||
|
text="Invite New Members"
|
||||||
|
ghost
|
||||||
|
xs
|
||||||
|
/>
|
||||||
|
</Container.Footer>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default PendingInviteMembersTab;
|
||||||
|
|
||||||
|
const RoleDD: FC<{
|
||||||
|
role: number;
|
||||||
|
onSelect: (role: { name: string; id: number }) => void;
|
||||||
|
}> = ({ role, onSelect }) => {
|
||||||
|
const [isOpen, toggleOpen] = useState(false);
|
||||||
|
|
||||||
|
const _role = RoleOptions.find((r) => r.id == role);
|
||||||
|
if (!_role) return <></>;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DropdownMenu
|
||||||
|
onOpenChange={(v) => toggleOpen(v)}
|
||||||
|
handler={() => (
|
||||||
|
<Button
|
||||||
|
text={_role.name}
|
||||||
|
rightIcon={
|
||||||
|
<VscTriangleDown
|
||||||
|
size={12}
|
||||||
|
className={cx({ 'transform rotate-180': isOpen })}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
disabled
|
||||||
|
ghost
|
||||||
|
xs
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
options={RoleOptions}
|
||||||
|
onSelect={onSelect}
|
||||||
|
disabled={true}
|
||||||
|
width={115}
|
||||||
|
sm
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -65,22 +65,6 @@ const UserDDMenus: FC<{ title: string; isGuest: boolean }> = ({
|
|||||||
isGuest,
|
isGuest,
|
||||||
}) => {
|
}) => {
|
||||||
const guestOptions = [
|
const guestOptions = [
|
||||||
{
|
|
||||||
name: title,
|
|
||||||
isLabel: true,
|
|
||||||
postfix: () => (
|
|
||||||
<>
|
|
||||||
<br />
|
|
||||||
<div
|
|
||||||
className={
|
|
||||||
'text-sm font-light leading-3 text-app-foreground-inactive'
|
|
||||||
}
|
|
||||||
>
|
|
||||||
User
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: 'Sign in',
|
name: 'Sign in',
|
||||||
postfix: () => (
|
postfix: () => (
|
||||||
@@ -102,23 +86,6 @@ const UserDDMenus: FC<{ title: string; isGuest: boolean }> = ({
|
|||||||
];
|
];
|
||||||
|
|
||||||
const userOptions = [
|
const userOptions = [
|
||||||
{
|
|
||||||
name: title,
|
|
||||||
isLabel: true,
|
|
||||||
postfix: () => (
|
|
||||||
<>
|
|
||||||
<br />
|
|
||||||
<div
|
|
||||||
className={
|
|
||||||
'text-sm font-light leading-3 text-app-foreground-inactive'
|
|
||||||
}
|
|
||||||
>
|
|
||||||
User
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
// TODO: add the onClick action
|
|
||||||
{
|
{
|
||||||
name: 'User Profile',
|
name: 'User Profile',
|
||||||
postfix: () => (
|
postfix: () => (
|
||||||
@@ -126,6 +93,9 @@ const UserDDMenus: FC<{ title: string; isGuest: boolean }> = ({
|
|||||||
<VscAccount size={14} />
|
<VscAccount size={14} />
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
|
onClick: () => {
|
||||||
|
platformContext.app.modals.openUserProfile();
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Create new organization',
|
name: 'Create new organization',
|
||||||
@@ -175,15 +145,24 @@ const UserDDMenus: FC<{ title: string; isGuest: boolean }> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<DropdownMenu
|
<DropdownMenu
|
||||||
handler={() => (
|
handler={() => <span className="pl-1 cursor-pointer">{title}</span>}
|
||||||
<span className="pl-1 cursor-pointer">{title}</span>
|
|
||||||
)}
|
|
||||||
options={isGuest ? guestOptions : userOptions}
|
options={isGuest ? guestOptions : userOptions}
|
||||||
|
header={
|
||||||
|
<div className="!capitalize !pt-[0.2rem] !pb-2 !px-3 !block !bg-focus2 ">
|
||||||
|
{title}
|
||||||
|
<br />
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
'text-sm font-light leading-3 text-app-foreground-inactive'
|
||||||
|
}
|
||||||
|
>
|
||||||
|
User
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
onSelect={(v) => v.onClick()}
|
onSelect={(v) => v.onClick()}
|
||||||
classNames={{
|
classNames={{
|
||||||
dropdown: '!pt-0 mt-2 min-w-fit',
|
dropdown: '!pt-0 mt-2 min-w-fit',
|
||||||
label:
|
|
||||||
'!capitalize flex items-center text-app-foreground !pt-[0.2rem] !pb-2 !px-3 !block !text-base leading-6 !bg-focus2 ',
|
|
||||||
item: '!py-1 !px-3',
|
item: '!py-1 !px-3',
|
||||||
}}
|
}}
|
||||||
width={150}
|
width={150}
|
||||||
@@ -197,22 +176,6 @@ const WorkspaceDDMenus: FC<{ title: string; disabled?: boolean }> = ({
|
|||||||
disabled = false,
|
disabled = false,
|
||||||
}) => {
|
}) => {
|
||||||
const options = [
|
const options = [
|
||||||
{
|
|
||||||
name: title,
|
|
||||||
isLabel: true,
|
|
||||||
postfix: () => (
|
|
||||||
<>
|
|
||||||
<br />
|
|
||||||
<div
|
|
||||||
className={
|
|
||||||
'text-sm font-light leading-3 text-app-foreground-inactive'
|
|
||||||
}
|
|
||||||
>
|
|
||||||
Workspace
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: 'Workspace Management',
|
name: 'Workspace Management',
|
||||||
disabled,
|
disabled,
|
||||||
@@ -265,15 +228,24 @@ const WorkspaceDDMenus: FC<{ title: string; disabled?: boolean }> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<DropdownMenu
|
<DropdownMenu
|
||||||
handler={() => (
|
handler={() => <span className="pl-1 cursor-pointer">{title}</span>}
|
||||||
<span className="pl-1 cursor-pointer">{title}</span>
|
|
||||||
)}
|
|
||||||
options={options}
|
options={options}
|
||||||
|
header={
|
||||||
|
<div className="!capitalize !pt-[0.2rem] !pb-2 !px-3 !block !bg-focus2 ">
|
||||||
|
{title}
|
||||||
|
<br />
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
'text-sm font-light leading-3 text-app-foreground-inactive'
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Workspace
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
onSelect={(v) => v.onClick()}
|
onSelect={(v) => v.onClick()}
|
||||||
classNames={{
|
classNames={{
|
||||||
dropdown: '!pt-0 mt-2 min-w-fit',
|
dropdown: '!pt-0 mt-2 min-w-fit',
|
||||||
label:
|
|
||||||
'!capitalize flex items-center text-app-foreground !pt-[0.2rem] !pb-2 !px-3 !block !text-base leading-6 !bg-focus2 ',
|
|
||||||
item: '!py-1 !px-3',
|
item: '!py-1 !px-3',
|
||||||
}}
|
}}
|
||||||
width={150}
|
width={150}
|
||||||
@@ -287,22 +259,6 @@ const OrgDDMenus: FC<{ title: string; disabled?: boolean }> = ({
|
|||||||
disabled = false,
|
disabled = false,
|
||||||
}) => {
|
}) => {
|
||||||
const options = [
|
const options = [
|
||||||
{
|
|
||||||
name: title,
|
|
||||||
isLabel: true,
|
|
||||||
postfix: () => (
|
|
||||||
<>
|
|
||||||
<br />
|
|
||||||
<div
|
|
||||||
className={
|
|
||||||
'text-sm font-light leading-3 text-app-foreground-inactive'
|
|
||||||
}
|
|
||||||
>
|
|
||||||
Organization
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: 'Org Management',
|
name: 'Org Management',
|
||||||
disabled,
|
disabled,
|
||||||
@@ -343,15 +299,24 @@ const OrgDDMenus: FC<{ title: string; disabled?: boolean }> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<DropdownMenu
|
<DropdownMenu
|
||||||
handler={() => (
|
handler={() => <span className="pl-1 cursor-pointer">{title}</span>}
|
||||||
<span className="pl-1 cursor-pointer">{title}</span>
|
|
||||||
)}
|
|
||||||
options={options}
|
options={options}
|
||||||
|
header={
|
||||||
|
<div className="!capitalize !pt-[0.2rem] !pb-2 !px-3 !block !bg-focus2 ">
|
||||||
|
{title}
|
||||||
|
<br />
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
'text-sm font-light leading-3 text-app-foreground-inactive'
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Organization
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
onSelect={(v) => v.onClick()}
|
onSelect={(v) => v.onClick()}
|
||||||
classNames={{
|
classNames={{
|
||||||
dropdown: '!pt-0 mt-2 min-w-fit',
|
dropdown: '!pt-0 mt-2 min-w-fit',
|
||||||
label:
|
|
||||||
'!capitalize flex items-center text-app-foreground !pt-[0.2rem] !pb-2 !px-3 !block !text-base leading-6 !bg-focus2 ',
|
|
||||||
item: '!py-1 !px-3',
|
item: '!py-1 !px-3',
|
||||||
}}
|
}}
|
||||||
width={140}
|
width={140}
|
||||||
|
|||||||
@@ -5,18 +5,19 @@ export const Regex = {
|
|||||||
),
|
),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* allow alphanumeric and underscore
|
* allow alphanumeric and single hyphen
|
||||||
* don't allow spaces and special characters
|
* don't allow spaces and special characters
|
||||||
* characters range between 6 to 20
|
* characters range between 6 to 20
|
||||||
|
* @ref: https://github.com/shinnn/github-username-regex/blob/master/index.js
|
||||||
*/
|
*/
|
||||||
Username: /^[a-zA-Z0-9\_]{6,20}$/,
|
Username: /^[a-z\d](?:[a-z\d]|-(?=[a-z\d])){5,19}$/i,
|
||||||
WorkspaceName: /^[a-zA-Z0-9\_]{6,20}$/,
|
WorkspaceName: /^[a-z\d](?:[a-z\d]|-(?=[a-z\d])){5,19}$/i,
|
||||||
OrgName: /^[a-zA-Z0-9\_]{4,20}$/,
|
OrgName: /^[a-z\d](?:[a-z\d]|-(?=[a-z\d])){3,19}$/i,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* don't allow any special character
|
* don't allow any special character
|
||||||
* @ref: https://stackoverflow.com/a/23127284
|
* @ref: https://stackoverflow.com/a/23127284
|
||||||
* allows: colName, colName_, _colNmae, col_name
|
* allows: colName, colName_, _colName, col_name
|
||||||
* not allow" colName. , colName?, colName/@ or any special character in the name
|
* not allow" colName. , colName?, colName/@ or any special character in the name
|
||||||
* TODO: add character range
|
* TODO: add character range
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -116,7 +116,8 @@ const initApp = async () => {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e, 'error while connecting the socket');
|
console.log(e, 'error while connecting the socket');
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
.catch(console.log);
|
||||||
};
|
};
|
||||||
const initUser = (user: any) => {
|
const initUser = (user: any) => {
|
||||||
const { setUser } = useUserStore.getState();
|
const { setUser } = useUserStore.getState();
|
||||||
|
|||||||
@@ -78,6 +78,12 @@ const modalService = {
|
|||||||
open(EPlatformModalTypes.SwitchOrg);
|
open(EPlatformModalTypes.SwitchOrg);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
openAllInvitation: () => {
|
||||||
|
const { isGuest } = useUserStore.getState();
|
||||||
|
if (isGuest) return modalService.openSignIn();
|
||||||
|
open(EPlatformModalTypes.AllInvitation);
|
||||||
|
},
|
||||||
|
|
||||||
// Cookie, Ssl, Proxy
|
// Cookie, Ssl, Proxy
|
||||||
openCookieManager: () => {
|
openCookieManager: () => {
|
||||||
const { isGuest } = useUserStore.getState();
|
const { isGuest } = useUserStore.getState();
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ const promptInput: TOpenPromptInput = (props) => {
|
|||||||
size: 400,
|
size: 400,
|
||||||
classNames: {
|
classNames: {
|
||||||
header: 'border-0 pb-0',
|
header: 'border-0 pb-0',
|
||||||
body: 'px-6',
|
body: 'px-6 relative',
|
||||||
content: 'min-h-0',
|
content: 'min-h-0',
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -68,6 +68,7 @@ const promptSaveItem: TOpenPromptSaveItem = (props) => {
|
|||||||
size: 400,
|
size: 400,
|
||||||
classNames: {
|
classNames: {
|
||||||
header: 'border-0 px-6 pt-6 pb-0',
|
header: 'border-0 px-6 pt-6 pb-0',
|
||||||
|
body: 'relative'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -101,7 +102,7 @@ const confirm: TConfirmApi = (props) => {
|
|||||||
size: 400,
|
size: 400,
|
||||||
classNames: {
|
classNames: {
|
||||||
header: 'border-0',
|
header: 'border-0',
|
||||||
body: 'px-6',
|
body: 'px-6 relative',
|
||||||
content: 'min-h-0',
|
content: 'min-h-0',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ export enum EPlatformModalTypes {
|
|||||||
|
|
||||||
// user
|
// user
|
||||||
UserProfile = 'userProfile',
|
UserProfile = 'userProfile',
|
||||||
|
AllInvitation = 'allInvitation',
|
||||||
|
|
||||||
// cookie
|
// cookie
|
||||||
CookieManager = 'cookieManager',
|
CookieManager = 'cookieManager',
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { FC } from 'react';
|
import { FC } from 'react';
|
||||||
import { Drawer as MantineDrawer, DrawerProps, ScrollArea, createStyles } from '@mantine/core';
|
import { Drawer as MantineDrawer, DrawerProps, ScrollArea, createStyles } from '@mantine/core';
|
||||||
import { useDisclosure } from '@mantine/hooks';
|
|
||||||
|
|
||||||
export interface IDrawer extends DrawerProps { }
|
export interface IDrawer extends DrawerProps { }
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,15 @@
|
|||||||
import type { MenuProps } from '@mantine/core';
|
import type { MenuProps } from '@mantine/core';
|
||||||
|
import { ReactNode } from 'react';
|
||||||
|
|
||||||
export interface IDropdownMenu {
|
export interface IDropdownMenu {
|
||||||
|
/**
|
||||||
|
* Add the custom header for options
|
||||||
|
*/
|
||||||
|
header?: ReactNode;
|
||||||
|
/**
|
||||||
|
* Add the custom footer for options
|
||||||
|
*/
|
||||||
|
footer?: ReactNode;
|
||||||
/**
|
/**
|
||||||
* Add id to the dropdown wrapper
|
* Add id to the dropdown wrapper
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -98,9 +98,22 @@ Example.args = {
|
|||||||
prefix: () => <VscMultipleWindows size={18} />,
|
prefix: () => <VscMultipleWindows size={18} />,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
header:
|
||||||
|
<div className="!capitalize !pt-[0.2rem] !pb-2 !px-3 !block !bg-focus2 ">
|
||||||
|
Header title
|
||||||
|
<br />
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
'text-sm font-light leading-3 text-app-foreground-inactive'
|
||||||
|
}
|
||||||
|
>
|
||||||
|
User
|
||||||
|
</div>
|
||||||
|
</div>,
|
||||||
|
footer: <div className='text-center'>3.0.0</div>,
|
||||||
handler: () => <Button text={'Create'} primary ghost xs />,
|
handler: () => <Button text={'Create'} primary ghost xs />,
|
||||||
classNames: {
|
classNames: {
|
||||||
dropdown: '-ml-[2px]',
|
dropdown: '-ml-[2px] pt-0',
|
||||||
},
|
},
|
||||||
onSelect: (value: any) => console.log(`selected item :`, value),
|
onSelect: (value: any) => console.log(`selected item :`, value),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,12 +12,16 @@ enum EDefaultStyles {
|
|||||||
divider = 'bg-app-border border-app-border',
|
divider = 'bg-app-border border-app-border',
|
||||||
disabled = 'opacity-50 cursor-default',
|
disabled = 'opacity-50 cursor-default',
|
||||||
disabledItem = '!text-activityBar-foreground-inactive !cursor-default',
|
disabledItem = '!text-activityBar-foreground-inactive !cursor-default',
|
||||||
|
header = 'text-app-foreground p-0 text-base leading-6',
|
||||||
|
footer = 'text-activityBar-foreground-inactive px-5 py-2 text-sm leading-3',
|
||||||
}
|
}
|
||||||
|
|
||||||
const DropdownMenu: FC<IDropdownMenu> = ({
|
const DropdownMenu: FC<IDropdownMenu> = ({
|
||||||
id = '',
|
id = '',
|
||||||
selected = '',
|
selected = '',
|
||||||
width = 200,
|
width = 200,
|
||||||
|
header,
|
||||||
|
footer,
|
||||||
options = [],
|
options = [],
|
||||||
handler,
|
handler,
|
||||||
classNames = {},
|
classNames = {},
|
||||||
@@ -25,7 +29,7 @@ const DropdownMenu: FC<IDropdownMenu> = ({
|
|||||||
onOpenChange = () => {},
|
onOpenChange = () => {},
|
||||||
disabled = false,
|
disabled = false,
|
||||||
menuProps = {},
|
menuProps = {},
|
||||||
sm = false
|
sm = false,
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<Menu
|
<Menu
|
||||||
@@ -33,7 +37,9 @@ const DropdownMenu: FC<IDropdownMenu> = ({
|
|||||||
shadow="md"
|
shadow="md"
|
||||||
width={width}
|
width={width}
|
||||||
classNames={classNames}
|
classNames={classNames}
|
||||||
onChange={(v) => disabled || options.length === 0 ? {} : onOpenChange(v)}
|
onChange={(v) =>
|
||||||
|
disabled || options.length === 0 ? {} : onOpenChange(v)
|
||||||
|
}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
{...menuProps}
|
{...menuProps}
|
||||||
>
|
>
|
||||||
@@ -51,13 +57,21 @@ const DropdownMenu: FC<IDropdownMenu> = ({
|
|||||||
</Menu.Target>
|
</Menu.Target>
|
||||||
|
|
||||||
<Menu.Dropdown
|
<Menu.Dropdown
|
||||||
className={cx(EDefaultStyles.dropdown,
|
className={cx(
|
||||||
|
EDefaultStyles.dropdown,
|
||||||
{ 'py-2.5': sm },
|
{ 'py-2.5': sm },
|
||||||
{ 'py-[15px]': !sm },
|
{ 'py-[15px]': !sm },
|
||||||
{
|
{
|
||||||
'hidden border-0': options.length === 0,
|
'hidden border-0': options.length === 0,
|
||||||
})}
|
}
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
|
{!!header ? (
|
||||||
|
<Menu.Label className={EDefaultStyles.header}>{header}</Menu.Label>
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
)}
|
||||||
|
|
||||||
{options.map((item, i) => {
|
{options.map((item, i) => {
|
||||||
return (
|
return (
|
||||||
<Fragment key={`menu-item-${i}`}>
|
<Fragment key={`menu-item-${i}`}>
|
||||||
@@ -70,10 +84,10 @@ const DropdownMenu: FC<IDropdownMenu> = ({
|
|||||||
<Menu.Item
|
<Menu.Item
|
||||||
className={cx(
|
className={cx(
|
||||||
{
|
{
|
||||||
[EDefaultStyles.item]: !sm
|
[EDefaultStyles.item]: !sm,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
[EDefaultStyles.itemSmall]: sm
|
[EDefaultStyles.itemSmall]: sm,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'font-bold': selected === item.name,
|
'font-bold': selected === item.name,
|
||||||
@@ -114,6 +128,11 @@ const DropdownMenu: FC<IDropdownMenu> = ({
|
|||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
{!!footer ? (
|
||||||
|
<Menu.Label className={EDefaultStyles.footer}>{footer}</Menu.Label>
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
)}
|
||||||
</Menu.Dropdown>
|
</Menu.Dropdown>
|
||||||
</Menu>
|
</Menu>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -547,6 +547,10 @@
|
|||||||
.\!mb-3{
|
.\!mb-3{
|
||||||
margin-bottom: 0.75rem !important;
|
margin-bottom: 0.75rem !important;
|
||||||
|
|
||||||
|
}
|
||||||
|
.\!mb-4{
|
||||||
|
margin-bottom: 1rem !important;
|
||||||
|
|
||||||
}
|
}
|
||||||
.\!ml-auto{
|
.\!ml-auto{
|
||||||
margin-left: auto !important;
|
margin-left: auto !important;
|
||||||
@@ -751,6 +755,10 @@
|
|||||||
.mt-8{
|
.mt-8{
|
||||||
margin-top: 2rem;
|
margin-top: 2rem;
|
||||||
|
|
||||||
|
}
|
||||||
|
.mt-\[10vh\]{
|
||||||
|
margin-top: 10vh;
|
||||||
|
|
||||||
}
|
}
|
||||||
.mt-\[50\%\]{
|
.mt-\[50\%\]{
|
||||||
margin-top: 50%;
|
margin-top: 50%;
|
||||||
@@ -831,6 +839,10 @@
|
|||||||
.\!h-80{
|
.\!h-80{
|
||||||
height: 20rem !important;
|
height: 20rem !important;
|
||||||
|
|
||||||
|
}
|
||||||
|
.\!h-\[80vh\]{
|
||||||
|
height: 80vh !important;
|
||||||
|
|
||||||
}
|
}
|
||||||
.\!h-fit{
|
.\!h-fit{
|
||||||
height: -moz-fit-content !important;
|
height: -moz-fit-content !important;
|
||||||
@@ -913,37 +925,25 @@
|
|||||||
height: 340px;
|
height: 340px;
|
||||||
|
|
||||||
}
|
}
|
||||||
.h-\[450px\]{
|
.h-\[34px\]{
|
||||||
height: 450px;
|
height: 34px;
|
||||||
|
|
||||||
}
|
|
||||||
.h-\[480px\]{
|
|
||||||
height: 480px;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
.h-\[50vh\]{
|
.h-\[50vh\]{
|
||||||
height: 50vh;
|
height: 50vh;
|
||||||
|
|
||||||
}
|
|
||||||
.h-\[600px\]{
|
|
||||||
height: 600px;
|
|
||||||
|
|
||||||
}
|
|
||||||
.h-\[700px\]{
|
|
||||||
height: 700px;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
.h-\[70vh\]{
|
.h-\[70vh\]{
|
||||||
height: 70vh;
|
height: 70vh;
|
||||||
|
|
||||||
}
|
|
||||||
.h-\[750px\]{
|
|
||||||
height: 750px;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
.h-\[80vh\]{
|
.h-\[80vh\]{
|
||||||
height: 80vh;
|
height: 80vh;
|
||||||
|
|
||||||
|
}
|
||||||
|
.h-\[90vh\]{
|
||||||
|
height: 90vh;
|
||||||
|
|
||||||
}
|
}
|
||||||
.h-fit{
|
.h-fit{
|
||||||
height: -moz-fit-content;
|
height: -moz-fit-content;
|
||||||
@@ -973,6 +973,10 @@
|
|||||||
.max-h-56{
|
.max-h-56{
|
||||||
max-height: 14rem;
|
max-height: 14rem;
|
||||||
|
|
||||||
|
}
|
||||||
|
.max-h-\[200px\]{
|
||||||
|
max-height: 200px;
|
||||||
|
|
||||||
}
|
}
|
||||||
.min-h-0{
|
.min-h-0{
|
||||||
min-height: 0px;
|
min-height: 0px;
|
||||||
@@ -2423,6 +2427,12 @@
|
|||||||
--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);
|
--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);
|
||||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||||
|
|
||||||
|
}
|
||||||
|
.shadow-sm{
|
||||||
|
--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);
|
||||||
|
--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);
|
||||||
|
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||||
|
|
||||||
}
|
}
|
||||||
.\!shadow-popover-shadow{
|
.\!shadow-popover-shadow{
|
||||||
--tw-shadow-color: var(--popover-shadow) !important;
|
--tw-shadow-color: var(--popover-shadow) !important;
|
||||||
|
|||||||
@@ -106,8 +106,6 @@ const BodyTab: FC<any> = () => {
|
|||||||
return <BinaryBody body={body || {}} onChange={changeBodyValue} />;
|
return <BinaryBody body={body || {}} onChange={changeBodyValue} />;
|
||||||
case ERestBodyTypes.GraphQL:
|
case ERestBodyTypes.GraphQL:
|
||||||
return <GraphQLBody body={body || {}} onChange={changeBodyValue} />;
|
return <GraphQLBody body={body || {}} onChange={changeBodyValue} />;
|
||||||
case ERestBodyTypes.None:
|
|
||||||
return <NoBodyTab selectBodyType={_selectBodyType} />;
|
|
||||||
default:
|
default:
|
||||||
return <></>;
|
return <></>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -112,6 +112,7 @@ const SIOVersionDropDown: FC<any> = ({
|
|||||||
className={cx({ 'transform rotate-180': isDropDownOpen })}
|
className={cx({ 'transform rotate-180': isDropDownOpen })}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
animate={false}
|
||||||
secondary
|
secondary
|
||||||
xs
|
xs
|
||||||
/>
|
/>
|
||||||
|
|||||||
165
pnpm-lock.yaml
generated
165
pnpm-lock.yaml
generated
@@ -135,6 +135,9 @@ importers:
|
|||||||
node-polyfill-webpack-plugin:
|
node-polyfill-webpack-plugin:
|
||||||
specifier: ^2.0.0
|
specifier: ^2.0.0
|
||||||
version: 2.0.1(webpack@5.75.0)
|
version: 2.0.1(webpack@5.75.0)
|
||||||
|
npm-run-all:
|
||||||
|
specifier: ^4.1.5
|
||||||
|
version: 4.1.5
|
||||||
postcss-loader:
|
postcss-loader:
|
||||||
specifier: ^7.0.2
|
specifier: ^7.0.2
|
||||||
version: 7.0.2(postcss@8.4.27)(webpack@5.75.0)
|
version: 7.0.2(postcss@8.4.27)(webpack@5.75.0)
|
||||||
@@ -162,6 +165,9 @@ importers:
|
|||||||
style-loader:
|
style-loader:
|
||||||
specifier: ^3.3.1
|
specifier: ^3.3.1
|
||||||
version: 3.3.1(webpack@5.75.0)
|
version: 3.3.1(webpack@5.75.0)
|
||||||
|
terser-webpack-plugin:
|
||||||
|
specifier: ^5.3.9
|
||||||
|
version: 5.3.9(webpack@5.75.0)
|
||||||
ts-loader:
|
ts-loader:
|
||||||
specifier: ^9.2.8
|
specifier: ^9.2.8
|
||||||
version: 9.4.2(typescript@5.0.2)(webpack@5.75.0)
|
version: 9.4.2(typescript@5.0.2)(webpack@5.75.0)
|
||||||
@@ -192,6 +198,9 @@ importers:
|
|||||||
webpack-httpolyglot-server:
|
webpack-httpolyglot-server:
|
||||||
specifier: ^0.3.0
|
specifier: ^0.3.0
|
||||||
version: 0.3.0(webpack@5.75.0)
|
version: 0.3.0(webpack@5.75.0)
|
||||||
|
webpack-merge:
|
||||||
|
specifier: ^5.9.0
|
||||||
|
version: 5.9.0
|
||||||
worker-loader:
|
worker-loader:
|
||||||
specifier: ^3.0.8
|
specifier: ^3.0.8
|
||||||
version: 3.0.8(webpack@5.75.0)
|
version: 3.0.8(webpack@5.75.0)
|
||||||
@@ -478,8 +487,8 @@ importers:
|
|||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../packages/firecamp-agent-manager
|
version: link:../../packages/firecamp-agent-manager
|
||||||
'@firecamp/cloud-apis':
|
'@firecamp/cloud-apis':
|
||||||
specifier: ^0.2.8
|
specifier: 0.2.10
|
||||||
version: 0.2.8
|
version: 0.2.10
|
||||||
'@firecamp/cookie-manager':
|
'@firecamp/cookie-manager':
|
||||||
specifier: ^0.0.0
|
specifier: ^0.0.0
|
||||||
version: link:../../packages/firecamp-cookie-manager
|
version: link:../../packages/firecamp-cookie-manager
|
||||||
@@ -5011,8 +5020,8 @@ packages:
|
|||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@firecamp/cloud-apis@0.2.8:
|
/@firecamp/cloud-apis@0.2.10:
|
||||||
resolution: {integrity: sha512-RYgD/d39YyN91chDESwdGDUdK6Ph9oX14y1HXnMfACnEnviOtCQkMkjBLu0RoSPfqHiLJe8PopgASfv/XOAT7g==}
|
resolution: {integrity: sha512-aWTxsmfUygfa0Tv9TaRUhbNPTP9I6CVjJhrY9kLJwdtzRcbg5jW7oqnD1HEl0662pwPyYJ1weC3XOo2/cJJ+JQ==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
dependencies:
|
dependencies:
|
||||||
axios: 0.21.4
|
axios: 0.21.4
|
||||||
@@ -10220,6 +10229,7 @@ packages:
|
|||||||
|
|
||||||
/async-each@1.0.3:
|
/async-each@1.0.3:
|
||||||
resolution: {integrity: sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==}
|
resolution: {integrity: sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==}
|
||||||
|
requiresBuild: true
|
||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -10831,6 +10841,7 @@ packages:
|
|||||||
/big-integer@1.6.51:
|
/big-integer@1.6.51:
|
||||||
resolution: {integrity: sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==}
|
resolution: {integrity: sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==}
|
||||||
engines: {node: '>=0.6'}
|
engines: {node: '>=0.6'}
|
||||||
|
requiresBuild: true
|
||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -10845,6 +10856,7 @@ packages:
|
|||||||
/binary-extensions@1.13.1:
|
/binary-extensions@1.13.1:
|
||||||
resolution: {integrity: sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==}
|
resolution: {integrity: sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
requiresBuild: true
|
||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -10945,6 +10957,7 @@ packages:
|
|||||||
|
|
||||||
/bplist-parser@0.1.1:
|
/bplist-parser@0.1.1:
|
||||||
resolution: {integrity: sha512-2AEM0FXy8ZxVLBuqX0hqt1gDwcnz2zygEkQ6zaD5Wko/sB9paUNwlpawrFtKeHUAQUOzjVy9AO4oeonqIHKA9Q==}
|
resolution: {integrity: sha512-2AEM0FXy8ZxVLBuqX0hqt1gDwcnz2zygEkQ6zaD5Wko/sB9paUNwlpawrFtKeHUAQUOzjVy9AO4oeonqIHKA9Q==}
|
||||||
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
big-integer: 1.6.51
|
big-integer: 1.6.51
|
||||||
dev: true
|
dev: true
|
||||||
@@ -11289,6 +11302,7 @@ packages:
|
|||||||
/camelcase-keys@2.1.0:
|
/camelcase-keys@2.1.0:
|
||||||
resolution: {integrity: sha512-bA/Z/DERHKqoEOrp+qeGKw1QlvEQkGZSc0XaY6VnTxZr+Kv1G5zFwttpjv8qxZ/sBPT4nthwZaAcsAZTJlSKXQ==}
|
resolution: {integrity: sha512-bA/Z/DERHKqoEOrp+qeGKw1QlvEQkGZSc0XaY6VnTxZr+Kv1G5zFwttpjv8qxZ/sBPT4nthwZaAcsAZTJlSKXQ==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
camelcase: 2.1.1
|
camelcase: 2.1.1
|
||||||
map-obj: 1.0.1
|
map-obj: 1.0.1
|
||||||
@@ -11312,6 +11326,7 @@ packages:
|
|||||||
/camelcase@2.1.1:
|
/camelcase@2.1.1:
|
||||||
resolution: {integrity: sha512-DLIsRzJVBQu72meAKPkWQOLcujdXT32hwdfnkI1frSiSRMK1MofjKHf+MEx0SB6fjEFXL8fBDv1dKymBlOp4Qw==}
|
resolution: {integrity: sha512-DLIsRzJVBQu72meAKPkWQOLcujdXT32hwdfnkI1frSiSRMK1MofjKHf+MEx0SB6fjEFXL8fBDv1dKymBlOp4Qw==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
requiresBuild: true
|
||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -11476,6 +11491,7 @@ packages:
|
|||||||
/chokidar@2.1.8:
|
/chokidar@2.1.8:
|
||||||
resolution: {integrity: sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==}
|
resolution: {integrity: sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==}
|
||||||
deprecated: Chokidar 2 does not receive security updates since 2019. Upgrade to chokidar 3 with 15x fewer dependencies
|
deprecated: Chokidar 2 does not receive security updates since 2019. Upgrade to chokidar 3 with 15x fewer dependencies
|
||||||
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
anymatch: 2.0.0
|
anymatch: 2.0.0
|
||||||
async-each: 1.0.3
|
async-each: 1.0.3
|
||||||
@@ -11927,7 +11943,7 @@ packages:
|
|||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
/concat-map@0.0.1:
|
/concat-map@0.0.1:
|
||||||
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
|
resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=}
|
||||||
|
|
||||||
/concat-stream@1.4.11:
|
/concat-stream@1.4.11:
|
||||||
resolution: {integrity: sha512-X3JMh8+4je3U1cQpG87+f9lXHDrqcb2MVLg9L7o8b1UZ0DzhRrUpdn65ttzu10PpJPPI3MQNkis+oha6TSA9Mw==}
|
resolution: {integrity: sha512-X3JMh8+4je3U1cQpG87+f9lXHDrqcb2MVLg9L7o8b1UZ0DzhRrUpdn65ttzu10PpJPPI3MQNkis+oha6TSA9Mw==}
|
||||||
@@ -14564,6 +14580,7 @@ packages:
|
|||||||
/find-up@1.1.2:
|
/find-up@1.1.2:
|
||||||
resolution: {integrity: sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==}
|
resolution: {integrity: sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
path-exists: 2.1.0
|
path-exists: 2.1.0
|
||||||
pinkie-promise: 2.0.1
|
pinkie-promise: 2.0.1
|
||||||
@@ -15030,6 +15047,7 @@ packages:
|
|||||||
/get-stdin@4.0.1:
|
/get-stdin@4.0.1:
|
||||||
resolution: {integrity: sha512-F5aQMywwJ2n85s4hJPTT9RPxGmubonuB10MNYo17/xph174n2MIR33HRguhzVag10O/npM7SPk73LMZNP+FaWw==}
|
resolution: {integrity: sha512-F5aQMywwJ2n85s4hJPTT9RPxGmubonuB10MNYo17/xph174n2MIR33HRguhzVag10O/npM7SPk73LMZNP+FaWw==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
requiresBuild: true
|
||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -16071,6 +16089,7 @@ packages:
|
|||||||
/indent-string@2.1.0:
|
/indent-string@2.1.0:
|
||||||
resolution: {integrity: sha512-aqwDFWSgSgfRaEwao5lg5KEcVd/2a+D1rvoG7NdilmYz0NwRk6StWpWdz/Hpk34MKPpx7s8XxUqimfcQK6gGlg==}
|
resolution: {integrity: sha512-aqwDFWSgSgfRaEwao5lg5KEcVd/2a+D1rvoG7NdilmYz0NwRk6StWpWdz/Hpk34MKPpx7s8XxUqimfcQK6gGlg==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
repeating: 2.0.1
|
repeating: 2.0.1
|
||||||
dev: true
|
dev: true
|
||||||
@@ -16220,6 +16239,7 @@ packages:
|
|||||||
/is-binary-path@1.0.1:
|
/is-binary-path@1.0.1:
|
||||||
resolution: {integrity: sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==}
|
resolution: {integrity: sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
binary-extensions: 1.13.1
|
binary-extensions: 1.13.1
|
||||||
dev: true
|
dev: true
|
||||||
@@ -16353,6 +16373,7 @@ packages:
|
|||||||
/is-finite@1.1.0:
|
/is-finite@1.1.0:
|
||||||
resolution: {integrity: sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==}
|
resolution: {integrity: sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
requiresBuild: true
|
||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -16584,6 +16605,7 @@ packages:
|
|||||||
|
|
||||||
/is-utf8@0.2.1:
|
/is-utf8@0.2.1:
|
||||||
resolution: {integrity: sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==}
|
resolution: {integrity: sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==}
|
||||||
|
requiresBuild: true
|
||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -18469,6 +18491,7 @@ packages:
|
|||||||
/load-json-file@1.1.0:
|
/load-json-file@1.1.0:
|
||||||
resolution: {integrity: sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==}
|
resolution: {integrity: sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
graceful-fs: 4.2.11
|
graceful-fs: 4.2.11
|
||||||
parse-json: 2.2.0
|
parse-json: 2.2.0
|
||||||
@@ -18980,6 +19003,7 @@ packages:
|
|||||||
/meow@3.7.0:
|
/meow@3.7.0:
|
||||||
resolution: {integrity: sha512-TNdwZs0skRlpPpCUK25StC4VH+tP5GgeY1HQOOGP+lQ2xtdkN2VtT/5tiX9k3IWpkBPV9b3LsAWXn4GGi/PrSA==}
|
resolution: {integrity: sha512-TNdwZs0skRlpPpCUK25StC4VH+tP5GgeY1HQOOGP+lQ2xtdkN2VtT/5tiX9k3IWpkBPV9b3LsAWXn4GGi/PrSA==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
camelcase-keys: 2.1.0
|
camelcase-keys: 2.1.0
|
||||||
decamelize: 1.2.0
|
decamelize: 1.2.0
|
||||||
@@ -20172,6 +20196,7 @@ packages:
|
|||||||
/parse-json@2.2.0:
|
/parse-json@2.2.0:
|
||||||
resolution: {integrity: sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==}
|
resolution: {integrity: sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
error-ex: 1.3.2
|
error-ex: 1.3.2
|
||||||
dev: true
|
dev: true
|
||||||
@@ -20256,11 +20281,13 @@ packages:
|
|||||||
|
|
||||||
/path-dirname@1.0.2:
|
/path-dirname@1.0.2:
|
||||||
resolution: {integrity: sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==}
|
resolution: {integrity: sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==}
|
||||||
|
requiresBuild: true
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/path-exists@2.1.0:
|
/path-exists@2.1.0:
|
||||||
resolution: {integrity: sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==}
|
resolution: {integrity: sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
pinkie-promise: 2.0.1
|
pinkie-promise: 2.0.1
|
||||||
dev: true
|
dev: true
|
||||||
@@ -20310,6 +20337,7 @@ packages:
|
|||||||
/path-type@1.1.0:
|
/path-type@1.1.0:
|
||||||
resolution: {integrity: sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==}
|
resolution: {integrity: sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
graceful-fs: 4.2.11
|
graceful-fs: 4.2.11
|
||||||
pify: 2.3.0
|
pify: 2.3.0
|
||||||
@@ -20402,6 +20430,7 @@ packages:
|
|||||||
/pinkie-promise@2.0.1:
|
/pinkie-promise@2.0.1:
|
||||||
resolution: {integrity: sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==}
|
resolution: {integrity: sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
pinkie: 2.0.4
|
pinkie: 2.0.4
|
||||||
dev: true
|
dev: true
|
||||||
@@ -20415,6 +20444,7 @@ packages:
|
|||||||
/pinkie@2.0.4:
|
/pinkie@2.0.4:
|
||||||
resolution: {integrity: sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==}
|
resolution: {integrity: sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
requiresBuild: true
|
||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -21583,6 +21613,7 @@ packages:
|
|||||||
/read-pkg-up@1.0.1:
|
/read-pkg-up@1.0.1:
|
||||||
resolution: {integrity: sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==}
|
resolution: {integrity: sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
find-up: 1.1.2
|
find-up: 1.1.2
|
||||||
read-pkg: 1.1.0
|
read-pkg: 1.1.0
|
||||||
@@ -21609,6 +21640,7 @@ packages:
|
|||||||
/read-pkg@1.1.0:
|
/read-pkg@1.1.0:
|
||||||
resolution: {integrity: sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==}
|
resolution: {integrity: sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
load-json-file: 1.1.0
|
load-json-file: 1.1.0
|
||||||
normalize-package-data: 2.5.0
|
normalize-package-data: 2.5.0
|
||||||
@@ -21689,6 +21721,7 @@ packages:
|
|||||||
/readdirp@2.2.1:
|
/readdirp@2.2.1:
|
||||||
resolution: {integrity: sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==}
|
resolution: {integrity: sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==}
|
||||||
engines: {node: '>=0.10'}
|
engines: {node: '>=0.10'}
|
||||||
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
graceful-fs: 4.2.11
|
graceful-fs: 4.2.11
|
||||||
micromatch: 3.1.10
|
micromatch: 3.1.10
|
||||||
@@ -21720,6 +21753,7 @@ packages:
|
|||||||
/redent@1.0.0:
|
/redent@1.0.0:
|
||||||
resolution: {integrity: sha512-qtW5hKzGQZqKoh6JNSD+4lfitfPKGz42e6QwiRmPM5mmKtR0N41AbJRYu0xJi7nhOJ4WDgRkKvAk6tw4WIwR4g==}
|
resolution: {integrity: sha512-qtW5hKzGQZqKoh6JNSD+4lfitfPKGz42e6QwiRmPM5mmKtR0N41AbJRYu0xJi7nhOJ4WDgRkKvAk6tw4WIwR4g==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
indent-string: 2.1.0
|
indent-string: 2.1.0
|
||||||
strip-indent: 1.0.1
|
strip-indent: 1.0.1
|
||||||
@@ -21931,6 +21965,7 @@ packages:
|
|||||||
/repeating@2.0.1:
|
/repeating@2.0.1:
|
||||||
resolution: {integrity: sha512-ZqtSMuVybkISo2OWvqvm7iHSWngvdaW3IpsT9/uP8v4gMi591LY6h35wdOfvQdWCKFWZWm2Y1Opp4kV7vQKT6A==}
|
resolution: {integrity: sha512-ZqtSMuVybkISo2OWvqvm7iHSWngvdaW3IpsT9/uP8v4gMi591LY6h35wdOfvQdWCKFWZWm2Y1Opp4kV7vQKT6A==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
is-finite: 1.1.0
|
is-finite: 1.1.0
|
||||||
dev: true
|
dev: true
|
||||||
@@ -23255,6 +23290,7 @@ packages:
|
|||||||
/strip-bom@2.0.0:
|
/strip-bom@2.0.0:
|
||||||
resolution: {integrity: sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==}
|
resolution: {integrity: sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
is-utf8: 0.2.1
|
is-utf8: 0.2.1
|
||||||
dev: true
|
dev: true
|
||||||
@@ -23288,6 +23324,7 @@ packages:
|
|||||||
resolution: {integrity: sha512-I5iQq6aFMM62fBEAIB/hXzwJD6EEZ0xEGCX2t7oXqaKPIRgt4WruAQ285BISgdkP+HLGWyeGmNJcpIwFeRYRUA==}
|
resolution: {integrity: sha512-I5iQq6aFMM62fBEAIB/hXzwJD6EEZ0xEGCX2t7oXqaKPIRgt4WruAQ285BISgdkP+HLGWyeGmNJcpIwFeRYRUA==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
get-stdin: 4.0.1
|
get-stdin: 4.0.1
|
||||||
dev: true
|
dev: true
|
||||||
@@ -23659,6 +23696,53 @@ packages:
|
|||||||
serialize-javascript: 6.0.1
|
serialize-javascript: 6.0.1
|
||||||
terser: 5.16.1
|
terser: 5.16.1
|
||||||
webpack: 5.75.0(webpack-cli@5.0.1)
|
webpack: 5.75.0(webpack-cli@5.0.1)
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/terser-webpack-plugin@5.3.9(webpack@5.75.0):
|
||||||
|
resolution: {integrity: sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==}
|
||||||
|
engines: {node: '>= 10.13.0'}
|
||||||
|
peerDependencies:
|
||||||
|
'@swc/core': '*'
|
||||||
|
esbuild: '*'
|
||||||
|
uglify-js: '*'
|
||||||
|
webpack: ^5.1.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@swc/core':
|
||||||
|
optional: true
|
||||||
|
esbuild:
|
||||||
|
optional: true
|
||||||
|
uglify-js:
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@jridgewell/trace-mapping': 0.3.17
|
||||||
|
jest-worker: 27.5.1
|
||||||
|
schema-utils: 3.1.1
|
||||||
|
serialize-javascript: 6.0.1
|
||||||
|
terser: 5.19.2
|
||||||
|
webpack: 5.75.0(webpack-cli@5.0.1)
|
||||||
|
|
||||||
|
/terser-webpack-plugin@5.3.9(webpack@5.88.2):
|
||||||
|
resolution: {integrity: sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==}
|
||||||
|
engines: {node: '>= 10.13.0'}
|
||||||
|
peerDependencies:
|
||||||
|
'@swc/core': '*'
|
||||||
|
esbuild: '*'
|
||||||
|
uglify-js: '*'
|
||||||
|
webpack: ^5.1.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@swc/core':
|
||||||
|
optional: true
|
||||||
|
esbuild:
|
||||||
|
optional: true
|
||||||
|
uglify-js:
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@jridgewell/trace-mapping': 0.3.18
|
||||||
|
jest-worker: 27.5.1
|
||||||
|
schema-utils: 3.3.0
|
||||||
|
serialize-javascript: 6.0.1
|
||||||
|
terser: 5.19.2
|
||||||
|
webpack: 5.88.2(webpack-cli@5.0.1)
|
||||||
|
|
||||||
/terser-webpack-plugin@5.3.9(webpack@5.88.2):
|
/terser-webpack-plugin@5.3.9(webpack@5.88.2):
|
||||||
resolution: {integrity: sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==}
|
resolution: {integrity: sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==}
|
||||||
@@ -23703,6 +23787,27 @@ packages:
|
|||||||
acorn: 8.8.2
|
acorn: 8.8.2
|
||||||
commander: 2.20.3
|
commander: 2.20.3
|
||||||
source-map-support: 0.5.21
|
source-map-support: 0.5.21
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/terser@5.19.2:
|
||||||
|
resolution: {integrity: sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
hasBin: true
|
||||||
|
dependencies:
|
||||||
|
'@jridgewell/source-map': 0.3.5
|
||||||
|
acorn: 8.8.2
|
||||||
|
commander: 2.20.3
|
||||||
|
source-map-support: 0.5.21
|
||||||
|
|
||||||
|
/terser@5.19.2:
|
||||||
|
resolution: {integrity: sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
hasBin: true
|
||||||
|
dependencies:
|
||||||
|
'@jridgewell/source-map': 0.3.5
|
||||||
|
acorn: 8.10.0
|
||||||
|
commander: 2.20.3
|
||||||
|
source-map-support: 0.5.21
|
||||||
|
|
||||||
/terser@5.19.2:
|
/terser@5.19.2:
|
||||||
resolution: {integrity: sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA==}
|
resolution: {integrity: sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA==}
|
||||||
@@ -23897,6 +24002,7 @@ packages:
|
|||||||
/trim-newlines@1.0.0:
|
/trim-newlines@1.0.0:
|
||||||
resolution: {integrity: sha512-Nm4cF79FhSTzrLKGDMi3I4utBtFv8qKy4sq1enftf2gMdpqI8oVQTAfySkTz5r49giVzDj88SVZXP4CeYQwjaw==}
|
resolution: {integrity: sha512-Nm4cF79FhSTzrLKGDMi3I4utBtFv8qKy4sq1enftf2gMdpqI8oVQTAfySkTz5r49giVzDj88SVZXP4CeYQwjaw==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
requiresBuild: true
|
||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -24593,6 +24699,7 @@ packages:
|
|||||||
/untildify@2.1.0:
|
/untildify@2.1.0:
|
||||||
resolution: {integrity: sha512-sJjbDp2GodvkB0FZZcn7k6afVisqX5BZD7Yq3xp4nN2O15BBK0cLm3Vwn2vQaF7UDS0UUsrQMkkplmDI5fskig==}
|
resolution: {integrity: sha512-sJjbDp2GodvkB0FZZcn7k6afVisqX5BZD7Yq3xp4nN2O15BBK0cLm3Vwn2vQaF7UDS0UUsrQMkkplmDI5fskig==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
os-homedir: 1.0.2
|
os-homedir: 1.0.2
|
||||||
dev: true
|
dev: true
|
||||||
@@ -25059,7 +25166,7 @@ packages:
|
|||||||
webpack: 5.75.0(webpack-cli@5.0.1)
|
webpack: 5.75.0(webpack-cli@5.0.1)
|
||||||
webpack-bundle-analyzer: 4.7.0
|
webpack-bundle-analyzer: 4.7.0
|
||||||
webpack-dev-server: 4.11.1(webpack-cli@5.0.1)(webpack@5.75.0)
|
webpack-dev-server: 4.11.1(webpack-cli@5.0.1)(webpack@5.75.0)
|
||||||
webpack-merge: 5.8.0
|
webpack-merge: 5.9.0
|
||||||
|
|
||||||
/webpack-dev-middleware@2.0.6(webpack@5.75.0):
|
/webpack-dev-middleware@2.0.6(webpack@5.75.0):
|
||||||
resolution: {integrity: sha512-tj5LLD9r4tDuRIDa5Mu9lnY2qBBehAITv6A9irqXhw/HQquZgTx3BCd57zYbU2gMDnncA49ufK2qVQSbaKJwOw==}
|
resolution: {integrity: sha512-tj5LLD9r4tDuRIDa5Mu9lnY2qBBehAITv6A9irqXhw/HQquZgTx3BCd57zYbU2gMDnncA49ufK2qVQSbaKJwOw==}
|
||||||
@@ -25226,8 +25333,8 @@ packages:
|
|||||||
uuid: 3.4.0
|
uuid: 3.4.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/webpack-merge@5.8.0:
|
/webpack-merge@5.9.0:
|
||||||
resolution: {integrity: sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==}
|
resolution: {integrity: sha512-6NbRQw4+Sy50vYNTw7EyOn41OZItPiXB8GNv3INSoe3PSFaHJEz3SHTrYVaRm2LilNGnFUzh0FAwqPEmU/CwDg==}
|
||||||
engines: {node: '>=10.0.0'}
|
engines: {node: '>=10.0.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
clone-deep: 4.0.1
|
clone-deep: 4.0.1
|
||||||
@@ -25328,7 +25435,47 @@ packages:
|
|||||||
neo-async: 2.6.2
|
neo-async: 2.6.2
|
||||||
schema-utils: 3.1.1
|
schema-utils: 3.1.1
|
||||||
tapable: 2.2.1
|
tapable: 2.2.1
|
||||||
terser-webpack-plugin: 5.3.6(webpack@5.75.0)
|
terser-webpack-plugin: 5.3.9(webpack@5.75.0)
|
||||||
|
watchpack: 2.4.0
|
||||||
|
webpack-cli: 5.0.1(webpack-bundle-analyzer@4.7.0)(webpack-dev-server@4.11.1)(webpack@5.75.0)
|
||||||
|
webpack-sources: 3.2.3
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- '@swc/core'
|
||||||
|
- esbuild
|
||||||
|
- uglify-js
|
||||||
|
|
||||||
|
/webpack@5.88.2(webpack-cli@5.0.1):
|
||||||
|
resolution: {integrity: sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ==}
|
||||||
|
engines: {node: '>=10.13.0'}
|
||||||
|
hasBin: true
|
||||||
|
peerDependencies:
|
||||||
|
webpack-cli: '*'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
webpack-cli:
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@types/eslint-scope': 3.7.4
|
||||||
|
'@types/estree': 1.0.1
|
||||||
|
'@webassemblyjs/ast': 1.11.6
|
||||||
|
'@webassemblyjs/wasm-edit': 1.11.6
|
||||||
|
'@webassemblyjs/wasm-parser': 1.11.6
|
||||||
|
acorn: 8.10.0
|
||||||
|
acorn-import-assertions: 1.9.0(acorn@8.10.0)
|
||||||
|
browserslist: 4.21.9
|
||||||
|
chrome-trace-event: 1.0.3
|
||||||
|
enhanced-resolve: 5.15.0
|
||||||
|
es-module-lexer: 1.3.0
|
||||||
|
eslint-scope: 5.1.1
|
||||||
|
events: 3.3.0
|
||||||
|
glob-to-regexp: 0.4.1
|
||||||
|
graceful-fs: 4.2.11
|
||||||
|
json-parse-even-better-errors: 2.3.1
|
||||||
|
loader-runner: 4.3.0
|
||||||
|
mime-types: 2.1.35
|
||||||
|
neo-async: 2.6.2
|
||||||
|
schema-utils: 3.3.0
|
||||||
|
tapable: 2.2.1
|
||||||
|
terser-webpack-plugin: 5.3.9(webpack@5.88.2)
|
||||||
watchpack: 2.4.0
|
watchpack: 2.4.0
|
||||||
webpack-cli: 5.0.1(webpack-bundle-analyzer@4.7.0)(webpack-dev-server@4.11.1)(webpack@5.75.0)
|
webpack-cli: 5.0.1(webpack-bundle-analyzer@4.7.0)(webpack-dev-server@4.11.1)(webpack@5.75.0)
|
||||||
webpack-sources: 3.2.3
|
webpack-sources: 3.2.3
|
||||||
|
|||||||
@@ -1,45 +0,0 @@
|
|||||||
/* eslint-disable no-console */
|
|
||||||
require('dotenv').config();
|
|
||||||
const fs = require('fs');
|
|
||||||
const path = require('path');
|
|
||||||
require('shelljs/global');
|
|
||||||
const { Environment, AppFormat } = require('./constants');
|
|
||||||
const build = require('../webpack.prod');
|
|
||||||
|
|
||||||
const env = process.env.NODE_ENV;
|
|
||||||
|
|
||||||
module.exports = async () => {
|
|
||||||
try {
|
|
||||||
// hold the build path as per the environment mode
|
|
||||||
const buildPath = path.join(`${__dirname}/../build/${env}`);
|
|
||||||
// copy project assets and generate config.
|
|
||||||
const directoryPaths = [path.join(`${__dirname}/../build`), buildPath];
|
|
||||||
|
|
||||||
// Remove build before start bundle
|
|
||||||
rm('-rf', buildPath);
|
|
||||||
|
|
||||||
// Create build directories
|
|
||||||
directoryPaths.forEach((directoryPath) => {
|
|
||||||
if (!fs.existsSync(directoryPath)) mkdir(directoryPath);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Copy react app assets
|
|
||||||
cp(
|
|
||||||
'-R',
|
|
||||||
path.join(`${__dirname}/../platform/firecamp-platform/public/assets/*`),
|
|
||||||
buildPath
|
|
||||||
);
|
|
||||||
|
|
||||||
// generate package.json and manifest based on app environment
|
|
||||||
// exec(`node ${buildPath}/build-scripts/init-package.js`);
|
|
||||||
|
|
||||||
if (env === Environment.Production || env === Environment.Staging) {
|
|
||||||
await build();
|
|
||||||
}
|
|
||||||
return Promise.resolve();
|
|
||||||
} catch (error) {
|
|
||||||
return Promise.reject(error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (env === Environment.Development) module.exports();
|
|
||||||
@@ -1,21 +1,12 @@
|
|||||||
/* eslint-disable no-console */
|
/* eslint-disable no-console */
|
||||||
require('dotenv-vault-core').config();
|
require('dotenv-vault-core').config();
|
||||||
const { red, yellow } = require('colors');
|
const { red, yellow } = require('colors');
|
||||||
const semver = require('semver');
|
// const semver = require('semver');
|
||||||
require('shelljs/global');
|
require('shelljs/global');
|
||||||
const build = require('./build');
|
|
||||||
const { version } = require('../package.json');
|
const { version } = require('../package.json');
|
||||||
const { Environment, AppFormat } = require('./constants');
|
const { Environment } = require('./constants');
|
||||||
|
|
||||||
const env = process.env.NODE_ENV;
|
const env = process.env.NODE_ENV;
|
||||||
const helper = {
|
|
||||||
buildWebApp: async () => {
|
|
||||||
process.env.NODE_OPTIONS = '--max-old-space-size=4096';
|
|
||||||
await build();
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// set app version in the environment
|
|
||||||
process.env.APP_VERSION = version;
|
process.env.APP_VERSION = version;
|
||||||
|
|
||||||
// check FIRECAMP_API_HOST env. variable value does not contains invalid value
|
// check FIRECAMP_API_HOST env. variable value does not contains invalid value
|
||||||
@@ -33,20 +24,5 @@ if (
|
|||||||
process.env.FIRECAMP_API_HOST
|
process.env.FIRECAMP_API_HOST
|
||||||
)})`
|
)})`
|
||||||
);
|
);
|
||||||
process.exit();
|
process.exit(1);
|
||||||
}
|
|
||||||
|
|
||||||
const preBuildCliCommands = async () => {
|
|
||||||
// pre conditions can be validated here
|
|
||||||
return Promise.resolve();
|
|
||||||
};
|
|
||||||
|
|
||||||
if ([Environment.Production, Environment.Staging].includes(env)) {
|
|
||||||
try {
|
|
||||||
preBuildCliCommands().then(async () => {
|
|
||||||
await helper.buildWebApp();
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<title>Firecamp, API campsite for developers.</title>
|
<title>Firecamp, API campsite for developers.</title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<meta NAME="robots" CONTENT="noindex,nofollow">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
@@ -2,11 +2,47 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<title>Firecamp, API campsite for developers.</title>
|
<!-- HTML Meta Tags -->
|
||||||
|
<title>Firecamp, The API Campsite for Developers.</title>
|
||||||
|
<meta
|
||||||
|
name="description"
|
||||||
|
content="Build APIs 3x faster with Firecamp's features like team collaboration, API documentation, API collection etc. Boost your confidence to build APIs for millions of users with Firecamp's simple, powerful, and open-source platform."
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- Facebook Meta Tags -->
|
||||||
|
<meta property="og:url" content="https://firecamp.dev/" />
|
||||||
|
<meta property="og:type" content="website" />
|
||||||
|
<meta
|
||||||
|
property="og:title"
|
||||||
|
content="Firecamp, The API Campsite for Developers."
|
||||||
|
/>
|
||||||
|
<meta
|
||||||
|
property="og:description"
|
||||||
|
content="Build APIs 3x faster with Firecamp's features like team collaboration, API documentation, API collection etc. Boost your confidence to build APIs for millions of users with Firecamp's simple, powerful, and open-source platform."
|
||||||
|
/>
|
||||||
|
<meta property="og:image" content="https://firecamp.io/og.png" />
|
||||||
|
|
||||||
|
<!-- Twitter Meta Tags -->
|
||||||
|
<meta name="twitter:card" content="summary_large_image" />
|
||||||
|
<meta property="twitter:domain" content="firecamp.dev" />
|
||||||
|
<meta property="twitter:url" content="https://firecamp.dev/" />
|
||||||
|
<meta
|
||||||
|
name="twitter:title"
|
||||||
|
content="Firecamp, The API Campsite for Developers."
|
||||||
|
/>
|
||||||
|
<meta
|
||||||
|
name="twitter:description"
|
||||||
|
content="Build APIs 3x faster with Firecamp's features like team collaboration, API documentation, API collection etc. Boost your confidence to build APIs for millions of users with Firecamp's simple, powerful, and open-source platform."
|
||||||
|
/>
|
||||||
|
<meta name="twitter:image" content="https://firecamp.io/og.png" />
|
||||||
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests" />
|
<meta
|
||||||
|
http-equiv="Content-Security-Policy"
|
||||||
|
content="upgrade-insecure-requests"
|
||||||
|
/>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -2,132 +2,26 @@
|
|||||||
require('dotenv').config();
|
require('dotenv').config();
|
||||||
/* eslint-disable no-console */
|
/* eslint-disable no-console */
|
||||||
require('dotenv-vault-core').config();
|
require('dotenv-vault-core').config();
|
||||||
console.log(process.env.FIRECAMP_API_HOST, 'FIRECAMP_API_HOST'); // for debugging purposes. remove when ready.
|
|
||||||
|
|
||||||
const webpack = require('webpack');
|
const webpack = require('webpack');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||||
// const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');
|
// const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');
|
||||||
const NodePolyfillPlugin = require('node-polyfill-webpack-plugin');
|
const NodePolyfillPlugin = require('node-polyfill-webpack-plugin');
|
||||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
const { Environment } = require('./scripts/constants');
|
const CopyPlugin = require('copy-webpack-plugin');
|
||||||
|
|
||||||
const env = process.env.NODE_ENV;
|
|
||||||
|
|
||||||
const metadata = require('./package.json');
|
const metadata = require('./package.json');
|
||||||
|
|
||||||
exports.common = {
|
const NodeEnv = process.env.NODE_ENV;
|
||||||
entry: {
|
console.log(process.env.FIRECAMP_API_HOST, 'FIRECAMP_API_HOST'); // for debugging purposes. remove when ready.
|
||||||
index: path.join(
|
|
||||||
__dirname,
|
|
||||||
'./platform/firecamp-platform/src/containers/index.tsx'
|
|
||||||
),
|
|
||||||
identity: path.join(
|
|
||||||
__dirname,
|
|
||||||
'./platform/firecamp-platform/src/containers/identity.tsx'
|
|
||||||
),
|
|
||||||
},
|
|
||||||
optimization: {
|
|
||||||
nodeEnv: process.env.NODE_ENV,
|
|
||||||
minimize: true,
|
|
||||||
runtimeChunk: 'single',
|
|
||||||
splitChunks: {
|
|
||||||
// name: 'vendor',
|
|
||||||
// chunks(chunk) {
|
|
||||||
// // To prevent generate separate chunk for background script
|
|
||||||
// // Because all node_modules not needed in background script
|
|
||||||
// return !chunk?.name?.includes('background');
|
|
||||||
// },
|
|
||||||
chunks: 'all',
|
|
||||||
maxInitialRequests: Infinity,
|
|
||||||
minSize: 0,
|
|
||||||
cacheGroups: {
|
|
||||||
vendor: {
|
|
||||||
test: /[\\/]node_modules[\\/]/,
|
|
||||||
name(module) {
|
|
||||||
return 'vender';
|
|
||||||
|
|
||||||
// get the name. E.g. node_modules/packageName/not/this/part.js
|
const plugins = [
|
||||||
// or node_modules/packageName
|
|
||||||
// const packageName = module.context.match(
|
|
||||||
// /[\\/]node_modules[\\/](.*?)([\\/]|$)/
|
|
||||||
// )[1];
|
|
||||||
|
|
||||||
// // npm package names are URL-safe, but some servers don't like @ symbols
|
|
||||||
// return `npm.${packageName.replace('@', '')}`;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
resolve: {
|
|
||||||
extensions: ['*', '.mjs', '.js', '.json', '.jsx', '.ts', '.tsx', '.svg'],
|
|
||||||
alias: {
|
|
||||||
// faker: path.resolve('./node_modules/faker'),
|
|
||||||
react: path.resolve('./node_modules/react'),
|
|
||||||
'react-dom': path.resolve('./node_modules/react-dom'),
|
|
||||||
lodash: path.resolve('./node_modules/lodash'),
|
|
||||||
nanoid: path.resolve('./node_modules/nanoid'),
|
|
||||||
'awesome-notifications': path.resolve(
|
|
||||||
'./node_modules/awesome-notifications'
|
|
||||||
),
|
|
||||||
'@babel/runtime': path.resolve('./node_modules/@babel/runtime'),
|
|
||||||
'monaco-editor': path.resolve('./node_modules/monaco-editor'),
|
|
||||||
},
|
|
||||||
fallback: {
|
|
||||||
fs: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const outputPath = `${__dirname}/build/${env}`;
|
|
||||||
const publicPath = '';
|
|
||||||
exports.output = {
|
|
||||||
globalObject: 'this',
|
|
||||||
filename: '[name].bundle.js',
|
|
||||||
chunkFilename: '[name].bundle.js',
|
|
||||||
path: outputPath,
|
|
||||||
publicPath,
|
|
||||||
};
|
|
||||||
|
|
||||||
// exports.output.path = path.join(__dirname, `./build/${env}`);
|
|
||||||
if (env === Environment.Development) exports.output.clean = true;
|
|
||||||
|
|
||||||
exports.env = {
|
|
||||||
NODE_ENV: JSON.stringify(process.env.NODE_ENV),
|
|
||||||
FIRECAMP_API_HOST: JSON.stringify(process.env.FIRECAMP_API_HOST),
|
|
||||||
FIRECAMP_CLOUD_AGENT: JSON.stringify(process.env.FIRECAMP_CLOUD_AGENT),
|
|
||||||
FIRECAMP_EXTENSION_AGENT_ID: JSON.stringify(
|
|
||||||
process.env.FIRECAMP_EXTENSION_AGENT_ID
|
|
||||||
),
|
|
||||||
APP_VERSION: JSON.stringify(metadata.version),
|
|
||||||
AppFormat: JSON.stringify(process.env.AppFormat),
|
|
||||||
SENTRY_DSN: JSON.stringify(process.env.SENTRY_DSN),
|
|
||||||
CRISP_WEBSITE_ID: JSON.stringify(process.env.CRISP_WEBSITE_ID),
|
|
||||||
CRISP_FIRECAMP_DEV: JSON.stringify(process.env.CRISP_FIRECAMP_DEV),
|
|
||||||
GOOGLE_OAUTH2_CLIENT_ID: JSON.stringify(process.env.GOOGLE_OAUTH2_CLIENT_ID),
|
|
||||||
GOOGLE_OAUTH2_REDIRECT_URI: JSON.stringify(
|
|
||||||
process.env.GOOGLE_OAUTH2_REDIRECT_URI
|
|
||||||
),
|
|
||||||
GITHUB_OAUTH2_CLIENT_ID: JSON.stringify(process.env.GITHUB_OAUTH2_CLIENT_ID),
|
|
||||||
GITHUB_OAUTH2_REDIRECT_URI: JSON.stringify(
|
|
||||||
process.env.GITHUB_OAUTH2_REDIRECT_URI
|
|
||||||
),
|
|
||||||
GOOGLE_ANALYTICS_CHROME_ID: JSON.stringify(
|
|
||||||
process.env.GOOGLE_ANALYTICS_CHROME_ID
|
|
||||||
),
|
|
||||||
GOOGLE_ANALYTICS_ELECTRON_ID: JSON.stringify(
|
|
||||||
process.env.GOOGLE_ANALYTICS_ELECTRON_ID
|
|
||||||
),
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.plugins = [
|
|
||||||
new HtmlWebpackPlugin({
|
new HtmlWebpackPlugin({
|
||||||
inject: true,
|
inject: true,
|
||||||
chunks: ['index'],
|
chunks: ['index'],
|
||||||
filename: 'index.html',
|
filename: 'index.html',
|
||||||
template: 'templates/index.html',
|
template: 'templates/index.html',
|
||||||
favicon: 'templates/favicon.png',
|
favicon: 'templates/favicon.png',
|
||||||
|
hash: true,
|
||||||
}),
|
}),
|
||||||
new HtmlWebpackPlugin({
|
new HtmlWebpackPlugin({
|
||||||
inject: true,
|
inject: true,
|
||||||
@@ -156,10 +50,79 @@ exports.plugins = [
|
|||||||
// publicPath: '/js',
|
// publicPath: '/js',
|
||||||
// filename: '[name].worker.bundle.js',
|
// filename: '[name].worker.bundle.js',
|
||||||
// languages: ['javascript', 'html', 'typescript', 'json'],
|
// languages: ['javascript', 'html', 'typescript', 'json'],
|
||||||
// }),
|
// }),11
|
||||||
|
new webpack.DefinePlugin({
|
||||||
|
'process.env': {
|
||||||
|
NODE_ENV: JSON.stringify(process.env.NODE_ENV),
|
||||||
|
FIRECAMP_API_HOST: JSON.stringify(process.env.FIRECAMP_API_HOST),
|
||||||
|
FIRECAMP_CLOUD_AGENT: JSON.stringify(process.env.FIRECAMP_CLOUD_AGENT),
|
||||||
|
FIRECAMP_EXTENSION_AGENT_ID: JSON.stringify(
|
||||||
|
process.env.FIRECAMP_EXTENSION_AGENT_ID
|
||||||
|
),
|
||||||
|
APP_VERSION: JSON.stringify(metadata.version),
|
||||||
|
AppFormat: JSON.stringify(process.env.AppFormat),
|
||||||
|
SENTRY_DSN: JSON.stringify(process.env.SENTRY_DSN),
|
||||||
|
CRISP_WEBSITE_ID: JSON.stringify(process.env.CRISP_WEBSITE_ID),
|
||||||
|
CRISP_FIRECAMP_DEV: JSON.stringify(process.env.CRISP_FIRECAMP_DEV),
|
||||||
|
GOOGLE_OAUTH2_CLIENT_ID: JSON.stringify(
|
||||||
|
process.env.GOOGLE_OAUTH2_CLIENT_ID
|
||||||
|
),
|
||||||
|
GOOGLE_OAUTH2_REDIRECT_URI: JSON.stringify(
|
||||||
|
process.env.GOOGLE_OAUTH2_REDIRECT_URI
|
||||||
|
),
|
||||||
|
GITHUB_OAUTH2_CLIENT_ID: JSON.stringify(
|
||||||
|
process.env.GITHUB_OAUTH2_CLIENT_ID
|
||||||
|
),
|
||||||
|
GITHUB_OAUTH2_REDIRECT_URI: JSON.stringify(
|
||||||
|
process.env.GITHUB_OAUTH2_REDIRECT_URI
|
||||||
|
),
|
||||||
|
GOOGLE_ANALYTICS_CHROME_ID: JSON.stringify(
|
||||||
|
process.env.GOOGLE_ANALYTICS_CHROME_ID
|
||||||
|
),
|
||||||
|
GOOGLE_ANALYTICS_ELECTRON_ID: JSON.stringify(
|
||||||
|
process.env.GOOGLE_ANALYTICS_ELECTRON_ID
|
||||||
|
),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
new CopyPlugin({
|
||||||
|
patterns: [
|
||||||
|
{
|
||||||
|
from: `${__dirname}/platform/firecamp-platform/public/assets`,
|
||||||
|
to: `${__dirname}/build/${NodeEnv}`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
exports.rules = [
|
const rules = [
|
||||||
|
{
|
||||||
|
test: /\.(ts|js)x?$/,
|
||||||
|
exclude: /node_modules/,
|
||||||
|
loader: 'babel-loader',
|
||||||
|
options: {
|
||||||
|
cacheDirectory: true,
|
||||||
|
presets: [
|
||||||
|
'@babel/preset-env',
|
||||||
|
[
|
||||||
|
'@babel/preset-react',
|
||||||
|
{
|
||||||
|
runtime: 'automatic',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'@babel/preset-typescript',
|
||||||
|
],
|
||||||
|
plugins: [
|
||||||
|
[
|
||||||
|
'@babel/plugin-transform-runtime',
|
||||||
|
{
|
||||||
|
regenerator: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
['@babel/plugin-proposal-export-default-from'],
|
||||||
|
'add-module-exports',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
{ test: /\.flow$/, loader: 'ignore-loader' },
|
{ test: /\.flow$/, loader: 'ignore-loader' },
|
||||||
{
|
{
|
||||||
test: /\.css$/,
|
test: /\.css$/,
|
||||||
@@ -195,3 +158,68 @@ exports.rules = [
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
entry: {
|
||||||
|
index: path.join(
|
||||||
|
__dirname,
|
||||||
|
'./platform/firecamp-platform/src/containers/index.tsx'
|
||||||
|
),
|
||||||
|
identity: path.join(
|
||||||
|
__dirname,
|
||||||
|
'./platform/firecamp-platform/src/containers/identity.tsx'
|
||||||
|
),
|
||||||
|
},
|
||||||
|
optimization: {
|
||||||
|
runtimeChunk: 'single',
|
||||||
|
splitChunks: {
|
||||||
|
// name: 'vendor',
|
||||||
|
// chunks(chunk) {
|
||||||
|
// // To prevent generate separate chunk for background script
|
||||||
|
// // Because all node_modules not needed in background script
|
||||||
|
// return !chunk?.name?.includes('background');
|
||||||
|
// },
|
||||||
|
chunks: 'all',
|
||||||
|
maxInitialRequests: Infinity,
|
||||||
|
minSize: 0,
|
||||||
|
cacheGroups: {
|
||||||
|
vendor: {
|
||||||
|
test: /[\\/]node_modules[\\/]/,
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
name(module) {
|
||||||
|
return 'vender';
|
||||||
|
|
||||||
|
// get the name. E.g. node_modules/packageName/not/this/part.js
|
||||||
|
// or node_modules/packageName
|
||||||
|
// const packageName = module.context.match(
|
||||||
|
// /[\\/]node_modules[\\/](.*?)([\\/]|$)/
|
||||||
|
// )[1];
|
||||||
|
|
||||||
|
// // npm package names are URL-safe, but some servers don't like @ symbols
|
||||||
|
// return `npm.${packageName.replace('@', '')}`;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
extensions: ['*', '.mjs', '.js', '.json', '.jsx', '.ts', '.tsx', '.svg'],
|
||||||
|
alias: {
|
||||||
|
// faker: path.resolve('./node_modules/faker'),
|
||||||
|
react: path.resolve('./node_modules/react'),
|
||||||
|
'react-dom': path.resolve('./node_modules/react-dom'),
|
||||||
|
lodash: path.resolve('./node_modules/lodash'),
|
||||||
|
nanoid: path.resolve('./node_modules/nanoid'),
|
||||||
|
'awesome-notifications': path.resolve(
|
||||||
|
'./node_modules/awesome-notifications'
|
||||||
|
),
|
||||||
|
'@babel/runtime': path.resolve('./node_modules/@babel/runtime'),
|
||||||
|
'monaco-editor': path.resolve('./node_modules/monaco-editor'),
|
||||||
|
},
|
||||||
|
fallback: {
|
||||||
|
fs: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plugins,
|
||||||
|
module: { rules },
|
||||||
|
};
|
||||||
@@ -1,18 +1,36 @@
|
|||||||
// imports environment
|
|
||||||
require('dotenv').config();
|
|
||||||
|
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const webpack = require('webpack');
|
const webpack = require('webpack');
|
||||||
const BundleAnalyzerPlugin =
|
const { merge } = require('webpack-merge');
|
||||||
require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
|
// const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
|
||||||
const { common, env, plugins, rules, output } = require('./webpack.config');
|
const TerserPlugin = require('terser-webpack-plugin');
|
||||||
|
const base = require('./webpack.common');
|
||||||
|
|
||||||
const withReport = process.env.npm_config_withReport;
|
// const withReport = process.env.npm_config_withReport;
|
||||||
|
const nodeEnv = process.env.NODE_ENV;
|
||||||
|
|
||||||
module.exports = {
|
module.exports = merge(base, {
|
||||||
...common,
|
|
||||||
mode: 'development',
|
mode: 'development',
|
||||||
devtool: 'eval-cheap-module-source-map',
|
devtool: 'cheap-module-source-map',
|
||||||
|
output: {
|
||||||
|
clean: true,
|
||||||
|
globalObject: 'this',
|
||||||
|
filename: '[name].dev.js',
|
||||||
|
chunkFilename: '[name].dev.js',
|
||||||
|
path: `${__dirname}/build/${nodeEnv}`,
|
||||||
|
publicPath: '',
|
||||||
|
},
|
||||||
|
optimization: {
|
||||||
|
nodeEnv: 'development',
|
||||||
|
minimizer: [
|
||||||
|
new TerserPlugin({
|
||||||
|
parallel: 4,
|
||||||
|
minify: TerserPlugin.esbuildMinify,
|
||||||
|
// terserOptions: {
|
||||||
|
// sourceMap: 'external',
|
||||||
|
// },
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
},
|
||||||
devServer: {
|
devServer: {
|
||||||
//server: 'https',
|
//server: 'https',
|
||||||
static: path.join(__dirname, './build/development'),
|
static: path.join(__dirname, './build/development'),
|
||||||
@@ -28,51 +46,9 @@ module.exports = {
|
|||||||
'X-Requested-With, content-type, Authorization',
|
'X-Requested-With, content-type, Authorization',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
output,
|
|
||||||
plugins: [
|
plugins: [
|
||||||
...plugins,
|
|
||||||
new webpack.HotModuleReplacementPlugin(),
|
new webpack.HotModuleReplacementPlugin(),
|
||||||
new webpack.IgnorePlugin({ resourceRegExp: /[^/]+\/[\S]+.dev$/ }),
|
new webpack.IgnorePlugin({ resourceRegExp: /[^/]+\/[\S]+.dev$/ }),
|
||||||
new webpack.DefinePlugin({
|
|
||||||
'process.env': {
|
|
||||||
...env,
|
|
||||||
FIRECAMP_EXTENSION_AGENT_ID: JSON.stringify(
|
|
||||||
process.env.FIRECAMP_EXTENSION_AGENT_ID
|
|
||||||
),
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
// new BundleAnalyzerPlugin(),
|
// new BundleAnalyzerPlugin(),
|
||||||
],
|
],
|
||||||
module: {
|
});
|
||||||
rules: [
|
|
||||||
...rules,
|
|
||||||
{
|
|
||||||
test: /\.(ts|js)x?$/,
|
|
||||||
exclude: /node_modules/,
|
|
||||||
loader: 'babel-loader',
|
|
||||||
options: {
|
|
||||||
presets: [
|
|
||||||
'@babel/preset-env',
|
|
||||||
[
|
|
||||||
'@babel/preset-react',
|
|
||||||
{
|
|
||||||
runtime: 'automatic',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'@babel/preset-typescript',
|
|
||||||
],
|
|
||||||
plugins: [
|
|
||||||
[
|
|
||||||
'@babel/plugin-transform-runtime',
|
|
||||||
{
|
|
||||||
regenerator: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
['@babel/plugin-proposal-export-default-from'],
|
|
||||||
'add-module-exports',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|||||||
109
webpack.prod.js
109
webpack.prod.js
@@ -1,94 +1,37 @@
|
|||||||
/* eslint-disable no-console */
|
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const webpack = require('webpack');
|
const webpack = require('webpack');
|
||||||
const CompressionPlugin = require('compression-webpack-plugin');
|
const { merge } = require('webpack-merge');
|
||||||
const { common, env, plugins, rules } = require('./webpack.config');
|
const TerserPlugin = require('terser-webpack-plugin');
|
||||||
|
// const CompressionPlugin = require('compression-webpack-plugin');
|
||||||
|
const base = require('./webpack.common');
|
||||||
|
|
||||||
const nodeEnv = process.env.NODE_ENV;
|
const nodeEnv = process.env.NODE_ENV;
|
||||||
const config = {
|
|
||||||
...common,
|
module.exports = merge(base, {
|
||||||
mode: 'production',
|
mode: 'production',
|
||||||
output: {
|
output: {
|
||||||
|
clean: true,
|
||||||
globalObject: 'this',
|
globalObject: 'this',
|
||||||
filename: '[name].bundle.js',
|
filename: '[name].min.js',
|
||||||
chunkFilename: '[name].bundle.js',
|
chunkFilename: '[name].min.js',
|
||||||
path: path.join(__dirname, `./build/${nodeEnv}`),
|
path: path.join(__dirname, `./build/${nodeEnv}`),
|
||||||
},
|
},
|
||||||
plugins: [
|
optimization: {
|
||||||
...plugins,
|
nodeEnv: 'production',
|
||||||
new webpack.ProvidePlugin({
|
// minimize: true,
|
||||||
React: 'react',
|
minimizer: [
|
||||||
}),
|
new TerserPlugin({
|
||||||
new webpack.IgnorePlugin({ resourceRegExp: /[^/]+\/[\S]+.prod$/ }),
|
parallel: 4,
|
||||||
new webpack.DefinePlugin({
|
minify: TerserPlugin.esbuildMinify,
|
||||||
'process.env': env,
|
// terserOptions: {
|
||||||
}),
|
// sourceMap: 'external',
|
||||||
new CompressionPlugin(),
|
// },
|
||||||
],
|
}),
|
||||||
module: {
|
|
||||||
rules: [
|
|
||||||
...rules,
|
|
||||||
{
|
|
||||||
test: /\.(ts|js)x?$/,
|
|
||||||
exclude: /node_modules/,
|
|
||||||
loader: 'babel-loader',
|
|
||||||
options: {
|
|
||||||
presets: [
|
|
||||||
'@babel/preset-env',
|
|
||||||
[
|
|
||||||
'@babel/preset-react',
|
|
||||||
{
|
|
||||||
runtime: 'automatic',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'@babel/preset-typescript',
|
|
||||||
],
|
|
||||||
plugins: [
|
|
||||||
[
|
|
||||||
'@babel/plugin-transform-runtime',
|
|
||||||
{
|
|
||||||
regenerator: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
['@babel/plugin-proposal-export-default-from'],
|
|
||||||
'add-module-exports',
|
|
||||||
['transform-remove-console', { exclude: ['info'] }],
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
};
|
plugins: [
|
||||||
|
new webpack.ProvidePlugin({ React: 'react' }),
|
||||||
module.exports = () =>
|
new webpack.IgnorePlugin({ resourceRegExp: /[^/]+\/[\S]+.prod$/ }),
|
||||||
new Promise((resolve, reject) => {
|
// new CompressionPlugin(),
|
||||||
console.log('[Webpack Build]');
|
],
|
||||||
console.log('-'.repeat(80));
|
});
|
||||||
|
|
||||||
const compiler = webpack(config);
|
|
||||||
|
|
||||||
compiler.run((err, stats) => {
|
|
||||||
if (err) {
|
|
||||||
console.error(err.stack || err);
|
|
||||||
if (err.details) {
|
|
||||||
console.error(err.details);
|
|
||||||
}
|
|
||||||
|
|
||||||
reject(err.stack || err.details || err);
|
|
||||||
}
|
|
||||||
|
|
||||||
const info = stats.toJson();
|
|
||||||
|
|
||||||
if (stats.hasErrors()) {
|
|
||||||
console.error(info.errors);
|
|
||||||
|
|
||||||
reject(info.errors);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stats.hasWarnings()) {
|
|
||||||
console.warn(info.warnings);
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|||||||
Reference in New Issue
Block a user