├── .editorconfig ├── .eslintrc ├── .github └── ISSUE_TEMPLATE │ ├── bug-report-for-new-version.md │ ├── bug_report.md │ └── feature_request.md ├── .gitignore ├── .gitmodules ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── buildUtils ├── webpack.development.js └── webpack.production.js ├── openapi.config.json ├── openapitools.json ├── package-lock.json ├── package.json ├── prettier.config.js ├── public ├── favicon │ ├── android-icon-144x144.png │ ├── android-icon-192x192.png │ ├── android-icon-36x36.png │ ├── android-icon-48x48.png │ ├── android-icon-72x72.png │ ├── android-icon-96x96.png │ ├── apple-icon-114x114.png │ ├── apple-icon-120x120.png │ ├── apple-icon-144x144.png │ ├── apple-icon-152x152.png │ ├── apple-icon-180x180.png │ ├── apple-icon-57x57.png │ ├── apple-icon-60x60.png │ ├── apple-icon-72x72.png │ ├── apple-icon-76x76.png │ ├── apple-icon-precomposed.png │ ├── apple-icon.png │ ├── browserconfig.xml │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── favicon-96x96.png │ ├── favicon.ico │ ├── manifest.json │ ├── ms-icon-144x144.png │ ├── ms-icon-150x150.png │ ├── ms-icon-310x310.png │ └── ms-icon-70x70.png ├── index.html ├── manifest.json ├── robots.txt ├── style.css └── svg │ ├── loading.svg │ └── wildduck.png ├── src ├── assets │ └── icons │ │ ├── DkimIcon.tsx │ │ ├── DomainAccessIcon.tsx │ │ ├── DomainAliasIcon.tsx │ │ ├── ForwardedAddressesIcon.tsx │ │ ├── RecalculateQuotaIcon.tsx │ │ ├── ResetPasswordIcon.tsx │ │ ├── WildDuckIcon.tsx │ │ └── wildduck.png ├── client │ ├── AxiosClient.ts │ ├── RequestClient.ts │ └── wildduck-api │ │ ├── .gitignore │ │ ├── .npmignore │ │ ├── .openapi-generator-ignore │ │ ├── .openapi-generator │ │ ├── FILES │ │ └── VERSION │ │ ├── api.ts │ │ ├── base.ts │ │ ├── common.ts │ │ ├── configuration.ts │ │ ├── git_push.sh │ │ └── index.ts ├── components │ ├── AccessToken │ │ ├── AccessToken.tsx │ │ └── index.ts │ ├── Address │ │ ├── Address.tsx │ │ ├── AddressInformation.tsx │ │ ├── AddressInformationForm.tsx │ │ ├── AddressTable.tsx │ │ ├── Columns.tsx │ │ └── index.ts │ ├── App │ │ ├── App.tsx │ │ └── index.tsx │ ├── Archive │ │ ├── Archive.tsx │ │ ├── ArchiveTable.tsx │ │ ├── Columns.tsx │ │ ├── RestoreAllMessagesModal.tsx │ │ └── index.ts │ ├── Authentication │ │ ├── Authentication.tsx │ │ ├── AuthenticationTable.tsx │ │ ├── Columns.tsx │ │ └── index.ts │ ├── Autoreplies │ │ ├── Autoreplies.tsx │ │ ├── AutorepliesForm.tsx │ │ └── index.ts │ ├── ContentArea │ │ ├── ContentArea.tsx │ │ └── index.ts │ ├── CreateDkim │ │ ├── CreateDkim.tsx │ │ └── index.ts │ ├── CreateNewAddress │ │ ├── CreateNewAddress.tsx │ │ ├── CreateNewAddressForm.tsx │ │ └── index.ts │ ├── CreateNewDomainAlias │ │ ├── CreateNewDomainAlias.tsx │ │ ├── CreateNewDomainAliasForm.tsx │ │ └── index.ts │ ├── CreateNewForwardedAddress │ │ ├── CreateNewForwardedAddress.tsx │ │ ├── CreateNewForwardedAddressForm.tsx │ │ └── index.ts │ ├── CreateNewUser │ │ ├── CreateNewUser.tsx │ │ ├── CreateNewUserForm.tsx │ │ └── index.ts │ ├── CustomLink │ │ └── index.tsx │ ├── Dkim │ │ ├── Dkim.tsx │ │ ├── DkimColumns.tsx │ │ ├── DkimTable.tsx │ │ └── index.ts │ ├── DkimDetails │ │ ├── DkimDetails.tsx │ │ └── index.ts │ ├── DomainAccess │ │ ├── DomainAccess.tsx │ │ └── index.ts │ ├── DomainAliases │ │ ├── Columns.tsx │ │ ├── DomainAliases.tsx │ │ ├── DomainAliasesTable.tsx │ │ ├── SearchAlias.tsx │ │ └── index.ts │ ├── ErrorBoundary │ │ ├── ErrorBoundary.tsx │ │ ├── ErrorPage.tsx │ │ └── index.ts │ ├── Filters │ │ ├── AddFiltersForm.tsx │ │ ├── Filters.tsx │ │ ├── FiltersTable.tsx │ │ └── index.ts │ ├── FloatingButton.tsx │ ├── FormLayout.ts │ ├── ForwardedAddress │ │ ├── Columns.tsx │ │ ├── ForwardedAddress.tsx │ │ ├── ForwardedAddressTable.tsx │ │ ├── RenameDomain.tsx │ │ └── index.ts │ ├── ForwardedAddressInformation │ │ ├── ForwardedAddressInformation.tsx │ │ ├── ForwardedAddressInformationForm.tsx │ │ ├── ListTarget.tsx │ │ └── index.ts │ ├── Header │ │ ├── Header.tsx │ │ └── index.ts │ ├── HtmlRenderer │ │ ├── HtmlRenderer.tsx │ │ └── index.ts │ ├── LoaderBoundary │ │ ├── LoaderBoundary.tsx │ │ └── index.ts │ ├── LoadingPage │ │ ├── LoadingPage.tsx │ │ └── index.ts │ ├── Mailboxes │ │ ├── Columns.tsx │ │ ├── MailboxEditForm.tsx │ │ ├── MailboxSearch.tsx │ │ ├── Mailboxes.tsx │ │ ├── MailboxesTable.tsx │ │ └── index.ts │ ├── Messages │ │ ├── MailboxMessages.tsx │ │ ├── MessageActions.tsx │ │ ├── MessageDetails.tsx │ │ ├── MessageSource.tsx │ │ ├── Messages.tsx │ │ ├── MessagesList.tsx │ │ ├── MessagesSearch.tsx │ │ └── index.ts │ ├── NavigationBar │ │ ├── NavigationBar.tsx │ │ └── index.ts │ ├── Page │ │ ├── Page.tsx │ │ └── index.ts │ ├── ResolveId │ │ ├── ResolveId.tsx │ │ └── index.ts │ ├── User │ │ ├── User.tsx │ │ ├── UserDetailsForm.tsx │ │ └── index.ts │ ├── Users │ │ ├── Columns.tsx │ │ ├── FilterSearch.tsx │ │ ├── ManageActions.tsx │ │ ├── ResetPassword.tsx │ │ ├── Users.tsx │ │ ├── UsersTable.tsx │ │ └── index.ts │ ├── Widgets │ │ └── Link.tsx │ └── index.tsx ├── config │ └── menuConfig.ts ├── hooks │ ├── useAddress.ts │ ├── useAddressInformation.ts │ ├── useAllowedList.ts │ ├── useArchive.ts │ ├── useAuthentication.ts │ ├── useAutoreplyDetails.ts │ ├── useBlockedList.ts │ ├── useCreateAddress.ts │ ├── useCreateAllowedDomain.ts │ ├── useCreateBlockedDomain.ts │ ├── useCreateDkim.ts │ ├── useCreateDomainAliases.ts │ ├── useCreateFilter.ts │ ├── useCreateForwardedAddress.ts │ ├── useCreateUser.ts │ ├── useDeleteAddress.ts │ ├── useDeleteAutoreply.ts │ ├── useDeleteDkim.ts │ ├── useDeleteDomain.ts │ ├── useDeleteDomainAliases.ts │ ├── useDeleteFilter.ts │ ├── useDeleteForwardedAddress.ts │ ├── useDeleteMessage.ts │ ├── useDeleteMessagesInMailbox.ts │ ├── useDeleteUser.ts │ ├── useDkim.ts │ ├── useDkimDetails.ts │ ├── useDomainAliases.ts │ ├── useDownloadAttachment.ts │ ├── useFIlterDetails.ts │ ├── useFilters.ts │ ├── useForwardedAddress.ts │ ├── useForwardedAddressInformation.ts │ ├── useLogoutUser.ts │ ├── useMailboxes.ts │ ├── useMessageDetails.ts │ ├── useMessageSource.ts │ ├── useMessages.ts │ ├── useRecalculateQuota.ts │ ├── useRecalculateQuotaForAll.ts │ ├── useRenameDomain.ts │ ├── useResetPassword.ts │ ├── useRestoreArchiveMessage.ts │ ├── useRestoreArchiveMessages.ts │ ├── useUpdateAddress.ts │ ├── useUpdateAutoreply.ts │ ├── useUpdateFilter.ts │ ├── useUpdateForwardedAddress.ts │ ├── useUpdateMailbox.ts │ ├── useUpdateUserDetails.ts │ ├── useUserDetails.ts │ └── useUsers.ts ├── lib │ ├── axios │ │ └── AxiosInterceptors.ts │ └── constants │ │ ├── Formatter.ts │ │ └── constant.ts ├── logic │ ├── addressLogic.ts │ ├── appLogic.ts │ ├── archiveLogic.ts │ ├── authenticationLogic.ts │ ├── dkimLogic.ts │ ├── domainAccessLogic.ts │ ├── domainAliasesLogic.ts │ ├── filtersLogic.ts │ ├── mailboxesLogic.ts │ ├── messagesLogic.ts │ ├── navigationLogic.ts │ └── usersLogic.ts ├── react-query.config.ts ├── store │ └── index.ts ├── styles │ ├── antd.less │ └── style.css ├── types │ ├── address.d.ts │ ├── axios.d.ts │ ├── dkim.d.ts │ ├── domainAliases.d.ts │ ├── navigationBar.d.ts │ ├── storage.d.ts │ └── users.d.ts └── utils │ ├── AppEvents.ts │ ├── FilterDropDown.tsx │ ├── FilterDropdownStyle.css │ ├── Pagination.tsx │ ├── constants.ts │ ├── getColumnsWithFilterAndSort.tsx │ ├── getUniqValuesBy.ts │ ├── handleError.ts │ ├── logicUtils.ts │ └── showConfirm.ts ├── tsconfig.json └── webpack.config.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = tab 5 | indent_size = 4 6 | tab_size = 4 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = true 14 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "ignorePatterns": ["src/assets/icons/*"], 4 | "settings": { 5 | "react": { 6 | "version": "detect" 7 | } 8 | }, 9 | "env": { 10 | "browser": true, 11 | "node": true, 12 | "commonjs": true, 13 | "es6": true 14 | }, 15 | "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended", "plugin:react/recommended"], 16 | "parser": "@typescript-eslint/parser", 17 | "parserOptions": { 18 | "ecmaFeatures": { 19 | "jsx": true 20 | }, 21 | "ecmaVersion": 2018, 22 | "sourceType": "module" 23 | }, 24 | "plugins": ["eslint-plugin-react", "@typescript-eslint", "react"], 25 | "rules": { 26 | "no-console": 0, 27 | "@typescript-eslint/no-explicit-any": 0, 28 | "react/display-name": 0, 29 | "@typescript-eslint/interface-name-prefix": 0, 30 | "@typescript-eslint/explicit-member-accessibility": 0, 31 | "@typescript-eslint/array-type": 0, 32 | "@typescript-eslint/no-var-requires": 0, 33 | "@typescript-eslint/explicit-function-return-type": 0, 34 | "@typescript-eslint/no-unused-vars": 0, 35 | "@typescript-eslint/indent": [ 36 | "error", 37 | "tab", 38 | { 39 | "SwitchCase": 1 40 | } 41 | ], 42 | "quotes": [ 43 | "error", 44 | "single", 45 | { 46 | "allowTemplateLiterals": true 47 | } 48 | ], 49 | "semi": ["error", "always"], 50 | "max-len": [ 51 | "error", 52 | { 53 | "code": 120, 54 | "tabWidth": 4 55 | } 56 | ] 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report-for-new-version.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug Report For New Version 3 | about: Describe this issue template's purpose here. 4 | title: "[NEW-VERSION-BUG]" 5 | labels: new-version-bug 6 | assignees: Lakkanna 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See an error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **What device are you on?** 27 | 28 | **Which node version are you using?** 29 | 30 | **Additional context** 31 | Add any other context about the problem here. 32 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "[BUG]" 5 | labels: bug 6 | assignees: Lakkanna 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See an error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **What device are you on?** 27 | 28 | **Which Node version are you using?** 29 | 30 | **Additional context** 31 | Add any other context about the problem here. 32 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: "[FEATURE]" 5 | labels: enhancement 6 | assignees: Lakkanna 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/314e/wildduck-ui/ca14b2291e64ceab07da2af2e8fd80ce0693821e/.gitmodules -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ## [Unreleased] 4 | 5 | - Making project open source 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Kesav Kolla 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | WildDuck UI logo 3 |

4 | 5 |

6 | Administrative UI for WildDuck IMAP server 7 |

8 | 9 |

10 | Contribute 11 | · 12 | Code of Conduct 13 | · 14 | Change Log 15 |

16 | 17 | ## Setup 18 | 19 | ```js 20 | git clone https://github.com/softwareartistry/wildduck-ui.git 21 | 22 | cd wildduck-ui 23 | npm install --legacy-peer-deps 24 | npm run dev 25 | 26 | ``` 27 | 28 | \* Note Currently project supports node version below or v14.16.0 29 | 30 | ### Dev Server 31 | 32 | `npm run dev` 33 | 34 | 35 | 36 | ### Pre-requisite 37 | 38 | - Need IMAP Server endpoint to make API calls 39 | - Access Token 40 | 41 | - You can find accessToken that is setup in your server, which locates in `/opt/wildduck/config/api.toml` 42 | - If accessToken is commentend please uncomment and set secure accessToken, example 43 | 44 | ```toml 45 | # If set requires all API calls to have accessToken query argument with that value 46 | 47 | #accessToken="somesecretvalue" 48 | 49 | accessToken="somesecretvalue" 50 | ``` 51 | 52 | ### Tech Stack 53 | 54 | - [React](https://reactjs.org/) 55 | - [Typescript](https://www.typescriptlang.org/) 56 | - [React Query](https://react-query.tanstack.com/) 57 | - [KeaJS](https://kea.js.org/) 58 | - [Ant Design](https://ant.design/) 59 | - Open Api ( [_@openapitools/openapi-generator-cli_](https://github.com/OpenAPITools/openapi-generator-cli) to 60 | generate API's from https://docs.wildduck.email/api/openapi.yml) 61 | 62 | wildduck-ui 63 | 64 | ```shell 65 | git add [files] 66 | git commit -m 'your commit message' 67 | git push 68 | ``` 69 | 70 | ## Contributions 71 | 72 | Project is open to contributions, but I recommend creating an issue or replying in a comment to let me know what you are 73 | working on first that way we don't overwrite each other. 74 | 75 | Please read [CONTRIBUTING.md](./CONTRIBUTING.md) for details on this project. 76 | 77 | ## Code of Conduct 78 | 79 | Please read [CODE_OF_CONDUCT.md](./CODE_OF_CONDUCT.md) for details on our code of conduct. 80 | -------------------------------------------------------------------------------- /buildUtils/webpack.development.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const webpack = require('webpack'); 3 | 4 | module.exports = { 5 | mode: 'development', 6 | devtool: 'inline-source-map', 7 | output: { 8 | publicPath: '/', 9 | filename: 'bundle.js', 10 | chunkFilename: 'bundle.[name].js', 11 | }, 12 | module: { 13 | rules: [ 14 | { 15 | test: /\.less$/, 16 | include: /(src)/, 17 | use: [ 18 | { loader: 'style-loader' }, 19 | { loader: 'css-loader' }, 20 | { 21 | loader: 'less-loader', 22 | options: { 23 | lessOptions: { 24 | javascriptEnabled: true, 25 | }, 26 | }, 27 | }, 28 | ], 29 | }, 30 | { 31 | test: /\.css$/, 32 | use: ['style-loader', 'css-loader'], 33 | }, 34 | ], 35 | }, 36 | plugins: [new webpack.HotModuleReplacementPlugin()], 37 | devServer: { 38 | compress: true, 39 | contentBase: path.join(__dirname, 'dist'), 40 | historyApiFallback: true, 41 | host: '0.0.0.0', 42 | hot: true, 43 | port: 3000, 44 | progress: true, 45 | watchContentBase: true, 46 | clientLogLevel: 'error', 47 | }, 48 | }; 49 | -------------------------------------------------------------------------------- /buildUtils/webpack.production.js: -------------------------------------------------------------------------------- 1 | const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 2 | 3 | module.exports = { 4 | mode: 'production', 5 | output: { 6 | filename: 'bundle.main.[contenthash:8].js', 7 | chunkFilename: 'bundle.[name].[contenthash:8].js', 8 | }, 9 | module: { 10 | rules: [ 11 | { 12 | test: /\.less$/, 13 | include: /(src)/, 14 | use: [ 15 | { loader: MiniCssExtractPlugin.loader }, 16 | { loader: 'css-loader' }, 17 | { 18 | loader: 'less-loader', 19 | options: { 20 | lessOptions: { 21 | javascriptEnabled: true, 22 | }, 23 | }, 24 | }, 25 | ], 26 | }, 27 | { 28 | test: /\.css$/, 29 | use: [{ loader: MiniCssExtractPlugin.loader }, 'css-loader'], 30 | }, 31 | ], 32 | }, 33 | plugins: [ 34 | new MiniCssExtractPlugin({ 35 | filename: '[name].[hash].css', 36 | chunkFilename: '[id].[hash].css', 37 | }), 38 | ], 39 | }; 40 | -------------------------------------------------------------------------------- /openapi.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "supportsES6": true, 3 | "withoutPrefixEnums": true, 4 | "withInterfaces": true 5 | } 6 | -------------------------------------------------------------------------------- /openapitools.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "node_modules/@openapitools/openapi-generator-cli/config.schema.json", 3 | "spaces": 2, 4 | "generator-cli": { 5 | "version": "5.1.0" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /prettier.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | arrowParens: 'always', 3 | bracketSpacing: true, 4 | htmlWhitespaceSensitivity: 'css', 5 | insertPragma: false, 6 | jsxBracketSameLine: false, 7 | jsxSingleQuote: true, 8 | proseWrap: 'always', 9 | quoteProps: 'as-needed', 10 | requirePragma: false, 11 | semi: true, 12 | singleQuote: true, 13 | tabWidth: 4, 14 | trailingComma: 'all', 15 | useTabs: true, 16 | vueIndentScriptAndStyle: false, 17 | printWidth: 120, 18 | }; 19 | -------------------------------------------------------------------------------- /public/favicon/android-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/314e/wildduck-ui/ca14b2291e64ceab07da2af2e8fd80ce0693821e/public/favicon/android-icon-144x144.png -------------------------------------------------------------------------------- /public/favicon/android-icon-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/314e/wildduck-ui/ca14b2291e64ceab07da2af2e8fd80ce0693821e/public/favicon/android-icon-192x192.png -------------------------------------------------------------------------------- /public/favicon/android-icon-36x36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/314e/wildduck-ui/ca14b2291e64ceab07da2af2e8fd80ce0693821e/public/favicon/android-icon-36x36.png -------------------------------------------------------------------------------- /public/favicon/android-icon-48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/314e/wildduck-ui/ca14b2291e64ceab07da2af2e8fd80ce0693821e/public/favicon/android-icon-48x48.png -------------------------------------------------------------------------------- /public/favicon/android-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/314e/wildduck-ui/ca14b2291e64ceab07da2af2e8fd80ce0693821e/public/favicon/android-icon-72x72.png -------------------------------------------------------------------------------- /public/favicon/android-icon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/314e/wildduck-ui/ca14b2291e64ceab07da2af2e8fd80ce0693821e/public/favicon/android-icon-96x96.png -------------------------------------------------------------------------------- /public/favicon/apple-icon-114x114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/314e/wildduck-ui/ca14b2291e64ceab07da2af2e8fd80ce0693821e/public/favicon/apple-icon-114x114.png -------------------------------------------------------------------------------- /public/favicon/apple-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/314e/wildduck-ui/ca14b2291e64ceab07da2af2e8fd80ce0693821e/public/favicon/apple-icon-120x120.png -------------------------------------------------------------------------------- /public/favicon/apple-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/314e/wildduck-ui/ca14b2291e64ceab07da2af2e8fd80ce0693821e/public/favicon/apple-icon-144x144.png -------------------------------------------------------------------------------- /public/favicon/apple-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/314e/wildduck-ui/ca14b2291e64ceab07da2af2e8fd80ce0693821e/public/favicon/apple-icon-152x152.png -------------------------------------------------------------------------------- /public/favicon/apple-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/314e/wildduck-ui/ca14b2291e64ceab07da2af2e8fd80ce0693821e/public/favicon/apple-icon-180x180.png -------------------------------------------------------------------------------- /public/favicon/apple-icon-57x57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/314e/wildduck-ui/ca14b2291e64ceab07da2af2e8fd80ce0693821e/public/favicon/apple-icon-57x57.png -------------------------------------------------------------------------------- /public/favicon/apple-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/314e/wildduck-ui/ca14b2291e64ceab07da2af2e8fd80ce0693821e/public/favicon/apple-icon-60x60.png -------------------------------------------------------------------------------- /public/favicon/apple-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/314e/wildduck-ui/ca14b2291e64ceab07da2af2e8fd80ce0693821e/public/favicon/apple-icon-72x72.png -------------------------------------------------------------------------------- /public/favicon/apple-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/314e/wildduck-ui/ca14b2291e64ceab07da2af2e8fd80ce0693821e/public/favicon/apple-icon-76x76.png -------------------------------------------------------------------------------- /public/favicon/apple-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/314e/wildduck-ui/ca14b2291e64ceab07da2af2e8fd80ce0693821e/public/favicon/apple-icon-precomposed.png -------------------------------------------------------------------------------- /public/favicon/apple-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/314e/wildduck-ui/ca14b2291e64ceab07da2af2e8fd80ce0693821e/public/favicon/apple-icon.png -------------------------------------------------------------------------------- /public/favicon/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | #ffffff -------------------------------------------------------------------------------- /public/favicon/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/314e/wildduck-ui/ca14b2291e64ceab07da2af2e8fd80ce0693821e/public/favicon/favicon-16x16.png -------------------------------------------------------------------------------- /public/favicon/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/314e/wildduck-ui/ca14b2291e64ceab07da2af2e8fd80ce0693821e/public/favicon/favicon-32x32.png -------------------------------------------------------------------------------- /public/favicon/favicon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/314e/wildduck-ui/ca14b2291e64ceab07da2af2e8fd80ce0693821e/public/favicon/favicon-96x96.png -------------------------------------------------------------------------------- /public/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/314e/wildduck-ui/ca14b2291e64ceab07da2af2e8fd80ce0693821e/public/favicon/favicon.ico -------------------------------------------------------------------------------- /public/favicon/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "App", 3 | "icons": [ 4 | { 5 | "src": "\/android-icon-36x36.png", 6 | "sizes": "36x36", 7 | "type": "image\/png", 8 | "density": "0.75" 9 | }, 10 | { 11 | "src": "\/android-icon-48x48.png", 12 | "sizes": "48x48", 13 | "type": "image\/png", 14 | "density": "1.0" 15 | }, 16 | { 17 | "src": "\/android-icon-72x72.png", 18 | "sizes": "72x72", 19 | "type": "image\/png", 20 | "density": "1.5" 21 | }, 22 | { 23 | "src": "\/android-icon-96x96.png", 24 | "sizes": "96x96", 25 | "type": "image\/png", 26 | "density": "2.0" 27 | }, 28 | { 29 | "src": "\/android-icon-144x144.png", 30 | "sizes": "144x144", 31 | "type": "image\/png", 32 | "density": "3.0" 33 | }, 34 | { 35 | "src": "\/android-icon-192x192.png", 36 | "sizes": "192x192", 37 | "type": "image\/png", 38 | "density": "4.0" 39 | } 40 | ] 41 | } -------------------------------------------------------------------------------- /public/favicon/ms-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/314e/wildduck-ui/ca14b2291e64ceab07da2af2e8fd80ce0693821e/public/favicon/ms-icon-144x144.png -------------------------------------------------------------------------------- /public/favicon/ms-icon-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/314e/wildduck-ui/ca14b2291e64ceab07da2af2e8fd80ce0693821e/public/favicon/ms-icon-150x150.png -------------------------------------------------------------------------------- /public/favicon/ms-icon-310x310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/314e/wildduck-ui/ca14b2291e64ceab07da2af2e8fd80ce0693821e/public/favicon/ms-icon-310x310.png -------------------------------------------------------------------------------- /public/favicon/ms-icon-70x70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/314e/wildduck-ui/ca14b2291e64ceab07da2af2e8fd80ce0693821e/public/favicon/ms-icon-70x70.png -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "WildDuck UI", 3 | "short_name": "WildDuck UI", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "theme_color": "#00152a", 7 | "background_color": "#fff", 8 | "description": "Administrative UI for WildDuck IMAP server", 9 | "icons": [ 10 | { 11 | "src": "favicon/android-icon-48x48.png", 12 | "sizes": "48x48", 13 | "type": "image/png" 14 | }, 15 | { 16 | "src": "favicon/android-icon-72x72.png", 17 | "sizes": "72x72", 18 | "type": "image/png" 19 | }, 20 | { 21 | "src": "favicon/android-icon-96x96.png", 22 | "sizes": "96x96", 23 | "type": "image/png" 24 | }, 25 | { 26 | "src": "favicon/android-icon-144x144.png", 27 | "sizes": "144x144", 28 | "type": "image/png" 29 | }, 30 | { 31 | "src": "favicon/android-icon-152x152.png", 32 | "sizes": "152x152", 33 | "type": "image/png" 34 | }, 35 | { 36 | "src": "favicon/android-icon-192x192.png", 37 | "sizes": "192x192", 38 | "type": "image/png", 39 | "purpose": "maskable" 40 | } 41 | ], 42 | "splash_pages": null 43 | } 44 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /public/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | position: relative; 3 | margin: 0px; 4 | padding: 0px; 5 | font-family: 'Roboto', 'Helvetica', 'Arial', sans-serif; 6 | } 7 | 8 | #splash-screen { 9 | background: linear-gradient(to right, #fff, #fff); 10 | position: absolute; 11 | width: 100vw; 12 | height: 100vh; 13 | top: 0px; 14 | left: 0px; 15 | z-index: 9999; 16 | display: flex; 17 | flex-direction: column; 18 | justify-content: center; 19 | align-items: center; 20 | } 21 | 22 | #logo { 23 | width: auto; 24 | height: 250px; 25 | } 26 | 27 | #splash-screen .loading-animation { 28 | color: #bf360c; 29 | font-size: 0.8rem; 30 | font-weight: 400; 31 | line-height: 4rem; 32 | } 33 | 34 | #splash-screen .loading-animation img { 35 | transform: scale(0.6); 36 | } 37 | -------------------------------------------------------------------------------- /public/svg/loading.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 11 | 12 | 13 | 17 | 21 | 22 | 23 | 27 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /public/svg/wildduck.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/314e/wildduck-ui/ca14b2291e64ceab07da2af2e8fd80ce0693821e/public/svg/wildduck.png -------------------------------------------------------------------------------- /src/assets/icons/DkimIcon.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const DkimIcon: React.FC = () => ( 4 | 5 | 7 | 12 | 17 | 22 | 27 | 28 | ); 29 | 30 | export default DkimIcon; 31 | -------------------------------------------------------------------------------- /src/assets/icons/DomainAccessIcon.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const DomainAccessIcon: React.FC = () => ( 4 | 5 | 9 | 10 | 11 | 12 | 13 | 14 | ); 15 | 16 | export default DomainAccessIcon; 17 | -------------------------------------------------------------------------------- /src/assets/icons/DomainAliasIcon.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const DomainAliasIcon: React.FC = () => { 4 | return ( 5 | 6 | 11 | 16 | 21 | 26 | 27 | ); 28 | }; 29 | 30 | export default DomainAliasIcon; 31 | -------------------------------------------------------------------------------- /src/assets/icons/RecalculateQuotaIcon.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const RecalculateQuotaIcon: React.FC = () => ( 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | ); 27 | 28 | export default RecalculateQuotaIcon; 29 | -------------------------------------------------------------------------------- /src/assets/icons/WildDuckIcon.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const WildDuckIcon: React.FC = () => { 4 | return ( 5 | WildDuck UI 6 | ); 7 | }; 8 | 9 | export default WildDuckIcon; 10 | -------------------------------------------------------------------------------- /src/assets/icons/wildduck.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/314e/wildduck-ui/ca14b2291e64ceab07da2af2e8fd80ce0693821e/src/assets/icons/wildduck.png -------------------------------------------------------------------------------- /src/client/RequestClient.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Lakkanna Walikar 3 | * @description Request client to make api requests 4 | * @exports {Api} api, Client, axiosInstance 5 | */ 6 | 7 | import { AxiosRequestConfig } from 'axios'; 8 | import AxiosClient, { IApi } from './AxiosClient'; 9 | import _ from 'lodash'; 10 | 11 | /** 12 | * Class to get axios instance, Client to make api request and generated api's 13 | * 14 | * axiosInstance - instance of axios with interceptor config and base 15 | * Client - instance to make request 16 | * api - generated api 17 | */ 18 | class RequestClient extends AxiosClient { 19 | constructor() { 20 | super(); 21 | } 22 | 23 | /** 24 | * method to get axios request with configuration 25 | * 26 | * can make request's to api using this method 27 | * @param {AxiosRequestConfig} config - configuration to make api request, 28 | * @example 29 | * url, method, headers 30 | * 31 | * @returns {Promise>} response after making api request with configuration 32 | */ 33 | public request = async (config: AxiosRequestConfig) => { 34 | return await this.getAxiosInstance().request(config); 35 | }; 36 | 37 | /** 38 | * method to get request method to make api requests 39 | * @returns {request} request method 40 | */ 41 | public getClient = () => { 42 | return this.request; 43 | }; 44 | } 45 | 46 | /** 47 | * instance of RequestClient 48 | * @type {RequestClient} 49 | */ 50 | const requestClient = new RequestClient(); 51 | 52 | /** 53 | * reference to request method in RequestClient 54 | * 55 | * make api calls by passing config 56 | * @example 57 | * Client({url: 'example.com', method: 'get'}) 58 | * @returns {Promise>} response from requested api 59 | */ 60 | const client = requestClient.getClient(); 61 | 62 | /** 63 | * instance of Axios 64 | */ 65 | const axiosInstance = requestClient.getAxiosInstance(); 66 | 67 | /** 68 | * generated open-api 69 | * 70 | * reference to getApi in RequestClient 71 | * contains list of api generated from open-api 72 | * @example 73 | * result = await api.salesMetricsApi.getRevenueForecastApiV1GetRevenueForecastGet(startDate, endDate); 74 | * @exports 75 | */ 76 | const api: IApi = new Proxy(({} as unknown) as IApi, { 77 | get: (__, props) => { 78 | return _.get(requestClient.getApi(), props); 79 | }, 80 | }); 81 | 82 | export { client as Client, axiosInstance, api }; 83 | export default api; 84 | -------------------------------------------------------------------------------- /src/client/wildduck-api/.gitignore: -------------------------------------------------------------------------------- 1 | wwwroot/*.js 2 | node_modules 3 | typings 4 | dist 5 | -------------------------------------------------------------------------------- /src/client/wildduck-api/.npmignore: -------------------------------------------------------------------------------- 1 | # empty npmignore to ensure all required files (e.g., in the dist folder) are published by npm -------------------------------------------------------------------------------- /src/client/wildduck-api/.openapi-generator-ignore: -------------------------------------------------------------------------------- 1 | # OpenAPI Generator Ignore 2 | # Generated by openapi-generator https://github.com/openapitools/openapi-generator 3 | 4 | # Use this file to prevent files from being overwritten by the generator. 5 | # The patterns follow closely to .gitignore or .dockerignore. 6 | 7 | # As an example, the C# client generator defines ApiClient.cs. 8 | # You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line: 9 | #ApiClient.cs 10 | 11 | # You can match any string of characters against a directory, file or extension with a single asterisk (*): 12 | #foo/*/qux 13 | # The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux 14 | 15 | # You can recursively match patterns against a directory, file or extension with a double asterisk (**): 16 | #foo/**/qux 17 | # This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux 18 | 19 | # You can also negate patterns with an exclamation (!). 20 | # For example, you can ignore all files in a docs folder with the file extension .md: 21 | #docs/*.md 22 | # Then explicitly reverse the ignore rule for a single file: 23 | #!docs/README.md 24 | -------------------------------------------------------------------------------- /src/client/wildduck-api/.openapi-generator/FILES: -------------------------------------------------------------------------------- 1 | .gitignore 2 | .npmignore 3 | api.ts 4 | base.ts 5 | common.ts 6 | configuration.ts 7 | git_push.sh 8 | index.ts 9 | -------------------------------------------------------------------------------- /src/client/wildduck-api/.openapi-generator/VERSION: -------------------------------------------------------------------------------- 1 | 5.1.0 -------------------------------------------------------------------------------- /src/client/wildduck-api/base.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable */ 2 | /* eslint-disable */ 3 | /** 4 | * WildDuck API 5 | * WildDuck API docs 6 | * 7 | * The version of the OpenAPI document: 1.0.0 8 | * 9 | * 10 | * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). 11 | * https://openapi-generator.tech 12 | * Do not edit the class manually. 13 | */ 14 | 15 | 16 | import { Configuration } from "./configuration"; 17 | // Some imports not used depending on template conditions 18 | // @ts-ignore 19 | import globalAxios, { AxiosPromise, AxiosInstance } from 'axios'; 20 | 21 | export const BASE_PATH = "https://api.wildduck.email".replace(/\/+$/, ""); 22 | 23 | /** 24 | * 25 | * @export 26 | */ 27 | export const COLLECTION_FORMATS = { 28 | csv: ",", 29 | ssv: " ", 30 | tsv: "\t", 31 | pipes: "|", 32 | }; 33 | 34 | /** 35 | * 36 | * @export 37 | * @interface RequestArgs 38 | */ 39 | export interface RequestArgs { 40 | url: string; 41 | options: any; 42 | } 43 | 44 | /** 45 | * 46 | * @export 47 | * @class BaseAPI 48 | */ 49 | export class BaseAPI { 50 | protected configuration: Configuration | undefined; 51 | 52 | constructor(configuration?: Configuration, protected basePath: string = BASE_PATH, protected axios: AxiosInstance = globalAxios) { 53 | if (configuration) { 54 | this.configuration = configuration; 55 | this.basePath = configuration.basePath || this.basePath; 56 | } 57 | } 58 | }; 59 | 60 | /** 61 | * 62 | * @export 63 | * @class RequiredError 64 | * @extends {Error} 65 | */ 66 | export class RequiredError extends Error { 67 | name: "RequiredError" = "RequiredError"; 68 | constructor(public field: string, msg?: string) { 69 | super(msg); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/client/wildduck-api/git_push.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ref: https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/ 3 | # 4 | # Usage example: /bin/sh ./git_push.sh wing328 openapi-pestore-perl "minor update" "gitlab.com" 5 | 6 | git_user_id=$1 7 | git_repo_id=$2 8 | release_note=$3 9 | git_host=$4 10 | 11 | if [ "$git_host" = "" ]; then 12 | git_host="github.com" 13 | echo "[INFO] No command line input provided. Set \$git_host to $git_host" 14 | fi 15 | 16 | if [ "$git_user_id" = "" ]; then 17 | git_user_id="GIT_USER_ID" 18 | echo "[INFO] No command line input provided. Set \$git_user_id to $git_user_id" 19 | fi 20 | 21 | if [ "$git_repo_id" = "" ]; then 22 | git_repo_id="GIT_REPO_ID" 23 | echo "[INFO] No command line input provided. Set \$git_repo_id to $git_repo_id" 24 | fi 25 | 26 | if [ "$release_note" = "" ]; then 27 | release_note="Minor update" 28 | echo "[INFO] No command line input provided. Set \$release_note to $release_note" 29 | fi 30 | 31 | # Initialize the local directory as a Git repository 32 | git init 33 | 34 | # Adds the files in the local repository and stages them for commit. 35 | git add . 36 | 37 | # Commits the tracked changes and prepares them to be pushed to a remote repository. 38 | git commit -m "$release_note" 39 | 40 | # Sets the new remote 41 | git_remote=`git remote` 42 | if [ "$git_remote" = "" ]; then # git remote not defined 43 | 44 | if [ "$GIT_TOKEN" = "" ]; then 45 | echo "[INFO] \$GIT_TOKEN (environment variable) is not set. Using the git credential in your environment." 46 | git remote add origin https://${git_host}/${git_user_id}/${git_repo_id}.git 47 | else 48 | git remote add origin https://${git_user_id}:${GIT_TOKEN}@${git_host}/${git_user_id}/${git_repo_id}.git 49 | fi 50 | 51 | fi 52 | 53 | git pull origin master 54 | 55 | # Pushes (Forces) the changes in the local repository up to the remote repository 56 | echo "Git pushing to https://${git_host}/${git_user_id}/${git_repo_id}.git" 57 | git push origin master 2>&1 | grep -v 'To https' 58 | 59 | -------------------------------------------------------------------------------- /src/client/wildduck-api/index.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable */ 2 | /* eslint-disable */ 3 | /** 4 | * WildDuck API 5 | * WildDuck API docs 6 | * 7 | * The version of the OpenAPI document: 1.0.0 8 | * 9 | * 10 | * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). 11 | * https://openapi-generator.tech 12 | * Do not edit the class manually. 13 | */ 14 | 15 | 16 | export * from "./api"; 17 | export * from "./configuration"; 18 | 19 | -------------------------------------------------------------------------------- /src/components/AccessToken/AccessToken.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Aditya Negi 3 | * @description access token screen 4 | */ 5 | 6 | import React from 'react'; 7 | import { Input, Form, Button } from 'antd'; 8 | import { useActions } from 'kea'; 9 | 10 | import Page from '../Page'; 11 | import { accessTokenString, apiString } from '../../lib/constants/constant'; 12 | import AxiosInterceptor from 'app-ui/lib/axios/AxiosInterceptors'; 13 | 14 | import appLogic from 'app-ui/logic/appLogic'; 15 | 16 | /** 17 | * access token component 18 | */ 19 | const AccessToken: React.FC = () => { 20 | const { setAccessToken } = useActions(appLogic); 21 | 22 | const onFinish = (values: { accessToken: string; api: string }) => { 23 | sessionStorage.setItem(apiString, values.api); 24 | sessionStorage.setItem(accessTokenString, values.accessToken); 25 | setAccessToken(values.accessToken); 26 | 27 | new AxiosInterceptor().inject({ 28 | baseURL: values.api, 29 | headers: { 'Content-Type': 'application/json' }, 30 | }); 31 | }; 32 | 33 | return ( 34 | 35 |
36 | 46 | 47 | 48 | 58 | 59 | 60 | 61 | 64 | 65 |
66 |
67 | ); 68 | }; 69 | 70 | export default AccessToken; 71 | -------------------------------------------------------------------------------- /src/components/AccessToken/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Aditya Negi 3 | * @description resolve id screen container 4 | */ 5 | 6 | import AccessToken from './AccessToken'; 7 | 8 | export default AccessToken; 9 | -------------------------------------------------------------------------------- /src/components/Address/Address.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description Address Component 4 | */ 5 | 6 | import React from 'react'; 7 | import { useValues } from 'kea'; 8 | 9 | import CreateNewAddress from '../CreateNewAddress'; 10 | import AddressTable from './AddressTable'; 11 | import AddressInformation from './AddressInformation'; 12 | 13 | import addressLogic from 'app-ui/logic/addressLogic'; 14 | 15 | /** 16 | * Address Component 17 | */ 18 | const Address: React.FC = () => { 19 | const { creatNewAddressToggle, addressInformationToggle } = useValues(addressLogic); 20 | 21 | if (creatNewAddressToggle) return ; 22 | else if (addressInformationToggle) return ; 23 | else return ; 24 | }; 25 | 26 | export default Address; 27 | -------------------------------------------------------------------------------- /src/components/Address/AddressInformation.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description AddressInformation Component 4 | */ 5 | 6 | import React from 'react'; 7 | import { Breadcrumb } from 'antd'; 8 | import { useActions, useValues } from 'kea'; 9 | import { useParams } from 'react-router-dom'; 10 | 11 | import Page from '../Page'; 12 | import AddressInformationForm from './AddressInformationForm'; 13 | 14 | import useAddressInformation from 'app-ui/hooks/useAddressInformation'; 15 | 16 | import addressLogic from 'app-ui/logic/addressLogic'; 17 | 18 | /** 19 | * AddressInformation Component 20 | */ 21 | const AddressInformation: React.FC = () => { 22 | const { addressId } = useValues(addressLogic); 23 | 24 | const { id }: any = useParams(); 25 | 26 | const { data, isLoading, isError } = useAddressInformation(id, addressId); 27 | const { setAddressInformationToggle } = useActions(addressLogic); 28 | 29 | const pageBreadcrumb = ( 30 | 31 | 32 | { 34 | event.stopPropagation(); 35 | setAddressInformationToggle(false); 36 | }} 37 | > 38 | Address Info 39 | 40 | 41 | Edit Address 42 | 43 | ); 44 | 45 | return ( 46 | 47 | 48 | 49 | ); 50 | }; 51 | 52 | export default AddressInformation; 53 | -------------------------------------------------------------------------------- /src/components/Address/AddressTable.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Table, Tooltip } from 'antd'; 3 | import { useActions } from 'kea'; 4 | import _ from 'lodash'; 5 | import { useParams } from 'react-router-dom'; 6 | 7 | import { DiffOutlined } from '@ant-design/icons'; 8 | import FloatingButton from '../FloatingButton'; 9 | import { getAddressColumns } from './Columns'; 10 | 11 | import useAddress from 'app-ui/hooks/useAddress'; 12 | import useDeleteAddress from 'app-ui/hooks/useDeleteAddress'; 13 | 14 | import addressLogic from 'app-ui/logic/addressLogic'; 15 | 16 | const AddressTable: React.FC = () => { 17 | const { setAddressInformationToggle, setCreatNewAddressToggle, setAddressId } = useActions(addressLogic); 18 | 19 | const { id }: any = useParams(); 20 | 21 | const { data, isLoading } = useAddress(id); 22 | 23 | const { mutate } = useDeleteAddress(); 24 | 25 | const columns = React.useMemo( 26 | () => 27 | getAddressColumns({ 28 | dataSource: data, 29 | edit: (addressId: string) => { 30 | setAddressId(addressId); 31 | setAddressInformationToggle(true); 32 | }, 33 | deleteAddress: (addressId: string) => mutate({ userId: id, addressId: addressId }), 34 | }), 35 | [data], 36 | ); 37 | 38 | return ( 39 | <> 40 | 10 ? null : false} 46 | /> 47 | 48 | 49 | { 51 | setCreatNewAddressToggle(true); 52 | }} 53 | /> 54 | 55 | 56 | 57 | ); 58 | }; 59 | 60 | export default AddressTable; 61 | -------------------------------------------------------------------------------- /src/components/Address/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description Container for Address Component 4 | */ 5 | 6 | import Address from './Address'; 7 | 8 | export default Address; 9 | -------------------------------------------------------------------------------- /src/components/App/index.tsx: -------------------------------------------------------------------------------- 1 | import App from './App'; 2 | 3 | export default App; 4 | -------------------------------------------------------------------------------- /src/components/Archive/Archive.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description Archive Component 4 | */ 5 | 6 | import React from 'react'; 7 | 8 | import ArchiveTable from './ArchiveTable'; 9 | import RestoreAllMessagesModal from './RestoreAllMessagesModal'; 10 | 11 | /** 12 | * Archive Component 13 | */ 14 | const Archive: React.FC = () => { 15 | return ( 16 | <> 17 | 18 | 19 | 20 | ); 21 | }; 22 | 23 | export default Archive; 24 | -------------------------------------------------------------------------------- /src/components/Archive/RestoreAllMessagesModal.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description RestoreAllMessagesModal Component 4 | */ 5 | 6 | import React from 'react'; 7 | import { Modal, Typography, DatePicker } from 'antd'; 8 | import { useActions, useValues } from 'kea'; 9 | import _ from 'lodash'; 10 | import moment from 'moment'; 11 | import { useParams } from 'react-router-dom'; 12 | 13 | import { ExclamationCircleOutlined } from '@ant-design/icons'; 14 | import { DATE_TIME_FORMAT } from 'app-ui/utils/constants'; 15 | import useRestoreArchiveMessages from 'app-ui/hooks/useRestoreArchiveMessages'; 16 | 17 | import archiveLogic from 'app-ui/logic/archiveLogic'; 18 | 19 | const { Title } = Typography; 20 | 21 | const { RangePicker } = DatePicker; 22 | 23 | const RestoreAllMessagesModal = () => { 24 | const { setDateData, setIsModalVisible } = useActions(archiveLogic); 25 | const { dateData, isModalVisible } = useValues(archiveLogic); 26 | 27 | const { id }: any = useParams(); 28 | 29 | const { mutate } = useRestoreArchiveMessages(); 30 | 31 | const handleOk = () => { 32 | mutate({ 33 | userId: id, 34 | params: { 35 | start: _.get(dateData, '0', moment('2000-01-01 00:00:00')).format(DATE_TIME_FORMAT), 36 | end: _.get(dateData, '1', moment()).format(DATE_TIME_FORMAT), 37 | }, 38 | }); 39 | setIsModalVisible(false); 40 | }; 41 | 42 | const handleCancel = () => { 43 | setIsModalVisible(false); 44 | setDateData([]); 45 | }; 46 | 47 | return ( 48 | 49 | 50 | <ExclamationCircleOutlined /> 51 | Are you sure you want to Restore all messages ? 52 | 53 |

Select the start and end date (by default it will restores all the mails).

54 | current && current > moment().endOf('day')} 56 | onChange={(value) => setDateData(value)} 57 | showTime 58 | defaultValue={ 59 | _.isEmpty(dateData) ? ('' as any) : [moment(_.get(dateData, '0')), moment(_.get(dateData, '1'))] 60 | } 61 | /> 62 |
63 | ); 64 | }; 65 | 66 | export default RestoreAllMessagesModal; 67 | -------------------------------------------------------------------------------- /src/components/Archive/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description Container for Archive Component 4 | */ 5 | 6 | import Archive from './Archive'; 7 | 8 | export default Archive; 9 | -------------------------------------------------------------------------------- /src/components/Authentication/Authentication.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description Authentication Component 4 | */ 5 | 6 | import React from 'react'; 7 | 8 | import AuthenticationTable from './AuthenticationTable'; 9 | 10 | /** 11 | * Authentication Component 12 | */ 13 | const Authentication: React.FC = () => { 14 | return ; 15 | }; 16 | 17 | export default Authentication; 18 | -------------------------------------------------------------------------------- /src/components/Authentication/AuthenticationTable.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description AuthenticationTable Component 4 | */ 5 | 6 | import React from 'react'; 7 | import { Table } from 'antd'; 8 | import { useActions, useValues } from 'kea'; 9 | import _ from 'lodash'; 10 | import { useParams } from 'react-router-dom'; 11 | 12 | import { getAuthenticatonColumns } from './Columns'; 13 | import useAuthentication from 'app-ui/hooks/useAuthentication'; 14 | import { Pagination } from 'app-ui/utils/Pagination'; 15 | 16 | import authenticationLogic from 'app-ui/logic/authenticationLogic'; 17 | 18 | const AuthenticationTable: React.FC = () => { 19 | const { page, limit, previous, next } = useValues(authenticationLogic); 20 | const { setLimit, setPage, setNext, setPrevious } = useActions(authenticationLogic); 21 | 22 | const { id }: any = useParams(); 23 | 24 | const { data: results, isLoading } = useAuthentication(id, { 25 | page: page, 26 | next: page === 1 ? undefined : next || undefined, 27 | previous: previous || undefined, 28 | limit: limit, 29 | }); 30 | 31 | const { data, nextCursor, previousCursor } = _.isUndefined(results) 32 | ? { data: [], nextCursor: undefined, previousCursor: undefined } 33 | : results; 34 | setNext(nextCursor); 35 | setPrevious(previousCursor); 36 | 37 | const columns = React.useMemo(() => getAuthenticatonColumns({ dataSource: data }), [data]); 38 | return ( 39 | <> 40 | 50 |
58 | 59 | ); 60 | }; 61 | 62 | export default AuthenticationTable; 63 | -------------------------------------------------------------------------------- /src/components/Authentication/Columns.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description ForwardedAddress Table 4 | */ 5 | 6 | import _ from 'lodash'; 7 | import moment from 'moment'; 8 | 9 | import getColumnsWithFilterAndSort from 'app-ui/utils/getColumnsWithFilterAndSort'; 10 | import { DATE_TIME_FORMAT_AP } from 'app-ui/utils/constants'; 11 | 12 | export const getAuthenticatonColumns = ({ dataSource }: { dataSource: any }): any => { 13 | const columns = [ 14 | { 15 | title: 'Action', 16 | dataIndex: 'action', 17 | key: 'action', 18 | filter: true, 19 | }, 20 | { 21 | title: 'Events', 22 | dataIndex: 'events', 23 | key: 'events', 24 | sortable: 'number', 25 | }, 26 | { 27 | title: 'Result', 28 | dataIndex: 'result', 29 | key: 'result', 30 | align: 'center', 31 | filter: true, 32 | }, 33 | { 34 | title: 'Protocol', 35 | dataIndex: 'protocol', 36 | key: 'protocol', 37 | filter: true, 38 | }, 39 | { 40 | title: 'Source', 41 | dataIndex: 'source', 42 | key: 'source', 43 | align: 'center' as const, 44 | }, 45 | { 46 | title: 'Required Scope', 47 | dataIndex: 'requiredScope', 48 | key: 'requiredScope', 49 | align: 'center' as const, 50 | filter: true, 51 | }, 52 | { 53 | title: 'Session id', 54 | dataIndex: 'sess', 55 | key: 'sess', 56 | }, 57 | { 58 | title: 'ip address', 59 | dataIndex: 'ip', 60 | key: 'ip', 61 | align: 'center' as const, 62 | filter: true, 63 | }, 64 | { 65 | title: 'Session created', 66 | dataIndex: 'created', 67 | key: 'created', 68 | align: 'center' as const, 69 | sortable: 'date', 70 | render: (date: string) => moment(date).format(DATE_TIME_FORMAT_AP), 71 | }, 72 | { 73 | title: 'Session expires', 74 | dataIndex: 'expires', 75 | key: 'expires', 76 | align: 'center' as const, 77 | sortable: 'date', 78 | render: (date: string) => moment(date).format(DATE_TIME_FORMAT_AP), 79 | }, 80 | { 81 | title: 'Last activity', 82 | dataIndex: 'last', 83 | key: 'last', 84 | align: 'center' as const, 85 | sortable: 'date', 86 | render: (date: string) => moment(date).format(DATE_TIME_FORMAT_AP), 87 | }, 88 | ]; 89 | 90 | return getColumnsWithFilterAndSort(columns, dataSource); 91 | }; 92 | -------------------------------------------------------------------------------- /src/components/Authentication/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description Container for Authentication Component 4 | */ 5 | 6 | import Authentication from './Authentication'; 7 | 8 | export default Authentication; 9 | -------------------------------------------------------------------------------- /src/components/Autoreplies/Autoreplies.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description Autoreplies Component 4 | */ 5 | 6 | import React from 'react'; 7 | import { Tooltip } from 'antd'; 8 | import { useParams } from 'react-router-dom'; 9 | 10 | import { DeleteOutlined } from '@ant-design/icons'; 11 | import showConfirm from 'app-ui/utils/showConfirm'; 12 | import FloatingButton from '../FloatingButton'; 13 | import Page from '../Page'; 14 | import AutorepliesForm from './AutorepliesForm'; 15 | 16 | import useDeleteAutoreply from 'app-ui/hooks/useDeleteAutoreply'; 17 | import useAutoreplyDetails from 'app-ui/hooks/useAutoreplyDetails'; 18 | 19 | /** 20 | * Autoreplies Component 21 | */ 22 | const Autoreplies: React.FC = () => { 23 | const { id }: any = useParams(); 24 | 25 | const { data, isLoading, isError } = useAutoreplyDetails(id); 26 | 27 | const { mutate: deleteAutoreply } = useDeleteAutoreply(); 28 | 29 | return ( 30 | 31 | 32 | 33 | 34 | 36 | showConfirm(() => { 37 | deleteAutoreply(id); 38 | }, 'Are you sure you want to delete?') 39 | } 40 | /> 41 | 42 | 43 | 44 | ); 45 | }; 46 | 47 | export default Autoreplies; 48 | -------------------------------------------------------------------------------- /src/components/Autoreplies/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description Container for Autoreplies Component 4 | */ 5 | 6 | import Autoreplies from './Autoreplies'; 7 | 8 | export default Autoreplies; 9 | -------------------------------------------------------------------------------- /src/components/ContentArea/index.ts: -------------------------------------------------------------------------------- 1 | import ContentArea from './ContentArea'; 2 | 3 | export default ContentArea; 4 | -------------------------------------------------------------------------------- /src/components/CreateDkim/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Aditya Negi 3 | * @description create dkim screen container 4 | */ 5 | 6 | import CreateDkim from './CreateDkim'; 7 | 8 | export default CreateDkim; 9 | -------------------------------------------------------------------------------- /src/components/CreateNewAddress/CreateNewAddress.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description CreateNewAddress Component 4 | */ 5 | 6 | import React from 'react'; 7 | import { Breadcrumb } from 'antd'; 8 | import { useActions } from 'kea'; 9 | 10 | import Page from '../Page'; 11 | import CreateNewAddressForm from './CreateNewAddressForm'; 12 | 13 | import addressLogic from 'app-ui/logic/addressLogic'; 14 | 15 | /** 16 | * CreateNewAddress Component 17 | */ 18 | const CreateNewAddress: React.FC = () => { 19 | const { setCreatNewAddressToggle } = useActions(addressLogic); 20 | 21 | const pageBreadcrumb = ( 22 | 23 | 24 | { 26 | event.stopPropagation(); 27 | setCreatNewAddressToggle(false); 28 | }} 29 | > 30 | Address Info 31 | 32 | 33 | Create New Address 34 | 35 | ); 36 | 37 | return ( 38 | 39 | 40 | 41 | ); 42 | }; 43 | 44 | export default CreateNewAddress; 45 | -------------------------------------------------------------------------------- /src/components/CreateNewAddress/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description Container for CreateNewAddress Component 4 | */ 5 | 6 | import CreateNewAddress from './CreateNewAddress'; 7 | 8 | export default CreateNewAddress; 9 | -------------------------------------------------------------------------------- /src/components/CreateNewDomainAlias/CreateNewDomainAlias.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description CreateNewDomainAlias Component 4 | */ 5 | 6 | import React from 'react'; 7 | import { Breadcrumb } from 'antd'; 8 | 9 | import Link from 'app-ui/components/CustomLink'; 10 | import Page from '../Page'; 11 | import CreateNewDomainAliasForm from './CreateNewDomainAliasForm'; 12 | 13 | /** 14 | * CreateNewDomainAlias Component 15 | */ 16 | const CreateNewDomainAlias: React.FC = () => { 17 | const breadcrum = ( 18 | 19 | 20 | Domain Aliases 21 | 22 | Create New Address 23 | 24 | ); 25 | 26 | return ( 27 | 28 | 29 | 30 | ); 31 | }; 32 | 33 | export default CreateNewDomainAlias; 34 | -------------------------------------------------------------------------------- /src/components/CreateNewDomainAlias/CreateNewDomainAliasForm.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description CreateNewDomainAliasForm Component 4 | */ 5 | 6 | import React from 'react'; 7 | import { Form, Input, Button } from 'antd'; 8 | import _ from 'lodash'; 9 | import { useHistory } from 'react-router-dom'; 10 | 11 | import { tailLayout, layout } from '../FormLayout'; 12 | import { getBasePath } from '../CustomLink'; 13 | 14 | import useCreateDomainAliases from 'app-ui/hooks/useCreateDomainAliases'; 15 | 16 | /** 17 | * CreateNewDomainAliasForm Component 18 | */ 19 | const CreateNewDomainAliasForm = (): JSX.Element => { 20 | const { mutate, isSuccess, data } = useCreateDomainAliases(); 21 | 22 | const history = useHistory(); 23 | 24 | if (isSuccess && !_.get(data, 'data.error')) { 25 | history.push(`${getBasePath()}/domain-aliases`); 26 | } 27 | 28 | const [form] = Form.useForm(); 29 | 30 | const onFinish = (values: any) => { 31 | mutate(values); 32 | }; 33 | 34 | const onReset = () => { 35 | form.resetFields(); 36 | }; 37 | 38 | return ( 39 |
40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 50 | 53 | 54 | 55 | ); 56 | }; 57 | 58 | export default CreateNewDomainAliasForm; 59 | -------------------------------------------------------------------------------- /src/components/CreateNewDomainAlias/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description CreateNewDomainAlias Component Container 4 | */ 5 | 6 | import CreateNewDomainAlias from './CreateNewDomainAlias'; 7 | 8 | export default CreateNewDomainAlias; 9 | -------------------------------------------------------------------------------- /src/components/CreateNewForwardedAddress/CreateNewForwardedAddress.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description CreateNewForwardedAddress Component 4 | */ 5 | 6 | import React from 'react'; 7 | import { Breadcrumb } from 'antd'; 8 | 9 | import Link from 'app-ui/components/CustomLink'; 10 | import Page from '../Page'; 11 | import CreateNewForwardedAddressForm from './CreateNewForwardedAddressForm'; 12 | 13 | /** 14 | * CreateNewForwardedAddress Component 15 | */ 16 | const CreateNewForwardedAddress: React.FC = () => { 17 | const breadcrum = ( 18 | 19 | 20 | Forwarded Addresses 21 | 22 | Create new Forwarded Address 23 | 24 | ); 25 | 26 | return ( 27 | 28 | 29 | 30 | ); 31 | }; 32 | 33 | export default CreateNewForwardedAddress; 34 | -------------------------------------------------------------------------------- /src/components/CreateNewForwardedAddress/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description Container for CreateNewForwardedAddress Component 4 | */ 5 | 6 | import CreateNewForwardedAddress from './CreateNewForwardedAddress'; 7 | 8 | export default CreateNewForwardedAddress; 9 | -------------------------------------------------------------------------------- /src/components/CreateNewUser/CreateNewUser.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Aditya Negi 3 | * @description Add Users screen 4 | */ 5 | 6 | import React from 'react'; 7 | import { Breadcrumb } from 'antd'; 8 | 9 | import Page from 'components/Page'; 10 | import Link from 'app-ui/components/CustomLink'; 11 | import CreateNewUserForm from './CreateNewUserForm'; 12 | 13 | const CreateNewUser: React.FC = () => { 14 | const pageBreadcrumb = ( 15 | 16 | 17 | Users 18 | 19 | Add User 20 | 21 | ); 22 | 23 | return ( 24 | 25 | 26 | 27 | ); 28 | }; 29 | 30 | export default CreateNewUser; 31 | -------------------------------------------------------------------------------- /src/components/CreateNewUser/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description CreateNewUser Component Container 4 | */ 5 | 6 | import CreateNewUser from './CreateNewUser'; 7 | 8 | export default CreateNewUser; 9 | -------------------------------------------------------------------------------- /src/components/CustomLink/index.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Lakkanna Walikar 3 | * @description Custom Link component to prefix basepath for to 4 | */ 5 | 6 | import React from 'react'; 7 | import { Link, LinkProps } from 'react-router-dom'; 8 | import _ from 'lodash'; 9 | 10 | export const getBasePath = (): string => { 11 | return _.get(window, 'basePath', '').slice(0, -1); 12 | }; 13 | 14 | /** 15 | * CustomLink to prefix basepath for to 16 | * @param props 17 | */ 18 | function CustomLink (props: LinkProps & React.RefAttributes ): ReturnType> { 19 | const {to, children, ...restProps} = props; 20 | return ( 21 | {children} 22 | ); 23 | } 24 | 25 | export default CustomLink; 26 | -------------------------------------------------------------------------------- /src/components/Dkim/Dkim.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Aditya Negi 3 | * @description Dkim screen 4 | */ 5 | 6 | import React from 'react'; 7 | import { useActions } from 'kea'; 8 | import { Button, Input, Row, Col } from 'antd'; 9 | 10 | import Page from 'components/Page'; 11 | import Link from 'app-ui/components/CustomLink'; 12 | import DkimTable from './DkimTable'; 13 | 14 | import dkimLogic from 'app-ui/logic/dkimLogic'; 15 | 16 | /** 17 | * Dkim component 18 | */ 19 | const Dkim: React.FC = () => { 20 | const { setQuery } = useActions(dkimLogic); 21 | 22 | const { Search } = Input; 23 | 24 | const FilterSearch = () => { 25 | const onFinish = (values: any) => { 26 | setQuery(values); 27 | }; 28 | 29 | return ; 30 | }; 31 | 32 | return ( 33 | 37 | Create DKIM key for Domain 38 | , 39 | ]} 40 | > 41 | 42 |
{} 43 | 44 | 45 | 46 | 47 | 48 | ); 49 | }; 50 | 51 | export default Dkim; 52 | -------------------------------------------------------------------------------- /src/components/Dkim/DkimColumns.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Aditya Negi 3 | * @description Dkim Table Columns 4 | */ 5 | 6 | import React from 'react'; 7 | import moment from 'moment'; 8 | import { Space, Button, Tooltip } from 'antd'; 9 | 10 | import { EditFilled, DeleteFilled } from '@ant-design/icons'; 11 | import { DATE_TIME_FORMAT_AP } from 'app-ui/utils/constants'; 12 | import showConfirm from 'app-ui/utils/showConfirm'; 13 | import getColumnsWithFilterAndSort from 'app-ui/utils/getColumnsWithFilterAndSort'; 14 | import { GetDkimKeysResult } from 'client/wildduck-api'; 15 | import { DkimDetailsLink } from '../Widgets/Link'; 16 | 17 | export const getDkimColumns: any = ({ dataSource, deleteDkim }: { dataSource: any; deleteDkim(id: string): void }) => { 18 | const columnsDkim = [ 19 | { 20 | title: 'Domain', 21 | dataIndex: 'domain', 22 | filter: true, 23 | render: (text: string, record: GetDkimKeysResult) => , 24 | }, 25 | { 26 | title: 'Selector', 27 | filter: true, 28 | dataIndex: 'selector', 29 | }, 30 | { 31 | title: 'Description', 32 | dataIndex: 'description', 33 | }, 34 | { 35 | title: 'Created', 36 | dataIndex: 'created', 37 | sortable: 'date', 38 | align: 'center' as const, 39 | render: (date: string) => moment(date).format(DATE_TIME_FORMAT_AP), 40 | }, 41 | { 42 | title: 'Actions', 43 | dataIndex: 'Action', 44 | align: 'center' as const, 45 | render: (text: string, record: GetDkimKeysResult) => ( 46 | 47 | 48 | 52 | 53 | 54 | } 55 | /> 56 | 57 | 58 | 67 | 68 | 69 | ), 70 | }, 71 | ]; 72 | 73 | return getColumnsWithFilterAndSort(columnsDkim, dataSource); 74 | }; 75 | -------------------------------------------------------------------------------- /src/components/Dkim/DkimTable.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Aditya Negi 3 | * @description Dkim Table 4 | */ 5 | 6 | import React from 'react'; 7 | import { Table } from 'antd'; 8 | import { useValues, useActions } from 'kea'; 9 | import _ from 'lodash'; 10 | 11 | import { getDkimColumns } from './DkimColumns'; 12 | import { Pagination } from 'app-ui/utils/Pagination'; 13 | 14 | import useDeleteDkim from 'app-ui/hooks/useDeleteDkim'; 15 | import useDkim from 'app-ui/hooks/useDkim'; 16 | 17 | import dkimLogic from 'app-ui/logic/dkimLogic'; 18 | 19 | const DkimTable: React.FC = () => { 20 | const { query, page, limit, next, previous } = useValues(dkimLogic); 21 | const { setPrevious, setLimit, setNext, setPage } = useActions(dkimLogic); 22 | const { data: results, isLoading } = useDkim({ 23 | query: query, 24 | page: page, 25 | next: page === 1 ? undefined : next || undefined, 26 | previous: previous || undefined, 27 | limit: limit, 28 | }); 29 | const { data, previousCursor, nextCursor } = _.isUndefined(results) 30 | ? { data: [], nextCursor: undefined, previousCursor: undefined } 31 | : results; 32 | 33 | const { mutate } = useDeleteDkim(); 34 | 35 | const columns = React.useMemo( 36 | () => 37 | getDkimColumns({ 38 | dataSource: data, 39 | deleteDkim: (id: string) => mutate(id), 40 | }), 41 | [data], 42 | ); 43 | 44 | return ( 45 | <> 46 | 56 |
65 | 66 | ); 67 | }; 68 | 69 | export default DkimTable; 70 | -------------------------------------------------------------------------------- /src/components/Dkim/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Aditya Negi 3 | * @description Dkim screen container 4 | */ 5 | 6 | import Dkim from './Dkim'; 7 | 8 | export default Dkim; 9 | -------------------------------------------------------------------------------- /src/components/DkimDetails/DkimDetails.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Aditya Negi 3 | * @description Dkim Details screen 4 | */ 5 | 6 | import React from 'react'; 7 | import { Tabs, Descriptions, Breadcrumb } from 'antd'; 8 | import { useParams, Link } from 'react-router-dom'; 9 | 10 | import Page from 'components/Page'; 11 | 12 | import useDkimDetails from 'app-ui/hooks/useDkimDetails'; 13 | 14 | const DkimDetails: React.SFC = () => { 15 | const { TabPane } = Tabs; 16 | const params: { id: string } = useParams(); 17 | const { data, isLoading } = useDkimDetails(params.id); 18 | 19 | const DescriptionBox = () => { 20 | return ( 21 | !isLoading && ( 22 | 23 | {data.id} 24 | {data.domain} 25 | {data.selector} 26 | {data.description} 27 | {data.fingerprint} 28 | {data.dnsTxt.name} 29 | {data.dnsTxt.value} 30 | {data.created} 31 | 32 | ) 33 | ); 34 | }; 35 | 36 | const pageBreadcrumb = ( 37 | 38 | 39 | DKIM 40 | 41 | 42 | {!isLoading && data.domain} 43 | 44 | ); 45 | return ( 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | ); 54 | }; 55 | 56 | export default DkimDetails; 57 | -------------------------------------------------------------------------------- /src/components/DkimDetails/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Aditya Negi 3 | * @description DkimDetails screen container 4 | */ 5 | 6 | import DkimDetails from './DkimDetails'; 7 | 8 | export default DkimDetails; 9 | -------------------------------------------------------------------------------- /src/components/DomainAccess/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description DomainAccess Component Container 4 | */ 5 | 6 | import DomainAccess from './DomainAccess'; 7 | 8 | export default DomainAccess; 9 | -------------------------------------------------------------------------------- /src/components/DomainAliases/Columns.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description DomainAliases Table Columns 4 | */ 5 | 6 | import React from 'react'; 7 | import { Space, Button, Tooltip } from 'antd'; 8 | 9 | import { DeleteFilled } from '@ant-design/icons'; 10 | import getColumnsWithFilterAndSort from 'app-ui/utils/getColumnsWithFilterAndSort'; 11 | import showConfirm from 'app-ui/utils/showConfirm'; 12 | 13 | export const getDomainAliasesColumns = ({ 14 | dataSource, 15 | deleteDomainAliases, 16 | }: { 17 | dataSource: any; 18 | deleteDomainAliases(value: string): void; 19 | }): any => { 20 | const columnDomainAliases = [ 21 | { 22 | title: 'Alias', 23 | dataIndex: 'alias', 24 | sortable: 'string', 25 | filter: true, 26 | }, 27 | { 28 | title: 'Domain', 29 | dataIndex: 'domain', 30 | sortable: 'string', 31 | filter: true, 32 | }, 33 | { 34 | title: 'Action', 35 | key: 'action', 36 | width: 100, 37 | align: 'center' as const, 38 | render: (text: string, record: any) => ( 39 | 40 | 41 | 50 | 51 | 52 | ), 53 | }, 54 | ]; 55 | 56 | return getColumnsWithFilterAndSort(columnDomainAliases, dataSource); 57 | }; 58 | -------------------------------------------------------------------------------- /src/components/DomainAliases/DomainAliases.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description DomainAliases Component 4 | */ 5 | 6 | import React from 'react'; 7 | import { Button, Col, Row } from 'antd'; 8 | 9 | import Link from 'app-ui/components/CustomLink'; 10 | import Page from '../Page'; 11 | import DomainAliasesTable from './DomainAliasesTable'; 12 | import SearchAlias from './SearchAlias'; 13 | 14 | /** 15 | * DomainAliases Component 16 | */ 17 | const DomainAliases: React.FC = () => { 18 | return ( 19 | 23 | Create new Domain Alias 24 | , 25 | ]} 26 | > 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | ); 37 | }; 38 | 39 | export default DomainAliases; 40 | -------------------------------------------------------------------------------- /src/components/DomainAliases/DomainAliasesTable.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description DomainAliasesTable Component 4 | */ 5 | 6 | import React from 'react'; 7 | import { Table } from 'antd'; 8 | import { useValues, useActions } from 'kea'; 9 | import _ from 'lodash'; 10 | 11 | import { getDomainAliasesColumns } from './Columns'; 12 | import { Pagination } from 'app-ui/utils/Pagination'; 13 | 14 | import domainAliasesLogic from 'app-ui/logic/domainAliasesLogic'; 15 | 16 | import useDomainAliases from 'app-ui/hooks/useDomainAliases'; 17 | import useDeleteDomainAliases from 'app-ui/hooks/useDeleteDomainAliases'; 18 | 19 | /** 20 | * DomainAliasesTable Component 21 | */ 22 | const DomainAliasesTable: React.FC = () => { 23 | const { setPage, setLimit, setNext, setPrevious } = useActions(domainAliasesLogic); 24 | 25 | const { query, limit, page, next, previous } = useValues(domainAliasesLogic); 26 | 27 | const { mutate } = useDeleteDomainAliases(); 28 | 29 | const { data: results, isLoading } = useDomainAliases({ 30 | query: _.isEmpty(query) ? undefined : query, 31 | page: page, 32 | next: page === 1 ? undefined : next || undefined, 33 | previous: previous || undefined, 34 | limit: limit, 35 | }); 36 | 37 | const { data, nextCursor, previousCursor } = _.isUndefined(results) 38 | ? { data: [], nextCursor: undefined, previousCursor: undefined } 39 | : results; 40 | setNext(nextCursor); 41 | setPrevious(previousCursor); 42 | 43 | const columns = React.useMemo( 44 | () => 45 | getDomainAliasesColumns({ 46 | dataSource: data, 47 | deleteDomainAliases: (aliasId: string) => mutate(aliasId), 48 | }), 49 | [data], 50 | ); 51 | 52 | return _.isUndefined(data) ? null : ( 53 | <> 54 | 64 | 74 | 75 | ); 76 | }; 77 | 78 | export default DomainAliasesTable; 79 | -------------------------------------------------------------------------------- /src/components/DomainAliases/SearchAlias.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description SearchAlias Component 4 | */ 5 | 6 | import React from 'react'; 7 | import { useActions, useValues } from 'kea'; 8 | 9 | import Search from 'antd/lib/input/Search'; 10 | 11 | import domainAliasesLogic from 'app-ui/logic/domainAliasesLogic'; 12 | 13 | /** 14 | * SearchAlias Component 15 | */ 16 | const SearchAlias: React.FC = () => { 17 | const { setQuery } = useActions(domainAliasesLogic); 18 | const { query } = useValues(domainAliasesLogic); 19 | 20 | const onSearch = (value: string) => { 21 | setQuery(value); 22 | }; 23 | 24 | return ( 25 | 33 | ); 34 | }; 35 | 36 | export default SearchAlias; 37 | -------------------------------------------------------------------------------- /src/components/DomainAliases/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description Container for DomainAliases Component 4 | */ 5 | 6 | import DomainAliases from './DomainAliases'; 7 | 8 | export default DomainAliases; 9 | -------------------------------------------------------------------------------- /src/components/ErrorBoundary/ErrorBoundary.tsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import _ from 'lodash'; 3 | import log from 'loglevel'; 4 | 5 | import ErrorPage from './ErrorPage'; 6 | 7 | /** 8 | * class component to handle erros 9 | * @class ErrorBoundary 10 | * @extends Component 11 | */ 12 | class ErrorBoundary extends Component { 13 | /** 14 | * lifecycle to catch DOM errors 15 | * 16 | * @param {object|string} error error message 17 | * @param info {object|string} info stack information of error 18 | */ 19 | componentDidCatch(error: Error, info: React.ErrorInfo): void { 20 | const { setError } = this.props.actions; 21 | if (error && _.isFunction(setError)) { 22 | setError({ error, info }); 23 | } else { 24 | log.error(error, info); 25 | } 26 | } 27 | 28 | /** 29 | * ErrorBoundary Renderer 30 | */ 31 | render(): JSX.Element | React.ReactNode { 32 | const { error, children } = this.props; 33 | if (error) { 34 | return ; 35 | } 36 | return children; 37 | } 38 | } 39 | 40 | export default ErrorBoundary; 41 | -------------------------------------------------------------------------------- /src/components/ErrorBoundary/ErrorPage.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import _ from 'lodash'; 3 | import { Result } from 'antd'; 4 | import { WarningFilled } from '@ant-design/icons'; 5 | import { ResultProps } from 'antd/lib/result'; 6 | 7 | /** 8 | * interface for Error 9 | * @interface IError 10 | */ 11 | interface IError { 12 | [key: string]: { 13 | /** 14 | * title 15 | * @type {ResultProps['status']} 16 | */ 17 | title: ResultProps['status']; 18 | /** 19 | * description 20 | * @type {string} 21 | */ 22 | description: string; 23 | }; 24 | } 25 | 26 | /** 27 | * data for common errors 28 | */ 29 | const commonErrors: IError = { 30 | error403: { 31 | title: 403, 32 | description: 'Unauthorized Access', 33 | }, 34 | error404: { 35 | title: 404, 36 | description: 'Page Not Found', 37 | }, 38 | error500: { 39 | title: 500, 40 | description: 'Server Error', 41 | }, 42 | }; 43 | 44 | /** 45 | * functional component to render error 46 | * @param {any} props 47 | */ 48 | const ErrorPage = (props: any) => { 49 | let error = commonErrors.error404; 50 | 51 | if (_.has(props, 'error') && _.has(commonErrors, `error${_.get(props, 'error')}`)) { 52 | error = _.get(commonErrors, `error${_.get(props, 'error')}`); 53 | } else { 54 | error = props; 55 | } 56 | 57 | return } />; 58 | }; 59 | 60 | export default ErrorPage; 61 | -------------------------------------------------------------------------------- /src/components/ErrorBoundary/index.ts: -------------------------------------------------------------------------------- 1 | import { connect } from 'kea'; 2 | import ErrorBoundary from './ErrorBoundary'; 3 | import appLogic from 'app-ui/logic/appLogic'; 4 | 5 | const logic = connect({ 6 | values: [appLogic, ['error']], 7 | actions: [appLogic, ['setError']], 8 | }); 9 | 10 | export default logic(ErrorBoundary) as any; 11 | -------------------------------------------------------------------------------- /src/components/Filters/Filters.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Aditya Negi 3 | * @description Filters Component 4 | */ 5 | 6 | import React from 'react'; 7 | import _ from 'lodash'; 8 | import { useValues } from 'kea'; 9 | 10 | import AddFiltersForm from './AddFiltersForm'; 11 | import FiltersTable from './FiltersTable'; 12 | 13 | import filtersLogic from 'app-ui/logic/filtersLogic'; 14 | 15 | const Filters: React.FC = () => { 16 | const { showAddFilterForm, filterId } = useValues(filtersLogic); 17 | 18 | return ( 19 | <> 20 | {showAddFilterForm ? : null} 21 | {!_.isEmpty(filterId) ? : null} 22 | {_.isEmpty(filterId) && !showAddFilterForm && } 23 | 24 | ); 25 | }; 26 | 27 | export default Filters; 28 | -------------------------------------------------------------------------------- /src/components/Filters/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Aditya Negi 3 | * @description Container for Storage Component 4 | */ 5 | import Filters from './Filters'; 6 | 7 | export default Filters; 8 | -------------------------------------------------------------------------------- /src/components/FloatingButton.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Aditya Negi 3 | * @description Floating Button 4 | */ 5 | 6 | import React from 'react'; 7 | 8 | export interface FloatingButtonProps { 9 | children?: React.ReactNode; 10 | } 11 | 12 | const FloatingButton: React.SFC = (props: FloatingButtonProps) => { 13 | return ( 14 |
15 |
16 |

{props.children}

17 |
18 |
19 |

+

20 | 24 |
25 |
26 | ); 27 | }; 28 | 29 | export default FloatingButton; 30 | -------------------------------------------------------------------------------- /src/components/FormLayout.ts: -------------------------------------------------------------------------------- 1 | const layout = { 2 | labelCol: { 3 | span: 4, 4 | }, 5 | wrapperCol: { 6 | span: 6, 7 | }, 8 | }; 9 | const tailLayout = { 10 | wrapperCol: { 11 | offset: 4, 12 | span: 8, 13 | }, 14 | }; 15 | export { layout, tailLayout }; 16 | -------------------------------------------------------------------------------- /src/components/ForwardedAddress/Columns.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description ForwardedAddress Table Columns 4 | */ 5 | 6 | import React from 'react'; 7 | import _ from 'lodash'; 8 | import { Space, Button, Tag, Tooltip } from 'antd'; 9 | 10 | import { DeleteFilled, EditFilled } from '@ant-design/icons'; 11 | import getColumnsWithFilterAndSort from 'app-ui/utils/getColumnsWithFilterAndSort'; 12 | import showConfirm from 'app-ui/utils/showConfirm'; 13 | import { ForwardedAddressLink } from '../Widgets/Link'; 14 | 15 | export const getForwardedAddressColumns = ({ 16 | dataSource, 17 | deleteAddress, 18 | }: { 19 | dataSource: any; 20 | deleteAddress(value: string): void; 21 | }): any => { 22 | const columnsForwarded = [ 23 | { 24 | title: 'Forwarded address', 25 | dataIndex: 'address', 26 | key: 'address', 27 | filter: true, 28 | render: (text: string, record: Address.IForwardedAddress) => ( 29 | 30 | 31 | 32 | ), 33 | }, 34 | { 35 | title: 'Name', 36 | dataIndex: 'name', 37 | key: 'name', 38 | filter: true, 39 | }, 40 | { 41 | title: 'Tags', 42 | key: 'tags', 43 | dataIndex: 'tags', 44 | filter: true, 45 | align: 'center' as const, 46 | render: (tags: string[]) => ( 47 | <> 48 | {_.map(tags, (tag) => { 49 | return {tag}; 50 | })} 51 | 52 | ), 53 | }, 54 | { 55 | title: 'Action', 56 | key: 'action', 57 | align: 'center' as const, 58 | width: 100, 59 | render: (text: string, record: Address.IForwardedAddress) => ( 60 | 61 | 62 | 66 | 67 | 68 | } 69 | /> 70 | 71 | 72 | 81 | 82 | 83 | ), 84 | }, 85 | ]; 86 | 87 | return getColumnsWithFilterAndSort(columnsForwarded, dataSource); 88 | }; 89 | -------------------------------------------------------------------------------- /src/components/ForwardedAddress/ForwardedAddress.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description ForwardedAddress Component 4 | */ 5 | 6 | import React from 'react'; 7 | import { Button, Breadcrumb, Row, Col } from 'antd'; 8 | import { useActions, useValues } from 'kea'; 9 | 10 | import Link from 'app-ui/components/CustomLink'; 11 | import Page from '../Page'; 12 | import Search from 'antd/lib/input/Search'; 13 | import RenameDomain from './RenameDomain'; 14 | import ForwardedAddressTable from './ForwardedAddressTable'; 15 | 16 | import addressLogic from 'app-ui/logic/addressLogic'; 17 | 18 | /** 19 | * ForwardedAddress Component 20 | */ 21 | const ForwardedAddress: React.FC = () => { 22 | const { error, renameDomainToggle, query } = useValues(addressLogic); 23 | const { setQuery, setRenameDomainToggle } = useActions(addressLogic); 24 | 25 | const onSearch = (value: string) => { 26 | setQuery(value); 27 | }; 28 | 29 | return !renameDomainToggle ? ( 30 | 31 | ) : ( 32 |
51 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | ); 65 | }; 66 | 67 | export default ForwardedAddress; 68 | -------------------------------------------------------------------------------- /src/components/ForwardedAddress/ForwardedAddressTable.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description ForwardedAddress Table 4 | */ 5 | 6 | import React from 'react'; 7 | import _ from 'lodash'; 8 | import { Table } from 'antd'; 9 | import { useValues } from 'kea'; 10 | 11 | import { getForwardedAddressColumns } from './Columns'; 12 | 13 | import useDeleteForwadedAddress from 'app-ui/hooks/useDeleteForwardedAddress'; 14 | import useForwadedAddress from 'app-ui/hooks/useForwardedAddress'; 15 | 16 | import addressLogic from 'app-ui/logic/addressLogic'; 17 | 18 | /** 19 | * ForwardedAddressTable Component 20 | */ 21 | 22 | const ForwardedAddressTable = (): JSX.Element => { 23 | const { query } = useValues(addressLogic); 24 | 25 | const { data, isLoading } = useForwadedAddress({ query: query }); 26 | 27 | const { mutate } = useDeleteForwadedAddress(); 28 | 29 | const forwardedAddressData = _.filter(data, (address) => _.get(address, 'forwarded')); 30 | 31 | const columns = React.useMemo( 32 | () => 33 | getForwardedAddressColumns({ 34 | dataSource: forwardedAddressData, 35 | deleteAddress: (addressId: string) => mutate(addressId), 36 | }), 37 | [forwardedAddressData], 38 | ); 39 | 40 | return ( 41 |
49 | ); 50 | }; 51 | 52 | export default ForwardedAddressTable; 53 | -------------------------------------------------------------------------------- /src/components/ForwardedAddress/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description Container for ForwardedAddress Component 4 | */ 5 | 6 | import ForwardedAddress from './ForwardedAddress'; 7 | 8 | export default ForwardedAddress; 9 | -------------------------------------------------------------------------------- /src/components/ForwardedAddressInformation/ForwardedAddressInformation.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description ForwardedAddressInformation Component 4 | */ 5 | 6 | import React from 'react'; 7 | import { Tabs, Breadcrumb } from 'antd'; 8 | import _ from 'lodash'; 9 | import { useParams } from 'react-router-dom'; 10 | 11 | import Link from 'app-ui/components/CustomLink'; 12 | import Page from '../Page'; 13 | import ForwardedAddressInformationForm from './ForwardedAddressInformationForm'; 14 | import ListTarget from './ListTarget'; 15 | import { ForwardedAddressInfoFomatter } from 'app-ui/lib/constants/Formatter'; 16 | 17 | import useForwardedAddressInformation from 'app-ui/hooks/useForwardedAddressInformation'; 18 | 19 | import 'styles/style.css'; 20 | 21 | const { TabPane } = Tabs; 22 | 23 | /** 24 | * ForwardedAddressInformation Component 25 | */ 26 | const ForwardedAddressInformation: React.FC = () => { 27 | const { id }: any = useParams(); 28 | 29 | const { data, isLoading, isError } = useForwardedAddressInformation(id); 30 | 31 | const formattedData = ForwardedAddressInfoFomatter(data); 32 | 33 | const breadcrum = ( 34 | 35 | 36 | Forwarded Addresses 37 | 38 | {_.get(data, 'address')} 39 | 40 | ); 41 | 42 | return ( 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | ); 54 | }; 55 | 56 | export default ForwardedAddressInformation; 57 | -------------------------------------------------------------------------------- /src/components/ForwardedAddressInformation/ListTarget.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description ListTargets Component 4 | */ 5 | 6 | import React from 'react'; 7 | import { List } from 'antd'; 8 | import _ from 'lodash'; 9 | 10 | const ListTarget: React.FC<{ data: any }> = ({ data }: any) => { 11 | return _.isUndefined(_.get(data, 'address')) ? null : ( 12 | {item}} 17 | /> 18 | ); 19 | }; 20 | 21 | export default ListTarget; 22 | -------------------------------------------------------------------------------- /src/components/ForwardedAddressInformation/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description Container for ForwardedAddressInformation Component 4 | */ 5 | 6 | import ForwardedAddressInformation from './ForwardedAddressInformation'; 7 | 8 | export default ForwardedAddressInformation; 9 | -------------------------------------------------------------------------------- /src/components/Header/Header.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Harish.R 3 | * @description Header component 4 | */ 5 | 6 | import React from 'react'; 7 | import { Button, Layout, Tooltip } from 'antd'; 8 | import { useActions } from 'kea'; 9 | import { LogoutOutlined } from '@ant-design/icons'; 10 | import WildDuckIcon from '../../assets/icons/WildDuckIcon'; 11 | import { accessTokenString, apiString } from 'app-ui/lib/constants/constant'; 12 | import appLogic from 'app-ui/logic/appLogic'; 13 | 14 | /** 15 | * class component for Header 16 | * @class Header 17 | * @extends PureComponent 18 | */ 19 | const Header = () => { 20 | const { setAccessToken } = useActions(appLogic); 21 | const logout = () => { 22 | sessionStorage.removeItem(accessTokenString); 23 | sessionStorage.removeItem(apiString); 24 | setAccessToken(''); 25 | }; 26 | 27 | /** Header Renderer */ 28 | return ( 29 | 30 | 31 | 32 | 33 | 34 | 35 | ); 36 | }; 37 | 38 | export default Header; 39 | -------------------------------------------------------------------------------- /src/components/Header/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Harish.R 3 | * @description container for Header component 4 | */ 5 | 6 | import Header from './Header'; 7 | 8 | export default Header; 9 | -------------------------------------------------------------------------------- /src/components/HtmlRenderer/HtmlRenderer.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Lakkanna Walikar 3 | * @description Html render component 4 | */ 5 | 6 | import React, { ReactElement } from 'react'; 7 | 8 | /** 9 | * IProps 10 | */ 11 | interface IProps { 12 | /** 13 | * stringifiedHtml 14 | * string to render as html 15 | * @type {string} 16 | */ 17 | stringifiedHtml: string; 18 | /** 19 | * pointerEvents 20 | * @type {string} 21 | */ 22 | disablePointerEvents?: boolean; 23 | /** 24 | * className 25 | * @type {string} 26 | */ 27 | className?: string; 28 | 29 | /** 30 | * className 31 | * @type {React.CSSProperties} 32 | */ 33 | style: React.CSSProperties; 34 | } 35 | 36 | /** 37 | * functional component to render string as HTML 38 | * @param param0 39 | */ 40 | const HtmlRenderer = ({ stringifiedHtml, disablePointerEvents, style, ...restProps }: IProps): ReactElement => { 41 | return ( 42 |
47 | ); 48 | }; 49 | 50 | HtmlRenderer.defaultProps = { 51 | style: {}, 52 | disablePointerEvents: true, 53 | }; 54 | 55 | export default HtmlRenderer; 56 | -------------------------------------------------------------------------------- /src/components/HtmlRenderer/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Lakkanna Walikar 3 | * @description HTML renderer 4 | */ 5 | 6 | import HtmlRenderer from './HtmlRenderer'; 7 | export default HtmlRenderer; 8 | -------------------------------------------------------------------------------- /src/components/LoaderBoundary/LoaderBoundary.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Harish.R 3 | * @description LoaderBoundary component 4 | */ 5 | 6 | import React from 'react'; 7 | import { Spin } from 'antd'; 8 | 9 | /** 10 | * props for LoaderBoundary 11 | * @interface IProps 12 | */ 13 | interface IProps { 14 | /** 15 | * 16 | * loading 17 | * @type {boolean} 18 | * @memberof IProps 19 | */ 20 | loading?: boolean; 21 | /** 22 | * 23 | * children 24 | * @type {React.ReactNode} 25 | * optional 26 | */ 27 | children?: React.ReactNode; 28 | } 29 | 30 | /** 31 | * functional component to loaderBoundary 32 | * @param {IProps} props 33 | */ 34 | const loaderBoundary = (props: IProps) => ( 35 | 36 | {props.loading ? ( 37 |
38 | 39 |
40 | ) : ( 41 | props.children 42 | )} 43 |
44 | ); 45 | 46 | export default loaderBoundary; 47 | -------------------------------------------------------------------------------- /src/components/LoaderBoundary/index.ts: -------------------------------------------------------------------------------- 1 | import LoaderBoundary from './LoaderBoundary'; 2 | 3 | export default LoaderBoundary; 4 | -------------------------------------------------------------------------------- /src/components/LoadingPage/LoadingPage.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Harish.R 3 | * @description LoadingPage component 4 | */ 5 | 6 | import React from 'react'; 7 | import { LoadingComponentProps } from 'react-loadable'; 8 | 9 | import ErrorPage from 'app-ui/components/ErrorBoundary/ErrorPage'; 10 | import LoaderBoundary from '../LoaderBoundary'; 11 | 12 | /** 13 | * functional component for loadingPage 14 | * @param {LoadingComponentProps} props 15 | */ 16 | const loadingPage = (props: LoadingComponentProps): JSX.Element => { 17 | if (props.error || props.timedOut) { 18 | return ; 19 | } else { 20 | return ; 21 | } 22 | }; 23 | 24 | export default loadingPage; 25 | -------------------------------------------------------------------------------- /src/components/LoadingPage/index.ts: -------------------------------------------------------------------------------- 1 | import LoadingPage from './LoadingPage'; 2 | 3 | export default LoadingPage; 4 | -------------------------------------------------------------------------------- /src/components/Mailboxes/MailboxSearch.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description MailboxSearch Component 4 | */ 5 | 6 | import React from 'react'; 7 | 8 | import { Button, Form, Switch } from 'antd'; 9 | import { useActions } from 'kea'; 10 | 11 | import mailboxesLogic from 'app-ui/logic/mailboxesLogic'; 12 | 13 | /** 14 | * MailboxSearch Component 15 | */ 16 | const MailboxSearch = () => { 17 | const { setSpecialUse } = useActions(mailboxesLogic); 18 | 19 | const [form] = Form.useForm(); 20 | 21 | const onFinish = ({ specialUse }: any) => { 22 | setSpecialUse(specialUse); 23 | }; 24 | 25 | return ( 26 |
34 | 40 | 41 | 42 | 43 | 46 | 47 | 48 | ); 49 | }; 50 | 51 | export default MailboxSearch; 52 | -------------------------------------------------------------------------------- /src/components/Mailboxes/Mailboxes.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description Mailboxes Component 4 | */ 5 | 6 | import React from 'react'; 7 | import { useValues } from 'kea'; 8 | 9 | import Messages from '../Messages'; 10 | import MailboxEditForm from './MailboxEditForm'; 11 | import MailboxesTable from './MailboxesTable'; 12 | import MailboxSearch from './MailboxSearch'; 13 | 14 | import mailboxesLogic from 'app-ui/logic/mailboxesLogic'; 15 | 16 | /** 17 | * Mailboxes Component 18 | */ 19 | const Mailboxes: React.FC = () => { 20 | const { updateMailboxToggle, showMailboxMessagesTable } = useValues(mailboxesLogic); 21 | 22 | return updateMailboxToggle ? ( 23 | 24 | ) : showMailboxMessagesTable ? ( 25 | 26 | ) : ( 27 | <> 28 | 29 | 30 | 31 | ); 32 | }; 33 | 34 | export default Mailboxes; 35 | -------------------------------------------------------------------------------- /src/components/Mailboxes/MailboxesTable.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description MailboxesTable Component 4 | */ 5 | 6 | import React from 'react'; 7 | import _ from 'lodash'; 8 | import { Table } from 'antd'; 9 | import { useActions, useValues } from 'kea'; 10 | import { useParams } from 'react-router-dom'; 11 | 12 | import { getMailboxesColumns } from './Columns'; 13 | import useDeleteMessagesInMailbox from 'app-ui/hooks/useDeleteMessagesInMailbox'; 14 | 15 | import useMailboxes from 'app-ui/hooks/useMailboxes'; 16 | 17 | import messagesLogic from 'app-ui/logic/messagesLogic'; 18 | import mailboxesLogic from 'app-ui/logic/mailboxesLogic'; 19 | 20 | /** 21 | * MailboxesTable Component 22 | */ 23 | const MailboxesTable: React.FC = () => { 24 | const { id }: any = useParams(); 25 | 26 | const { specialUse } = useValues(mailboxesLogic); 27 | 28 | const { data, isLoading } = useMailboxes({ userId: id, params: { specialUse: specialUse } }); 29 | 30 | const { 31 | setMailboxName, 32 | setShowMailboxMessagesTable, 33 | setMailboxId, 34 | setUpdateMailboxToggle, 35 | setSelectedMailboxData, 36 | } = useActions(mailboxesLogic); 37 | 38 | const { setMessageDetailsToggle, setMessageSourceToggle, setMessageId, setAttachmentId } = useActions( 39 | messagesLogic, 40 | ); 41 | 42 | const { mutate } = useDeleteMessagesInMailbox(); 43 | 44 | const columns = React.useMemo( 45 | () => 46 | getMailboxesColumns({ 47 | dataSource: data, 48 | drilldown: (record: any) => { 49 | setShowMailboxMessagesTable(true); 50 | setMailboxId(record.id); 51 | setMailboxName(record.name); 52 | setMessageDetailsToggle(false); 53 | setMessageSourceToggle(false); 54 | setMessageId(''); 55 | setAttachmentId(''); 56 | }, 57 | edit: (record: any) => { 58 | setUpdateMailboxToggle(true); 59 | setSelectedMailboxData({ 60 | mailboxId: _.get(record, 'id'), 61 | path: _.get(record, 'path'), 62 | subscribed: _.get(record, 'subscribed'), 63 | hidden: !_.get(record, 'hidden'), 64 | retention: _.get(record, 'retention', 0), 65 | }); 66 | }, 67 | deleteAllMessages: (mailboxId: string) => mutate({ userId: id, mailboxId: mailboxId }), 68 | }), 69 | [data], 70 | ); 71 | 72 | return ( 73 |
10 ? null : false} 80 | /> 81 | ); 82 | }; 83 | 84 | export default MailboxesTable; 85 | -------------------------------------------------------------------------------- /src/components/Mailboxes/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description Container for Mailboxes Component 4 | */ 5 | 6 | import Mailboxes from './Mailboxes'; 7 | 8 | export default Mailboxes; 9 | -------------------------------------------------------------------------------- /src/components/Messages/MailboxMessages.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description Messages Display 4 | */ 5 | 6 | import React from 'react'; 7 | import { List } from 'antd'; 8 | import _ from 'lodash'; 9 | import { useActions, useValues } from 'kea'; 10 | import { useParams } from 'react-router-dom'; 11 | 12 | import MessageList from './MessagesList'; 13 | import MessagesSearch from './MessagesSearch'; 14 | import { Pagination } from 'app-ui/utils/Pagination'; 15 | 16 | import useMessages from 'app-ui/hooks/useMessages'; 17 | 18 | import mailboxesLogic from 'app-ui/logic/mailboxesLogic'; 19 | import messagesLogic from 'app-ui/logic/messagesLogic'; 20 | 21 | const MailboxMessages: React.FC = () => { 22 | const { limit, next, previous, page, unseen } = useValues(messagesLogic); 23 | const { setLimit, setNext, setPrevious, setPage } = useActions(messagesLogic); 24 | 25 | const { mailboxId } = useValues(mailboxesLogic); 26 | 27 | const { id }: any = useParams(); 28 | 29 | const { data: results, isLoading } = useMessages({ 30 | userId: id, 31 | mailboxId: mailboxId, 32 | params: { 33 | unseen: unseen, 34 | page: page, 35 | next: page === 1 ? undefined : next || undefined, 36 | previous: previous || undefined, 37 | limit: limit, 38 | }, 39 | }); 40 | 41 | const { data, nextCursor, previousCursor } = _.isUndefined(results) 42 | ? { data: [], nextCursor: undefined, previousCursor: undefined } 43 | : results; 44 | setNext(nextCursor); 45 | setPrevious(previousCursor); 46 | 47 | return ( 48 | <> 49 | 50 | 60 | } 67 | /> 68 | 69 | ); 70 | }; 71 | 72 | export default MailboxMessages; 73 | -------------------------------------------------------------------------------- /src/components/Messages/MessageActions.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Aditya 3 | * @description Messages Actions Component 4 | */ 5 | 6 | import React from 'react'; 7 | import { Space, Tooltip, Button } from 'antd'; 8 | import { useActions } from 'kea'; 9 | import { useParams } from 'react-router-dom'; 10 | 11 | import { GetMessagesResult } from 'client/wildduck-api'; 12 | import { MailOutlined, DeleteFilled } from '@ant-design/icons'; 13 | import showConfirm from 'app-ui/utils/showConfirm'; 14 | 15 | import useDeleteMessage from 'app-ui/hooks/useDeleteMessage'; 16 | 17 | import messagesLogic from 'app-ui/logic/messagesLogic'; 18 | 19 | const MessageActions: React.FC<{ messageDetails: GetMessagesResult }> = ({ 20 | messageDetails, 21 | }: { 22 | messageDetails: GetMessagesResult; 23 | }) => { 24 | const { id }: any = useParams(); 25 | const { mutate } = useDeleteMessage(); 26 | const { setMessageId, setMessageSourceToggle } = useActions(messagesLogic); 27 | 28 | return ( 29 | 30 | 31 | 41 | 42 | 43 | 54 | 55 | 56 | ); 57 | }; 58 | 59 | export default MessageActions; 60 | -------------------------------------------------------------------------------- /src/components/Messages/MessageSource.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description MessagesSource Component 4 | */ 5 | 6 | import React from 'react'; 7 | import { Card, Breadcrumb } from 'antd'; 8 | import BraftEditor from 'braft-editor'; 9 | import { useParams } from 'react-router-dom'; 10 | import { useActions, useValues } from 'kea'; 11 | 12 | import Page from '../Page'; 13 | 14 | import mailboxesLogic from 'app-ui/logic/mailboxesLogic'; 15 | import messagesLogic from 'app-ui/logic/messagesLogic'; 16 | 17 | import useMessageSource from 'app-ui/hooks/useMessageSource'; 18 | 19 | const MessageSource: React.FC = () => { 20 | const { mailboxId, mailboxName } = useValues(mailboxesLogic); 21 | const { setUpdateMailboxToggle, setShowMailboxMessagesTable } = useActions(mailboxesLogic); 22 | 23 | const { setMessageSourceToggle } = useActions(messagesLogic); 24 | const { messageId } = useValues(messagesLogic); 25 | 26 | const { id }: any = useParams(); 27 | 28 | const { data } = useMessageSource({ userId: id, mailboxId: mailboxId, messageNumber: messageId }); 29 | 30 | const pageBreadcrumb = ( 31 | 32 | 33 | { 35 | event.stopPropagation(); 36 | setUpdateMailboxToggle(false); 37 | setShowMailboxMessagesTable(false); 38 | }} 39 | > 40 | Mailboxes 41 | 42 | 43 | 44 | { 46 | event.stopPropagation(); 47 | setMessageSourceToggle(false); 48 | }} 49 | > 50 | {mailboxName} 51 | 52 | 53 | Message Source 54 | 55 | ); 56 | 57 | return ( 58 | 59 | 60 | 61 | 62 | 63 | ); 64 | }; 65 | 66 | export default MessageSource; 67 | -------------------------------------------------------------------------------- /src/components/Messages/Messages.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description Messages Component 4 | */ 5 | 6 | import React from 'react'; 7 | import { Breadcrumb } from 'antd'; 8 | import { useActions, useValues } from 'kea'; 9 | 10 | import MailboxMessages from './MailboxMessages'; 11 | import { Page } from '../Page/Page'; 12 | import MessageSource from './MessageSource'; 13 | import MessageDetails from './MessageDetails'; 14 | 15 | import messagesLogic from 'app-ui/logic/messagesLogic'; 16 | import mailboxesLogic from 'app-ui/logic/mailboxesLogic'; 17 | 18 | /** 19 | * Messages Component 20 | */ 21 | const Messages: React.FC = () => { 22 | const { setUpdateMailboxToggle, setShowMailboxMessagesTable } = useActions(mailboxesLogic); 23 | const { mailboxName } = useValues(mailboxesLogic); 24 | const { messageSourceToggle, messageDetailsToggle } = useValues(messagesLogic); 25 | 26 | const pageBreadcrumb = ( 27 | 28 | 29 | { 31 | event.stopPropagation(); 32 | setUpdateMailboxToggle(false); 33 | setShowMailboxMessagesTable(false); 34 | }} 35 | > 36 | Mailboxes 37 | 38 | 39 | {mailboxName} 40 | 41 | ); 42 | 43 | if (messageDetailsToggle) { 44 | return ; 45 | } else if (messageSourceToggle) { 46 | return ; 47 | } else { 48 | return ( 49 | 50 | 51 | 52 | ); 53 | } 54 | // } 55 | }; 56 | 57 | export default Messages; 58 | -------------------------------------------------------------------------------- /src/components/Messages/MessagesList.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description Messages List Component 4 | */ 5 | 6 | import React from 'react'; 7 | import { List } from 'antd'; 8 | import moment from 'moment'; 9 | import { useActions } from 'kea'; 10 | 11 | import { GetMessagesResult } from 'client/wildduck-api'; 12 | import { DATE_TIME_FORMAT_AP } from 'app-ui/utils/constants'; 13 | import MessageActions from './MessageActions'; 14 | 15 | import messagesLogic from 'app-ui/logic/messagesLogic'; 16 | 17 | const MessageList: React.FC<{ item: GetMessagesResult }> = ({ item }: { item: GetMessagesResult }) => { 18 | const { setMessageId, setMessageDetailsToggle } = useActions(messagesLogic); 19 | return ( 20 | }> 21 | { 25 | setMessageId(item.id); 26 | setMessageDetailsToggle(true); 27 | }} 28 | > 29 | {`${item.from.name}<${item.from.address}> ${moment(item.date).format(DATE_TIME_FORMAT_AP)}`} 30 | 31 | } 32 | description={`${item.subject} - ${item.intro}`} 33 | /> 34 | 35 | ); 36 | }; 37 | 38 | export default MessageList; 39 | -------------------------------------------------------------------------------- /src/components/Messages/MessagesSearch.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description MessagesSearch Component 4 | */ 5 | 6 | import React from 'react'; 7 | import _ from 'lodash'; 8 | import { Button, Form, Switch } from 'antd'; 9 | import { useActions } from 'kea'; 10 | 11 | import messagesLogic from 'app-ui/logic/messagesLogic'; 12 | 13 | /** 14 | * MessagesSearch Component 15 | */ 16 | const MessagesSearch: React.FC = () => { 17 | const { setUnseen } = useActions(messagesLogic); 18 | 19 | const [form] = Form.useForm(); 20 | 21 | const onFinish = ({ unseen }: any) => { 22 | setUnseen(unseen); 23 | }; 24 | 25 | return ( 26 |
27 | 33 | 34 | 35 | 36 | 39 | 40 | 41 | ); 42 | }; 43 | 44 | export default MessagesSearch; 45 | -------------------------------------------------------------------------------- /src/components/Messages/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description Container for Messages Component 4 | */ 5 | 6 | import Messages from './Messages'; 7 | 8 | export default Messages; 9 | -------------------------------------------------------------------------------- /src/components/NavigationBar/index.ts: -------------------------------------------------------------------------------- 1 | import NavigationLogic from 'app-ui/logic/navigationLogic'; 2 | import NavigationBar from './NavigationBar'; 3 | 4 | export default NavigationLogic(NavigationBar) as any; 5 | -------------------------------------------------------------------------------- /src/components/Page/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Lakkanna Walikar 3 | * @description container for Page component 4 | */ 5 | 6 | import Page from './Page'; 7 | 8 | export default Page; 9 | -------------------------------------------------------------------------------- /src/components/ResolveId/ResolveId.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Aditya Negi 3 | * @description resolve id screen 4 | */ 5 | 6 | import React from 'react'; 7 | import { Input, Descriptions, Breadcrumb, Card } from 'antd'; 8 | import { useActions, useValues } from 'kea'; 9 | 10 | import Page from '../Page'; 11 | import Link from 'app-ui/components/CustomLink'; 12 | 13 | import dkimLogic from 'app-ui/logic/dkimLogic'; 14 | 15 | /** 16 | * ResolveId component 17 | */ 18 | const ResolveId: React.FC = () => { 19 | const { Search } = Input; 20 | const { resolveId } = useActions(dkimLogic); 21 | const { domainId } = useValues(dkimLogic); 22 | const onSearch = (value: any) => { 23 | if (value.length > 0) { 24 | resolveId(value); 25 | } 26 | }; 27 | const descriptionBox = ( 28 | 29 | 30 | {domainId} 31 | 32 | 33 | ); 34 | 35 | const pageBreadcrumb = ( 36 | 37 | 38 | DKIM 39 | 40 | 41 | Resolve DKIM ID 42 | 43 | ); 44 | return ( 45 | 46 | 47 | {domainId.length > 0 && descriptionBox} 48 | 49 | ); 50 | }; 51 | 52 | export default ResolveId; 53 | -------------------------------------------------------------------------------- /src/components/ResolveId/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Aditya Negi 3 | * @description resolve id screen container 4 | */ 5 | 6 | import ResolveId from './ResolveId'; 7 | 8 | export default ResolveId; 9 | -------------------------------------------------------------------------------- /src/components/User/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description Container for User Component 4 | */ 5 | 6 | import User from './User'; 7 | 8 | export default User; 9 | -------------------------------------------------------------------------------- /src/components/Users/FilterSearch.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description FilterSearch Component 4 | */ 5 | 6 | import React from 'react'; 7 | import { Button, Form, Input } from 'antd'; 8 | import { useActions } from 'kea'; 9 | 10 | import usersLogic from 'app-ui/logic/usersLogic'; 11 | 12 | /** 13 | * FilterSearch Component 14 | */ 15 | const FilterSearch: React.FC = () => { 16 | const { setSearchParams } = useActions(usersLogic); 17 | 18 | const [form] = Form.useForm(); 19 | 20 | const onFinish = (values: any) => { 21 | setSearchParams(values); 22 | }; 23 | 24 | return ( 25 |
35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 48 | 49 | 50 | ); 51 | }; 52 | 53 | export default FilterSearch; 54 | -------------------------------------------------------------------------------- /src/components/Users/ResetPassword.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description ResetPassword screen 4 | */ 5 | 6 | import React from 'react'; 7 | import { Modal, Typography } from 'antd'; 8 | import { useActions, useValues } from 'kea'; 9 | 10 | import usersLogic from 'app-ui/logic/usersLogic'; 11 | 12 | const ResetPassword: React.FC = () => { 13 | const { setShowResetPasswordModal, setPassword } = useActions(usersLogic); 14 | const { password, showResetPasswordModal } = useValues(usersLogic); 15 | 16 | return ( 17 | { 22 | setShowResetPasswordModal(false); 23 | setPassword(''); 24 | }} 25 | > 26 | {password} 27 | 28 | ); 29 | }; 30 | 31 | export default ResetPassword; 32 | -------------------------------------------------------------------------------- /src/components/Users/Users.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Aditya Negi 3 | * @description Users screen 4 | */ 5 | 6 | import React from 'react'; 7 | import { Button } from 'antd'; 8 | 9 | import Link from 'app-ui/components/CustomLink'; 10 | import Page from 'components/Page'; 11 | import showConfirm from 'app-ui/utils/showConfirm'; 12 | import FilterSearch from './FilterSearch'; 13 | import UsersTable from './UsersTable'; 14 | import ResetPassword from './ResetPassword'; 15 | 16 | import useRecalculateQuotaForAll from 'app-ui/hooks/useRecalculateQuotaForAll'; 17 | 18 | const Users: React.FC = () => { 19 | const { mutate } = useRecalculateQuotaForAll(); 20 | 21 | return ( 22 | 28 | showConfirm(() => mutate(), 'Are you sure you want to Recalculate Quota For All Users ?') 29 | } 30 | > 31 | Recalculate Quota For All Users 32 | , 33 | , 36 | ]} 37 | > 38 | 39 | 40 | 41 | 42 | ); 43 | }; 44 | 45 | export default Users; 46 | -------------------------------------------------------------------------------- /src/components/Users/UsersTable.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Aditya Negi 3 | * @description Users Table 4 | */ 5 | 6 | import React from 'react'; 7 | import { Table } from 'antd'; 8 | import { useActions, useValues } from 'kea'; 9 | import _ from 'lodash'; 10 | 11 | import { getUsersColumns } from './Columns'; 12 | import { Pagination } from 'app-ui/utils/Pagination'; 13 | 14 | import useUsers from 'app-ui/hooks/useUsers'; 15 | import useDeleteUser from 'app-ui/hooks/useDeleteUser'; 16 | 17 | import usersLogic from 'app-ui/logic/usersLogic'; 18 | 19 | const UsersTable: React.FC = () => { 20 | const { setPage, setLimit, setNext, setPrevious } = useActions(usersLogic); 21 | const { searchParams, limit, page, next, previous } = useValues(usersLogic); 22 | 23 | const { data: results, isLoading } = useUsers({ 24 | query: searchParams?.query, 25 | tags: searchParams?.tags, 26 | requiredTags: searchParams?.requiredTags, 27 | page: page, 28 | next: page === 1 ? undefined : next || undefined, 29 | previous: previous || undefined, 30 | limit: limit, 31 | }); 32 | 33 | const { data, nextCursor, previousCursor } = _.isUndefined(results) 34 | ? { data: [], nextCursor: undefined, previousCursor: undefined } 35 | : results; 36 | setNext(nextCursor); 37 | setPrevious(previousCursor); 38 | 39 | const { mutate } = useDeleteUser(); 40 | 41 | const columns = React.useMemo( 42 | () => getUsersColumns({ dataSource: data, deleteUser: (userId: string) => mutate(userId) }), 43 | [data], 44 | ); 45 | 46 | return ( 47 | <> 48 | 58 |
68 | 69 | ); 70 | }; 71 | 72 | export default UsersTable; 73 | -------------------------------------------------------------------------------- /src/components/Users/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description Container for Users Component 4 | */ 5 | 6 | import Users from './Users'; 7 | 8 | export default Users; 9 | -------------------------------------------------------------------------------- /src/components/Widgets/Link.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description Link 4 | */ 5 | 6 | import React from 'react'; 7 | 8 | import Link from 'app-ui/components/CustomLink'; 9 | 10 | interface IProps { 11 | name: string | JSX.Element; 12 | id: string; 13 | } 14 | 15 | /** ForwardedAddress link */ 16 | const ForwardedAddressLink = ({ id, name }: IProps): JSX.Element => { 17 | return {name}; 18 | }; 19 | 20 | /** UserLink link */ 21 | const UserLink = ({ id, name }: IProps): JSX.Element => { 22 | return {name}; 23 | }; 24 | 25 | /** DkimDetailsLink */ 26 | const DkimDetailsLink = ({ id, name }: IProps): JSX.Element => { 27 | return {name}; 28 | }; 29 | 30 | export { ForwardedAddressLink, UserLink, DkimDetailsLink }; 31 | -------------------------------------------------------------------------------- /src/components/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import { Provider } from 'react-redux'; 4 | import store from 'store/index'; 5 | import AxiosInterceptor from 'app-ui/lib/axios/AxiosInterceptors'; 6 | import { apiString } from 'app-ui/lib/constants/constant'; 7 | 8 | new AxiosInterceptor().inject({ 9 | baseURL: sessionStorage.getItem(apiString), 10 | headers: { 'Content-Type': 'application/json' }, 11 | }); 12 | 13 | const MainApp = React.lazy(() => import('./App')); 14 | 15 | const PersistedApp = () => ( 16 | 17 | }> 18 | 19 | 20 | 21 | ); 22 | 23 | ReactDOM.render(, document.getElementById('root')); 24 | 25 | if ((module as any).hot) { 26 | (module as any).hot.accept('./index', () => { 27 | // tslint:disable-next-line: variable-name 28 | const NextApp = require('./index').default; 29 | ReactDOM.render(, document.getElementById('root')); 30 | }); 31 | } 32 | -------------------------------------------------------------------------------- /src/hooks/useAddress.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description React hook useAddress 4 | */ 5 | 6 | import { useQuery } from 'react-query'; 7 | import _ from 'lodash'; 8 | 9 | import { addKey } from 'app-ui/utils/logicUtils'; 10 | import api from 'client/RequestClient'; 11 | 12 | /** 13 | * useAddress 14 | */ 15 | const useAddress = (userId: string) => { 16 | return useQuery(['useAddress'], async () => { 17 | const { data } = await api.addressApi.getUserAddresses(userId); 18 | return addKey(_.get(data, 'results', [])); 19 | }); 20 | }; 21 | 22 | export default useAddress; 23 | -------------------------------------------------------------------------------- /src/hooks/useAddressInformation.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description React hook useAddressInformation 4 | */ 5 | 6 | import { useQuery } from 'react-query'; 7 | 8 | import api from 'client/RequestClient'; 9 | 10 | /** 11 | * useAddressInformation 12 | */ 13 | const useAddressInformation = (userId: string, addressId: string) => { 14 | return useQuery(['useAddressInformation', addressId], async () => { 15 | const { data } = await api.addressApi.getUserAddress(userId, addressId); 16 | return data; 17 | }); 18 | }; 19 | 20 | export default useAddressInformation; 21 | -------------------------------------------------------------------------------- /src/hooks/useAllowedList.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Aditya Negi 3 | * @description React hook useAllowedList 4 | */ 5 | 6 | import { useQuery } from 'react-query'; 7 | import _ from 'lodash'; 8 | 9 | import api from 'client/RequestClient'; 10 | 11 | /* 12 | * useAllowedList 13 | */ 14 | 15 | const useAllowedList = (tag: string) => { 16 | return useQuery( 17 | ['query-allowList', tag], 18 | async () => { 19 | const { data } = await api.domainAccessApi.getAllowedDomain(tag); 20 | return _.get(data, 'results', []); 21 | }, 22 | { enabled: !_.isEmpty(tag), staleTime: 3000 }, 23 | ); 24 | }; 25 | 26 | export default useAllowedList; 27 | -------------------------------------------------------------------------------- /src/hooks/useArchive.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description React hook useArchive 4 | */ 5 | 6 | import { useQuery } from 'react-query'; 7 | import _ from 'lodash'; 8 | 9 | import { addKey } from 'app-ui/utils/logicUtils'; 10 | import api from 'client/RequestClient'; 11 | 12 | interface IParam { 13 | userId: string; 14 | params: any; 15 | } 16 | 17 | /** 18 | * useArchive 19 | */ 20 | const useArchive = ({ userId, params }: IParam) => { 21 | return useQuery(['useArchive', params?.limit, params?.page], async () => { 22 | const { data } = await api.archiveApi.getArchivedMessages( 23 | userId, 24 | _.get(params, 'limit'), 25 | _.get(params, 'page'), 26 | _.get(params, 'order'), 27 | _.get(params, 'next'), 28 | _.get(params, 'previous'), 29 | ); 30 | return { 31 | previousCursor: _.get(data, 'previousCursor', ''), 32 | nextCursor: _.get(data, 'nextCursor', ''), 33 | data: addKey(_.get(data, 'results', []), ['messageId', 'mailbox', 'thread', 'id']), 34 | }; 35 | }); 36 | }; 37 | 38 | export default useArchive; 39 | -------------------------------------------------------------------------------- /src/hooks/useAuthentication.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description React hook useAuthentication 4 | */ 5 | 6 | import { useQuery } from 'react-query'; 7 | import _ from 'lodash'; 8 | 9 | import api from 'client/RequestClient'; 10 | import { addKey } from 'app-ui/utils/logicUtils'; 11 | 12 | /** 13 | * useAuthentication 14 | */ 15 | const useAuthentication = (userId: string, params: any) => { 16 | return useQuery(['useAuthentication', userId, params?.limit, params?.page], async () => { 17 | const { data } = await api.authenticationApi.getAuthlog( 18 | userId, 19 | _.get(params, 'action'), 20 | _.get(params, 'filterIp'), 21 | _.get(params, 'limit'), 22 | _.get(params, 'page'), 23 | _.get(params, 'next'), 24 | _.get(params, 'previous'), 25 | ); 26 | return { 27 | data: addKey(_.get(data, 'results', [])), 28 | previousCursor: _.get(data, 'previousCursor', ''), 29 | nextCursor: _.get(data, 'nextCursor', ''), 30 | }; 31 | }); 32 | }; 33 | 34 | export default useAuthentication; 35 | -------------------------------------------------------------------------------- /src/hooks/useAutoreplyDetails.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description React hook useAutoreplyDetails 4 | */ 5 | 6 | import { useQuery } from 'react-query'; 7 | 8 | import api from 'client/RequestClient'; 9 | 10 | /** 11 | * useAutoreplyDetails 12 | */ 13 | const useAutoreplyDetails = (userId: string) => { 14 | return useQuery(['useAutoreplyDetails', userId], async () => { 15 | const { data } = await api.autorepliesApi.getAutoreply(userId); 16 | return data; 17 | }); 18 | }; 19 | 20 | export default useAutoreplyDetails; 21 | -------------------------------------------------------------------------------- /src/hooks/useBlockedList.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Aditya Negi 3 | * @description React hook useBlockedList 4 | */ 5 | 6 | import { useQuery } from 'react-query'; 7 | import _ from 'lodash'; 8 | 9 | import api from 'client/RequestClient'; 10 | 11 | /* 12 | * useBlockedList 13 | */ 14 | 15 | const useBlockedList = (tag: string) => { 16 | return useQuery( 17 | ['query-blockList', tag], 18 | async () => { 19 | const { data } = await api.domainAccessApi.getBlockedDomain(tag); 20 | return _.get(data, 'results', []); 21 | }, 22 | { enabled: !_.isEmpty(tag), staleTime: 3000 }, 23 | ); 24 | }; 25 | 26 | export default useBlockedList; 27 | -------------------------------------------------------------------------------- /src/hooks/useCreateAddress.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description React hook useCreateAddress 4 | */ 5 | 6 | import { useMutation, useQueryClient } from 'react-query'; 7 | 8 | import api from 'client/RequestClient'; 9 | import AppEvents, { Events } from 'app-ui/utils/AppEvents'; 10 | import { CreateUserAddressRequest } from 'client/wildduck-api'; 11 | import handleError from 'app-ui/utils/handleError'; 12 | 13 | interface IProp { 14 | userId: string; 15 | addressDetails: CreateUserAddressRequest; 16 | } 17 | 18 | /** 19 | * useCreateAddress 20 | */ 21 | const useCreateAddress = () => { 22 | const queryClient = useQueryClient(); 23 | 24 | return useMutation( 25 | ({ userId, addressDetails }: IProp) => api.addressApi.createUserAddress(userId, addressDetails), 26 | { 27 | onError: () => { 28 | AppEvents.publish(Events.Error, 'Error'); 29 | }, 30 | onSuccess: ({ data }) => { 31 | handleError(data); 32 | queryClient.invalidateQueries('useAddress'); 33 | }, 34 | }, 35 | ); 36 | }; 37 | 38 | export default useCreateAddress; 39 | -------------------------------------------------------------------------------- /src/hooks/useCreateAllowedDomain.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Aditya Negi 3 | * @description React hook useCreateAllowedDomain 4 | */ 5 | 6 | import { useMutation, useQueryClient } from 'react-query'; 7 | 8 | import api from 'client/RequestClient'; 9 | import AppEvents, { Events } from 'app-ui/utils/AppEvents'; 10 | 11 | /* 12 | * useCreateAllowedDomain 13 | */ 14 | const useCreateAllowedDomain = () => { 15 | const queryClient = useQueryClient(); 16 | 17 | return useMutation( 18 | (domain: { tag: string; domain: string }) => 19 | api.domainAccessApi.createAllowedDomain(domain.tag, { domain: domain.domain }), 20 | { 21 | onSuccess: () => { 22 | AppEvents.publish(Events.Success, 'Success'); 23 | queryClient.invalidateQueries('query-allowList'); 24 | queryClient.invalidateQueries('query-blockList'); 25 | }, 26 | onError: () => { 27 | AppEvents.publish(Events.Error, 'Error'); 28 | }, 29 | }, 30 | ); 31 | }; 32 | 33 | export default useCreateAllowedDomain; 34 | -------------------------------------------------------------------------------- /src/hooks/useCreateBlockedDomain.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Aditya Negi 3 | * @description React hook useCreateBlockedDomain 4 | */ 5 | 6 | import { useMutation, useQueryClient } from 'react-query'; 7 | 8 | import api from 'client/RequestClient'; 9 | import AppEvents, { Events } from 'app-ui/utils/AppEvents'; 10 | 11 | /* 12 | * useCreateBlockedDomain 13 | */ 14 | const useCreateBlockedDomain = () => { 15 | const queryClient = useQueryClient(); 16 | 17 | return useMutation( 18 | (domain: { tag: string; domain: string }) => 19 | api.domainAccessApi.createBlockedDomain(domain.tag, { domain: domain.domain }), 20 | { 21 | onSuccess: () => { 22 | AppEvents.publish(Events.Success, 'Success'); 23 | queryClient.invalidateQueries('query-blockList'); 24 | queryClient.invalidateQueries('query-allowList'); 25 | }, 26 | onError: () => { 27 | AppEvents.publish(Events.Error, 'Error'); 28 | }, 29 | }, 30 | ); 31 | }; 32 | 33 | export default useCreateBlockedDomain; 34 | -------------------------------------------------------------------------------- /src/hooks/useCreateDkim.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Aditya Negi 3 | * @description React hook useCreateDkim 4 | */ 5 | 6 | import { useMutation, useQueryClient } from 'react-query'; 7 | import _ from 'lodash'; 8 | 9 | import api from 'client/RequestClient'; 10 | import AppEvents, { Events } from 'app-ui/utils/AppEvents'; 11 | import { UpdateDkimKeyRequest } from 'client/wildduck-api'; 12 | 13 | /* 14 | * useCreateDkim 15 | */ 16 | const useCreateDkim = () => { 17 | const queryClient = useQueryClient(); 18 | 19 | return useMutation((dkim: UpdateDkimKeyRequest) => api.dkimApi.updateDkimKey(dkim), { 20 | onSuccess: () => { 21 | AppEvents.publish(Events.Success, 'Success'); 22 | queryClient.invalidateQueries('query-dkim'); 23 | }, 24 | onError: () => { 25 | AppEvents.publish(Events.Error, 'Error'); 26 | }, 27 | }); 28 | }; 29 | 30 | export default useCreateDkim; 31 | -------------------------------------------------------------------------------- /src/hooks/useCreateDomainAliases.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description React hook useCreateDomainAliases 4 | */ 5 | 6 | import { useMutation } from 'react-query'; 7 | 8 | import api from 'client/RequestClient'; 9 | import AppEvents, { Events } from 'app-ui/utils/AppEvents'; 10 | import { CreateDomainAliasRequest } from 'client/wildduck-api'; 11 | import handleError from 'app-ui/utils/handleError'; 12 | 13 | /** 14 | * useCreateDomainAliases 15 | */ 16 | const useCreateDomainAliases = () => { 17 | return useMutation( 18 | (newDomainAlias: CreateDomainAliasRequest) => api.domainAliasesApi.createDomainAlias(newDomainAlias), 19 | { 20 | onError: () => { 21 | AppEvents.publish(Events.Error, 'Error'); 22 | }, 23 | onSuccess: ({ data }) => { 24 | handleError(data); 25 | }, 26 | }, 27 | ); 28 | }; 29 | 30 | export default useCreateDomainAliases; 31 | -------------------------------------------------------------------------------- /src/hooks/useCreateFilter.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description React hook useCreateFilter 4 | */ 5 | 6 | import { useMutation } from 'react-query'; 7 | 8 | import api from 'client/RequestClient'; 9 | import AppEvents, { Events } from 'app-ui/utils/AppEvents'; 10 | import { CreateFilterRequest } from 'client/wildduck-api'; 11 | import handleError from 'app-ui/utils/handleError'; 12 | 13 | /** 14 | * useCreateFilter 15 | */ 16 | const useCreateFilter = () => { 17 | return useMutation( 18 | ({ userId, filterDetails }: { userId: string; filterDetails: CreateFilterRequest }) => 19 | api.filtersApi.createFilter(userId, filterDetails), 20 | { 21 | onError: () => { 22 | AppEvents.publish(Events.Error, 'Error'); 23 | }, 24 | onSuccess: ({ data }) => { 25 | handleError(data); 26 | }, 27 | }, 28 | ); 29 | }; 30 | 31 | export default useCreateFilter; 32 | -------------------------------------------------------------------------------- /src/hooks/useCreateForwardedAddress.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description React hook useCreateForwardedAddress 4 | */ 5 | 6 | import { useMutation } from 'react-query'; 7 | 8 | import api from 'client/RequestClient'; 9 | import AppEvents, { Events } from 'app-ui/utils/AppEvents'; 10 | import { CreateForwardedAddressRequest } from 'client/wildduck-api'; 11 | import handleError from 'app-ui/utils/handleError'; 12 | 13 | /** 14 | * useCreateForwardedAddress 15 | */ 16 | const useCreateForwardedAddress = () => { 17 | return useMutation( 18 | (newForwardedAddress: CreateForwardedAddressRequest) => 19 | api.addressApi.createForwardedAddress(newForwardedAddress), 20 | { 21 | onError: () => { 22 | AppEvents.publish(Events.Error, 'Error'); 23 | }, 24 | onSuccess: ({ data }) => { 25 | handleError(data); 26 | }, 27 | }, 28 | ); 29 | }; 30 | 31 | export default useCreateForwardedAddress; 32 | -------------------------------------------------------------------------------- /src/hooks/useCreateUser.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description React hook useCreateUser 4 | */ 5 | 6 | import { useMutation } from 'react-query'; 7 | 8 | import api from 'client/RequestClient'; 9 | import AppEvents, { Events } from 'app-ui/utils/AppEvents'; 10 | import { CreateUserRequest } from 'client/wildduck-api'; 11 | import handleError from 'app-ui/utils/handleError'; 12 | 13 | /** 14 | * useCreateUser 15 | */ 16 | const useCreateUser = () => { 17 | return useMutation((user: CreateUserRequest) => api.usersApi.createUser(user), { 18 | onError: () => { 19 | AppEvents.publish(Events.Error, 'Error'); 20 | }, 21 | onSuccess: ({ data }) => { 22 | handleError(data); 23 | }, 24 | }); 25 | }; 26 | 27 | export default useCreateUser; 28 | -------------------------------------------------------------------------------- /src/hooks/useDeleteAddress.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description React hook useDeleteAddress 4 | */ 5 | 6 | import { useMutation, useQueryClient } from 'react-query'; 7 | 8 | import api from 'client/RequestClient'; 9 | import AppEvents, { Events } from 'app-ui/utils/AppEvents'; 10 | 11 | interface IDeleteAddress { 12 | userId: string; 13 | addressId: string; 14 | } 15 | 16 | /** 17 | * useDeleteAddress 18 | */ 19 | const useDeleteAddress = () => { 20 | const queryClient = useQueryClient(); 21 | 22 | return useMutation(({ userId, addressId }: IDeleteAddress) => api.addressApi.deleteUserAddress(userId, addressId), { 23 | onError: () => { 24 | AppEvents.publish(Events.Error, 'Error'); 25 | }, 26 | onSuccess: () => { 27 | AppEvents.publish(Events.Success, 'Success'); 28 | queryClient.invalidateQueries('useAddress'); 29 | }, 30 | }); 31 | }; 32 | 33 | export default useDeleteAddress; 34 | -------------------------------------------------------------------------------- /src/hooks/useDeleteAutoreply.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description React hook useDeleteAutoreply 4 | */ 5 | 6 | import { useMutation, useQueryClient } from 'react-query'; 7 | 8 | import api from 'client/RequestClient'; 9 | import AppEvents, { Events } from 'app-ui/utils/AppEvents'; 10 | 11 | /** 12 | * useDeleteAutoreply 13 | */ 14 | const useDeleteAutoreply = () => { 15 | const queryClient = useQueryClient(); 16 | 17 | return useMutation((userId: string) => api.autorepliesApi.deleteAutoreply(userId), { 18 | onError: () => { 19 | AppEvents.publish(Events.Error, 'Error'); 20 | }, 21 | onSuccess: () => { 22 | AppEvents.publish(Events.Success, 'Success'); 23 | queryClient.invalidateQueries('useAutoreplyDetails'); 24 | }, 25 | }); 26 | }; 27 | 28 | export default useDeleteAutoreply; 29 | -------------------------------------------------------------------------------- /src/hooks/useDeleteDkim.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Aditya Negi 3 | * @description React hook useDeleteDkim 4 | */ 5 | 6 | import { useMutation, useQueryClient } from 'react-query'; 7 | 8 | import api from 'client/RequestClient'; 9 | import AppEvents, { Events } from 'app-ui/utils/AppEvents'; 10 | 11 | /* 12 | * useDeleteDkim 13 | */ 14 | const useDeleteDkim = () => { 15 | const queryClient = useQueryClient(); 16 | 17 | return useMutation((dkimId: string) => api.dkimApi.deleteDkimKey(dkimId), { 18 | onSuccess: () => { 19 | AppEvents.publish(Events.Success, 'Success'); 20 | queryClient.invalidateQueries('query-dkim'); 21 | }, 22 | onError: () => { 23 | AppEvents.publish(Events.Error, 'Error'); 24 | }, 25 | }); 26 | }; 27 | 28 | export default useDeleteDkim; 29 | -------------------------------------------------------------------------------- /src/hooks/useDeleteDomain.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Aditya Negi 3 | * @description React hook useDeleteDomain 4 | */ 5 | 6 | import { useMutation, useQueryClient } from 'react-query'; 7 | 8 | import api from 'client/RequestClient'; 9 | import AppEvents, { Events } from 'app-ui/utils/AppEvents'; 10 | 11 | /* 12 | * useDeleteDomain 13 | */ 14 | const useDeleteDomain = () => { 15 | const queryClient = useQueryClient(); 16 | 17 | return useMutation((id: string) => api.domainAccessApi.deleteDomainListing(id), { 18 | onSuccess: () => { 19 | AppEvents.publish(Events.Success, 'Deleted !'); 20 | queryClient.invalidateQueries('query-blockList'); 21 | queryClient.invalidateQueries('query-allowList'); 22 | }, 23 | onError: () => { 24 | AppEvents.publish(Events.Error, 'Error'); 25 | }, 26 | }); 27 | }; 28 | 29 | export default useDeleteDomain; 30 | -------------------------------------------------------------------------------- /src/hooks/useDeleteDomainAliases.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description React hook useDeleteDomainAliases 4 | */ 5 | 6 | import { useMutation, useQueryClient } from 'react-query'; 7 | 8 | import api from 'client/RequestClient'; 9 | import AppEvents, { Events } from 'app-ui/utils/AppEvents'; 10 | 11 | /** 12 | * useDeleteDomainAliases 13 | */ 14 | const useDeleteDomainAliases = () => { 15 | const queryClient = useQueryClient(); 16 | 17 | return useMutation((aliasId: string) => api.domainAliasesApi.deleteDomainAlias(aliasId), { 18 | onError: () => { 19 | AppEvents.publish(Events.Error, 'Error'); 20 | }, 21 | onSuccess: () => { 22 | AppEvents.publish(Events.Success, 'Success'); 23 | queryClient.invalidateQueries('useDomainAliases'); 24 | }, 25 | }); 26 | }; 27 | 28 | export default useDeleteDomainAliases; 29 | -------------------------------------------------------------------------------- /src/hooks/useDeleteFilter.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description React hook useDeleteFilter 4 | */ 5 | 6 | import { useMutation, useQueryClient } from 'react-query'; 7 | 8 | import api from 'client/RequestClient'; 9 | import AppEvents, { Events } from 'app-ui/utils/AppEvents'; 10 | import { CreateFilterRequest } from 'client/wildduck-api'; 11 | import handleError from 'app-ui/utils/handleError'; 12 | 13 | /** 14 | * useDeleteFilter 15 | */ 16 | const useDeleteFilter = () => { 17 | const queryClient = useQueryClient(); 18 | 19 | return useMutation( 20 | ({ userId, filterId }: { userId: string; filterId: string }) => api.filtersApi.deleteFilter(userId, filterId), 21 | { 22 | onError: () => { 23 | AppEvents.publish(Events.Error, 'Error'); 24 | }, 25 | onSuccess: ({ data }) => { 26 | handleError(data); 27 | queryClient.invalidateQueries('query-filters'); 28 | }, 29 | }, 30 | ); 31 | }; 32 | 33 | export default useDeleteFilter; 34 | -------------------------------------------------------------------------------- /src/hooks/useDeleteForwardedAddress.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description React hook useDeleteForwadedAddress 4 | */ 5 | 6 | import { useMutation, useQueryClient } from 'react-query'; 7 | 8 | import api from 'client/RequestClient'; 9 | import AppEvents, { Events } from 'app-ui/utils/AppEvents'; 10 | 11 | /** 12 | * useDeleteForwadedAddress 13 | */ 14 | const useDeleteForwadedAddress = () => { 15 | const queryClient = useQueryClient(); 16 | 17 | return useMutation((addressId: string) => api.addressApi.deleteForwardedAddress(addressId), { 18 | onError: () => { 19 | AppEvents.publish(Events.Error, 'Error'); 20 | }, 21 | onSuccess: () => { 22 | AppEvents.publish(Events.Success, 'Success'); 23 | queryClient.invalidateQueries('useForwardedAddress'); 24 | }, 25 | }); 26 | }; 27 | 28 | export default useDeleteForwadedAddress; 29 | -------------------------------------------------------------------------------- /src/hooks/useDeleteMessage.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description React hook useDeleteMessage 4 | */ 5 | 6 | import { useMutation, useQueryClient } from 'react-query'; 7 | 8 | import api from 'client/RequestClient'; 9 | import AppEvents, { Events } from 'app-ui/utils/AppEvents'; 10 | 11 | interface IParams { 12 | userId: string; 13 | mailboxId: string; 14 | messageNumber: number; 15 | } 16 | 17 | /** 18 | * useDeleteMessage 19 | */ 20 | const useDeleteMessage = () => { 21 | const queryClient = useQueryClient(); 22 | 23 | return useMutation( 24 | ({ userId, mailboxId, messageNumber }: IParams) => 25 | api.messagesApi.deleteMessage(userId, mailboxId, messageNumber), 26 | { 27 | onError: () => { 28 | AppEvents.publish(Events.Error, 'Error'); 29 | }, 30 | onSuccess: () => { 31 | AppEvents.publish(Events.Success, 'Success'); 32 | queryClient.invalidateQueries('useMessages'); 33 | }, 34 | }, 35 | ); 36 | }; 37 | 38 | export default useDeleteMessage; 39 | -------------------------------------------------------------------------------- /src/hooks/useDeleteMessagesInMailbox.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description React hook useDeleteMessagesInMailbox 4 | */ 5 | 6 | import { useMutation, useQueryClient } from 'react-query'; 7 | 8 | import api from 'client/RequestClient'; 9 | import AppEvents, { Events } from 'app-ui/utils/AppEvents'; 10 | 11 | interface IParams { 12 | userId: string; 13 | mailboxId: string; 14 | } 15 | 16 | /** 17 | * useDeleteMessagesInMailbox 18 | */ 19 | const useDeleteMessagesInMailbox = () => { 20 | const queryClient = useQueryClient(); 21 | 22 | return useMutation(({ userId, mailboxId }: IParams) => api.messagesApi.deleteMessagesInMailbox(userId, mailboxId), { 23 | onError: () => { 24 | AppEvents.publish(Events.Error, 'Error'); 25 | }, 26 | onSuccess: () => { 27 | AppEvents.publish(Events.Success, 'Success'); 28 | queryClient.invalidateQueries('useMailboxes'); 29 | }, 30 | }); 31 | }; 32 | 33 | export default useDeleteMessagesInMailbox; 34 | -------------------------------------------------------------------------------- /src/hooks/useDeleteUser.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description React hook useDeleteUser 4 | */ 5 | 6 | import { useMutation, useQueryClient } from 'react-query'; 7 | 8 | import api from 'client/RequestClient'; 9 | import AppEvents, { Events } from 'app-ui/utils/AppEvents'; 10 | 11 | /** 12 | * useDeleteUser 13 | */ 14 | const useDeleteUser = () => { 15 | const queryClient = useQueryClient(); 16 | 17 | return useMutation((userId: string) => api.usersApi.deleteUser(userId), { 18 | onError: () => { 19 | AppEvents.publish(Events.Error, 'Error'); 20 | }, 21 | onSuccess: () => { 22 | AppEvents.publish(Events.Success, 'Success'); 23 | queryClient.invalidateQueries('useUsers'); 24 | }, 25 | }); 26 | }; 27 | 28 | export default useDeleteUser; 29 | -------------------------------------------------------------------------------- /src/hooks/useDkim.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Aditya Negi 3 | * @description React hook useDkim 4 | */ 5 | 6 | import { useQuery } from 'react-query'; 7 | import _ from 'lodash'; 8 | 9 | import { addKey } from 'app-ui/utils/logicUtils'; 10 | import api from 'client/RequestClient'; 11 | 12 | /* 13 | * useDkim 14 | */ 15 | 16 | interface DkimProps { 17 | query?: string; 18 | limit?: number; 19 | next?: number; 20 | previous?: number; 21 | page?: number; 22 | } 23 | 24 | const useDkim = ({ query = '', limit, page, next, previous }: DkimProps) => { 25 | return useQuery(['query-dkim', query, page, limit], async () => { 26 | const { data } = await api.dkimApi.getDkimKeys(query, limit, page, _.toString(next), _.toString(previous)); 27 | return { 28 | previousCursor: _.get(data, 'previousCursor'), 29 | nextCursor: _.get(data, 'nextCursor'), 30 | data: addKey(_.get(data, 'results', [])), 31 | }; 32 | }); 33 | }; 34 | 35 | export default useDkim; 36 | -------------------------------------------------------------------------------- /src/hooks/useDkimDetails.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Aditya Negi 3 | * @description React hook useDkimDetails 4 | */ 5 | 6 | import { useQuery } from 'react-query'; 7 | import _ from 'lodash'; 8 | 9 | import api from 'client/RequestClient'; 10 | 11 | /* 12 | * useDkimDetails 13 | */ 14 | const useDkimDetails = (dkimId: string) => { 15 | return useQuery( 16 | ['query-dkim', dkimId], 17 | async () => { 18 | const { data } = await api.dkimApi.getDkimKey(dkimId); 19 | return data; 20 | }, 21 | { enabled: !_.isEmpty(dkimId) }, 22 | ); 23 | }; 24 | 25 | export default useDkimDetails; 26 | -------------------------------------------------------------------------------- /src/hooks/useDomainAliases.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description React hook useDomainAliases 4 | */ 5 | 6 | import { useQuery } from 'react-query'; 7 | import _ from 'lodash'; 8 | 9 | import { addKey } from 'app-ui/utils/logicUtils'; 10 | import api from 'client/RequestClient'; 11 | 12 | /** 13 | * useDomainAliases 14 | */ 15 | const useDomainAliases = (params: any) => { 16 | return useQuery(['useDomainAliases', params?.query, params?.limit, params?.page], async () => { 17 | const { data } = await api.domainAliasesApi.getDomainAliases( 18 | _.get(params, 'query'), 19 | _.get(params, 'limit'), 20 | _.get(params, 'page'), 21 | _.get(params, 'next'), 22 | _.get(params, 'previous'), 23 | ); 24 | 25 | return { 26 | previousCursor: _.get(data, 'previousCursor'), 27 | nextCursor: _.get(data, 'nextCursor'), 28 | data: addKey(_.get(data, 'results', [])), 29 | }; 30 | }); 31 | }; 32 | 33 | export default useDomainAliases; 34 | -------------------------------------------------------------------------------- /src/hooks/useDownloadAttachment.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description React hook useDownloadAttachment 4 | */ 5 | 6 | import _ from 'lodash'; 7 | import { useQuery } from 'react-query'; 8 | 9 | import api from 'client/RequestClient'; 10 | 11 | interface IParams { 12 | userId: string; 13 | attachment: any; 14 | mailboxId: string; 15 | messageId: number; 16 | } 17 | 18 | /** 19 | * useDownloadAttachment 20 | */ 21 | const useDownloadAttachment = ({ userId, attachment, mailboxId, messageId }: IParams) => { 22 | return useQuery( 23 | ['useDownloadAttachment', mailboxId, messageId, attachment], 24 | async () => { 25 | const { contentType, id, filename } = attachment; 26 | const { data } = await api.messagesApi.getMessageAttachment(userId, mailboxId, messageId, id, { 27 | responseType: 'blob', 28 | }); 29 | const link = document.createElement('a'); 30 | const fileCreated = new Blob([data], { type: contentType }); 31 | link.href = URL.createObjectURL(fileCreated); 32 | link.download = filename; 33 | link.click(); 34 | }, 35 | { enabled: !_.isEmpty(messageId) && !_.isEmpty(attachment) }, 36 | ); 37 | }; 38 | 39 | export default useDownloadAttachment; 40 | -------------------------------------------------------------------------------- /src/hooks/useFIlterDetails.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Aditya Negi 3 | * @description React hook useFilterDetails 4 | */ 5 | 6 | import { useQuery } from 'react-query'; 7 | import _ from 'lodash'; 8 | 9 | import api from 'client/RequestClient'; 10 | 11 | /* 12 | * useFilterDetails 13 | */ 14 | 15 | const useFilterDetails = (id: string, filterId: string) => { 16 | return useQuery( 17 | ['query-filterDetails', id, filterId], 18 | async () => { 19 | const { data } = await api.filtersApi.getFilter(id, filterId); 20 | const details = {}; 21 | _.assign( 22 | details, 23 | _.get(data, 'query', {}), 24 | _.get(data, 'action', {}), 25 | _.pick(data, ['id', 'name', 'disabled']), 26 | ); 27 | return details; 28 | }, 29 | { enabled: !_.isEmpty(filterId) }, 30 | ); 31 | }; 32 | 33 | export default useFilterDetails; 34 | -------------------------------------------------------------------------------- /src/hooks/useFilters.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Aditya Negi 3 | * @description React hook useFilters 4 | */ 5 | 6 | import { useQuery } from 'react-query'; 7 | import _ from 'lodash'; 8 | 9 | import { addKey } from 'app-ui/utils/logicUtils'; 10 | import api from 'client/RequestClient'; 11 | 12 | /* 13 | * useFilters 14 | */ 15 | 16 | const useFilters = (id: string) => { 17 | return useQuery( 18 | ['query-filters', id], 19 | async () => { 20 | const { data } = await api.filtersApi.getFilters(id); 21 | return addKey(_.get(data, 'results', [])); 22 | }, 23 | { enabled: !_.isEmpty(id) }, 24 | ); 25 | }; 26 | 27 | export default useFilters; 28 | -------------------------------------------------------------------------------- /src/hooks/useForwardedAddress.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description React hook useForwadedAddress 4 | */ 5 | 6 | import { useQuery } from 'react-query'; 7 | import _ from 'lodash'; 8 | 9 | import { addKey } from 'app-ui/utils/logicUtils'; 10 | import api from 'client/RequestClient'; 11 | 12 | /** 13 | * useForwadedAddress 14 | */ 15 | const useForwadedAddress = (params?: Address.IParams) => { 16 | return useQuery(['useForwardedAddress', params?.query], async () => { 17 | let addressList: any = []; 18 | let response = await api.addressApi.getAddresses( 19 | _.get(params, 'query', ' '), 20 | '', 21 | _.get(params, 'tags', ' '), 22 | _.get(params, 'requiredTags', ' '), 23 | _.get(params, 'metaData', false), 24 | _.get(params, 'internalData', false), 25 | _.get(params, 'limit', 250), 26 | _.get(params, 'page', 1), 27 | _.toString(_.get(params, 'next')), 28 | _.toString(_.get(params, 'previous')), 29 | ); 30 | 31 | addressList = _.get(response, 'data.results', []); 32 | 33 | while (!_.isEmpty(_.get(response, 'nextCursor'))) { 34 | response = await api.addressApi.getAddresses( 35 | _.get(params, 'query', ' '), 36 | '', 37 | _.get(params, 'tags', ' '), 38 | _.get(params, 'requiredTags', ' '), 39 | _.get(params, 'metaData', false), 40 | _.get(params, 'internalData', false), 41 | _.get(params, 'limit', 250), 42 | _.get(params, 'page', 1), 43 | _.toString(_.get(params, 'next')), 44 | _.toString(_.get(params, 'previous')), 45 | ); 46 | 47 | _.concat(addressList, _.get(response, 'data.results', [])); 48 | } 49 | return addKey(addressList); 50 | }); 51 | }; 52 | 53 | export default useForwadedAddress; 54 | -------------------------------------------------------------------------------- /src/hooks/useForwardedAddressInformation.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description React hook useForwardedAddressInformation 4 | */ 5 | 6 | import { useQuery } from 'react-query'; 7 | 8 | import api from 'client/RequestClient'; 9 | 10 | /** 11 | * useForwardedAddressInformation 12 | */ 13 | const useForwardedAddressInformation = (addressId: string) => { 14 | return useQuery(['useForwardedAddressInformation', addressId], async () => { 15 | const { data } = await api.addressApi.getForwardedAddress(addressId); 16 | return data; 17 | }); 18 | }; 19 | 20 | export default useForwardedAddressInformation; 21 | -------------------------------------------------------------------------------- /src/hooks/useLogoutUser.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description React hook useLogoutUser 4 | */ 5 | 6 | import { useMutation } from 'react-query'; 7 | 8 | import api from 'client/RequestClient'; 9 | import AppEvents, { Events } from 'app-ui/utils/AppEvents'; 10 | 11 | /** 12 | * useLogoutUser 13 | */ 14 | const useLogoutUser = () => { 15 | return useMutation((userId: string) => api.usersApi.logoutUser(userId, { reason: 'you have been logged out' }), { 16 | onError: () => { 17 | AppEvents.publish(Events.Error, 'Error'); 18 | }, 19 | onSuccess: () => { 20 | AppEvents.publish(Events.Success, 'Success'); 21 | }, 22 | }); 23 | }; 24 | 25 | export default useLogoutUser; 26 | -------------------------------------------------------------------------------- /src/hooks/useMailboxes.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description React hook useMailboxes 4 | */ 5 | 6 | import { useQuery } from 'react-query'; 7 | import _ from 'lodash'; 8 | 9 | import { addKey } from 'app-ui/utils/logicUtils'; 10 | import api from 'client/RequestClient'; 11 | 12 | interface IParams { 13 | userId: string; 14 | params?: any; 15 | } 16 | 17 | /** 18 | * useMailboxes 19 | */ 20 | const useMailboxes = ({ userId, params }: IParams) => { 21 | return useQuery(['useMailboxes', params?.specialUse], async () => { 22 | if (!_.isEmpty(userId)) { 23 | const { data } = await api.mailboxesApi.getMailboxes( 24 | userId, 25 | _.get(params, 'specialUse'), 26 | _.get(params, 'showHidden', true), 27 | _.get(params, 'counters', true), 28 | _.get(params, 'sizes', true), 29 | ); 30 | return addKey(_.get(data, 'results', [])); 31 | } 32 | }); 33 | }; 34 | 35 | export default useMailboxes; 36 | -------------------------------------------------------------------------------- /src/hooks/useMessageDetails.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description React hook useMessageDetails 4 | */ 5 | 6 | import { useQuery } from 'react-query'; 7 | 8 | import api from 'client/RequestClient'; 9 | 10 | interface IParams { 11 | userId: string; 12 | messageId: any; 13 | mailboxId: string; 14 | } 15 | 16 | /** 17 | * useMessageDetails 18 | */ 19 | const useMessageDetails = ({ userId, messageId, mailboxId }: IParams) => { 20 | return useQuery(['useMessageDetails', mailboxId, messageId], async () => { 21 | const { data } = await api.messagesApi.getMessage(userId, mailboxId, messageId); 22 | return data; 23 | }); 24 | }; 25 | 26 | export default useMessageDetails; 27 | -------------------------------------------------------------------------------- /src/hooks/useMessageSource.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description React hook useMessageSource 4 | */ 5 | 6 | import { useQuery } from 'react-query'; 7 | 8 | import api from 'client/RequestClient'; 9 | 10 | interface IParams { 11 | userId: string; 12 | mailboxId: string; 13 | messageNumber: number; 14 | } 15 | /** 16 | * useMessageSource 17 | */ 18 | const useMessageSource = ({ userId, mailboxId, messageNumber }: IParams) => { 19 | return useQuery(['useMessageSource'], async () => { 20 | const { data } = await api.messagesApi.getMessageSource(userId, mailboxId, messageNumber); 21 | 22 | return data; 23 | }); 24 | }; 25 | 26 | export default useMessageSource; 27 | -------------------------------------------------------------------------------- /src/hooks/useMessages.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description React hook useMessages 4 | */ 5 | 6 | import { useQuery } from 'react-query'; 7 | import _ from 'lodash'; 8 | 9 | import { addKey } from 'app-ui/utils/logicUtils'; 10 | import api from 'client/RequestClient'; 11 | 12 | interface IParams { 13 | userId: string; 14 | mailboxId: string; 15 | params?: any; 16 | } 17 | 18 | /** 19 | * useMessages 20 | */ 21 | const useMessages = ({ userId, mailboxId, params }: IParams) => { 22 | return useQuery( 23 | ['useMessages', userId, mailboxId, params?.limit, params?.page, params?.specialUse, params?.unseen], 24 | async () => { 25 | const { data } = await api.messagesApi.getMessages( 26 | userId, 27 | mailboxId, 28 | _.get(params, 'unseen'), 29 | _.get(params, 'metaData', true), 30 | _.get(params, 'limit'), 31 | _.get(params, 'page'), 32 | _.get(params, 'order'), 33 | _.get(params, 'next'), 34 | _.get(params, 'previous'), 35 | ); 36 | 37 | return { 38 | data: addKey(_.get(data, 'results', []), ['messageId', 'mailbox', 'thread', 'id']), 39 | previousCursor: _.get(data, 'previousCursor', ''), 40 | nextCursor: _.get(data, 'nextCursor', ''), 41 | }; 42 | }, 43 | ); 44 | }; 45 | 46 | export default useMessages; 47 | -------------------------------------------------------------------------------- /src/hooks/useRecalculateQuota.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description React hook useRecalculateQuota 4 | */ 5 | 6 | import { useMutation, useQueryClient } from 'react-query'; 7 | 8 | import api from 'client/RequestClient'; 9 | import AppEvents, { Events } from 'app-ui/utils/AppEvents'; 10 | 11 | /** 12 | * useRecalculateQuota 13 | */ 14 | const useRecalculateQuota = () => { 15 | const queryClient = useQueryClient(); 16 | 17 | return useMutation((userId: string) => api.usersApi.recalculateQuota(userId), { 18 | onError: () => { 19 | AppEvents.publish(Events.Error, 'Error'); 20 | }, 21 | onSuccess: () => { 22 | AppEvents.publish(Events.Success, 'Success'); 23 | queryClient.invalidateQueries('useUsers'); 24 | }, 25 | }); 26 | }; 27 | 28 | export default useRecalculateQuota; 29 | -------------------------------------------------------------------------------- /src/hooks/useRecalculateQuotaForAll.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description React hook useRecalculateQuotaForAll 4 | */ 5 | 6 | import { useMutation, useQueryClient } from 'react-query'; 7 | 8 | import api from 'client/RequestClient'; 9 | import AppEvents, { Events } from 'app-ui/utils/AppEvents'; 10 | 11 | /** 12 | * useRecalculateQuotaForAll 13 | */ 14 | const useRecalculateQuotaForAll = () => { 15 | const queryClient = useQueryClient(); 16 | 17 | return useMutation(() => api.usersApi.recalculateQuotaAllUsers(), { 18 | onError: () => { 19 | AppEvents.publish(Events.Error, 'Error'); 20 | }, 21 | onSuccess: () => { 22 | AppEvents.publish(Events.Success, 'Success'); 23 | queryClient.invalidateQueries('useUsers'); 24 | }, 25 | }); 26 | }; 27 | 28 | export default useRecalculateQuotaForAll; 29 | -------------------------------------------------------------------------------- /src/hooks/useRenameDomain.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description React hook useRenameDomain 4 | */ 5 | 6 | import { useMutation, useQueryClient } from 'react-query'; 7 | 8 | import api from 'client/RequestClient'; 9 | import AppEvents, { Events } from 'app-ui/utils/AppEvents'; 10 | import { RenameDomainRequest } from 'client/wildduck-api'; 11 | 12 | /** 13 | * useRenameDomain 14 | */ 15 | const useRenameDomain = () => { 16 | const queryClient = useQueryClient(); 17 | 18 | return useMutation((newDomain: RenameDomainRequest) => api.addressApi.renameDomain(newDomain), { 19 | onError: () => { 20 | AppEvents.publish(Events.Error, 'Error'); 21 | }, 22 | onSuccess: () => { 23 | AppEvents.publish(Events.Success, 'Success'); 24 | queryClient.invalidateQueries('useForwardedAddress'); 25 | }, 26 | }); 27 | }; 28 | 29 | export default useRenameDomain; 30 | -------------------------------------------------------------------------------- /src/hooks/useResetPassword.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description React hook useResetPassword 4 | */ 5 | 6 | import { useMutation } from 'react-query'; 7 | 8 | import api from 'client/RequestClient'; 9 | import AppEvents, { Events } from 'app-ui/utils/AppEvents'; 10 | 11 | /** 12 | * useResetPassword 13 | */ 14 | const useResetPassword = () => { 15 | return useMutation((userId: string) => api.usersApi.resetUserPassword(userId), { 16 | onError: () => { 17 | AppEvents.publish(Events.Error, 'Error'); 18 | }, 19 | onSuccess: () => { 20 | AppEvents.publish(Events.Success, 'Success'); 21 | }, 22 | }); 23 | }; 24 | 25 | export default useResetPassword; 26 | -------------------------------------------------------------------------------- /src/hooks/useRestoreArchiveMessage.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description React hook useRestoreArchiveMessage 4 | */ 5 | 6 | import { useMutation, useQueryClient } from 'react-query'; 7 | 8 | import api from 'client/RequestClient'; 9 | import AppEvents, { Events } from 'app-ui/utils/AppEvents'; 10 | import { RestoreMessageRequest } from 'client/wildduck-api'; 11 | 12 | export interface IRestoreArchiveMessage { 13 | userId: string; 14 | message: number | string; 15 | params?: RestoreMessageRequest; 16 | } 17 | 18 | /** 19 | * useRestoreArchiveMessage 20 | */ 21 | const useRestoreArchiveMessage = () => { 22 | const queryClient = useQueryClient(); 23 | 24 | return useMutation( 25 | ({ userId, message, params }: IRestoreArchiveMessage) => 26 | api.archiveApi.restoreMessage(userId, message as number, params), 27 | { 28 | onError: () => { 29 | AppEvents.publish(Events.Error, 'Error'); 30 | }, 31 | onSuccess: () => { 32 | AppEvents.publish(Events.Success, 'Success'); 33 | queryClient.invalidateQueries('useArchive'); 34 | queryClient.invalidateQueries('useMailboxes'); 35 | }, 36 | }, 37 | ); 38 | }; 39 | 40 | export default useRestoreArchiveMessage; 41 | -------------------------------------------------------------------------------- /src/hooks/useRestoreArchiveMessages.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description React hook useRestoreArchiveMessages 4 | */ 5 | 6 | import { useMutation, useQueryClient } from 'react-query'; 7 | 8 | import api from 'client/RequestClient'; 9 | import AppEvents, { Events } from 'app-ui/utils/AppEvents'; 10 | import { RestoreMessagesRequest } from 'client/wildduck-api'; 11 | 12 | interface IParams { 13 | userId: string; 14 | params: RestoreMessagesRequest; 15 | } 16 | 17 | /** 18 | * useRestoreArchiveMessages 19 | */ 20 | const useRestoreArchiveMessages = () => { 21 | const queryClient = useQueryClient(); 22 | 23 | return useMutation(async ({ userId, params }: IParams) => await api.archiveApi.restoreMessages(userId, params), { 24 | onError: () => { 25 | AppEvents.publish(Events.Error, 'Error'); 26 | }, 27 | onSuccess: ({ data }) => { 28 | AppEvents.publish(Events.Success, data.success ? 'Success' : 'Changes will reflect after 15 sec'); 29 | queryClient.invalidateQueries('useArchive'); 30 | }, 31 | }); 32 | }; 33 | 34 | export default useRestoreArchiveMessages; 35 | -------------------------------------------------------------------------------- /src/hooks/useUpdateAddress.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description React hook useUpdateAddress 4 | */ 5 | 6 | import { useMutation, useQueryClient } from 'react-query'; 7 | 8 | import api from 'client/RequestClient'; 9 | import AppEvents, { Events } from 'app-ui/utils/AppEvents'; 10 | import { UpdateUserAddressRequest } from 'client/wildduck-api'; 11 | import handleError from 'app-ui/utils/handleError'; 12 | 13 | interface IParams { 14 | userId: string; 15 | addressId: string; 16 | updateAddressInfo: UpdateUserAddressRequest; 17 | } 18 | /** 19 | * useUpdateAddress 20 | */ 21 | const useUpdateAddress = () => { 22 | const queryClient = useQueryClient(); 23 | 24 | return useMutation( 25 | (params: IParams) => 26 | api.addressApi.updateUserAddress(params.userId, params.addressId, params.updateAddressInfo), 27 | { 28 | onError: () => { 29 | AppEvents.publish(Events.Error, 'Error'); 30 | }, 31 | onSuccess: ({ data }) => { 32 | handleError(data); 33 | queryClient.invalidateQueries('useAddressInformation'); 34 | }, 35 | }, 36 | ); 37 | }; 38 | 39 | export default useUpdateAddress; 40 | -------------------------------------------------------------------------------- /src/hooks/useUpdateAutoreply.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description React hook useUpdateAutoreply 4 | */ 5 | 6 | import { useMutation, useQueryClient } from 'react-query'; 7 | 8 | import api from 'client/RequestClient'; 9 | import AppEvents, { Events } from 'app-ui/utils/AppEvents'; 10 | import { UpdateAutoreplyRequest } from 'client/wildduck-api'; 11 | import handleError from 'app-ui/utils/handleError'; 12 | 13 | interface IParams { 14 | userId: string; 15 | updateAutoreply: UpdateAutoreplyRequest; 16 | } 17 | /** 18 | * useUpdateAutoreply 19 | */ 20 | const useUpdateAutoreply = () => { 21 | const queryClient = useQueryClient(); 22 | 23 | return useMutation((params: IParams) => api.autorepliesApi.updateAutoreply(params.userId, params.updateAutoreply), { 24 | onError: () => { 25 | AppEvents.publish(Events.Error, 'Error'); 26 | }, 27 | onSuccess: ({ data }) => { 28 | handleError(data); 29 | queryClient.invalidateQueries('useAutoreplyDetails'); 30 | }, 31 | }); 32 | }; 33 | 34 | export default useUpdateAutoreply; 35 | -------------------------------------------------------------------------------- /src/hooks/useUpdateFilter.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description React hook useUpdateFilter 4 | */ 5 | 6 | import { useMutation } from 'react-query'; 7 | 8 | import api from 'client/RequestClient'; 9 | import AppEvents, { Events } from 'app-ui/utils/AppEvents'; 10 | import { CreateFilterRequest } from 'client/wildduck-api'; 11 | import handleError from 'app-ui/utils/handleError'; 12 | 13 | /** 14 | * useUpdateFilter 15 | */ 16 | const useUpdateFilter = () => { 17 | return useMutation( 18 | ({ 19 | userId, 20 | filterId, 21 | filterDetails, 22 | }: { 23 | userId: string; 24 | filterId: string; 25 | filterDetails: CreateFilterRequest; 26 | }) => api.filtersApi.updateFilter(userId, filterId, filterDetails), 27 | { 28 | onError: () => { 29 | AppEvents.publish(Events.Error, 'Error'); 30 | }, 31 | onSuccess: ({ data }) => { 32 | handleError(data); 33 | }, 34 | }, 35 | ); 36 | }; 37 | 38 | export default useUpdateFilter; 39 | -------------------------------------------------------------------------------- /src/hooks/useUpdateForwardedAddress.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description React hook useUpdateForwardedAddress 4 | */ 5 | 6 | import { useMutation, useQueryClient } from 'react-query'; 7 | 8 | import api from 'client/RequestClient'; 9 | import AppEvents, { Events } from 'app-ui/utils/AppEvents'; 10 | import { UpdateForwardedAddressRequest } from 'client/wildduck-api'; 11 | import handleError from 'app-ui/utils/handleError'; 12 | 13 | interface IParams { 14 | addressId: string; 15 | updateForwardedAddressInformation: UpdateForwardedAddressRequest; 16 | } 17 | /** 18 | * useUpdateForwardedAddress 19 | */ 20 | const useUpdateForwardedAddress = () => { 21 | const queryClient = useQueryClient(); 22 | 23 | return useMutation( 24 | (params: IParams) => 25 | api.addressApi.updateForwardedAddress(params.addressId, params.updateForwardedAddressInformation), 26 | { 27 | onError: () => { 28 | AppEvents.publish(Events.Error, 'Error'); 29 | }, 30 | onSuccess: ({ data }) => { 31 | handleError(data); 32 | queryClient.invalidateQueries('useForwardedAddressInformation'); 33 | }, 34 | }, 35 | ); 36 | }; 37 | 38 | export default useUpdateForwardedAddress; 39 | -------------------------------------------------------------------------------- /src/hooks/useUpdateMailbox.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description React hook useUpdateMailbox 4 | */ 5 | 6 | import { useMutation, useQueryClient } from 'react-query'; 7 | 8 | import api from 'client/RequestClient'; 9 | import AppEvents, { Events } from 'app-ui/utils/AppEvents'; 10 | import { UpdateMailboxRequest } from 'client/wildduck-api'; 11 | import handleError from 'app-ui/utils/handleError'; 12 | 13 | interface IParams { 14 | userId: string; 15 | mailboxId: string; 16 | params: UpdateMailboxRequest; 17 | } 18 | /** 19 | * useUpdateMailbox 20 | */ 21 | const useUpdateMailbox = () => { 22 | const queryClient = useQueryClient(); 23 | 24 | return useMutation( 25 | ({ userId, mailboxId, params }: IParams) => api.mailboxesApi.updateMailbox(userId, mailboxId, params), 26 | { 27 | onError: () => { 28 | AppEvents.publish(Events.Error, 'Error'); 29 | }, 30 | onSuccess: ({ data }) => { 31 | handleError(data); 32 | queryClient.invalidateQueries('useMailboxes'); 33 | }, 34 | }, 35 | ); 36 | }; 37 | 38 | export default useUpdateMailbox; 39 | -------------------------------------------------------------------------------- /src/hooks/useUpdateUserDetails.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description React hook useUpdateUserDetails 4 | */ 5 | 6 | import { useMutation, useQueryClient } from 'react-query'; 7 | 8 | import api from 'client/RequestClient'; 9 | import AppEvents, { Events } from 'app-ui/utils/AppEvents'; 10 | import { UpdateUserRequest } from 'client/wildduck-api'; 11 | import handleError from 'app-ui/utils/handleError'; 12 | 13 | interface IParams { 14 | userDetails: UpdateUserRequest; 15 | userId: string; 16 | } 17 | 18 | /** 19 | * useUpdateUserDetails 20 | */ 21 | const useUpdateUserDetails = () => { 22 | const queryClient = useQueryClient(); 23 | 24 | return useMutation((params: IParams) => api.usersApi.updateUser(params.userId, params.userDetails), { 25 | onError: () => { 26 | AppEvents.publish(Events.Error, 'Error'); 27 | }, 28 | onSuccess: ({ data }) => { 29 | handleError(data); 30 | queryClient.invalidateQueries('useUserDetails'); 31 | }, 32 | }); 33 | }; 34 | 35 | export default useUpdateUserDetails; 36 | -------------------------------------------------------------------------------- /src/hooks/useUserDetails.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description React hook useUserDetails 4 | */ 5 | 6 | import { useQuery } from 'react-query'; 7 | 8 | import api from 'client/RequestClient'; 9 | 10 | /** 11 | * useUserDetails 12 | */ 13 | const useUserDetails = (userId: string) => { 14 | return useQuery(['useUserDetails', userId], async () => { 15 | const { data } = await api.usersApi.getUser(userId); 16 | return data; 17 | }); 18 | }; 19 | 20 | export default useUserDetails; 21 | -------------------------------------------------------------------------------- /src/hooks/useUsers.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description React hook useUsers 4 | */ 5 | 6 | import { useQuery } from 'react-query'; 7 | import _ from 'lodash'; 8 | 9 | import { addKey } from 'app-ui/utils/logicUtils'; 10 | import api from 'client/RequestClient'; 11 | 12 | /** 13 | * useUsers 14 | */ 15 | const useUsers = (params?: IUsers.IFilterUsers) => { 16 | return useQuery( 17 | ['useUsers', params?.query, params?.tags, params?.requiredTags, params?.page, params?.limit], 18 | async () => { 19 | const { data } = await api.usersApi.getUsers( 20 | params?.query, 21 | '', 22 | params?.tags, 23 | params?.requiredTags, 24 | params?.metaData, 25 | params?.internalData, 26 | params?.limit, 27 | params?.page, 28 | _.toString(params?.next), 29 | _.toString(params?.previous), 30 | ); 31 | return { 32 | data: addKey(_.sortBy(_.get(data, 'results', []), (user: any) => user.username)), 33 | previousCursor: _.get(data, 'previousCursor', ''), 34 | nextCursor: _.get(data, 'nextCursor', ''), 35 | }; 36 | }, 37 | ); 38 | }; 39 | 40 | export default useUsers; 41 | -------------------------------------------------------------------------------- /src/logic/addressLogic.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description address logic 4 | */ 5 | 6 | import { kea } from 'kea'; 7 | 8 | import { get } from 'app-ui/utils/logicUtils'; 9 | 10 | const addressLogic = kea({ 11 | path: () => ['address'], 12 | defaults: { 13 | updatableField: false, 14 | 15 | query: '', 16 | 17 | addressId: '', 18 | 19 | addressInformationToggle: false, 20 | creatNewAddressToggle: false, 21 | renameDomainToggle: true, 22 | }, 23 | actions: { 24 | setQuery: (query: string) => ({ query }), 25 | 26 | setAddressId: (addressId: string) => ({ addressId }), 27 | 28 | setAddressInformationToggle: (addressInformationToggle: boolean) => ({ addressInformationToggle }), 29 | setCreatNewAddressToggle: (creatNewAddressToggle: boolean) => ({ creatNewAddressToggle }), 30 | setRenameDomainToggle: (renameDomainToggle: boolean) => ({ renameDomainToggle }), 31 | }, 32 | reducers: { 33 | query: { 34 | setQuery: get('query'), 35 | }, 36 | 37 | addressId: { 38 | setAddressId: get('addressId'), 39 | }, 40 | 41 | renameDomainToggle: { 42 | setRenameDomainToggle: get('renameDomainToggle'), 43 | }, 44 | addressInformationToggle: { 45 | setAddressInformationToggle: get('addressInformationToggle'), 46 | }, 47 | creatNewAddressToggle: { 48 | setCreatNewAddressToggle: get('creatNewAddressToggle'), 49 | }, 50 | }, 51 | }); 52 | 53 | export default addressLogic; 54 | -------------------------------------------------------------------------------- /src/logic/appLogic.ts: -------------------------------------------------------------------------------- 1 | import { kea } from 'kea'; 2 | import _ from 'lodash'; 3 | import { get } from 'app-ui/utils/logicUtils'; 4 | import menuConfig from 'app-ui/config/menuConfig'; 5 | 6 | const appLogic = kea({ 7 | path: () => ['app'], 8 | defaults: { 9 | loading: true, 10 | error: false, 11 | menuConfig: [], 12 | basePath: '', 13 | accessToken: '', 14 | showFloatingButton: false, 15 | }, 16 | actions: { 17 | syncAppData: (basePath: string) => ({ basePath }), 18 | setError: true, 19 | setAccessToken: (token: string) => ({ token }), 20 | setShowFloatingButton: (status: boolean) => ({ status }), 21 | }, 22 | reducers: { 23 | basePath: { 24 | syncAppData: get('basePath'), 25 | }, 26 | loading: { 27 | syncAppData: _.stubFalse, 28 | }, 29 | error: { 30 | syncAppData: _.stubFalse, 31 | setError: _.stubTrue, 32 | }, 33 | menuConfig: { 34 | syncAppData: () => menuConfig, 35 | }, 36 | accessToken: { 37 | setAccessToken: get('token'), 38 | }, 39 | showFloatingButton: { 40 | setShowFloatingButton: get('status'), 41 | }, 42 | }, 43 | }); 44 | 45 | export default appLogic; 46 | -------------------------------------------------------------------------------- /src/logic/archiveLogic.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description archive logic 4 | */ 5 | 6 | import { kea } from 'kea'; 7 | 8 | import { get } from 'app-ui/utils/logicUtils'; 9 | 10 | const archiveLogic = kea({ 11 | path: () => ['archive'], 12 | defaults: { 13 | page: 1, 14 | limit: 20, 15 | next: '', 16 | previous: '', 17 | 18 | dateData: [], 19 | isModalVisible: false, 20 | }, 21 | actions: { 22 | setNext: (next: string) => ({ next }), 23 | setPrevious: (previous: string) => ({ previous }), 24 | setLimit: (limit: number) => ({ limit }), 25 | setPage: (page: number) => ({ page }), 26 | 27 | setDateData: (dateData: Array) => ({ dateData }), 28 | setIsModalVisible: (isModalVisible: boolean) => ({ isModalVisible }), 29 | }, 30 | reducers: { 31 | page: { 32 | setPage: get('page'), 33 | }, 34 | next: { 35 | setNext: get('next'), 36 | }, 37 | previous: { 38 | setPrevious: get('previous'), 39 | }, 40 | limit: { 41 | setLimit: get('limit'), 42 | }, 43 | 44 | dateData: { 45 | setDateData: get>('dateData'), 46 | }, 47 | isModalVisible: { 48 | setIsModalVisible: get('isModalVisible'), 49 | }, 50 | }, 51 | }); 52 | 53 | export default archiveLogic; 54 | -------------------------------------------------------------------------------- /src/logic/authenticationLogic.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description Authentication logic 4 | */ 5 | 6 | import { kea } from 'kea'; 7 | 8 | import { get } from 'app-ui/utils/logicUtils'; 9 | 10 | const authenticationLogic = kea({ 11 | path: () => ['authentication'], 12 | 13 | defaults: { 14 | limit: 20, 15 | next: '', 16 | previous: '', 17 | page: 1, 18 | }, 19 | 20 | actions: { 21 | setNext: (next: string) => ({ next }), 22 | setPrevious: (previous: string) => ({ previous }), 23 | setLimit: (limit: number) => ({ limit }), 24 | setPage: (page: number) => ({ page }), 25 | }, 26 | 27 | reducers: { 28 | next: { 29 | setNext: get('next'), 30 | }, 31 | previous: { 32 | setPrevious: get('previous'), 33 | }, 34 | limit: { 35 | setLimit: get('limit'), 36 | }, 37 | page: { 38 | setPage: get('page'), 39 | }, 40 | }, 41 | }); 42 | 43 | export default authenticationLogic; 44 | -------------------------------------------------------------------------------- /src/logic/dkimLogic.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Aditya Negi 3 | * @description Dkim logic 4 | */ 5 | 6 | import { kea } from 'kea'; 7 | 8 | import { get } from 'app-ui/utils/logicUtils'; 9 | 10 | const dkimLogic = kea({ 11 | path: () => ['dkim'], 12 | defaults: { 13 | next: '', 14 | previous: '', 15 | limit: 20, 16 | page: 1, 17 | 18 | query: '', 19 | }, 20 | actions: { 21 | setLimit: (limit: number) => ({ limit }), 22 | setNext: (next: string) => ({ next }), 23 | setPrevious: (previous: string) => ({ previous }), 24 | setPage: (page: number) => ({ page }), 25 | 26 | setQuery: (query: string) => ({ query }), 27 | }, 28 | reducers: { 29 | next: { 30 | setNext: get('next'), 31 | }, 32 | previous: { 33 | setPrevious: get('previous'), 34 | }, 35 | limit: { 36 | setLimit: get('limit'), 37 | }, 38 | page: { 39 | setPage: get('page'), 40 | }, 41 | 42 | query: { 43 | setQuery: get('query'), 44 | }, 45 | }, 46 | }); 47 | 48 | export default dkimLogic; 49 | -------------------------------------------------------------------------------- /src/logic/domainAccessLogic.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Aditya Negi 3 | * @description Domain access logic 4 | */ 5 | 6 | import { kea } from 'kea'; 7 | 8 | import { get } from 'app-ui/utils/logicUtils'; 9 | import { GetAllowedDomainResult } from 'client/wildduck-api'; 10 | 11 | const domainAccessLogic = kea({ 12 | path: () => ['domain-access'], 13 | defaults: { 14 | allowedList: [], 15 | blockedList: [], 16 | dataSource: [], 17 | tag: '', 18 | addDomainModalVisiblity: false, 19 | }, 20 | actions: { 21 | setAllowedList: (list: Array) => ({ list }), 22 | setBlockedList: (list: Array) => ({ list }), 23 | getAllowedList: (tags: string) => ({ tags }), 24 | getBlockedList: (tags: string) => ({ tags }), 25 | setDataSource: (list: GetAllowedDomainResult) => ({ 26 | list, 27 | }), 28 | setTag: (tag: string) => ({ tag }), 29 | setAddDomainModalVisiblity: (status: boolean) => ({ status }), 30 | }, 31 | reducers: { 32 | allowedList: { 33 | setAllowedList: get>('list'), 34 | }, 35 | blockedList: { 36 | setBlockedList: get>('list'), 37 | }, 38 | dataSource: { 39 | setDataSource: get>('list'), 40 | }, 41 | tag: { 42 | setTag: get('tag'), 43 | }, 44 | addDomainModalVisiblity: { 45 | setAddDomainModalVisiblity: get('status'), 46 | }, 47 | }, 48 | }); 49 | 50 | export default domainAccessLogic; 51 | -------------------------------------------------------------------------------- /src/logic/domainAliasesLogic.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description domain aliases logic 4 | */ 5 | 6 | import { kea } from 'kea'; 7 | 8 | import { get } from 'app-ui/utils/logicUtils'; 9 | 10 | const domainAliasesLogic = kea({ 11 | path: () => ['domainAliases'], 12 | defaults: { 13 | query: '', 14 | 15 | limit: 20, 16 | next: '', 17 | previous: '', 18 | page: 1, 19 | }, 20 | 21 | actions: { 22 | setQuery: (query: string) => ({ query }), 23 | 24 | setNext: (next: string) => ({ next }), 25 | setPrevious: (previous: string) => ({ previous }), 26 | setLimit: (limit: number) => ({ limit }), 27 | setPage: (page: number) => ({ page }), 28 | }, 29 | 30 | reducers: { 31 | query: { 32 | setQuery: get('query'), 33 | }, 34 | 35 | page: { 36 | setPage: get('page'), 37 | }, 38 | dir: { 39 | setDir: get('dir'), 40 | }, 41 | next: { 42 | setNext: get('next'), 43 | }, 44 | previous: { 45 | setPrevious: get('previous'), 46 | }, 47 | limit: { 48 | setLimit: get('limit'), 49 | }, 50 | }, 51 | }); 52 | 53 | export default domainAliasesLogic; 54 | -------------------------------------------------------------------------------- /src/logic/filtersLogic.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Aditya Negi 3 | * @description filters logic 4 | */ 5 | 6 | import { kea } from 'kea'; 7 | 8 | import { get } from 'app-ui/utils/logicUtils'; 9 | 10 | const filtersLogic = kea({ 11 | path: () => ['filters'], 12 | defaults: { 13 | showAddFilterForm: false, 14 | filterId: '', 15 | }, 16 | actions: { 17 | setShowAddFilterForm: (buttonStatus: boolean) => ({ buttonStatus }), 18 | setFilterId: (filterId: string) => ({ filterId }), 19 | }, 20 | reducers: { 21 | showAddFilterForm: { 22 | setShowAddFilterForm: get('buttonStatus'), 23 | }, 24 | filterId: { 25 | setFilterId: get('filterId'), 26 | }, 27 | }, 28 | }); 29 | 30 | export default filtersLogic; 31 | -------------------------------------------------------------------------------- /src/logic/mailboxesLogic.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description domain aliases logic 4 | */ 5 | 6 | import { kea } from 'kea'; 7 | 8 | import { get } from 'app-ui/utils/logicUtils'; 9 | import { UpdateMailboxRequest } from 'client/wildduck-api'; 10 | 11 | const mailboxesLogic = kea({ 12 | path: () => ['mailboxes'], 13 | defaults: { 14 | mailboxId: '', 15 | 16 | selectedMailboxData: {}, 17 | 18 | updateMailboxToggle: false, 19 | showMailboxMessagesTable: false, 20 | 21 | specialUse: false, 22 | 23 | mailboxName: '', 24 | }, 25 | actions: { 26 | setMailboxId: (mailboxId: boolean) => ({ mailboxId }), 27 | 28 | setSelectedMailboxData: (selectedMailboxData: UpdateMailboxRequest) => ({ selectedMailboxData }), 29 | 30 | setUpdateMailboxToggle: (updateMailboxToggle: boolean) => ({ updateMailboxToggle }), 31 | setShowMailboxMessagesTable: (showMailboxMessagesTable: boolean) => ({ showMailboxMessagesTable }), 32 | 33 | setSpecialUse: (specialUse: boolean) => ({ specialUse }), 34 | 35 | setMailboxName: (mailboxName: string) => ({ mailboxName }), 36 | }, 37 | reducers: { 38 | specialUse: { 39 | setSpecialUse: get('specialUse'), 40 | }, 41 | 42 | mailboxName: { 43 | setMailboxName: get('mailboxName'), 44 | }, 45 | 46 | updateMailboxToggle: { 47 | setUpdateMailboxToggle: get('updateMailboxToggle'), 48 | }, 49 | showMailboxMessagesTable: { 50 | setShowMailboxMessagesTable: get('showMailboxMessagesTable'), 51 | }, 52 | 53 | mailboxId: { 54 | setMailboxId: get('mailboxId'), 55 | }, 56 | 57 | selectedMailboxData: { 58 | setSelectedMailboxData: get('selectedMailboxData'), 59 | }, 60 | }, 61 | }); 62 | 63 | export default mailboxesLogic; 64 | -------------------------------------------------------------------------------- /src/logic/messagesLogic.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Aditya Negi 3 | * @description messages logic 4 | */ 5 | 6 | import { kea } from 'kea'; 7 | 8 | import { get } from 'app-ui/utils/logicUtils'; 9 | 10 | const messagesLogic = kea({ 11 | path: () => ['messages'], 12 | defaults: { 13 | limit: 20, 14 | next: '', 15 | previous: '', 16 | page: 1, 17 | 18 | messageId: '', 19 | attachmentId: '', 20 | 21 | unseen: false, 22 | 23 | showUploadMessageForm: false, 24 | messageDetailsToggle: false, 25 | messageSourceToggle: false, 26 | }, 27 | actions: { 28 | setPage: (page: number) => ({ page }), 29 | setNext: (next: string) => ({ next }), 30 | setPrevious: (previous: string) => ({ previous }), 31 | setLimit: (limit: number) => ({ limit }), 32 | 33 | setUnseen: (unseen: boolean) => ({ unseen }), 34 | 35 | setMessageId: (messageId: string | number) => ({ messageId }), 36 | setAttachmentId: (attachmentId: string | number) => ({ attachmentId }), 37 | 38 | setMessageDetailsToggle: (messageDetailsToggle: boolean) => ({ messageDetailsToggle }), 39 | setMessageSourceToggle: (messageSourceToggle: boolean) => ({ messageSourceToggle }), 40 | }, 41 | reducers: { 42 | messageId: { 43 | setMessageId: get('messageId'), 44 | }, 45 | attachmentId: { 46 | setAttachmentId: get('attachmentId'), 47 | }, 48 | 49 | messageSourceToggle: { 50 | setMessageSourceToggle: get('messageSourceToggle'), 51 | }, 52 | messageDetailsToggle: { 53 | setMessageDetailsToggle: get('messageDetailsToggle'), 54 | }, 55 | 56 | next: { 57 | setNext: get('next'), 58 | }, 59 | previous: { 60 | setPrevious: get('previous'), 61 | }, 62 | limit: { 63 | setLimit: get('limit'), 64 | }, 65 | page: { 66 | setPage: get('page'), 67 | }, 68 | 69 | unseen: { 70 | setUnseen: get('unseen'), 71 | }, 72 | }, 73 | }); 74 | 75 | export default messagesLogic; 76 | -------------------------------------------------------------------------------- /src/logic/navigationLogic.ts: -------------------------------------------------------------------------------- 1 | import { get } from 'app-ui/utils/logicUtils'; 2 | import { kea } from 'kea'; 3 | import _ from 'lodash'; 4 | 5 | import AppLogic from './appLogic'; 6 | 7 | const logic = kea({ 8 | connect: { 9 | values: [AppLogic, ['menuConfig', 'basePath']], 10 | }, 11 | 12 | path: () => ['navigations'], 13 | 14 | defaults: { 15 | collapsed: false, 16 | selectedKeys: [], 17 | openKeys: [], 18 | }, 19 | 20 | actions: () => ({ 21 | setCollapsed: (collapsed: boolean) => ({ collapsed }), 22 | setOpenKeys: (openKeys: string[]) => ({ openKeys }), 23 | setSelectedKeys: (selectedKeys: string[]) => ({ selectedKeys }), 24 | redirect: (nextURL: string) => ({ nextURL }), 25 | setNavigationKeys: (selectedKeys: string[], openKeys: string[]) => ({ selectedKeys, openKeys }), 26 | }), 27 | 28 | listeners: ({ actions, values }) => ({ 29 | redirect: ({ nextURL }: { nextURL: string }) => { 30 | let url = `/${nextURL}`; 31 | const { menuConfig } = values; 32 | const basePath = _.get(window, 'basePath', ''); 33 | if (basePath.length > 1 && new RegExp(`^${basePath}.*`).test(url)) { 34 | url = url.slice(basePath.length - 1); 35 | } 36 | const match = _.find(menuConfig, (config: string) => _.get(config, 'url') === url); 37 | actions.setNavigationKeys([_.get(match, 'key', '')], _.get(match, 'hierarchy', [])); 38 | }, 39 | }), 40 | 41 | reducers: () => ({ 42 | collapsed: { 43 | setCollapsed: get('collapsed'), 44 | }, 45 | openKeys: { 46 | setOpenKeys: get('openKeys'), 47 | setNavigationKeys: get('openKeys'), 48 | }, 49 | selectedKeys: { 50 | setSelectedKeys: get('selectedKeys'), 51 | setNavigationKeys: get('selectedKeys'), 52 | }, 53 | }), 54 | }); 55 | 56 | export default logic; 57 | -------------------------------------------------------------------------------- /src/logic/usersLogic.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Aditya Negi 3 | * @description Users logic 4 | */ 5 | 6 | import { kea } from 'kea'; 7 | 8 | import { get } from 'app-ui/utils/logicUtils'; 9 | 10 | const usersLogic = kea({ 11 | path: () => ['users'], 12 | defaults: { 13 | next: '', 14 | previous: '', 15 | limit: 20, 16 | page: 1, 17 | 18 | searchParams: {}, 19 | 20 | userDetails: {}, 21 | password: '', 22 | showResetPasswordModal: false, 23 | }, 24 | actions: { 25 | setPassword: (password: string) => ({ password }), 26 | setShowResetPasswordModal: (status: boolean) => ({ status }), 27 | 28 | setSearchParams: (searchParams: string) => ({ searchParams }), 29 | 30 | setNext: (next: string) => ({ next }), 31 | setPrevious: (previous: string) => ({ previous }), 32 | setLimit: (limit: number) => ({ limit }), 33 | setPage: (page: number) => ({ page }), 34 | }, 35 | reducers: { 36 | searchParams: { 37 | setSearchParams: get('searchParams'), 38 | }, 39 | 40 | next: { 41 | setNext: get('next'), 42 | }, 43 | previous: { 44 | setPrevious: get('previous'), 45 | }, 46 | limit: { 47 | setLimit: get('limit'), 48 | }, 49 | page: { 50 | setPage: get('page'), 51 | }, 52 | 53 | password: { 54 | setPassword: get('password'), 55 | }, 56 | showResetPasswordModal: { 57 | setShowResetPasswordModal: get('status'), 58 | }, 59 | }, 60 | }); 61 | 62 | export default usersLogic; 63 | -------------------------------------------------------------------------------- /src/react-query.config.ts: -------------------------------------------------------------------------------- 1 | const config = { 2 | defaultOptions: { 3 | queries: { 4 | retry: false, 5 | retryDelay: 5000, 6 | refetchOnWindowFocus: false, 7 | }, 8 | }, 9 | }; 10 | 11 | export default config; 12 | -------------------------------------------------------------------------------- /src/store/index.ts: -------------------------------------------------------------------------------- 1 | import { resetContext, getContext } from 'kea'; 2 | 3 | resetContext({ 4 | createStore: {}, 5 | plugins: [], 6 | }); 7 | 8 | export default getContext().store; 9 | -------------------------------------------------------------------------------- /src/types/axios.d.ts: -------------------------------------------------------------------------------- 1 | declare interface IAxiosInterceptors { 2 | request: any; 3 | response: any; 4 | reject: any; 5 | } 6 | 7 | declare type IAxiosInstance = import('axios').AxiosInstance; 8 | declare type IAxiosError = import('axios').AxiosError; 9 | declare type IAxiosRequestConfig = import('axios').AxiosRequestConfig; 10 | declare type IAxiosResponse = import('axios').AxiosResponse; 11 | -------------------------------------------------------------------------------- /src/types/dkim.d.ts: -------------------------------------------------------------------------------- 1 | declare namespace IDkim { 2 | interface IFilterGetDkimKeysList { 3 | query: string; 4 | limit: number; 5 | } 6 | 7 | interface ICreateDkim { 8 | domain: string; 9 | selector: string; 10 | description?: string; 11 | privateKey?: string; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/types/domainAliases.d.ts: -------------------------------------------------------------------------------- 1 | declare namespace DomainAliases { 2 | interface IRequstListParams { 3 | query: string; 4 | limit: number; 5 | page: number; 6 | next: number; 7 | previous: number; 8 | } 9 | 10 | type IDomainAliasesList = IDomainAliases[]; 11 | 12 | interface IResolveId { 13 | success: boolean; 14 | id: string; 15 | } 16 | 17 | interface IDomainAliasInfo { 18 | success: boolean; 19 | id: string; 20 | alias: string; 21 | domain: string; 22 | created: string; 23 | } 24 | 25 | interface ICreateNewDomainAlias { 26 | domain: string; 27 | alias: string; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/types/navigationBar.d.ts: -------------------------------------------------------------------------------- 1 | declare namespace Navigation { 2 | type Icon = { 3 | type: string; 4 | theme?: 'filled' | 'outlined' | 'twoTone'; 5 | }; 6 | 7 | interface IMenuItem { 8 | key: string; 9 | icon: Icon | React.FC; 10 | title: string; 11 | path: string; 12 | url: string; 13 | hideMenu: boolean; 14 | } 15 | 16 | type ISubMenuItem = { 17 | key: string; 18 | icon: Icon | React.FC; 19 | title: string; 20 | children: (ISubMenuItem | IMenuItem)[]; 21 | }; 22 | 23 | type IMenuItems = (ISubMenuItem | IMenuItem)[]; 24 | 25 | interface IStoreStates { 26 | route?: string; 27 | nextRoute?: string; 28 | collapsed: boolean; 29 | openKeys: string[]; 30 | selectedKeys: string[]; 31 | accessableFeatures: any[]; 32 | basePath: string; 33 | menuConfig: any; 34 | } 35 | 36 | interface IActions { 37 | setSelectedKeys: (keys: string[]) => void; 38 | setOpenKeys: (openKeys: string[]) => void; 39 | setCollapsed: (collapsed: boolean) => void; 40 | redirect: (nextUrl: string) => void; 41 | } 42 | 43 | interface Props extends IStoreStates { 44 | actions: IActions; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/types/storage.d.ts: -------------------------------------------------------------------------------- 1 | declare namespace Storage { 2 | interface IStorage { 3 | id: string; 4 | filename: string; 5 | size: number; 6 | } 7 | type IStorageList = IStorage[]; 8 | } 9 | -------------------------------------------------------------------------------- /src/types/users.d.ts: -------------------------------------------------------------------------------- 1 | declare namespace IUsers { 2 | interface IFilterUsers { 3 | query?: string; 4 | tags?: string; 5 | requiredTags?: string; 6 | limit?: number; 7 | metaData?: boolean; 8 | internalData?: boolean; 9 | page?: number; 10 | next?: number; 11 | previous?: number; 12 | } 13 | 14 | interface ICreateUser { 15 | username: string; 16 | name?: string; 17 | password: string; 18 | address?: string; 19 | pubKey?: string; 20 | metaData?: string; 21 | internalData?: string; 22 | language?: string; 23 | sess?: string; 24 | ip?: string; 25 | address?: string; 26 | address?: string; 27 | address?: string; 28 | address?: string; 29 | tags?: string[]; 30 | disabledScopes: string[]; 31 | targets?: string[]; 32 | fromWhitelist?: string[]; 33 | autoreply?: boolean; 34 | encryptMessages?: boolean; 35 | encryptForwarded?: boolean; 36 | quota?: number; 37 | recipients?: number; 38 | forwards?: number; 39 | imapMaxUpload?: number; 40 | pop3MaxDownload?: number; 41 | pop3MaxMessages?: number; 42 | imapMaxConnections?: number; 43 | receivedMax?: number; 44 | imapMaxDownload?: number; 45 | imapMaxDownload?: number; 46 | imapMaxDownload?: number; 47 | hasPasswordSet?: boolean; 48 | activated?: boolean; 49 | disabled?: boolean; 50 | suspended?: boolean; 51 | hashedPassword?: boolean; 52 | allowUnsafe?: boolean; 53 | requirePasswordChange?: boolean; 54 | addTagsToAddress?: boolean; 55 | uploadSentMessages?: boolean; 56 | addTagsToAddress?: boolean; 57 | addTagsToAddress?: boolean; 58 | } 59 | 60 | interface IResults { 61 | id: string; 62 | username: string; 63 | name: string; 64 | address: string; 65 | tags: Array; 66 | forward: Array; 67 | enabled2a: string[]; 68 | autoreply: boolean; 69 | encryptMessages: boolean; 70 | encryptForwarded: boolean; 71 | quota: { 72 | allowed: number; 73 | used: number; 74 | }; 75 | hasPasswordSet: boolean; 76 | activated: boolean; 77 | disabled: boolean; 78 | suspended: boolean; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/utils/AppEvents.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Event Bus using pub/sub design pattern 3 | * @author Harish.R 4 | */ 5 | 6 | import _ from 'lodash'; 7 | import log from 'loglevel'; 8 | 9 | /** 10 | * Events 11 | */ 12 | enum Events { 13 | Loading = 'M_LOADING', 14 | Warn = 'M_WARN', 15 | Info = 'M_INFO', 16 | Success = 'M_SUCCESS', 17 | Error = 'M_ERROR', 18 | N_Loading = 'N_LOADING', 19 | N_Warn = 'N_WARN', 20 | N_Info = 'N_INFO', 21 | N_Success = 'N_SUCCESS', 22 | N_Error = 'N_ERROR', 23 | MO_Success = 'MO_Success', 24 | MO_Error = 'MO_Error', 25 | MO_Info = 'MO_Info', 26 | MO_Warn = 'MO_Warn', 27 | } 28 | 29 | /** 30 | * App Events 31 | * @class 32 | */ 33 | class AppEvents { 34 | /** 35 | * All Subscriptions 36 | * @member subscribers 37 | */ 38 | subscribers: Record; 39 | constructor() { 40 | this.subscribers = {}; 41 | } 42 | 43 | /** 44 | * publish an event 45 | * @method publish 46 | * @param {string} event 47 | * @param rest 48 | */ 49 | publish = (event: string, ...rest: any) => { 50 | if (_.has(this.subscribers, event)) { 51 | _.forOwn(_.get(this.subscribers, event), (callback: any) => { 52 | try { 53 | callback(...rest); 54 | } catch (ex) { 55 | log.error(`[Eventbus] ${ex}`); 56 | } 57 | }); 58 | } 59 | }; 60 | 61 | /** 62 | * Subscribes an event 63 | * @method subscribe 64 | * @param {event} event 65 | * @param {function} callback 66 | */ 67 | subscribe = (event: string, callback: any) => { 68 | if (!_.has(this.subscribers, event)) { 69 | _.setWith(this.subscribers, event, [], Object); 70 | } 71 | if (_.isFunction(callback)) { 72 | _.get(this.subscribers, event).push(callback); 73 | } else { 74 | log.error(`[Eventbus] ${callback} is not a function`); 75 | } 76 | }; 77 | } 78 | 79 | export default new AppEvents(); 80 | 81 | export { Events }; 82 | -------------------------------------------------------------------------------- /src/utils/FilterDropdownStyle.css: -------------------------------------------------------------------------------- 1 | .filterWrapper .ant-list, .selectCheckBox { 2 | padding: 8px; 3 | } 4 | 5 | .filterFooter { 6 | width: 100%; 7 | display: inline-flex; 8 | flex-direction: row; 9 | justify-content: space-between; 10 | padding: 7px 8px; 11 | overflow: hidden; 12 | border-top: 1px solid #e8e8e8; 13 | } 14 | 15 | .filterWrapper .ant-list-item { 16 | display: flex; 17 | align-items: center; 18 | padding: 5px 0; 19 | border-bottom: 0 !important; 20 | } 21 | 22 | .filterListWrapper { 23 | max-height: 190px; 24 | overflow-y: scroll; 25 | } 26 | -------------------------------------------------------------------------------- /src/utils/Pagination.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag Kushwaha 3 | * @description Pagination Component 4 | */ 5 | 6 | import React from 'react'; 7 | import { Button, Tooltip, Select, Space } from 'antd'; 8 | import _ from 'lodash'; 9 | 10 | import { RightOutlined, LeftOutlined } from '@ant-design/icons'; 11 | 12 | interface IPagination { 13 | next: string; 14 | previous: string; 15 | limit: number; 16 | page: number; 17 | setLimit(value: number): void; 18 | setPrevious(value: string): void; 19 | setNext(value: string): void; 20 | setPage(value: number): void; 21 | } 22 | 23 | export const Pagination: React.FC = ({ 24 | limit, 25 | previous, 26 | next, 27 | page, 28 | setLimit, 29 | setPrevious, 30 | setNext, 31 | setPage, 32 | }: IPagination) => { 33 | return ( 34 | 35 | 36 | 46 | 47 | 60 | 61 | 71 | 72 | 73 | ); 74 | }; 75 | -------------------------------------------------------------------------------- /src/utils/constants.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Lakkanna Walikar 3 | * @description constants 4 | */ 5 | 6 | /** 7 | * DATE_TIME_FORMAT 8 | * @type {string} 9 | * @exports 10 | */ 11 | const DATE_TIME_FORMAT = 'YYYY-MM-DD HH:mm:ss'; 12 | 13 | /** 14 | * DATE_TIME_FORMAT_AP 15 | * @type {string} 16 | * @exports 17 | */ 18 | const DATE_TIME_FORMAT_AP = 'YYYY-MM-DD hh:mm:ss A'; 19 | 20 | export { DATE_TIME_FORMAT, DATE_TIME_FORMAT_AP }; 21 | -------------------------------------------------------------------------------- /src/utils/getUniqValuesBy.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Lakkanna Walikar 3 | */ 4 | 5 | import _ from 'lodash'; 6 | 7 | /** 8 | * index signature for object 9 | */ 10 | interface IIndexSignature { 11 | [key: string]: any; 12 | } 13 | 14 | /** 15 | * Function to get uniq values based on object key 16 | * 17 | * @param {RevenueForecastDetails} data - A revenue forecast detail 18 | * @param {string} filterFor - This is key in a object 19 | * @returns {string[]} Uniq values for given filterFor key from the array of object 20 | */ 21 | const getUniqValuesBy = (dataArray: IIndexSignature[], filterFor: string): string[] => { 22 | if (filterFor) { 23 | return _.chain(dataArray) 24 | .map((data) => _.toString( _.get(data, filterFor))) 25 | .filter((value) => value !== undefined) 26 | .uniq() 27 | .sort() 28 | .value(); 29 | } 30 | return []; 31 | }; 32 | 33 | export default getUniqValuesBy; 34 | -------------------------------------------------------------------------------- /src/utils/handleError.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Chirag 3 | * @description Handle error from the server 4 | */ 5 | 6 | import _ from 'lodash'; 7 | 8 | import AppEvents, { Events } from 'app-ui/utils/AppEvents'; 9 | 10 | const handleError = (data: any) => { 11 | let error = _.get(data, 'error', ''); 12 | if (_.isEqual(error, 'Mailbox update failed with code CANNOT')) { 13 | error = 'Special Mailbox path cannot be changed'; 14 | } else if (_.isEqual(error, 'Mailbox update failed with code ALREADYEXISTS')) { 15 | error = 'Mailbox with this name already exists'; 16 | } 17 | 18 | _.isEmpty(error) ? AppEvents.publish(Events.Success, 'Success') : AppEvents.publish(Events.Error, `${error}`); 19 | }; 20 | 21 | export default handleError; 22 | -------------------------------------------------------------------------------- /src/utils/logicUtils.ts: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import AppEvents, { Events } from './AppEvents'; 3 | 4 | /** 5 | * gets the specified value using key 6 | * @param key 7 | */ 8 | const get = (key: string, defaults?: T) => (state: T, payload: Record): T => { 9 | return _.get(payload, key, !_.isUndefined(defaults) ? defaults : state); 10 | }; 11 | 12 | /** 13 | * creates an object from specified keys 14 | * @param key 15 | */ 16 | const pick = (keys: K[]) => (state: T, payload: { [k in K]: T[k] }): { [k in K]: T[k] } => { 17 | return _.pick(payload, keys); 18 | }; 19 | 20 | /** 21 | * creates an array of object with keys 22 | * @param arrayOfObject 23 | */ 24 | const addKey = ( 25 | arrayOfObject: Array>, 26 | keys: Array = ['id'], 27 | ): Array> => { 28 | return _.map(arrayOfObject, (obj) => { 29 | let mkey = ''; 30 | return { 31 | ...obj, 32 | key: _.map(keys, (tkey: string) => { 33 | mkey += _.get(obj, tkey, ''); 34 | return mkey; 35 | }), 36 | }; 37 | }); 38 | }; 39 | 40 | const handleError = (error = '', success = 'Successfull !'): void => { 41 | _.isEmpty(error) ? AppEvents.publish(Events.Success, success) : AppEvents.publish(Events.Error, `${error}`); 42 | }; 43 | 44 | export { get, pick, addKey, handleError }; 45 | -------------------------------------------------------------------------------- /src/utils/showConfirm.ts: -------------------------------------------------------------------------------- 1 | import Modal from 'antd/lib/modal'; 2 | 3 | const { confirm } = Modal; 4 | 5 | function showConfirm(actionCall: () => void, title = 'Are you sure ?'): void { 6 | confirm({ 7 | title: title, 8 | onOk() { 9 | actionCall(); 10 | }, 11 | }); 12 | } 13 | 14 | export default showConfirm; 15 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "experimentalDecorators": true, 4 | "strictNullChecks": false, 5 | "baseUrl": ".", 6 | "outDir": "./dist", 7 | "sourceMap": true, 8 | "lib": ["dom", "dom.iterable", "esnext"], 9 | "allowJs": false, 10 | "allowSyntheticDefaultImports": true, 11 | "alwaysStrict": true, 12 | "skipLibCheck": true, 13 | "esModuleInterop": true, 14 | "strict": true, 15 | "forceConsistentCasingInFileNames": true, 16 | "module": "esnext", 17 | "target": "es6", 18 | "moduleResolution": "node", 19 | "resolveJsonModule": true, 20 | "isolatedModules": true, 21 | "jsx": "react", 22 | "removeComments": true, 23 | "paths": { 24 | "app-ui/*": ["src/*"], 25 | "components/*": ["src/components/*"], 26 | "lib/*": ["src/lib/*"], 27 | "ui-utils/*": ["src/utils/*"], 28 | "styles/*": ["src/styles/*"], 29 | "ui-types/*": ["src/types/*"], 30 | "redux-types/*": ["src/types/*"], 31 | "client/*": ["src/client/*"], 32 | "logic/*": ["src/logic/*"], 33 | "store/*": ["src/store/*"] 34 | } 35 | }, 36 | "include": ["src"], 37 | "exclude": ["node_modules"] 38 | } 39 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const webpack = require('webpack'); 3 | const { merge } = require('webpack-merge'); 4 | 5 | const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; 6 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 7 | const { CleanWebpackPlugin } = require('clean-webpack-plugin'); 8 | const CopyWebpackPlugin = require('copy-webpack-plugin'); 9 | 10 | const modeConfig = (mode) => require(`./buildUtils/webpack.${mode}`); 11 | 12 | const getIncludeDirs = () => [path.join(__dirname, 'src')]; 13 | 14 | const getPlugins = (analyse) => { 15 | const plugins = [ 16 | new CleanWebpackPlugin(), 17 | new HtmlWebpackPlugin({ 18 | template: './public/index.html', 19 | }), 20 | new CopyWebpackPlugin({ 21 | patterns: ['favicon', 'svg', 'style.css', 'manifest.json', 'robots.txt'].map((file) => ({ 22 | from: path.join(__dirname, `public/${file}`), 23 | to: path.join(__dirname, `dist/${file}`), 24 | })), 25 | }), 26 | // ___ANTD___ specific 27 | new webpack.ContextReplacementPlugin(/moment[/\\]locale$/, /es-us/), 28 | ]; 29 | if (analyse) { 30 | plugins.push(new BundleAnalyzerPlugin()); 31 | } 32 | return plugins; 33 | }; 34 | 35 | module.exports = (props) => { 36 | let mode = 'production'; 37 | if (props?.development) { 38 | mode = 'development'; 39 | } 40 | 41 | return merge( 42 | { 43 | entry: path.join(__dirname, 'src/components/index.tsx'), 44 | module: { 45 | rules: [ 46 | { 47 | test: /\.(png|svg|jpg|gif)$/, 48 | exclude: /(node_modules)/, 49 | use: 'file-loader', 50 | }, 51 | { 52 | test: /\.(ts|tsx)$/, 53 | include: getIncludeDirs(), 54 | loader: 'ts-loader', 55 | }, 56 | ], 57 | }, 58 | plugins: getPlugins(props.analyze), 59 | resolve: { 60 | alias: { 61 | 'app-ui': path.resolve(__dirname, 'src'), 62 | // UI 63 | components: path.resolve(__dirname, 'src/components'), 64 | lib: path.resolve(__dirname, 'src/lib'), 65 | 'ui-utils': path.resolve(__dirname, 'src/utils'), 66 | styles: path.resolve(__dirname, 'src/styles'), 67 | 'ui-types': path.resolve(__dirname, 'src/types'), 68 | client: path.resolve(__dirname, 'src/client'), 69 | store: path.resolve(__dirname, 'src/store'), 70 | }, 71 | extensions: ['.tsx', '.ts', '.js', '.json'], 72 | }, 73 | target: 'web', 74 | }, 75 | modeConfig(mode), 76 | ); 77 | }; 78 | --------------------------------------------------------------------------------