├── .babelrc
├── .eslintrc
├── .gitignore
├── .gitlab-ci.yml
├── .husky
└── pre-commit
├── .nvmrc
├── Dockerfile
├── LICENSE.md
├── README.md
├── config
└── jest
│ ├── cssTransform.js
│ └── fileTransform.js
├── configs
├── cmd.sh
├── default.conf
├── nginx-docker.conf
├── nginx.conf
└── redirect.html
├── jest.config.js
├── package-lock.json
├── package.json
├── public
├── VERSION.txt
├── apple-touch-icon.png
├── config.json
├── favicon-16x16.png
├── favicon-32x32.png
├── favicon.ico
├── index.html
├── locales
│ ├── locale-ar.json
│ ├── locale-bn.json
│ ├── locale-ca.json
│ ├── locale-cs.json
│ ├── locale-da.json
│ ├── locale-de.json
│ ├── locale-en.json
│ ├── locale-es.json
│ ├── locale-fi.json
│ ├── locale-fr.json
│ ├── locale-he.json
│ ├── locale-hi.json
│ ├── locale-hr.json
│ ├── locale-hu.json
│ ├── locale-it.json
│ ├── locale-ja.json
│ ├── locale-ko.json
│ ├── locale-nl.json
│ ├── locale-no.json
│ ├── locale-pl.json
│ ├── locale-pt-BR.json
│ ├── locale-pt.json
│ ├── locale-ru.json
│ ├── locale-sk.json
│ ├── locale-sv.json
│ ├── locale-uk.json
│ ├── locale-vi.json
│ ├── locale-zh-Hans.json
│ ├── locale-zh-Hant.json
│ └── locale-zh.json
└── manifest.json
├── src
├── actions
│ ├── actionCreators.js
│ ├── actionTypes.js
│ └── boundActionCreators.js
├── assets
│ ├── css
│ │ └── material-dashboard-react.css
│ ├── img
│ │ ├── apple-touch-icon.png
│ │ ├── background.jpg
│ │ ├── faces
│ │ │ └── marc.jpg
│ │ ├── favicon-16x16.png
│ │ ├── favicon-32x32.png
│ │ ├── favicon.ico
│ │ ├── logo.png
│ │ └── sc-logo.png
│ └── jss
│ │ ├── material-dashboard-react.js
│ │ └── material-dashboard-react
│ │ ├── appStyle.jsx
│ │ ├── buttonStyle.jsx
│ │ ├── chartCardStyle.jsx
│ │ ├── components
│ │ ├── buttonStyle.js
│ │ ├── cardAvatarStyle.js
│ │ ├── cardBodyStyle.js
│ │ ├── cardFooterStyle.js
│ │ ├── cardHeaderStyle.js
│ │ ├── cardIconStyle.js
│ │ ├── cardStyle.js
│ │ ├── customInputStyle.js
│ │ ├── customTabsStyle.js
│ │ ├── footerStyle.js
│ │ ├── headerLinksStyle.js
│ │ ├── headerStyle.js
│ │ ├── rtlHeaderLinksStyle.js
│ │ ├── sidebarStyle.js
│ │ ├── snackbarContentStyle.js
│ │ ├── tableStyle.js
│ │ ├── tasksStyle.js
│ │ └── typographyStyle.js
│ │ ├── customInputStyle.jsx
│ │ ├── dashboardStyle.jsx
│ │ ├── dropdownStyle.js
│ │ ├── footerStyle.jsx
│ │ ├── headerLinksStyle.jsx
│ │ ├── headerStyle.jsx
│ │ ├── iconButtonStyle.jsx
│ │ ├── iconsStyle.jsx
│ │ ├── profileCardStyle.jsx
│ │ ├── regularCardStyle.jsx
│ │ ├── sidebarStyle.jsx
│ │ ├── snackbarContentStyle.jsx
│ │ ├── statsCardStyle.jsx
│ │ ├── tableStyle.jsx
│ │ ├── tasksCardStyle.jsx
│ │ ├── tasksStyle.jsx
│ │ └── typographyStyle.jsx
├── components
│ ├── Card
│ │ ├── Card.js
│ │ ├── CardBody.js
│ │ ├── CardFooter.js
│ │ ├── CardHeader.js
│ │ ├── CardIcon.js
│ │ ├── ChartCard.jsx
│ │ ├── FileserverCard.jsx
│ │ ├── GroupCard.jsx
│ │ ├── HealthcheckCard.jsx
│ │ ├── LDAPCard.jsx
│ │ ├── LicenseCard.jsx
│ │ ├── OIDCCard.jsx
│ │ ├── ProfileCard.jsx
│ │ ├── RegularCard.jsx
│ │ ├── ReleaseCard.jsx
│ │ ├── SAMLCard.jsx
│ │ ├── SCIMCard.jsx
│ │ ├── Sessions.jsx
│ │ ├── StatsCard.jsx
│ │ ├── UserCard.jsx
│ │ └── VersionCard.jsx
│ ├── CustomButtons
│ │ ├── Button.jsx
│ │ └── IconButton.jsx
│ ├── CustomInput
│ │ └── CustomInput.jsx
│ ├── CustomTabs
│ │ └── CustomTabs.js
│ ├── Dialog
│ │ └── DeleteConfirmDialog.js
│ ├── Footer
│ │ └── Footer.jsx
│ ├── Form
│ │ └── LoginForm.jsx
│ ├── Grid
│ │ └── GridItem.jsx
│ ├── Header
│ │ ├── Header.jsx
│ │ └── HeaderLinks.jsx
│ ├── Notification
│ │ └── Notification.jsx
│ ├── Sidebar
│ │ └── Sidebar.jsx
│ ├── Snackbar
│ │ ├── Snackbar.jsx
│ │ └── SnackbarContent.jsx
│ ├── Table
│ │ ├── CustomMaterialTable.jsx
│ │ └── Table.jsx
│ ├── Tasks
│ │ └── Tasks.jsx
│ ├── Typography
│ │ ├── A.jsx
│ │ ├── Danger.jsx
│ │ ├── Info.jsx
│ │ ├── Muted.jsx
│ │ ├── P.jsx
│ │ ├── Primary.jsx
│ │ ├── Quote.jsx
│ │ ├── Small.jsx
│ │ ├── Success.jsx
│ │ └── Warning.jsx
│ └── index.js
├── containers
│ ├── App.js
│ ├── ChartCard
│ │ ├── browser.js
│ │ ├── device.js
│ │ ├── os.js
│ │ └── two_factor.js
│ ├── Index
│ │ ├── Index.js
│ │ └── SwitchRoutes.js
│ └── Login
│ │ └── Login.js
├── i18n.js
├── index.js
├── reducers
│ ├── admin_client.js
│ ├── client.js
│ ├── index.js
│ ├── notification.js
│ ├── persistent.js
│ ├── server.js
│ └── user.js
├── routes
│ ├── ee.js
│ ├── ldap.js
│ ├── oidc.js
│ ├── other.js
│ ├── saml.js
│ └── sidebar.js
├── services
│ ├── api-client.js
│ ├── api-server.js
│ ├── api-static.js
│ ├── browser-client.js
│ ├── clientjs.js
│ ├── converter.js
│ ├── converter.test.js
│ ├── cryptoLibrary.js
│ ├── device.js
│ ├── helper.js
│ ├── helper.test.js
│ ├── host.js
│ ├── ivalt.js
│ ├── notification.js
│ ├── store.js
│ ├── user.js
│ ├── webauthn.js
│ └── worker.js
├── setupTests.js
├── variables
│ ├── charts.jsx
│ ├── general.jsx
│ └── styles.jsx
└── views
│ ├── Dashboard
│ ├── HealthCheck.js
│ └── Index.jsx
│ ├── Group
│ ├── Create.js
│ ├── Edit.jsx
│ └── ShareRightCreate.js
│ ├── Groups
│ └── Index.jsx
│ ├── Icons
│ └── Icons.jsx
│ ├── LDAP
│ └── Index.jsx
│ ├── Notifications
│ └── Notifications.jsx
│ ├── OIDC
│ └── Index.jsx
│ ├── Policies
│ ├── Create.js
│ ├── Edit.jsx
│ └── Index.jsx
│ ├── SAML
│ └── Index.jsx
│ ├── SCIM
│ └── Index.jsx
│ ├── SecurityReport
│ └── Edit.jsx
│ ├── SecurityReports
│ └── Index.jsx
│ ├── TableList
│ └── TableList.jsx
│ ├── Typography
│ └── Typography.jsx
│ ├── User
│ ├── Create.js
│ └── Edit.jsx
│ ├── UserProfile
│ └── UserProfile.jsx
│ └── Users
│ └── Index.jsx
├── var
├── build-ubuntu.sh
├── deploy-docker.sh
├── deploy-github.sh
├── deploy_changelog.sh
├── deploy_nightlyartifacts.sh
├── deploy_releaseartifacts.sh
├── download_translations_from_artifactory.sh
├── package-webclient.sh
├── sync_translations.py
├── translate.py
├── update_version.sh
└── upload_translations.py
├── webpack.common.js
├── webpack.dev.js
└── webpack.prod.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | ["@babel/preset-env", { "targets": { "node": "current" } }],
4 | "@babel/preset-react"
5 | ],
6 | "plugins": [
7 | "@babel/plugin-proposal-class-properties",
8 | "@babel/plugin-transform-runtime"
9 | ]
10 | }
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "react-app",
3 | "rules": {
4 | "indent": "off"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build
11 |
12 | # misc
13 | .DS_Store
14 | .env.local
15 | .env.development.local
16 | .env.test.local
17 | .env.production.local
18 |
19 | npm-debug.log*
20 |
21 | .idea
22 | untranslated
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 | . "$(dirname -- "$0")/_/husky.sh"
3 |
4 | npx lint-staged
--------------------------------------------------------------------------------
/.nvmrc:
--------------------------------------------------------------------------------
1 | 22.11.0
2 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM psono-docker.jfrog.io/nginx:alpine
2 |
3 | LABEL maintainer="Sascha Pfeiffer "
4 |
5 | RUN apk upgrade --no-cache \
6 | && apk add --no-cache curl
7 |
8 | COPY ./configs/nginx.conf /etc/nginx/nginx.conf
9 | COPY ./configs/default.conf /etc/nginx/conf.d/default.conf
10 | COPY ./configs/cmd.sh /root/cmd.sh
11 | COPY ./build /usr/share/nginx/html/portal
12 | COPY ./configs/redirect.html /usr/share/nginx/html/index.html
13 |
14 | HEALTHCHECK --interval=30s --timeout=3s \
15 | CMD curl -f http://localhost/ || exit 1
16 |
17 | CMD ["/bin/sh", "/root/cmd.sh"]
18 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | # License:
2 |
3 | Copyright 2017 Sascha Pfeiffer
4 |
5 | Licensed under the Apache License, Version 2.0 (the "License");
6 | you may not use this file except in compliance with the License.
7 | You may obtain a copy of the License at
8 |
9 | http://www.apache.org/licenses/LICENSE-2.0
10 |
11 | Unless required by applicable law or agreed to in writing, software
12 | distributed under the License is distributed on an "AS IS" BASIS,
13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | See the License for the specific language governing permissions and
15 | limitations under the License.
16 |
17 | # Licenses of used software
18 |
19 | ## MIT: material-dashboard-react
20 |
21 | https://www.creative-tim.com/product/material-dashboard-react#
22 |
23 | MIT License
24 |
25 | Copyright (c) 2017 Creative Tim
26 |
27 | Permission is hereby granted, free of charge, to any person obtaining a copy
28 | of this software and associated documentation files (the "Software"), to deal
29 | in the Software without restriction, including without limitation the rights
30 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
31 | copies of the Software, and to permit persons to whom the Software is
32 | furnished to do so, subject to the following conditions:
33 |
34 | The above copyright notice and this permission notice shall be included in all
35 | copies or substantial portions of the Software.
36 |
37 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
38 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
39 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
40 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
41 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
42 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
43 | SOFTWARE.
44 |
45 |
46 | ## MIT: mui-org/material-ui
47 |
48 | https://github.com/mui-org/material-ui
49 |
50 | The MIT License (MIT)
51 |
52 | Copyright (c) 2014 Call-Em-All
53 |
54 | Permission is hereby granted, free of charge, to any person obtaining a copy
55 | of this software and associated documentation files (the "Software"), to deal
56 | in the Software without restriction, including without limitation the rights
57 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
58 | copies of the Software, and to permit persons to whom the Software is
59 | furnished to do so, subject to the following conditions:
60 |
61 | The above copyright notice and this permission notice shall be included in all
62 | copies or substantial portions of the Software.
63 |
64 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
65 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
66 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
67 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
68 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
69 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
70 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PSONO Admin Client - Password Manager
2 |
3 | [](https://gitlab.com/psono/psono-admin-client/commits/master)
4 | [](https://codeclimate.com/github/psono/psono-admin-client)
5 | [](https://hub.docker.com/r/psono/psono-admin-client/)
6 | [](https://discord.gg/VmBMzTSbGV)
7 | [](https://poeditor.com/join/project?hash=xwGlVVPZbM)
8 |
9 | # Canonical source
10 |
11 | The canonical source of PSONO Admin Client is [hosted on GitLab.com](https://gitlab.com/psono/psono-admin-client).
12 |
13 | # Documentation
14 |
15 | The documentation for the psono server can be found here:
16 |
17 | [Psono Documentation](https://doc.psono.com/)
18 |
19 | # Things that have not yet found a place in our docs
20 |
21 | This project was bootstrapped with [Create React App](https://github.com/facebookincubator/create-react-app).
22 |
23 | ## Install dependencies
24 |
25 | To start a server for development do the following
26 |
27 | npm install
28 |
29 | ## Start of a dev server
30 |
31 | To start a server for development do the following
32 |
33 | npm start
34 |
35 | Afterwards you can visit http://localhost:3000
36 |
37 | ## Build for production
38 |
39 | To build everything as standalone for production
40 |
41 | INLINE_RUNTIME_CHUNK=false npm run build
42 |
43 | Afterwards everthing can be found in the `/build` folder
44 |
45 | ## Run unittests
46 |
47 | To run unit tests
48 |
49 | npm test
50 |
51 | ## Run unittests (with coverage)
52 |
53 | To run unit tests
54 |
55 | npm test -- --coverage
56 |
57 |
58 | # LICENSE
59 |
60 | Visit the [License.md](/LICENSE.md) for more details
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/config/jest/cssTransform.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {
4 | process() {
5 | return 'module.exports = {};';
6 | },
7 | getCacheKey() {
8 | return 'cssTransform';
9 | },
10 | };
--------------------------------------------------------------------------------
/config/jest/fileTransform.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 |
5 | module.exports = {
6 | process(src, filename) {
7 | const assetFilename = JSON.stringify(path.basename(filename));
8 |
9 | if (filename.match(/\.svg$/)) {
10 | // Create a simple component that just renders the file basename
11 | const pascalCaseName = path.basename(filename, '.svg')
12 | .split(/[-_\s]+/)
13 | .map(word => word.charAt(0).toUpperCase() + word.slice(1))
14 | .join('');
15 |
16 | const componentName = `Svg${pascalCaseName}`;
17 |
18 | return `const React = require('react');
19 | module.exports = {
20 | __esModule: true,
21 | default: ${assetFilename},
22 | ReactComponent: React.forwardRef(function ${componentName}(props, ref) {
23 | return {
24 | $$typeof: Symbol.for('react.element'),
25 | type: 'svg',
26 | ref: ref,
27 | key: null,
28 | props: Object.assign({}, props, {
29 | children: ${assetFilename}
30 | })
31 | };
32 | }),
33 | };
34 | `;
35 | }
36 |
37 | return `module.exports = ${assetFilename};`;
38 | },
39 | getCacheKey() {
40 | return 'fileTransform';
41 | },
42 | };
--------------------------------------------------------------------------------
/configs/cmd.sh:
--------------------------------------------------------------------------------
1 | if [ ! -z "$PSONO_PORTAL_CONFIG_JSON" ]
2 | then
3 | echo "$PSONO_PORTAL_CONFIG_JSON" > /usr/share/nginx/html/portal/config.json
4 | fi
5 |
6 | nginx -g "daemon off;"
7 |
--------------------------------------------------------------------------------
/configs/default.conf:
--------------------------------------------------------------------------------
1 | server {
2 | listen 80;
3 | server_name localhost;
4 |
5 | #charset koi8-r;
6 | #access_log /var/log/nginx/host.access.log main;
7 |
8 | location / {
9 | root /usr/share/nginx/html;
10 | index index.html index.htm;
11 | try_files $uri /portal/index.html; # forward all requests to index.html
12 | }
13 |
14 | #error_page 404 /404.html;
15 |
16 | # redirect server error pages to the static page /50x.html
17 | #
18 | error_page 500 502 503 504 /50x.html;
19 | location = /50x.html {
20 | root /usr/share/nginx/html;
21 | }
22 |
23 | # proxy the PHP scripts to Apache listening on 127.0.0.1:80
24 | #
25 | #location ~ \.php$ {
26 | # proxy_pass http://127.0.0.1;
27 | #}
28 |
29 | # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
30 | #
31 | #location ~ \.php$ {
32 | # root html;
33 | # fastcgi_pass 127.0.0.1:9000;
34 | # fastcgi_index index.php;
35 | # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
36 | # include fastcgi_params;
37 | #}
38 |
39 | # deny access to .htaccess files, if Apache's document root
40 | # concurs with nginx's one
41 | #
42 | #location ~ /\.ht {
43 | # deny all;
44 | #}
45 | }
46 |
--------------------------------------------------------------------------------
/configs/nginx.conf:
--------------------------------------------------------------------------------
1 |
2 | user nginx;
3 | worker_processes 1;
4 |
5 | error_log /var/log/nginx/error.log warn;
6 | pid /var/run/nginx.pid;
7 |
8 |
9 | events {
10 | worker_connections 1024;
11 | }
12 |
13 |
14 | http {
15 | include /etc/nginx/mime.types;
16 | default_type application/octet-stream;
17 |
18 | log_format main '$remote_addr - $remote_user [$time_local] "$request" '
19 | '$status $body_bytes_sent "$http_referer" '
20 | '"$http_user_agent" "$http_x_forwarded_for"';
21 |
22 | access_log /var/log/nginx/access.log main;
23 |
24 | sendfile on;
25 | #tcp_nopush on;
26 |
27 | keepalive_timeout 65;
28 |
29 | #gzip on;
30 |
31 | include /etc/nginx/conf.d/*.conf;
32 | }
--------------------------------------------------------------------------------
/configs/redirect.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
9 | Page Redirection
10 |
11 |
12 |
13 | If you are not redirected automatically, follow this link to example .
14 |
15 |
16 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | roots: ['/src'],
3 | collectCoverageFrom: ['src/**/*.{js,jsx}', '!src/**/*.d.ts'],
4 | setupFiles: ['react-app-polyfill/jsdom'],
5 | setupFilesAfterEnv: ['/src/setupTests.js'],
6 | testMatch: ['/src/**/__tests__/**/*.{js,jsx}', '/src/**/*.{spec,test}.{js,jsx}'],
7 | testEnvironment: 'jsdom',
8 | transform: {
9 | '^.+\\.(js|jsx)$': '/node_modules/babel-jest',
10 | '^.+\\.css$': '/config/jest/cssTransform.js',
11 | '^(?!.*\\.(js|jsx|css|json)$)': '/config/jest/fileTransform.js',
12 | },
13 | transformIgnorePatterns: [
14 | '[/\\\\]node_modules[/\\\\].+\\.(js|jsx)$',
15 | '^.+\\.module\\.(css|sass|scss)$',
16 | ],
17 | modulePaths: [],
18 | moduleNameMapper: {
19 | '^react-native$': 'react-native-web',
20 | '^.+\\.module\\.(css|sass|scss)$': 'identity-obj-proxy',
21 | '\\.(css|less)$': 'identity-obj-proxy',
22 | },
23 | moduleFileExtensions: [
24 | 'js',
25 | 'jsx',
26 | 'json',
27 | 'node',
28 | ],
29 | watchPlugins: [
30 | 'jest-watch-typeahead/filename',
31 | 'jest-watch-typeahead/testname',
32 | ],
33 | coverageReporters: [
34 | 'html',
35 | 'text',
36 | 'cobertura',
37 | 'text-summary',
38 | ],
39 | };
--------------------------------------------------------------------------------
/public/VERSION.txt:
--------------------------------------------------------------------------------
1 | 0.1.0 (Build dummy)
--------------------------------------------------------------------------------
/public/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psono/psono-admin-client/dfe097433b3428558a8524b24103ec6fe93ab727/public/apple-touch-icon.png
--------------------------------------------------------------------------------
/public/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "backend_servers": [{
3 | "title": "Psono.pw"
4 | }],
5 | "allow_custom_server": true,
6 | "allow_registration": true,
7 | "allow_lost_password": true,
8 | "authentication_methods": ["AUTHKEY", "LDAP"],
9 | "saml_provider": [],
10 | "oidc_provider": []
11 | }
--------------------------------------------------------------------------------
/public/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psono/psono-admin-client/dfe097433b3428558a8524b24103ec6fe93ab727/public/favicon-16x16.png
--------------------------------------------------------------------------------
/public/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psono/psono-admin-client/dfe097433b3428558a8524b24103ec6fe93ab727/public/favicon-32x32.png
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psono/psono-admin-client/dfe097433b3428558a8524b24103ec6fe93ab727/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
11 |
12 |
13 |
14 |
15 |
16 |
20 | Psono Admin Panel
21 |
22 |
23 |
24 | You need to enable JavaScript to run this app.
25 |
26 |
27 |
37 |
38 |
--------------------------------------------------------------------------------
/public/locales/locale-ar.json:
--------------------------------------------------------------------------------
1 | {
2 |
3 | }
--------------------------------------------------------------------------------
/public/locales/locale-bn.json:
--------------------------------------------------------------------------------
1 | {
2 |
3 | }
--------------------------------------------------------------------------------
/public/locales/locale-ca.json:
--------------------------------------------------------------------------------
1 | {
2 |
3 | }
4 |
--------------------------------------------------------------------------------
/public/locales/locale-cs.json:
--------------------------------------------------------------------------------
1 | {
2 |
3 | }
--------------------------------------------------------------------------------
/public/locales/locale-da.json:
--------------------------------------------------------------------------------
1 | {
2 |
3 | }
--------------------------------------------------------------------------------
/public/locales/locale-de.json:
--------------------------------------------------------------------------------
1 | {
2 |
3 | }
--------------------------------------------------------------------------------
/public/locales/locale-es.json:
--------------------------------------------------------------------------------
1 | {
2 |
3 | }
--------------------------------------------------------------------------------
/public/locales/locale-fi.json:
--------------------------------------------------------------------------------
1 | {
2 |
3 | }
--------------------------------------------------------------------------------
/public/locales/locale-fr.json:
--------------------------------------------------------------------------------
1 | {
2 |
3 | }
--------------------------------------------------------------------------------
/public/locales/locale-he.json:
--------------------------------------------------------------------------------
1 | {
2 |
3 | }
--------------------------------------------------------------------------------
/public/locales/locale-hi.json:
--------------------------------------------------------------------------------
1 | {
2 |
3 | }
--------------------------------------------------------------------------------
/public/locales/locale-hr.json:
--------------------------------------------------------------------------------
1 | {
2 |
3 | }
--------------------------------------------------------------------------------
/public/locales/locale-hu.json:
--------------------------------------------------------------------------------
1 | {
2 |
3 | }
--------------------------------------------------------------------------------
/public/locales/locale-it.json:
--------------------------------------------------------------------------------
1 | {
2 |
3 | }
--------------------------------------------------------------------------------
/public/locales/locale-ja.json:
--------------------------------------------------------------------------------
1 | {
2 |
3 | }
--------------------------------------------------------------------------------
/public/locales/locale-ko.json:
--------------------------------------------------------------------------------
1 | {
2 |
3 | }
--------------------------------------------------------------------------------
/public/locales/locale-nl.json:
--------------------------------------------------------------------------------
1 | {
2 |
3 | }
--------------------------------------------------------------------------------
/public/locales/locale-no.json:
--------------------------------------------------------------------------------
1 | {
2 |
3 | }
--------------------------------------------------------------------------------
/public/locales/locale-pl.json:
--------------------------------------------------------------------------------
1 | {
2 |
3 | }
--------------------------------------------------------------------------------
/public/locales/locale-pt-BR.json:
--------------------------------------------------------------------------------
1 | {
2 |
3 | }
--------------------------------------------------------------------------------
/public/locales/locale-pt.json:
--------------------------------------------------------------------------------
1 | {
2 |
3 | }
--------------------------------------------------------------------------------
/public/locales/locale-ru.json:
--------------------------------------------------------------------------------
1 | {
2 |
3 | }
--------------------------------------------------------------------------------
/public/locales/locale-sk.json:
--------------------------------------------------------------------------------
1 | {
2 |
3 | }
--------------------------------------------------------------------------------
/public/locales/locale-sv.json:
--------------------------------------------------------------------------------
1 | {
2 |
3 | }
--------------------------------------------------------------------------------
/public/locales/locale-uk.json:
--------------------------------------------------------------------------------
1 | {
2 |
3 | }
--------------------------------------------------------------------------------
/public/locales/locale-vi.json:
--------------------------------------------------------------------------------
1 | {
2 |
3 | }
--------------------------------------------------------------------------------
/public/locales/locale-zh-Hans.json:
--------------------------------------------------------------------------------
1 | {
2 |
3 | }
--------------------------------------------------------------------------------
/public/locales/locale-zh-Hant.json:
--------------------------------------------------------------------------------
1 | {
2 |
3 | }
--------------------------------------------------------------------------------
/public/locales/locale-zh.json:
--------------------------------------------------------------------------------
1 | {
2 |
3 | }
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "Psono Admin Panel",
3 | "name": "The Admin Panel of the psono password manager",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": "./index.html",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/src/actions/actionTypes.js:
--------------------------------------------------------------------------------
1 | export const SET_KNOWN_HOSTS = 'SET_KNOWN_HOSTS';
2 | export const SET_USER_USERNAME = 'SET_USER_USERNAME';
3 | export const SET_USER_INFO_1 = 'SET_USER_INFO_1';
4 | export const SET_USER_INFO_2 = 'SET_USER_INFO_2';
5 | export const SET_USER_INFO_3 = 'SET_USER_INFO_3';
6 | export const LOGOUT = 'LOGOUT';
7 | export const SET_SERVER_URL = 'SET_SERVER_URL';
8 | export const SET_SERVER_INFO = 'SET_SERVER_INFO';
9 | export const SET_CLIENT_URL = 'SET_CLIENT_URL';
10 | export const SET_ADMIN_CLIENT_CONFIG = 'SET_ADMIN_CLIENT_CONFIG';
11 | export const NOTIFICATION_SEND = 'NOTIFICATION_SEND';
12 | export const NOTIFICATION_SET = 'NOTIFICATION_SET';
13 | export const SET_SERVER_SECRET_EXISTS = 'SET_SERVER_SECRET_EXISTS';
14 |
--------------------------------------------------------------------------------
/src/actions/boundActionCreators.js:
--------------------------------------------------------------------------------
1 | import store from '../services/store';
2 | import actionCreators from './actionCreators';
3 | import { bindActionCreators } from 'redux';
4 |
5 | export default bindActionCreators(actionCreators, store.dispatch);
6 |
--------------------------------------------------------------------------------
/src/assets/img/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psono/psono-admin-client/dfe097433b3428558a8524b24103ec6fe93ab727/src/assets/img/apple-touch-icon.png
--------------------------------------------------------------------------------
/src/assets/img/background.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psono/psono-admin-client/dfe097433b3428558a8524b24103ec6fe93ab727/src/assets/img/background.jpg
--------------------------------------------------------------------------------
/src/assets/img/faces/marc.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psono/psono-admin-client/dfe097433b3428558a8524b24103ec6fe93ab727/src/assets/img/faces/marc.jpg
--------------------------------------------------------------------------------
/src/assets/img/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psono/psono-admin-client/dfe097433b3428558a8524b24103ec6fe93ab727/src/assets/img/favicon-16x16.png
--------------------------------------------------------------------------------
/src/assets/img/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psono/psono-admin-client/dfe097433b3428558a8524b24103ec6fe93ab727/src/assets/img/favicon-32x32.png
--------------------------------------------------------------------------------
/src/assets/img/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psono/psono-admin-client/dfe097433b3428558a8524b24103ec6fe93ab727/src/assets/img/favicon.ico
--------------------------------------------------------------------------------
/src/assets/img/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psono/psono-admin-client/dfe097433b3428558a8524b24103ec6fe93ab727/src/assets/img/logo.png
--------------------------------------------------------------------------------
/src/assets/img/sc-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psono/psono-admin-client/dfe097433b3428558a8524b24103ec6fe93ab727/src/assets/img/sc-logo.png
--------------------------------------------------------------------------------
/src/assets/jss/material-dashboard-react/appStyle.jsx:
--------------------------------------------------------------------------------
1 | // ##############################
2 | // // // App styles
3 | // #############################
4 |
5 | import {
6 | drawerWidth,
7 | transition,
8 | container
9 | } from '../material-dashboard-react.js';
10 |
11 | const appStyle = theme => ({
12 | wrapper: {
13 | position: 'relative',
14 | top: '0',
15 | height: '100vh'
16 | },
17 | mainPanel: {
18 | [theme.breakpoints.up('md')]: {
19 | width: `calc(100% - ${drawerWidth}px)`
20 | },
21 | overflow: 'auto',
22 | position: 'relative',
23 | float: 'right',
24 | ...transition,
25 | maxHeight: '100%',
26 | width: '100%',
27 | overflowScrolling: 'touch'
28 | },
29 | content: {
30 | marginTop: '70px',
31 | padding: '30px 15px',
32 | minHeight: 'calc(100% - 123px)'
33 | },
34 | container,
35 | map: {
36 | marginTop: '70px'
37 | }
38 | });
39 |
40 | export default appStyle;
41 |
--------------------------------------------------------------------------------
/src/assets/jss/material-dashboard-react/chartCardStyle.jsx:
--------------------------------------------------------------------------------
1 | // ##############################
2 | // // // ChartCard styles
3 | // #############################
4 |
5 | import {
6 | card,
7 | cardHeader,
8 | defaultFont,
9 | orangeCardHeader,
10 | greenCardHeader,
11 | redCardHeader,
12 | blueCardHeader,
13 | purpleCardHeader,
14 | cardActions,
15 | grayColor,
16 | warningColor,
17 | dangerColor,
18 | successColor,
19 | infoColor,
20 | primaryColor,
21 | roseColor
22 | } from '../material-dashboard-react.js';
23 |
24 | const chartCardStyle = {
25 | card: {
26 | ...card,
27 | overflow: 'visible'
28 | },
29 | cardHeader: {
30 | ...cardHeader,
31 | padding: '0',
32 | minHeight: '160px',
33 | ...defaultFont
34 | },
35 | orangeCardHeader,
36 | greenCardHeader,
37 | redCardHeader,
38 | blueCardHeader,
39 | purpleCardHeader,
40 | cardContent: {
41 | padding: '15px 20px'
42 | },
43 | cardTitle: {
44 | marginTop: '0',
45 | marginBottom: '5px',
46 | ...defaultFont,
47 | fontSize: '1.175em'
48 | },
49 | cardCategory: {
50 | marginBottom: '0',
51 | color: grayColor[0],
52 | ...defaultFont,
53 | fontSize: '0.9em'
54 | },
55 | cardActions: {
56 | ...cardActions,
57 | padding: '0!important'
58 | },
59 | cardStats: {
60 | lineHeight: '22px',
61 | color: grayColor[0],
62 | fontSize: '12px',
63 | display: 'inline-block',
64 | margin: '0!important'
65 | },
66 | cardStatsIcon: {
67 | position: 'relative',
68 | top: '4px',
69 | width: '16px',
70 | height: '16px'
71 | },
72 | warningCardStatsIcon: {
73 | color: warningColor[0]
74 | },
75 | primaryCardStatsIcon: {
76 | color: primaryColor[0]
77 | },
78 | dangerCardStatsIcon: {
79 | color: dangerColor[0]
80 | },
81 | successCardStatsIcon: {
82 | color: successColor[0]
83 | },
84 | infoCardStatsIcon: {
85 | color: infoColor[0]
86 | },
87 | roseCardStatsIcon: {
88 | color: roseColor[0]
89 | },
90 | grayCardStatsIcon: {
91 | color: grayColor[0]
92 | },
93 | cardStatsLink: {
94 | color: primaryColor[0],
95 | textDecoration: 'none',
96 | ...defaultFont
97 | }
98 | };
99 |
100 | export default chartCardStyle;
101 |
--------------------------------------------------------------------------------
/src/assets/jss/material-dashboard-react/components/cardAvatarStyle.js:
--------------------------------------------------------------------------------
1 | import { hexToRgb, blackColor } from '../../material-dashboard-react.js';
2 |
3 | const cardAvatarStyle = {
4 | cardAvatar: {
5 | '&$cardAvatarProfile img': {
6 | width: '100%',
7 | height: 'auto'
8 | }
9 | },
10 | cardAvatarProfile: {
11 | maxWidth: '130px',
12 | maxHeight: '130px',
13 | margin: '-50px auto 0',
14 | borderRadius: '50%',
15 | overflow: 'hidden',
16 | padding: '0',
17 | boxShadow:
18 | '0 16px 38px -12px rgba(' +
19 | hexToRgb(blackColor) +
20 | ', 0.56), 0 4px 25px 0px rgba(' +
21 | hexToRgb(blackColor) +
22 | ', 0.12), 0 8px 10px -5px rgba(' +
23 | hexToRgb(blackColor) +
24 | ', 0.2)',
25 | '&$cardAvatarPlain': {
26 | marginTop: '0'
27 | }
28 | },
29 | cardAvatarPlain: {}
30 | };
31 |
32 | export default cardAvatarStyle;
33 |
--------------------------------------------------------------------------------
/src/assets/jss/material-dashboard-react/components/cardBodyStyle.js:
--------------------------------------------------------------------------------
1 | const cardBodyStyle = {
2 | cardBody: {
3 | padding: '0.9375rem 20px',
4 | flex: '1 1 auto',
5 | WebkitBoxFlex: '1',
6 | position: 'relative'
7 | },
8 | cardBodyPlain: {
9 | paddingLeft: '5px',
10 | paddingRight: '5px'
11 | },
12 | cardBodyProfile: {
13 | marginTop: '15px'
14 | }
15 | };
16 |
17 | export default cardBodyStyle;
18 |
--------------------------------------------------------------------------------
/src/assets/jss/material-dashboard-react/components/cardFooterStyle.js:
--------------------------------------------------------------------------------
1 | import { grayColor } from '../../material-dashboard-react.js';
2 |
3 | const cardFooterStyle = {
4 | cardFooter: {
5 | padding: '0',
6 | paddingTop: '10px',
7 | margin: '0 15px 10px',
8 | borderRadius: '0',
9 | justifyContent: 'space-between',
10 | alignItems: 'center',
11 | display: 'flex',
12 | backgroundColor: 'transparent',
13 | border: '0'
14 | },
15 | cardFooterProfile: {
16 | marginTop: '-15px'
17 | },
18 | cardFooterPlain: {
19 | paddingLeft: '5px',
20 | paddingRight: '5px',
21 | backgroundColor: 'transparent'
22 | },
23 | cardFooterStats: {
24 | borderTop: '1px solid ' + grayColor[10],
25 | marginTop: '20px',
26 | '& svg': {
27 | position: 'relative',
28 | top: '4px',
29 | marginRight: '3px',
30 | marginLeft: '3px',
31 | width: '16px',
32 | height: '16px'
33 | },
34 | '& .fab,& .fas,& .far,& .fal,& .material-icons': {
35 | fontSize: '16px',
36 | position: 'relative',
37 | top: '4px',
38 | marginRight: '3px',
39 | marginLeft: '3px'
40 | }
41 | },
42 | cardFooterChart: {
43 | borderTop: '1px solid ' + grayColor[10]
44 | }
45 | };
46 |
47 | export default cardFooterStyle;
48 |
--------------------------------------------------------------------------------
/src/assets/jss/material-dashboard-react/components/cardIconStyle.js:
--------------------------------------------------------------------------------
1 | import {
2 | warningCardHeader,
3 | successCardHeader,
4 | dangerCardHeader,
5 | infoCardHeader,
6 | primaryCardHeader,
7 | roseCardHeader,
8 | grayColor
9 | } from '../../material-dashboard-react.js';
10 |
11 | const cardIconStyle = {
12 | cardIcon: {
13 | '&$warningCardHeader,&$successCardHeader,&$dangerCardHeader,&$infoCardHeader,&$primaryCardHeader,&$roseCardHeader': {
14 | borderRadius: '3px',
15 | backgroundColor: grayColor[0],
16 | padding: '15px',
17 | marginTop: '-20px',
18 | marginRight: '15px',
19 | float: 'left'
20 | }
21 | },
22 | warningCardHeader,
23 | successCardHeader,
24 | dangerCardHeader,
25 | infoCardHeader,
26 | primaryCardHeader,
27 | roseCardHeader
28 | };
29 |
30 | export default cardIconStyle;
31 |
--------------------------------------------------------------------------------
/src/assets/jss/material-dashboard-react/components/cardStyle.js:
--------------------------------------------------------------------------------
1 | import {
2 | blackColor,
3 | whiteColor,
4 | hexToRgb
5 | } from '../../material-dashboard-react.js';
6 |
7 | const cardStyle = {
8 | card: {
9 | border: '0',
10 | marginBottom: '30px',
11 | marginTop: '30px',
12 | borderRadius: '6px',
13 | color: 'rgba(' + hexToRgb(blackColor) + ', 0.87)',
14 | background: whiteColor,
15 | width: '100%',
16 | boxShadow: '0 1px 4px 0 rgba(' + hexToRgb(blackColor) + ', 0.14)',
17 | position: 'relative',
18 | display: 'flex',
19 | flexDirection: 'column',
20 | minWidth: '0',
21 | wordWrap: 'break-word',
22 | fontSize: '.875rem'
23 | },
24 | cardPlain: {
25 | background: 'transparent',
26 | boxShadow: 'none'
27 | },
28 | cardProfile: {
29 | marginTop: '30px',
30 | textAlign: 'center'
31 | },
32 | cardChart: {
33 | '& p': {
34 | marginTop: '0px',
35 | paddingTop: '0px'
36 | }
37 | }
38 | };
39 |
40 | export default cardStyle;
41 |
--------------------------------------------------------------------------------
/src/assets/jss/material-dashboard-react/components/customInputStyle.js:
--------------------------------------------------------------------------------
1 | import {
2 | primaryColor,
3 | dangerColor,
4 | successColor,
5 | grayColor,
6 | defaultFont
7 | } from '../../material-dashboard-react.js';
8 |
9 | const customInputStyle = {
10 | disabled: {
11 | '&:before': {
12 | backgroundColor: 'transparent !important'
13 | }
14 | },
15 | underline: {
16 | '&:hover:not($disabled):before,&:before': {
17 | borderColor: grayColor[4] + ' !important',
18 | borderWidth: '1px !important'
19 | },
20 | '&:after': {
21 | borderColor: primaryColor[0]
22 | }
23 | },
24 | underlineError: {
25 | '&:after': {
26 | borderColor: dangerColor[0]
27 | }
28 | },
29 | underlineSuccess: {
30 | '&:after': {
31 | borderColor: successColor[0]
32 | }
33 | },
34 | labelRoot: {
35 | ...defaultFont,
36 | color: grayColor[3] + ' !important',
37 | fontWeight: '400',
38 | fontSize: '14px',
39 | lineHeight: '1.42857',
40 | letterSpacing: 'unset'
41 | },
42 | labelRootError: {
43 | color: dangerColor[0]
44 | },
45 | labelRootSuccess: {
46 | color: successColor[0]
47 | },
48 | feedback: {
49 | position: 'absolute',
50 | top: '18px',
51 | right: '0',
52 | zIndex: '2',
53 | display: 'block',
54 | width: '24px',
55 | height: '24px',
56 | textAlign: 'center',
57 | pointerEvents: 'none'
58 | },
59 | marginTop: {
60 | marginTop: '16px'
61 | },
62 | formControl: {
63 | paddingBottom: '10px',
64 | margin: '27px 0 0 0',
65 | position: 'relative',
66 | verticalAlign: 'unset'
67 | }
68 | };
69 |
70 | export default customInputStyle;
71 |
--------------------------------------------------------------------------------
/src/assets/jss/material-dashboard-react/components/customTabsStyle.js:
--------------------------------------------------------------------------------
1 | import { hexToRgb, whiteColor } from '../../material-dashboard-react.js';
2 |
3 | const customTabsStyle = {
4 | cardTitle: {
5 | float: 'left',
6 | padding: '10px 10px 10px 0px',
7 | lineHeight: '24px'
8 | },
9 | cardTitleRTL: {
10 | float: 'right',
11 | padding: '10px 0px 10px 10px !important'
12 | },
13 | displayNone: {
14 | display: 'none !important'
15 | },
16 | tabsRoot: {
17 | minHeight: 'unset !important',
18 | overflowX: 'visible',
19 | '& $tabRootButton': {
20 | fontSize: '0.875rem'
21 | }
22 | },
23 | tabRootButton: {
24 | minHeight: 'unset !important',
25 | minWidth: 'unset !important',
26 | width: 'unset !important',
27 | height: 'unset !important',
28 | maxWidth: 'unset !important',
29 | maxHeight: 'unset !important',
30 | padding: '10px 15px',
31 | borderRadius: '3px',
32 | lineHeight: '24px',
33 | border: '0 !important',
34 | color: whiteColor + ' !important',
35 | marginLeft: '4px',
36 | '&:last-child': {
37 | marginLeft: '0px'
38 | }
39 | },
40 | tabSelected: {
41 | backgroundColor: 'rgba(' + hexToRgb(whiteColor) + ', 0.2)',
42 | transition: '0.2s background-color 0.1s'
43 | },
44 | tabWrapper: {
45 | display: 'inline-block',
46 | minHeight: 'unset !important',
47 | minWidth: 'unset !important',
48 | width: 'unset !important',
49 | height: 'unset !important',
50 | maxWidth: 'unset !important',
51 | maxHeight: 'unset !important',
52 | fontWeight: '500',
53 | fontSize: '12px',
54 | marginTop: '1px',
55 | '& > svg,& > .material-icons': {
56 | verticalAlign: 'middle',
57 | margin: '-1px 5px 0 0 !important'
58 | }
59 | }
60 | };
61 |
62 | export default customTabsStyle;
63 |
--------------------------------------------------------------------------------
/src/assets/jss/material-dashboard-react/components/footerStyle.js:
--------------------------------------------------------------------------------
1 | import {
2 | defaultFont,
3 | container,
4 | primaryColor,
5 | grayColor
6 | } from '../../material-dashboard-react.js';
7 |
8 | const footerStyle = {
9 | block: {
10 | color: 'inherit',
11 | padding: '15px',
12 | textTransform: 'uppercase',
13 | borderRadius: '3px',
14 | textDecoration: 'none',
15 | position: 'relative',
16 | display: 'block',
17 | ...defaultFont,
18 | fontWeight: '500',
19 | fontSize: '12px'
20 | },
21 | left: {
22 | float: 'left!important',
23 | display: 'block'
24 | },
25 | right: {
26 | padding: '15px 0',
27 | margin: '0',
28 | fontSize: '14px',
29 | float: 'right!important'
30 | },
31 | footer: {
32 | bottom: '0',
33 | borderTop: '1px solid ' + grayColor[11],
34 | padding: '15px 0',
35 | ...defaultFont
36 | },
37 | container,
38 | a: {
39 | color: primaryColor,
40 | textDecoration: 'none',
41 | backgroundColor: 'transparent'
42 | },
43 | list: {
44 | marginBottom: '0',
45 | padding: '0',
46 | marginTop: '0'
47 | },
48 | inlineBlock: {
49 | display: 'inline-block',
50 | padding: '0px',
51 | width: 'auto'
52 | }
53 | };
54 | export default footerStyle;
55 |
--------------------------------------------------------------------------------
/src/assets/jss/material-dashboard-react/components/headerLinksStyle.js:
--------------------------------------------------------------------------------
1 | import {
2 | defaultFont,
3 | dangerColor,
4 | whiteColor
5 | } from '../../material-dashboard-react.js';
6 |
7 | import dropdownStyle from '../../material-dashboard-react/dropdownStyle.js';
8 |
9 | const headerLinksStyle = theme => ({
10 | ...dropdownStyle(theme),
11 | search: {
12 | '& > div': {
13 | marginTop: '0'
14 | },
15 | [theme.breakpoints.down('sm')]: {
16 | margin: '10px 15px !important',
17 | float: 'none !important',
18 | paddingTop: '1px',
19 | paddingBottom: '1px',
20 | padding: '0!important',
21 | width: '60%',
22 | marginTop: '40px',
23 | '& input': {
24 | color: whiteColor
25 | }
26 | }
27 | },
28 | linkText: {
29 | zIndex: '4',
30 | ...defaultFont,
31 | fontSize: '14px',
32 | margin: '0px'
33 | },
34 | buttonLink: {
35 | [theme.breakpoints.down('sm')]: {
36 | display: 'flex',
37 | margin: '10px 15px 0',
38 | width: '-webkit-fill-available',
39 | '& svg': {
40 | width: '24px',
41 | height: '30px',
42 | marginRight: '15px',
43 | marginLeft: '-15px'
44 | },
45 | '& .fab,& .fas,& .far,& .fal,& .material-icons': {
46 | fontSize: '24px',
47 | lineHeight: '30px',
48 | width: '24px',
49 | height: '30px',
50 | marginRight: '15px',
51 | marginLeft: '-15px'
52 | },
53 | '& > span': {
54 | justifyContent: 'flex-start',
55 | width: '100%'
56 | }
57 | }
58 | },
59 | searchButton: {
60 | [theme.breakpoints.down('sm')]: {
61 | top: '-50px !important',
62 | marginRight: '22px',
63 | float: 'right'
64 | }
65 | },
66 | margin: {
67 | zIndex: '4',
68 | margin: '0'
69 | },
70 | searchIcon: {
71 | width: '17px',
72 | zIndex: '4'
73 | },
74 | notifications: {
75 | zIndex: '4',
76 | [theme.breakpoints.up('md')]: {
77 | position: 'absolute',
78 | top: '2px',
79 | border: '1px solid ' + whiteColor,
80 | right: '4px',
81 | fontSize: '9px',
82 | background: dangerColor[0],
83 | color: whiteColor,
84 | minWidth: '16px',
85 | height: '16px',
86 | borderRadius: '10px',
87 | textAlign: 'center',
88 | lineHeight: '16px',
89 | verticalAlign: 'middle',
90 | display: 'block'
91 | },
92 | [theme.breakpoints.down('sm')]: {
93 | ...defaultFont,
94 | fontSize: '14px',
95 | marginRight: '8px'
96 | }
97 | },
98 | manager: {
99 | [theme.breakpoints.down('sm')]: {
100 | width: '100%'
101 | },
102 | display: 'inline-block'
103 | },
104 | searchWrapper: {
105 | [theme.breakpoints.down('sm')]: {
106 | width: '-webkit-fill-available',
107 | margin: '10px 15px 0'
108 | },
109 | display: 'inline-block'
110 | }
111 | });
112 |
113 | export default headerLinksStyle;
114 |
--------------------------------------------------------------------------------
/src/assets/jss/material-dashboard-react/components/headerStyle.js:
--------------------------------------------------------------------------------
1 | import {
2 | container,
3 | defaultFont,
4 | primaryColor,
5 | defaultBoxShadow,
6 | infoColor,
7 | successColor,
8 | warningColor,
9 | dangerColor,
10 | whiteColor,
11 | grayColor
12 | } from '../../material-dashboard-react.js';
13 |
14 | const headerStyle = () => ({
15 | appBar: {
16 | backgroundColor: 'transparent',
17 | boxShadow: 'none',
18 | borderBottom: '0',
19 | marginBottom: '0',
20 | position: 'absolute',
21 | width: '100%',
22 | paddingTop: '10px',
23 | zIndex: '1029',
24 | color: grayColor[7],
25 | border: '0',
26 | borderRadius: '3px',
27 | padding: '10px 0',
28 | transition: 'all 150ms ease 0s',
29 | minHeight: '50px',
30 | display: 'block'
31 | },
32 | container: {
33 | ...container,
34 | minHeight: '50px'
35 | },
36 | flex: {
37 | flex: 1
38 | },
39 | title: {
40 | ...defaultFont,
41 | letterSpacing: 'unset',
42 | lineHeight: '30px',
43 | fontSize: '18px',
44 | borderRadius: '3px',
45 | textTransform: 'none',
46 | color: 'inherit',
47 | margin: '0',
48 | '&:hover,&:focus': {
49 | background: 'transparent'
50 | }
51 | },
52 | appResponsive: {
53 | top: '8px'
54 | },
55 | primary: {
56 | backgroundColor: primaryColor[0],
57 | color: whiteColor,
58 | ...defaultBoxShadow
59 | },
60 | info: {
61 | backgroundColor: infoColor[0],
62 | color: whiteColor,
63 | ...defaultBoxShadow
64 | },
65 | success: {
66 | backgroundColor: successColor[0],
67 | color: whiteColor,
68 | ...defaultBoxShadow
69 | },
70 | warning: {
71 | backgroundColor: warningColor[0],
72 | color: whiteColor,
73 | ...defaultBoxShadow
74 | },
75 | danger: {
76 | backgroundColor: dangerColor[0],
77 | color: whiteColor,
78 | ...defaultBoxShadow
79 | }
80 | });
81 |
82 | export default headerStyle;
83 |
--------------------------------------------------------------------------------
/src/assets/jss/material-dashboard-react/components/rtlHeaderLinksStyle.js:
--------------------------------------------------------------------------------
1 | import {
2 | defaultFont,
3 | dangerColor,
4 | whiteColor
5 | } from '../../material-dashboard-react.js';
6 |
7 | import dropdownStyle from '../../material-dashboard-react/dropdownStyle.js';
8 |
9 | const headerLinksStyle = theme => ({
10 | ...dropdownStyle(theme),
11 | search: {
12 | '& > div': {
13 | marginTop: '0'
14 | },
15 | [theme.breakpoints.down('sm')]: {
16 | margin: '10px 15px !important',
17 | float: 'none !important',
18 | paddingTop: '1px',
19 | paddingBottom: '1px',
20 | padding: '0!important',
21 | width: '60%',
22 | marginTop: '40px',
23 | '& input': {
24 | color: whiteColor
25 | }
26 | }
27 | },
28 | linkText: {
29 | zIndex: '4',
30 | ...defaultFont,
31 | fontSize: '14px',
32 | margin: '0px'
33 | },
34 | buttonLink: {
35 | [theme.breakpoints.down('sm')]: {
36 | display: 'flex',
37 | margin: '10px 15px 0',
38 | width: '-webkit-fill-available',
39 | '& svg': {
40 | width: '24px',
41 | height: '30px',
42 | marginRight: '15px',
43 | marginLeft: '-15px'
44 | },
45 | '& .fab,& .fas,& .far,& .fal,& .material-icons': {
46 | fontSize: '24px',
47 | lineHeight: '30px',
48 | width: '24px',
49 | height: '30px',
50 | marginRight: '15px',
51 | marginLeft: '-15px'
52 | },
53 | '& > span': {
54 | justifyContent: 'flex-start',
55 | width: '100%'
56 | }
57 | }
58 | },
59 | searchButton: {
60 | [theme.breakpoints.down('sm')]: {
61 | top: '-50px !important',
62 | marginRight: '22px',
63 | float: 'right'
64 | }
65 | },
66 | margin: {
67 | zIndex: '4',
68 | margin: '0'
69 | },
70 | searchIcon: {
71 | width: '17px',
72 | zIndex: '4'
73 | },
74 | notifications: {
75 | zIndex: '4',
76 | [theme.breakpoints.up('md')]: {
77 | position: 'absolute',
78 | top: '2px',
79 | border: '1px solid ' + whiteColor,
80 | right: '4px',
81 | fontSize: '9px',
82 | background: dangerColor[0],
83 | color: whiteColor,
84 | minWidth: '16px',
85 | height: '16px',
86 | borderRadius: '10px',
87 | textAlign: 'center',
88 | lineHeight: '16px',
89 | verticalAlign: 'middle',
90 | display: 'block'
91 | },
92 | [theme.breakpoints.down('sm')]: {
93 | ...defaultFont,
94 | fontSize: '14px',
95 | marginRight: '8px'
96 | }
97 | },
98 | manager: {
99 | [theme.breakpoints.down('sm')]: {
100 | width: '100%'
101 | },
102 | display: 'inline-block'
103 | },
104 | searchWrapper: {
105 | [theme.breakpoints.down('sm')]: {
106 | width: '-webkit-fill-available',
107 | margin: '10px 15px 0'
108 | },
109 | display: 'inline-block'
110 | }
111 | });
112 |
113 | export default headerLinksStyle;
114 |
--------------------------------------------------------------------------------
/src/assets/jss/material-dashboard-react/components/snackbarContentStyle.js:
--------------------------------------------------------------------------------
1 | import {
2 | defaultFont,
3 | primaryBoxShadow,
4 | infoBoxShadow,
5 | successBoxShadow,
6 | warningBoxShadow,
7 | dangerBoxShadow,
8 | roseBoxShadow,
9 | whiteColor,
10 | blackColor,
11 | grayColor,
12 | infoColor,
13 | successColor,
14 | dangerColor,
15 | roseColor,
16 | primaryColor,
17 | warningColor,
18 | hexToRgb
19 | } from '../../material-dashboard-react.js';
20 |
21 | const snackbarContentStyle = {
22 | root: {
23 | ...defaultFont,
24 | flexWrap: 'unset',
25 | position: 'relative',
26 | padding: '20px 15px',
27 | lineHeight: '20px',
28 | marginBottom: '20px',
29 | fontSize: '14px',
30 | backgroundColor: whiteColor,
31 | color: grayColor[7],
32 | borderRadius: '3px',
33 | minWidth: 'unset',
34 | maxWidth: 'unset',
35 | boxShadow:
36 | '0 12px 20px -10px rgba(' +
37 | hexToRgb(whiteColor) +
38 | ', 0.28), 0 4px 20px 0px rgba(' +
39 | hexToRgb(blackColor) +
40 | ', 0.12), 0 7px 8px -5px rgba(' +
41 | hexToRgb(whiteColor) +
42 | ', 0.2)'
43 | },
44 | top20: {
45 | top: '20px'
46 | },
47 | top40: {
48 | top: '40px'
49 | },
50 | info: {
51 | backgroundColor: infoColor[3],
52 | color: whiteColor,
53 | ...infoBoxShadow
54 | },
55 | success: {
56 | backgroundColor: successColor[3],
57 | color: whiteColor,
58 | ...successBoxShadow
59 | },
60 | warning: {
61 | backgroundColor: warningColor[3],
62 | color: whiteColor,
63 | ...warningBoxShadow
64 | },
65 | danger: {
66 | backgroundColor: dangerColor[3],
67 | color: whiteColor,
68 | ...dangerBoxShadow
69 | },
70 | primary: {
71 | backgroundColor: primaryColor[3],
72 | color: whiteColor,
73 | ...primaryBoxShadow
74 | },
75 | rose: {
76 | backgroundColor: roseColor[3],
77 | color: whiteColor,
78 | ...roseBoxShadow
79 | },
80 | message: {
81 | padding: '0',
82 | display: 'block',
83 | maxWidth: '89%'
84 | },
85 | close: {
86 | width: '11px',
87 | height: '11px'
88 | },
89 | iconButton: {
90 | width: '24px',
91 | height: '24px',
92 | padding: '0px'
93 | },
94 | icon: {
95 | display: 'block',
96 | left: '15px',
97 | position: 'absolute',
98 | top: '50%',
99 | marginTop: '-15px',
100 | width: '30px',
101 | height: '30px'
102 | },
103 | infoIcon: {
104 | color: infoColor[3]
105 | },
106 | successIcon: {
107 | color: successColor[3]
108 | },
109 | warningIcon: {
110 | color: warningColor[3]
111 | },
112 | dangerIcon: {
113 | color: dangerColor[3]
114 | },
115 | primaryIcon: {
116 | color: primaryColor[3]
117 | },
118 | roseIcon: {
119 | color: roseColor[3]
120 | },
121 | iconMessage: {
122 | paddingLeft: '50px',
123 | display: 'block'
124 | },
125 | actionRTL: {
126 | marginLeft: '-8px',
127 | marginRight: 'auto'
128 | }
129 | };
130 |
131 | export default snackbarContentStyle;
132 |
--------------------------------------------------------------------------------
/src/assets/jss/material-dashboard-react/components/tableStyle.js:
--------------------------------------------------------------------------------
1 | import {
2 | warningColor,
3 | primaryColor,
4 | dangerColor,
5 | successColor,
6 | infoColor,
7 | roseColor,
8 | grayColor,
9 | defaultFont
10 | } from '../../material-dashboard-react.js';
11 |
12 | const tableStyle = theme => ({
13 | warningTableHeader: {
14 | color: warningColor[0]
15 | },
16 | primaryTableHeader: {
17 | color: primaryColor[0]
18 | },
19 | dangerTableHeader: {
20 | color: dangerColor[0]
21 | },
22 | successTableHeader: {
23 | color: successColor[0]
24 | },
25 | infoTableHeader: {
26 | color: infoColor[0]
27 | },
28 | roseTableHeader: {
29 | color: roseColor[0]
30 | },
31 | grayTableHeader: {
32 | color: grayColor[0]
33 | },
34 | table: {
35 | marginBottom: '0',
36 | width: '100%',
37 | maxWidth: '100%',
38 | backgroundColor: 'transparent',
39 | borderSpacing: '0',
40 | borderCollapse: 'collapse'
41 | },
42 | tableHeadCell: {
43 | color: 'inherit',
44 | ...defaultFont,
45 | '&, &$tableCell': {
46 | fontSize: '1em'
47 | }
48 | },
49 | tableCell: {
50 | ...defaultFont,
51 | lineHeight: '1.42857143',
52 | padding: '12px 8px',
53 | verticalAlign: 'middle',
54 | fontSize: '0.8125rem'
55 | },
56 | tableResponsive: {
57 | width: '100%',
58 | marginTop: theme.spacing(3),
59 | overflowX: 'auto'
60 | },
61 | tableHeadRow: {
62 | height: '56px',
63 | color: 'inherit',
64 | display: 'table-row',
65 | outline: 'none',
66 | verticalAlign: 'middle'
67 | },
68 | tableBodyRow: {
69 | height: '48px',
70 | color: 'inherit',
71 | display: 'table-row',
72 | outline: 'none',
73 | verticalAlign: 'middle'
74 | }
75 | });
76 |
77 | export default tableStyle;
78 |
--------------------------------------------------------------------------------
/src/assets/jss/material-dashboard-react/components/tasksStyle.js:
--------------------------------------------------------------------------------
1 | import {
2 | defaultFont,
3 | primaryColor,
4 | dangerColor,
5 | grayColor
6 | } from '../../material-dashboard-react.js';
7 | import tooltipStyle from '../../material-dashboard-react/tooltipStyle.js';
8 | import checkboxAdnRadioStyle from '../../material-dashboard-react/checkboxAdnRadioStyle.js';
9 | const tasksStyle = {
10 | ...tooltipStyle,
11 | ...checkboxAdnRadioStyle,
12 | table: {
13 | marginBottom: '0',
14 | overflow: 'visible'
15 | },
16 | tableRow: {
17 | position: 'relative',
18 | borderBottom: '1px solid ' + grayColor[5]
19 | },
20 | tableActions: {
21 | display: 'flex',
22 | border: 'none',
23 | padding: '12px 8px !important',
24 | verticalAlign: 'middle'
25 | },
26 | tableCell: {
27 | ...defaultFont,
28 | padding: '8px',
29 | verticalAlign: 'middle',
30 | border: 'none',
31 | lineHeight: '1.42857143',
32 | fontSize: '14px'
33 | },
34 | tableCellRTL: {
35 | textAlign: 'right'
36 | },
37 | tableActionButton: {
38 | width: '27px',
39 | height: '27px',
40 | padding: '0'
41 | },
42 | tableActionButtonIcon: {
43 | width: '17px',
44 | height: '17px'
45 | },
46 | edit: {
47 | backgroundColor: 'transparent',
48 | color: primaryColor[0],
49 | boxShadow: 'none'
50 | },
51 | close: {
52 | backgroundColor: 'transparent',
53 | color: dangerColor[0],
54 | boxShadow: 'none'
55 | }
56 | };
57 | export default tasksStyle;
58 |
--------------------------------------------------------------------------------
/src/assets/jss/material-dashboard-react/components/typographyStyle.js:
--------------------------------------------------------------------------------
1 | import {
2 | defaultFont,
3 | primaryColor,
4 | infoColor,
5 | successColor,
6 | warningColor,
7 | dangerColor,
8 | grayColor
9 | } from '../../material-dashboard-react.js';
10 |
11 | const typographyStyle = {
12 | defaultFontStyle: {
13 | ...defaultFont,
14 | fontSize: '14px'
15 | },
16 | defaultHeaderMargins: {
17 | marginTop: '20px',
18 | marginBottom: '10px'
19 | },
20 | quote: {
21 | padding: '10px 20px',
22 | margin: '0 0 20px',
23 | fontSize: '17.5px',
24 | borderLeft: '5px solid ' + grayColor[10]
25 | },
26 | quoteText: {
27 | margin: '0 0 10px',
28 | fontStyle: 'italic'
29 | },
30 | quoteAuthor: {
31 | display: 'block',
32 | fontSize: '80%',
33 | lineHeight: '1.42857143',
34 | color: grayColor[1]
35 | },
36 | mutedText: {
37 | color: grayColor[1]
38 | },
39 | primaryText: {
40 | color: primaryColor[0]
41 | },
42 | infoText: {
43 | color: infoColor[0]
44 | },
45 | successText: {
46 | color: successColor[0]
47 | },
48 | warningText: {
49 | color: warningColor[0]
50 | },
51 | dangerText: {
52 | color: dangerColor[0]
53 | }
54 | };
55 |
56 | export default typographyStyle;
57 |
--------------------------------------------------------------------------------
/src/assets/jss/material-dashboard-react/customInputStyle.jsx:
--------------------------------------------------------------------------------
1 | // ##############################
2 | // // // CustomInput styles
3 | // #############################
4 |
5 | import {
6 | primaryColor,
7 | dangerColor,
8 | successColor,
9 | defaultFont
10 | } from '../material-dashboard-react.js';
11 |
12 | const customInputStyle = {
13 | disabled: {
14 | '&:before': {
15 | backgroundColor: 'transparent !important'
16 | }
17 | },
18 | underline: {
19 | '&:hover:not($disabled):before,&:before': {
20 | backgroundColor: '#D2D2D2',
21 | height: '1px !important'
22 | },
23 | '&:after': {
24 | backgroundColor: primaryColor[0]
25 | }
26 | },
27 | underlineError: {
28 | '&:after': {
29 | backgroundColor: dangerColor[0]
30 | }
31 | },
32 | underlineSuccess: {
33 | '&:after': {
34 | backgroundColor: successColor[0]
35 | }
36 | },
37 | labelRoot: {
38 | ...defaultFont,
39 | color: '#AAAAAA',
40 | fontWeight: '400',
41 | fontSize: '14px',
42 | lineHeight: '1.42857'
43 | },
44 | labelRootError: {
45 | color: dangerColor[0]
46 | },
47 | labelRootSuccess: {
48 | color: successColor[0]
49 | },
50 | feedback: {
51 | position: 'absolute',
52 | top: '18px',
53 | right: '0',
54 | zIndex: '2',
55 | display: 'block',
56 | width: '24px',
57 | height: '24px',
58 | textAlign: 'center',
59 | pointerEvents: 'none'
60 | },
61 | marginTop: {
62 | marginTop: '16px'
63 | },
64 | formControl: {
65 | paddingBottom: '10px',
66 | margin: '27px 0 0 0',
67 | position: 'relative'
68 | }
69 | };
70 |
71 | export default customInputStyle;
72 |
--------------------------------------------------------------------------------
/src/assets/jss/material-dashboard-react/dashboardStyle.jsx:
--------------------------------------------------------------------------------
1 | import {
2 | successColor,
3 | whiteColor,
4 | grayColor,
5 | hexToRgb
6 | } from '../material-dashboard-react.js';
7 |
8 | const dashboardStyle = {
9 | successText: {
10 | color: successColor[0]
11 | },
12 | upArrowCardCategory: {
13 | width: '16px',
14 | height: '16px'
15 | },
16 | stats: {
17 | color: grayColor[0],
18 | display: 'inline-flex',
19 | fontSize: '12px',
20 | lineHeight: '22px',
21 | '& svg': {
22 | top: '4px',
23 | width: '16px',
24 | height: '16px',
25 | position: 'relative',
26 | marginRight: '3px',
27 | marginLeft: '3px'
28 | },
29 | '& .fab,& .fas,& .far,& .fal,& .material-icons': {
30 | top: '4px',
31 | fontSize: '16px',
32 | position: 'relative',
33 | marginRight: '3px',
34 | marginLeft: '3px'
35 | }
36 | },
37 | cardCategory: {
38 | color: grayColor[0],
39 | margin: '0',
40 | fontSize: '14px',
41 | marginTop: '0',
42 | paddingTop: '10px',
43 | marginBottom: '0'
44 | },
45 | cardCategoryWhite: {
46 | color: 'rgba(' + hexToRgb(whiteColor) + ',.62)',
47 | margin: '0',
48 | fontSize: '14px',
49 | marginTop: '0',
50 | marginBottom: '0'
51 | },
52 | cardTitle: {
53 | color: grayColor[2],
54 | marginTop: '0px',
55 | minHeight: 'auto',
56 | fontWeight: '300',
57 | fontFamily: "'Roboto', 'Helvetica', 'Arial', sans-serif",
58 | marginBottom: '3px',
59 | textDecoration: 'none',
60 | '& small': {
61 | color: grayColor[1],
62 | fontWeight: '400',
63 | lineHeight: '1'
64 | }
65 | },
66 | cardTitleWhite: {
67 | color: whiteColor,
68 | marginTop: '0px',
69 | minHeight: 'auto',
70 | fontWeight: '300',
71 | fontFamily: "'Roboto', 'Helvetica', 'Arial', sans-serif",
72 | marginBottom: '3px',
73 | textDecoration: 'none',
74 | '& small': {
75 | color: grayColor[1],
76 | fontWeight: '400',
77 | lineHeight: '1'
78 | }
79 | }
80 | };
81 |
82 | export default dashboardStyle;
83 |
--------------------------------------------------------------------------------
/src/assets/jss/material-dashboard-react/footerStyle.jsx:
--------------------------------------------------------------------------------
1 | import {
2 | defaultFont,
3 | container,
4 | primaryColor,
5 | grayColor
6 | } from '../material-dashboard-react.js';
7 |
8 | const footerStyle = {
9 | block: {
10 | color: 'inherit',
11 | padding: '15px',
12 | textTransform: 'uppercase',
13 | borderRadius: '3px',
14 | textDecoration: 'none',
15 | position: 'relative',
16 | display: 'block',
17 | ...defaultFont,
18 | fontWeight: '500',
19 | fontSize: '12px'
20 | },
21 | left: {
22 | float: 'left!important',
23 | display: 'block'
24 | },
25 | right: {
26 | padding: '15px 0',
27 | margin: '0',
28 | fontSize: '14px',
29 | float: 'right!important'
30 | },
31 | footer: {
32 | bottom: '0',
33 | borderTop: '1px solid ' + grayColor[11],
34 | padding: '15px 0',
35 | ...defaultFont
36 | },
37 | container,
38 | a: {
39 | color: primaryColor,
40 | textDecoration: 'none',
41 | backgroundColor: 'transparent'
42 | },
43 | list: {
44 | marginBottom: '0',
45 | padding: '0',
46 | marginTop: '0'
47 | },
48 | inlineBlock: {
49 | display: 'inline-block',
50 | padding: '0px',
51 | width: 'auto'
52 | }
53 | };
54 | export default footerStyle;
55 |
--------------------------------------------------------------------------------
/src/assets/jss/material-dashboard-react/headerLinksStyle.jsx:
--------------------------------------------------------------------------------
1 | import {
2 | defaultFont,
3 | dangerColor,
4 | whiteColor
5 | } from '../material-dashboard-react.js';
6 |
7 | import dropdownStyle from '../material-dashboard-react/dropdownStyle.js';
8 |
9 | const headerLinksStyle = theme => ({
10 | ...dropdownStyle(theme),
11 | search: {
12 | '& > div': {
13 | marginTop: '0'
14 | },
15 | [theme.breakpoints.down('sm')]: {
16 | margin: '10px 15px !important',
17 | float: 'none !important',
18 | paddingTop: '1px',
19 | paddingBottom: '1px',
20 | padding: '0!important',
21 | width: '60%',
22 | marginTop: '40px',
23 | '& input': {
24 | color: whiteColor
25 | }
26 | }
27 | },
28 | linkText: {
29 | zIndex: '4',
30 | ...defaultFont,
31 | fontSize: '14px',
32 | margin: '0px'
33 | },
34 | buttonLink: {
35 | [theme.breakpoints.down('sm')]: {
36 | display: 'flex',
37 | margin: '10px 15px 0',
38 | width: '-webkit-fill-available',
39 | '& svg': {
40 | width: '24px',
41 | height: '30px',
42 | marginRight: '15px',
43 | marginLeft: '-15px'
44 | },
45 | '& .fab,& .fas,& .far,& .fal,& .material-icons': {
46 | fontSize: '24px',
47 | lineHeight: '30px',
48 | width: '24px',
49 | height: '30px',
50 | marginRight: '15px',
51 | marginLeft: '-15px'
52 | },
53 | '& > span': {
54 | justifyContent: 'flex-start',
55 | width: '100%'
56 | }
57 | }
58 | },
59 | searchButton: {
60 | [theme.breakpoints.down('sm')]: {
61 | top: '-50px !important',
62 | marginRight: '22px',
63 | float: 'right'
64 | }
65 | },
66 | margin: {
67 | zIndex: '4',
68 | margin: '0'
69 | },
70 | searchIcon: {
71 | width: '17px',
72 | zIndex: '4'
73 | },
74 | notifications: {
75 | zIndex: '4',
76 | [theme.breakpoints.up('md')]: {
77 | position: 'absolute',
78 | top: '2px',
79 | border: '1px solid ' + whiteColor,
80 | right: '4px',
81 | fontSize: '9px',
82 | background: dangerColor[0],
83 | color: whiteColor,
84 | minWidth: '16px',
85 | height: '16px',
86 | borderRadius: '10px',
87 | textAlign: 'center',
88 | lineHeight: '16px',
89 | verticalAlign: 'middle',
90 | display: 'block'
91 | },
92 | [theme.breakpoints.down('sm')]: {
93 | ...defaultFont,
94 | fontSize: '14px',
95 | marginRight: '8px'
96 | }
97 | },
98 | manager: {
99 | [theme.breakpoints.down('sm')]: {
100 | width: '100%'
101 | },
102 | display: 'inline-block'
103 | },
104 | searchWrapper: {
105 | [theme.breakpoints.down('sm')]: {
106 | width: '-webkit-fill-available',
107 | margin: '10px 15px 0'
108 | },
109 | display: 'inline-block'
110 | }
111 | });
112 |
113 | export default headerLinksStyle;
114 |
--------------------------------------------------------------------------------
/src/assets/jss/material-dashboard-react/headerStyle.jsx:
--------------------------------------------------------------------------------
1 | import {
2 | container,
3 | defaultFont,
4 | primaryColor,
5 | defaultBoxShadow,
6 | infoColor,
7 | successColor,
8 | warningColor,
9 | dangerColor,
10 | whiteColor,
11 | grayColor
12 | } from '../material-dashboard-react.js';
13 |
14 | const headerStyle = () => ({
15 | appBar: {
16 | backgroundColor: 'transparent',
17 | boxShadow: 'none',
18 | borderBottom: '0',
19 | marginBottom: '0',
20 | position: 'absolute',
21 | width: '100%',
22 | paddingTop: '10px',
23 | zIndex: '1029',
24 | color: grayColor[7],
25 | border: '0',
26 | borderRadius: '3px',
27 | padding: '10px 0',
28 | transition: 'all 150ms ease 0s',
29 | minHeight: '50px',
30 | display: 'block'
31 | },
32 | container: {
33 | ...container,
34 | minHeight: '50px'
35 | },
36 | flex: {
37 | flex: 1
38 | },
39 | title: {
40 | ...defaultFont,
41 | letterSpacing: 'unset',
42 | lineHeight: '30px',
43 | fontSize: '18px',
44 | borderRadius: '3px',
45 | textTransform: 'none',
46 | color: 'inherit',
47 | margin: '0',
48 | '&:hover,&:focus': {
49 | background: 'transparent'
50 | }
51 | },
52 | appResponsive: {
53 | top: '8px'
54 | },
55 | primary: {
56 | backgroundColor: primaryColor[0],
57 | color: whiteColor,
58 | ...defaultBoxShadow
59 | },
60 | info: {
61 | backgroundColor: infoColor[0],
62 | color: whiteColor,
63 | ...defaultBoxShadow
64 | },
65 | success: {
66 | backgroundColor: successColor[0],
67 | color: whiteColor,
68 | ...defaultBoxShadow
69 | },
70 | warning: {
71 | backgroundColor: warningColor[0],
72 | color: whiteColor,
73 | ...defaultBoxShadow
74 | },
75 | danger: {
76 | backgroundColor: dangerColor[0],
77 | color: whiteColor,
78 | ...defaultBoxShadow
79 | }
80 | });
81 |
82 | export default headerStyle;
83 |
--------------------------------------------------------------------------------
/src/assets/jss/material-dashboard-react/iconsStyle.jsx:
--------------------------------------------------------------------------------
1 | // ##############################
2 | // // // Icons styles
3 | // #############################
4 |
5 | import { boxShadow } from '../material-dashboard-react.js';
6 |
7 | const iconsStyle = {
8 | iframe: {
9 | width: '100%',
10 | height: '500px',
11 | border: '0',
12 | ...boxShadow
13 | },
14 | iframeContainer: {
15 | margin: '0 -20px 0'
16 | }
17 | };
18 |
19 | export default iconsStyle;
20 |
--------------------------------------------------------------------------------
/src/assets/jss/material-dashboard-react/profileCardStyle.jsx:
--------------------------------------------------------------------------------
1 | // ##############################
2 | // // // ProfileCard styles
3 | // #############################
4 |
5 | import {
6 | card,
7 | boxShadow,
8 | grayColor,
9 | defaultFont
10 | } from '../material-dashboard-react.js';
11 |
12 | const profileCardStyle = {
13 | card: {
14 | marginTop: '30px',
15 | textAlign: 'center',
16 | ...card
17 | },
18 | cardHeader: {
19 | display: 'inline-block',
20 | width: '100%',
21 | padding: '0px'
22 | },
23 | cardAvatar: {
24 | maxWidth: '130px',
25 | maxHeight: '130px',
26 | margin: '-50px auto 0',
27 | borderRadius: '50%',
28 | overflow: 'hidden',
29 | ...boxShadow
30 | },
31 | img: {
32 | width: '100%',
33 | height: 'auto',
34 | verticalAlign: 'middle',
35 | border: '0'
36 | },
37 | textAlign: {
38 | textAlign: 'center'
39 | },
40 | cardSubtitle: {
41 | color: grayColor,
42 | ...defaultFont,
43 | fontSize: '1em',
44 | textTransform: 'uppercase',
45 | marginTop: '10px',
46 | marginBottom: '10px'
47 | },
48 | cardTitle: {
49 | ...defaultFont,
50 | fontSize: '1.3em',
51 | marginTop: '10px',
52 | marginBottom: '10px'
53 | },
54 | cardDescription: {
55 | ...defaultFont,
56 | padding: '15px 20px',
57 | margin: '0 0 10px'
58 | },
59 | cardActions: {
60 | height: 'auto',
61 | display: 'inline'
62 | }
63 | };
64 |
65 | export default profileCardStyle;
66 |
--------------------------------------------------------------------------------
/src/assets/jss/material-dashboard-react/regularCardStyle.jsx:
--------------------------------------------------------------------------------
1 | // ##############################
2 | // // // RegularCard styles
3 | // #############################
4 |
5 | import {
6 | card,
7 | cardHeader,
8 | defaultFont,
9 | orangeCardHeader,
10 | greenCardHeader,
11 | redCardHeader,
12 | blueCardHeader,
13 | purpleCardHeader
14 | } from '../material-dashboard-react.js';
15 |
16 | const regularCardStyle = {
17 | card: {
18 | ...card,
19 | overflow: 'visible'
20 | },
21 | cardPlain: {
22 | background: 'transparent',
23 | boxShadow: 'none'
24 | },
25 | cardHeader: {
26 | ...cardHeader,
27 | ...defaultFont
28 | },
29 | cardPlainHeader: {
30 | marginLeft: 0,
31 | marginRight: 0
32 | },
33 | orangeCardHeader,
34 | greenCardHeader,
35 | redCardHeader,
36 | blueCardHeader,
37 | purpleCardHeader,
38 | cardTitle: {
39 | color: '#FFFFFF',
40 | marginTop: '0',
41 | marginBottom: '5px',
42 | ...defaultFont,
43 | fontSize: '1.125em'
44 | },
45 | cardSubtitle: {
46 | ...defaultFont,
47 | marginBottom: '0',
48 | color: 'rgba(255, 255, 255, 0.62)',
49 | margin: '0 0 10px'
50 | },
51 | cardActions: {
52 | padding: '14px',
53 | display: 'block',
54 | height: 'auto'
55 | }
56 | };
57 |
58 | export default regularCardStyle;
59 |
--------------------------------------------------------------------------------
/src/assets/jss/material-dashboard-react/snackbarContentStyle.jsx:
--------------------------------------------------------------------------------
1 | // ##############################
2 | // // // SnackbarContent styles
3 | // #############################
4 |
5 | import {
6 | defaultFont,
7 | primaryBoxShadow,
8 | infoBoxShadow,
9 | successBoxShadow,
10 | warningBoxShadow,
11 | dangerBoxShadow
12 | } from '../material-dashboard-react.js';
13 |
14 | const snackbarContentStyle = {
15 | root: {
16 | ...defaultFont,
17 | position: 'relative',
18 | padding: '20px 15px',
19 | lineHeight: '20px',
20 | marginBottom: '20px',
21 | fontSize: '14px',
22 | backgroundColor: 'white',
23 | color: '#555555',
24 | borderRadius: '3px',
25 | boxShadow:
26 | '0 12px 20px -10px rgba(255, 255, 255, 0.28), 0 4px 20px 0px rgba(0, 0, 0, 0.12), 0 7px 8px -5px rgba(255, 255, 255, 0.2)'
27 | },
28 | info: {
29 | backgroundColor: '#00d3ee',
30 | color: '#ffffff',
31 | ...infoBoxShadow
32 | },
33 | success: {
34 | backgroundColor: '#5cb860',
35 | color: '#ffffff',
36 | ...successBoxShadow
37 | },
38 | warning: {
39 | backgroundColor: '#ffa21a',
40 | color: '#ffffff',
41 | ...warningBoxShadow
42 | },
43 | danger: {
44 | backgroundColor: '#f55a4e',
45 | color: '#ffffff',
46 | ...dangerBoxShadow
47 | },
48 | primary: {
49 | backgroundColor: '#af2cc5',
50 | color: '#ffffff',
51 | ...primaryBoxShadow
52 | },
53 | message: {
54 | padding: '0',
55 | display: 'block',
56 | maxWidth: '89%'
57 | },
58 | close: {
59 | width: '14px',
60 | height: '14px'
61 | },
62 | iconButton: {
63 | width: '24px',
64 | height: '24px'
65 | },
66 | icon: {
67 | display: 'block',
68 | left: '15px',
69 | position: 'absolute',
70 | top: '50%',
71 | marginTop: '-15px',
72 | width: '30px',
73 | height: '30px'
74 | },
75 | iconMessage: {
76 | paddingLeft: '65px',
77 | display: 'block'
78 | }
79 | };
80 |
81 | export default snackbarContentStyle;
82 |
--------------------------------------------------------------------------------
/src/assets/jss/material-dashboard-react/statsCardStyle.jsx:
--------------------------------------------------------------------------------
1 | // ##############################
2 | // // // StatsCard styles
3 | // #############################
4 |
5 | import {
6 | card,
7 | cardHeader,
8 | defaultFont,
9 | orangeCardHeader,
10 | greenCardHeader,
11 | redCardHeader,
12 | blueCardHeader,
13 | purpleCardHeader,
14 | cardActions,
15 | grayColor,
16 | warningColor,
17 | dangerColor,
18 | successColor,
19 | infoColor,
20 | primaryColor,
21 | roseColor
22 | } from '../material-dashboard-react.js';
23 |
24 | const statsCardStyle = {
25 | card: {
26 | ...card,
27 | overflow: 'visible'
28 | },
29 | cardHeader: {
30 | ...cardHeader,
31 | float: 'left',
32 | textAlign: 'center'
33 | },
34 | orangeCardHeader,
35 | greenCardHeader,
36 | redCardHeader,
37 | blueCardHeader,
38 | purpleCardHeader,
39 | cardContent: {
40 | textAlign: 'right',
41 | paddingTop: '10px',
42 | padding: '15px 20px'
43 | },
44 | cardIcon: {
45 | width: '40px!important',
46 | height: '36px!important',
47 | fill: '#fff!important'
48 | },
49 | cardAvatar: {
50 | margin: '8px'
51 | },
52 | cardCategory: {
53 | marginBottom: '0',
54 | color: grayColor[0],
55 | margin: '0 0 10px',
56 | ...defaultFont
57 | },
58 | cardTitle: {
59 | margin: '0',
60 | ...defaultFont,
61 | fontSize: '1.625em'
62 | },
63 | cardTitleSmall: {
64 | fontSize: '65%',
65 | fontWeight: '400',
66 | lineHeight: '1',
67 | color: '#777'
68 | },
69 | cardActions: {
70 | ...cardActions,
71 | padding: '0!important'
72 | },
73 | cardStats: {
74 | lineHeight: '22px',
75 | color: grayColor[0],
76 | fontSize: '12px',
77 | display: 'inline-block',
78 | margin: '0!important'
79 | },
80 | cardStatsIcon: {
81 | position: 'relative',
82 | top: '4px',
83 | width: '16px',
84 | height: '16px'
85 | },
86 | warningCardStatsIcon: {
87 | color: warningColor[0]
88 | },
89 | primaryCardStatsIcon: {
90 | color: primaryColor[0]
91 | },
92 | dangerCardStatsIcon: {
93 | color: dangerColor[0]
94 | },
95 | successCardStatsIcon: {
96 | color: successColor[0]
97 | },
98 | infoCardStatsIcon: {
99 | color: infoColor[0]
100 | },
101 | roseCardStatsIcon: {
102 | color: roseColor[0]
103 | },
104 | grayCardStatsIcon: {
105 | color: grayColor[0]
106 | },
107 | cardStatsLink: {
108 | color: primaryColor[0],
109 | textDecoration: 'none',
110 | ...defaultFont
111 | }
112 | };
113 |
114 | export default statsCardStyle;
115 |
--------------------------------------------------------------------------------
/src/assets/jss/material-dashboard-react/tableStyle.jsx:
--------------------------------------------------------------------------------
1 | // ##############################
2 | // // // Table styles
3 | // #############################
4 |
5 | import {
6 | warningColor,
7 | primaryColor,
8 | dangerColor,
9 | successColor,
10 | infoColor,
11 | roseColor,
12 | grayColor,
13 | defaultFont
14 | } from '../material-dashboard-react.js';
15 |
16 | const tableStyle = theme => ({
17 | warningTableHeader: {
18 | color: warningColor[0]
19 | },
20 | primaryTableHeader: {
21 | color: primaryColor[0]
22 | },
23 | dangerTableHeader: {
24 | color: dangerColor[0]
25 | },
26 | successTableHeader: {
27 | color: successColor[0]
28 | },
29 | infoTableHeader: {
30 | color: infoColor[0]
31 | },
32 | roseTableHeader: {
33 | color: roseColor[0]
34 | },
35 | grayTableHeader: {
36 | color: grayColor[0]
37 | },
38 | table: {
39 | marginBottom: '0',
40 | width: '100%',
41 | maxWidth: '100%',
42 | backgroundColor: 'transparent',
43 | borderSpacing: '0',
44 | borderCollapse: 'collapse'
45 | },
46 | tableHeadCell: {
47 | color: 'inherit',
48 | ...defaultFont,
49 | fontSize: '1em'
50 | },
51 | tableCell: {
52 | ...defaultFont,
53 | lineHeight: '1.42857143',
54 | padding: '12px 8px',
55 | verticalAlign: 'middle'
56 | },
57 | tableResponsive: {
58 | width: '100%',
59 | marginTop: theme.spacing(3),
60 | overflowX: 'auto'
61 | }
62 | });
63 |
64 | export default tableStyle;
65 |
--------------------------------------------------------------------------------
/src/assets/jss/material-dashboard-react/tasksCardStyle.jsx:
--------------------------------------------------------------------------------
1 | // ##############################
2 | // // // TasksCard styles
3 | // #############################
4 |
5 | import {
6 | card,
7 | cardHeader,
8 | defaultFont,
9 | primaryBoxShadow
10 | } from '../material-dashboard-react.js';
11 |
12 | const tasksCardStyle = theme => ({
13 | card: {
14 | ...card,
15 | overflow: 'visible'
16 | },
17 | cardHeader: {
18 | flex: 'none',
19 | ...cardHeader,
20 | ...defaultFont,
21 | background: 'linear-gradient(60deg, #ab47bc, #8e24aa)',
22 | ...primaryBoxShadow
23 | },
24 | cardTitle: {
25 | ...defaultFont,
26 | float: 'left',
27 | fontWeight: '500',
28 | padding: '10px 10px 10px 0',
29 | lineHeight: '24px',
30 | fontSize: '14px',
31 | color: '#FFFFFF'
32 | },
33 | tabWrapper: {
34 | width: 'auto',
35 | display: 'inline-flex',
36 | alignItems: 'inherit',
37 | flexDirection: 'row',
38 | justifyContent: 'center',
39 | [theme.breakpoints.down('sm')]: {
40 | display: 'flex'
41 | }
42 | },
43 | tabIcon: {
44 | float: 'left',
45 | [theme.breakpoints.down('sm')]: {
46 | marginTop: '-2px'
47 | }
48 | },
49 | displayNone: {
50 | display: 'none'
51 | },
52 | labelIcon: {
53 | height: '44px',
54 | width: '110px',
55 | minWidth: '72px',
56 | paddingLeft: '14px',
57 | borderRadius: '3px'
58 | },
59 | tabsContainer: {
60 | marginTop: '4px',
61 | color: '#FFFFFF',
62 | [theme.breakpoints.down('sm')]: {
63 | display: 'grid'
64 | }
65 | },
66 | tabs: {
67 | width: '110px',
68 | minWidth: '70px',
69 | paddingLeft: '12px'
70 | },
71 | cardHeaderContent: {
72 | flex: 'none'
73 | },
74 | label: {
75 | lineHeight: '19px',
76 | textTransform: 'uppercase',
77 | fontSize: '12px',
78 | fontWeight: '500',
79 | marginLeft: '-10px'
80 | },
81 | textColorInheritSelected: {
82 | backgroundColor: 'rgba(255, 255, 255, 0.2)',
83 | transition: 'background-color .4s'
84 | }
85 | });
86 |
87 | export default tasksCardStyle;
88 |
--------------------------------------------------------------------------------
/src/assets/jss/material-dashboard-react/tasksStyle.jsx:
--------------------------------------------------------------------------------
1 | // ##############################
2 | // // // Tasks styles
3 | // #############################
4 |
5 | import {
6 | defaultFont,
7 | primaryColor,
8 | dangerColor
9 | } from '../material-dashboard-react.js';
10 |
11 | const tasksStyle = {
12 | table: {
13 | marginBottom: '0',
14 | overflow: 'visible'
15 | },
16 | tableRow: {
17 | position: 'relative',
18 | borderBottom: '1px solid #dddddd'
19 | },
20 | tableActions: {
21 | display: 'flex',
22 | border: 'none',
23 | padding: '12px 8px !important',
24 | verticalAlign: 'middle'
25 | },
26 | tableCell: {
27 | ...defaultFont,
28 | padding: '8px',
29 | verticalAlign: 'middle',
30 | border: 'none',
31 | lineHeight: '1.42857143',
32 | fontSize: '14px'
33 | },
34 | tableActionButton: {
35 | width: '27px',
36 | height: '27px'
37 | },
38 | tableActionButtonIcon: {
39 | width: '17px',
40 | height: '17px'
41 | },
42 | edit: {
43 | backgroundColor: 'transparent',
44 | color: primaryColor,
45 | boxShadow: 'none'
46 | },
47 | close: {
48 | backgroundColor: 'transparent',
49 | color: dangerColor,
50 | boxShadow: 'none'
51 | },
52 | checked: {
53 | color: primaryColor
54 | },
55 | checkedIcon: {
56 | width: '20px',
57 | height: '20px',
58 | border: '1px solid rgba(0, 0, 0, .54)',
59 | borderRadius: '3px'
60 | },
61 | uncheckedIcon: {
62 | width: '0px',
63 | height: '0px',
64 | padding: '10px',
65 | border: '1px solid rgba(0, 0, 0, .54)',
66 | borderRadius: '3px'
67 | },
68 | tooltip: {
69 | padding: '10px 15px',
70 | minWidth: '130px',
71 | color: '#555555',
72 | lineHeight: '1.7em',
73 | background: '#FFFFFF',
74 | border: 'none',
75 | borderRadius: '3px',
76 | boxShadow:
77 | '0 8px 10px 1px rgba(0, 0, 0, 0.14), 0 3px 14px 2px rgba(0, 0, 0, 0.12), 0 5px 5px -3px rgba(0, 0, 0, 0.2)',
78 | maxWidth: '200px',
79 | textAlign: 'center',
80 | fontFamily: '"Helvetica Neue",Helvetica,Arial,sans-serif',
81 | fontSize: '12px',
82 | fontStyle: 'normal',
83 | fontWeight: '400',
84 | textShadow: 'none',
85 | textTransform: 'none',
86 | letterSpacing: 'normal',
87 | wordBreak: 'normal',
88 | wordSpacing: 'normal',
89 | wordWrap: 'normal',
90 | whiteSpace: 'normal',
91 | lineBreak: 'auto'
92 | }
93 | };
94 | export default tasksStyle;
95 |
--------------------------------------------------------------------------------
/src/assets/jss/material-dashboard-react/typographyStyle.jsx:
--------------------------------------------------------------------------------
1 | // ##############################
2 | // // // Typography styles
3 | // #############################
4 |
5 | import {
6 | defaultFont,
7 | primaryColor,
8 | infoColor,
9 | successColor,
10 | warningColor,
11 | dangerColor
12 | } from '../material-dashboard-react.js';
13 |
14 | const typographyStyle = {
15 | defaultFontStyle: {
16 | ...defaultFont,
17 | fontSize: '14px'
18 | },
19 | defaultHeaderMargins: {
20 | marginTop: '20px',
21 | marginBottom: '10px'
22 | },
23 | quote: {
24 | padding: '10px 20px',
25 | margin: '0 0 20px',
26 | fontSize: '17.5px',
27 | borderLeft: '5px solid #eee'
28 | },
29 | quoteText: {
30 | margin: '0 0 10px',
31 | fontStyle: 'italic'
32 | },
33 | quoteAuthor: {
34 | display: 'block',
35 | fontSize: '80%',
36 | lineHeight: '1.42857143',
37 | color: '#777'
38 | },
39 | mutedText: {
40 | color: '#777'
41 | },
42 | primaryText: {
43 | color: primaryColor[0]
44 | },
45 | infoText: {
46 | color: infoColor[0]
47 | },
48 | successText: {
49 | color: successColor[0]
50 | },
51 | warningText: {
52 | color: warningColor[0]
53 | },
54 | dangerText: {
55 | color: dangerColor[0]
56 | }
57 | };
58 |
59 | export default typographyStyle;
60 |
--------------------------------------------------------------------------------
/src/components/Card/Card.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | // nodejs library that concatenates classes
3 | import classNames from 'classnames';
4 | // nodejs library to set properties for components
5 | import PropTypes from 'prop-types';
6 | // @material-ui/core components
7 | import { makeStyles } from '@material-ui/core/styles';
8 | // @material-ui/icons
9 |
10 | // core components
11 | import styles from '../../assets/jss/material-dashboard-react/components/cardStyle.js';
12 |
13 | const useStyles = makeStyles(styles);
14 |
15 | export default function Card(props) {
16 | const classes = useStyles();
17 | const { className, children, plain, profile, chart, ...rest } = props;
18 | const cardClasses = classNames({
19 | [classes.card]: true,
20 | [classes.cardPlain]: plain,
21 | [classes.cardProfile]: profile,
22 | [classes.cardChart]: chart,
23 | [className]: className !== undefined
24 | });
25 | return (
26 |
27 | {children}
28 |
29 | );
30 | }
31 |
32 | Card.propTypes = {
33 | className: PropTypes.string,
34 | plain: PropTypes.bool,
35 | profile: PropTypes.bool,
36 | chart: PropTypes.bool,
37 | children: PropTypes.node
38 | };
39 |
--------------------------------------------------------------------------------
/src/components/Card/CardBody.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | // nodejs library that concatenates classes
3 | import classNames from 'classnames';
4 | // nodejs library to set properties for components
5 | import PropTypes from 'prop-types';
6 | // @material-ui/core components
7 | import { makeStyles } from '@material-ui/core/styles';
8 | // @material-ui/icons
9 |
10 | // core components
11 | import styles from '../../assets/jss/material-dashboard-react/components/cardBodyStyle.js';
12 |
13 | const useStyles = makeStyles(styles);
14 |
15 | export default function CardBody(props) {
16 | const classes = useStyles();
17 | const { className, children, plain, profile, ...rest } = props;
18 | const cardBodyClasses = classNames({
19 | [classes.cardBody]: true,
20 | [classes.cardBodyPlain]: plain,
21 | [classes.cardBodyProfile]: profile,
22 | [className]: className !== undefined
23 | });
24 | return (
25 |
26 | {children}
27 |
28 | );
29 | }
30 |
31 | CardBody.propTypes = {
32 | className: PropTypes.string,
33 | plain: PropTypes.bool,
34 | profile: PropTypes.bool,
35 | children: PropTypes.node
36 | };
37 |
--------------------------------------------------------------------------------
/src/components/Card/CardFooter.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | // nodejs library that concatenates classes
3 | import classNames from 'classnames';
4 | // nodejs library to set properties for components
5 | import PropTypes from 'prop-types';
6 | // @material-ui/core components
7 | import { makeStyles } from '@material-ui/core/styles';
8 | // @material-ui/icons
9 |
10 | // core components
11 | import styles from '../../assets/jss/material-dashboard-react/components/cardFooterStyle.js';
12 |
13 | const useStyles = makeStyles(styles);
14 |
15 | export default function CardFooter(props) {
16 | const classes = useStyles();
17 | const {
18 | className,
19 | children,
20 | plain,
21 | profile,
22 | stats,
23 | chart,
24 | ...rest
25 | } = props;
26 | const cardFooterClasses = classNames({
27 | [classes.cardFooter]: true,
28 | [classes.cardFooterPlain]: plain,
29 | [classes.cardFooterProfile]: profile,
30 | [classes.cardFooterStats]: stats,
31 | [classes.cardFooterChart]: chart,
32 | [className]: className !== undefined
33 | });
34 | return (
35 |
36 | {children}
37 |
38 | );
39 | }
40 |
41 | CardFooter.propTypes = {
42 | className: PropTypes.string,
43 | plain: PropTypes.bool,
44 | profile: PropTypes.bool,
45 | stats: PropTypes.bool,
46 | chart: PropTypes.bool,
47 | children: PropTypes.node
48 | };
49 |
--------------------------------------------------------------------------------
/src/components/Card/CardHeader.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | // nodejs library that concatenates classes
3 | import classNames from 'classnames';
4 | // nodejs library to set properties for components
5 | import PropTypes from 'prop-types';
6 | // @material-ui/core components
7 | import { makeStyles } from '@material-ui/core/styles';
8 | // @material-ui/icons
9 |
10 | // core components
11 | import styles from '../../assets/jss/material-dashboard-react/components/cardHeaderStyle.js';
12 |
13 | const useStyles = makeStyles(styles);
14 |
15 | export default function CardHeader(props) {
16 | const classes = useStyles();
17 | const { className, children, color, plain, stats, icon, ...rest } = props;
18 | const cardHeaderClasses = classNames({
19 | [classes.cardHeader]: true,
20 | [classes[color + 'CardHeader']]: color,
21 | [classes.cardHeaderPlain]: plain,
22 | [classes.cardHeaderStats]: stats,
23 | [classes.cardHeaderIcon]: icon,
24 | [className]: className !== undefined
25 | });
26 | return (
27 |
28 | {children}
29 |
30 | );
31 | }
32 |
33 | CardHeader.propTypes = {
34 | className: PropTypes.string,
35 | color: PropTypes.oneOf([
36 | 'warning',
37 | 'success',
38 | 'danger',
39 | 'info',
40 | 'primary',
41 | 'rose'
42 | ]),
43 | plain: PropTypes.bool,
44 | stats: PropTypes.bool,
45 | icon: PropTypes.bool,
46 | children: PropTypes.node
47 | };
48 |
--------------------------------------------------------------------------------
/src/components/Card/CardIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | // nodejs library that concatenates classes
3 | import classNames from 'classnames';
4 | // nodejs library to set properties for components
5 | import PropTypes from 'prop-types';
6 | // @material-ui/core components
7 | import { makeStyles } from '@material-ui/core/styles';
8 | // @material-ui/icons
9 |
10 | // core components
11 | import styles from '../../assets/jss/material-dashboard-react/components/cardIconStyle.js';
12 |
13 | const useStyles = makeStyles(styles);
14 |
15 | export default function CardIcon(props) {
16 | const classes = useStyles();
17 | const { className, children, color, ...rest } = props;
18 | const cardIconClasses = classNames({
19 | [classes.cardIcon]: true,
20 | [classes[color + 'CardHeader']]: color,
21 | [className]: className !== undefined
22 | });
23 | return (
24 |
25 | {children}
26 |
27 | );
28 | }
29 |
30 | CardIcon.propTypes = {
31 | className: PropTypes.string,
32 | color: PropTypes.oneOf([
33 | 'warning',
34 | 'success',
35 | 'danger',
36 | 'info',
37 | 'primary',
38 | 'rose'
39 | ]),
40 | children: PropTypes.node
41 | };
42 |
--------------------------------------------------------------------------------
/src/components/Card/ChartCard.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {
3 | withStyles,
4 | Card,
5 | CardContent,
6 | CardHeader,
7 | CardActions,
8 | Typography,
9 | } from '@material-ui/core';
10 | import PropTypes from 'prop-types';
11 | import FontAwesome from 'react-fontawesome';
12 |
13 | import chartCardStyle from '../../assets/jss/material-dashboard-react/chartCardStyle';
14 |
15 | const ChartCard = ({
16 | classes,
17 | chartColor,
18 | statIconColor,
19 | chart,
20 | title,
21 | text,
22 | statLink,
23 | statText,
24 | fontAwesomeStatsIcon,
25 | statIcon: StatIcon,
26 | }) => {
27 | return (
28 |
29 |
38 |
39 |
44 | {title}
45 |
46 |
47 | {text}
48 |
49 |
50 |
51 |
52 | {fontAwesomeStatsIcon ? (
53 |
54 | ) : (
55 |
62 | )}
63 | {statLink ? (
64 |
68 | {statLink.text}
69 |
70 | ) : statText ? (
71 | statText
72 | ) : null}
73 |
74 |
75 |
76 | );
77 | };
78 |
79 | ChartCard.defaultProps = {
80 | statIconColor: 'gray',
81 | chartColor: 'purple',
82 | };
83 |
84 | ChartCard.propTypes = {
85 | classes: PropTypes.object.isRequired,
86 | chart: PropTypes.object.isRequired,
87 | title: PropTypes.node,
88 | text: PropTypes.node,
89 | statIcon: PropTypes.elementType,
90 | fontAwesomeStatsIcon: PropTypes.node,
91 | statIconColor: PropTypes.oneOf([
92 | 'warning',
93 | 'primary',
94 | 'danger',
95 | 'success',
96 | 'info',
97 | 'rose',
98 | 'gray',
99 | ]),
100 | chartColor: PropTypes.oneOf(['orange', 'green', 'red', 'blue', 'purple']),
101 | statLink: PropTypes.object,
102 | statText: PropTypes.node,
103 | };
104 |
105 | export default withStyles(chartCardStyle)(ChartCard);
106 |
--------------------------------------------------------------------------------
/src/components/Card/FileserverCard.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { useTranslation } from 'react-i18next';
3 | import PropTypes from 'prop-types';
4 | import { Domain } from '@material-ui/icons';
5 |
6 | import CustomTabs from '../../components/CustomTabs/CustomTabs.js';
7 | import { CustomMaterialTable } from '../../components';
8 |
9 | const FileserverCard = ({ headerColor, fileserver }) => {
10 | const { t } = useTranslation();
11 |
12 | return (
13 |
39 | ),
40 | },
41 | ]}
42 | />
43 | );
44 | };
45 |
46 | FileserverCard.defaultProps = {
47 | headerColor: 'primary',
48 | };
49 |
50 | FileserverCard.propTypes = {
51 | headerColor: PropTypes.oneOf([
52 | 'warning',
53 | 'success',
54 | 'danger',
55 | 'info',
56 | 'primary',
57 | 'rose',
58 | ]),
59 | fileserver: PropTypes.array,
60 | };
61 |
62 | export default FileserverCard;
63 |
--------------------------------------------------------------------------------
/src/components/Card/HealthcheckCard.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import { useTranslation } from 'react-i18next';
4 |
5 | import { Warning, Done, Update, Favorite } from '@material-ui/icons';
6 |
7 | import StatsCard from './StatsCard';
8 |
9 | const HealthcheckCard = (props) => {
10 | const { t } = useTranslation();
11 | const { healthcheck, title, sub_title_success, sub_title_error } = props;
12 |
13 | const sub_title = healthcheck ? sub_title_success : sub_title_error;
14 |
15 | if (typeof healthcheck === 'undefined') {
16 | return (
17 |
26 | );
27 | } else if (!healthcheck) {
28 | return (
29 |
38 | );
39 | } else {
40 | return (
41 |
50 | );
51 | }
52 | };
53 |
54 | HealthcheckCard.defaultProps = {
55 | iconColor: 'purple',
56 | statIconColor: 'gray',
57 | };
58 |
59 | HealthcheckCard.propTypes = {
60 | title: PropTypes.node,
61 | sub_title_success: PropTypes.node,
62 | sub_title_error: PropTypes.node,
63 | };
64 |
65 | export default HealthcheckCard;
66 |
--------------------------------------------------------------------------------
/src/components/Card/LicenseCard.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import { Warning, Done, Update, Accessibility } from '@material-ui/icons';
5 | import StatsCard from './StatsCard';
6 |
7 | const LicenseCard = ({ active, licensed, total }) => {
8 | let ratio = `${active}/${total}`;
9 | let ratio_text = 'Active / Total';
10 |
11 | if (licensed) {
12 | ratio = `${ratio}/${licensed}`;
13 | ratio_text += ' / Licensed';
14 | }
15 |
16 | if (active === '') {
17 | return (
18 |
27 | );
28 | } else if (licensed && active === licensed) {
29 | return (
30 |
39 | );
40 | } else {
41 | return (
42 |
51 | );
52 | }
53 | };
54 |
55 | LicenseCard.defaultProps = {
56 | iconColor: 'purple',
57 | statIconColor: 'gray',
58 | };
59 |
60 | LicenseCard.propTypes = {
61 | active: PropTypes.node,
62 | total: PropTypes.node,
63 | licensed: PropTypes.node,
64 | valid_from: PropTypes.node,
65 | valid_till: PropTypes.node,
66 | };
67 |
68 | export default LicenseCard;
69 |
--------------------------------------------------------------------------------
/src/components/Card/OIDCCard.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { useTranslation } from 'react-i18next';
3 | import PropTypes from 'prop-types';
4 |
5 | import { withStyles } from '@material-ui/core';
6 | import { Group } from '@material-ui/icons';
7 | import Delete from '@material-ui/icons/Delete';
8 |
9 | import CustomTabs from '../../components/CustomTabs/CustomTabs.js';
10 | import { CustomMaterialTable } from '../../components';
11 |
12 | import tasksCardStyle from '../../assets/jss/material-dashboard-react/tasksCardStyle';
13 | import DeleteConfirmDialog from '../Dialog/DeleteConfirmDialog';
14 |
15 | const OIDCCard = ({ oidc_groups, onDeleteOidcGroups }) => {
16 | const { t } = useTranslation();
17 | const [deleteOidcGroups, setDeleteOidcGroups] = useState([]);
18 |
19 | return (
20 | <>
21 | {deleteOidcGroups.length > 0 && (
22 | {
25 | onDeleteOidcGroups(deleteOidcGroups);
26 | setDeleteOidcGroups([]);
27 | }}
28 | onAbort={() => {
29 | setDeleteOidcGroups([]);
30 | }}
31 | >
32 | {t('DELETE_OIDC_GROUP_CONFIRM_DIALOG')}
33 |
34 | )}
35 | {
65 | setDeleteOidcGroups([data]);
66 | },
67 | },
68 | ]}
69 | options={{
70 | pageSize: 10,
71 | }}
72 | />
73 | ),
74 | },
75 | ]}
76 | />
77 | >
78 | );
79 | };
80 |
81 | OIDCCard.propTypes = {
82 | oidc_groups: PropTypes.array,
83 | onDeleteOidcGroups: PropTypes.func.isRequired,
84 | };
85 |
86 | export default OIDCCard;
87 |
--------------------------------------------------------------------------------
/src/components/Card/ProfileCard.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {
3 | withStyles,
4 | Card,
5 | CardHeader,
6 | CardContent,
7 | CardActions,
8 | Typography,
9 | } from '@material-ui/core';
10 | import PropTypes from 'prop-types';
11 |
12 | import profileCardStyle from '../../assets/jss/material-dashboard-react/profileCardStyle';
13 |
14 | const ProfileCard = ({
15 | classes,
16 | subtitle,
17 | title,
18 | description,
19 | footer,
20 | avatar,
21 | }) => {
22 | return (
23 |
24 | }
30 | />
31 |
32 | {subtitle && (
33 |
34 | {subtitle}
35 |
36 | )}
37 | {title && (
38 |
39 | {title}
40 |
41 | )}
42 | {description && (
43 |
47 | {description}
48 |
49 | )}
50 |
51 |
54 | {footer}
55 |
56 |
57 | );
58 | };
59 |
60 | ProfileCard.propTypes = {
61 | classes: PropTypes.object.isRequired,
62 | title: PropTypes.node,
63 | subtitle: PropTypes.node,
64 | description: PropTypes.node,
65 | footer: PropTypes.node,
66 | avatar: PropTypes.string,
67 | };
68 |
69 | export default withStyles(profileCardStyle)(ProfileCard);
70 |
--------------------------------------------------------------------------------
/src/components/Card/RegularCard.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import classNames from 'classnames';
3 | import PropTypes from 'prop-types';
4 | // @material-ui/core components
5 | import withStyles from '@material-ui/core/styles/withStyles';
6 | import Card from '@material-ui/core/Card';
7 | import CardContent from '@material-ui/core/CardContent';
8 | import CardHeader from '@material-ui/core/CardHeader';
9 | import CardActions from '@material-ui/core/CardActions';
10 | // core components
11 | import regularCardStyle from '../../assets/jss/material-dashboard-react/regularCardStyle';
12 |
13 | function RegularCard({ ...props }) {
14 | const {
15 | classes,
16 | headerColor,
17 | plainCard,
18 | cardTitle,
19 | cardSubtitle,
20 | content,
21 | footer
22 | } = props;
23 | const plainCardClasses = classNames({
24 | [' ' + classes.cardPlain]: plainCard
25 | });
26 | const cardPlainHeaderClasses = classNames({
27 | [' ' + classes.cardPlainHeader]: plainCard
28 | });
29 | return (
30 |
31 |
44 | {content}
45 | {footer !== undefined ? (
46 |
47 | {footer}
48 |
49 | ) : null}
50 |
51 | );
52 | }
53 |
54 | RegularCard.defaultProps = {
55 | headerColor: 'purple'
56 | };
57 |
58 | RegularCard.propTypes = {
59 | plainCard: PropTypes.bool,
60 | classes: PropTypes.object.isRequired,
61 | headerColor: PropTypes.oneOf(['orange', 'green', 'red', 'blue', 'purple']),
62 | cardTitle: PropTypes.node,
63 | cardSubtitle: PropTypes.node,
64 | content: PropTypes.node,
65 | footer: PropTypes.node
66 | };
67 |
68 | export default withStyles(regularCardStyle)(RegularCard);
69 |
--------------------------------------------------------------------------------
/src/components/Card/SCIMCard.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { useTranslation } from 'react-i18next';
3 | import PropTypes from 'prop-types';
4 |
5 | import { withStyles } from '@material-ui/core';
6 | import { Group } from '@material-ui/icons';
7 | import Delete from '@material-ui/icons/Delete';
8 |
9 | import CustomTabs from '../../components/CustomTabs/CustomTabs.js';
10 | import { CustomMaterialTable } from '../../components';
11 |
12 | import tasksCardStyle from '../../assets/jss/material-dashboard-react/tasksCardStyle';
13 | import DeleteConfirmDialog from '../Dialog/DeleteConfirmDialog';
14 |
15 | const SCIMCard = ({ scim_groups, onDeleteScimGroups }) => {
16 | const { t } = useTranslation();
17 | const [deleteScimGroups, setDeleteScimGroups] = useState([]);
18 |
19 | return (
20 | <>
21 | {deleteScimGroups.length > 0 && (
22 | {
25 | onDeleteScimGroups(deleteScimGroups);
26 | setDeleteScimGroups([]);
27 | }}
28 | onAbort={() => {
29 | setDeleteScimGroups([]);
30 | }}
31 | >
32 | {t('DELETE_SCIM_GROUP_CONFIRM_DIALOG')}
33 |
34 | )}
35 |
44 | {
63 | setDeleteScimGroups([data]);
64 | },
65 | },
66 | ]}
67 | options={{
68 | pageSize: 10,
69 | }}
70 | />
71 |
72 | ),
73 | },
74 | ]}
75 | />
76 | >
77 | );
78 | };
79 |
80 | SCIMCard.propTypes = {
81 | scim_groups: PropTypes.array,
82 | onDeleteScimGroups: PropTypes.func.isRequired,
83 | };
84 |
85 | export default SCIMCard;
86 |
--------------------------------------------------------------------------------
/src/components/Card/Sessions.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import { Update, Accessibility } from '@material-ui/icons';
4 | import StatsCard from './StatsCard';
5 |
6 | const Sessions = ({ users, devices, total }) => {
7 | if (users === '' || devices === '' || total === '') {
8 | return (
9 |
18 | );
19 | } else {
20 | return (
21 |
29 | );
30 | }
31 | };
32 |
33 | Sessions.defaultProps = {
34 | iconColor: 'purple',
35 | statIconColor: 'gray',
36 | };
37 |
38 | Sessions.propTypes = {
39 | users: PropTypes.node,
40 | devices: PropTypes.node,
41 | total: PropTypes.node,
42 | };
43 |
44 | export default Sessions;
45 |
--------------------------------------------------------------------------------
/src/components/Card/VersionCard.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import { Trans, useTranslation } from 'react-i18next';
4 |
5 | import {
6 | InfoOutlined,
7 | Warning,
8 | Done,
9 | Update,
10 | ThumbUp,
11 | } from '@material-ui/icons';
12 |
13 | import StatsCard from './StatsCard';
14 |
15 | function VersionCard(props) {
16 | const { t } = useTranslation();
17 | const { used_version, latest_version, title } = props;
18 | if (!used_version || !latest_version) {
19 | return (
20 |
29 | );
30 | } else if (used_version === latest_version) {
31 | return (
32 |
40 | );
41 | } else {
42 | return (
43 |
55 | Version {{ latest_version }} available
56 |
57 | }
58 | />
59 | );
60 | }
61 | }
62 |
63 | VersionCard.defaultProps = {
64 | iconColor: 'purple',
65 | statIconColor: 'gray',
66 | };
67 |
68 | VersionCard.propTypes = {
69 | title: PropTypes.node.isRequired,
70 | used_version: PropTypes.node.isRequired,
71 | latest_version: PropTypes.node.isRequired,
72 | };
73 |
74 | export default VersionCard;
75 |
--------------------------------------------------------------------------------
/src/components/CustomButtons/Button.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | // nodejs library that concatenates classes
3 | import classNames from 'classnames';
4 | // nodejs library to set properties for components
5 | import PropTypes from 'prop-types';
6 |
7 | // material-ui components
8 | import { makeStyles } from '@material-ui/core/styles';
9 | import Button from '@material-ui/core/Button';
10 |
11 | import styles from '../../assets/jss/material-dashboard-react/components/buttonStyle.js';
12 |
13 | const useStyles = makeStyles(styles);
14 |
15 | export default function RegularButton(props) {
16 | const classes = useStyles();
17 | const {
18 | color,
19 | round,
20 | children,
21 | disabled,
22 | simple,
23 | size,
24 | block,
25 | link,
26 | justIcon,
27 | className,
28 | muiClasses,
29 | ...rest
30 | } = props;
31 | const btnClasses = classNames({
32 | [classes.button]: true,
33 | [classes[size]]: size,
34 | [classes[color]]: color,
35 | [classes.round]: round,
36 | [classes.disabled]: disabled,
37 | [classes.simple]: simple,
38 | [classes.block]: block,
39 | [classes.link]: link,
40 | [classes.justIcon]: justIcon,
41 | [className]: className
42 | });
43 | return (
44 |
45 | {children}
46 |
47 | );
48 | }
49 |
50 | RegularButton.propTypes = {
51 | color: PropTypes.oneOf([
52 | 'primary',
53 | 'info',
54 | 'success',
55 | 'warning',
56 | 'danger',
57 | 'rose',
58 | 'white',
59 | 'transparent'
60 | ]),
61 | size: PropTypes.oneOf(['sm', 'lg']),
62 | simple: PropTypes.bool,
63 | round: PropTypes.bool,
64 | disabled: PropTypes.bool,
65 | block: PropTypes.bool,
66 | link: PropTypes.bool,
67 | justIcon: PropTypes.bool,
68 | className: PropTypes.string,
69 | // use this to pass the classes props from Material-UI
70 | muiClasses: PropTypes.object,
71 | children: PropTypes.node
72 | };
73 |
--------------------------------------------------------------------------------
/src/components/CustomButtons/IconButton.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { withStyles, IconButton } from '@material-ui/core';
3 | import PropTypes from 'prop-types';
4 |
5 | import iconButtonStyle from '../../assets/jss/material-dashboard-react/iconButtonStyle';
6 |
7 | const IconCustomButton = ({
8 | classes,
9 | color,
10 | children,
11 | customClass,
12 | ...rest
13 | }) => {
14 | return (
15 |
23 | {children}
24 |
25 | );
26 | };
27 |
28 | IconCustomButton.propTypes = {
29 | classes: PropTypes.object.isRequired,
30 | color: PropTypes.oneOf([
31 | 'primary',
32 | 'info',
33 | 'success',
34 | 'warning',
35 | 'danger',
36 | 'rose',
37 | 'white',
38 | 'simple',
39 | ]),
40 | customClass: PropTypes.string,
41 | disabled: PropTypes.bool,
42 | children: PropTypes.node.isRequired,
43 | };
44 |
45 | export default withStyles(iconButtonStyle)(IconCustomButton);
46 |
--------------------------------------------------------------------------------
/src/components/CustomInput/CustomInput.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {
3 | withStyles,
4 | FormControl,
5 | InputLabel,
6 | Input,
7 | FormHelperText,
8 | } from '@material-ui/core';
9 | import { Clear, Check } from '@material-ui/icons';
10 | import PropTypes from 'prop-types';
11 |
12 | import customInputStyle from '../../assets/jss/material-dashboard-react/customInputStyle';
13 |
14 | const CustomInput = ({
15 | classes,
16 | formControlProps,
17 | helperText,
18 | labelText,
19 | id,
20 | labelProps,
21 | inputProps,
22 | error,
23 | success,
24 | }) => {
25 | return (
26 |
31 | {labelText !== undefined ? (
32 |
45 | {labelText}
46 |
47 | ) : null}
48 |
62 | {helperText && {helperText} }
63 | {error ? (
64 |
67 | ) : success ? (
68 |
71 | ) : null}
72 |
73 | );
74 | };
75 |
76 | CustomInput.propTypes = {
77 | classes: PropTypes.object.isRequired,
78 | helperText: PropTypes.node,
79 | labelText: PropTypes.node,
80 | labelProps: PropTypes.object,
81 | id: PropTypes.string,
82 | inputProps: PropTypes.object,
83 | formControlProps: PropTypes.object,
84 | error: PropTypes.bool,
85 | success: PropTypes.bool,
86 | };
87 |
88 | export default withStyles(customInputStyle)(CustomInput);
89 |
--------------------------------------------------------------------------------
/src/components/Dialog/DeleteConfirmDialog.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { useTranslation } from 'react-i18next';
3 | import Button from '@material-ui/core/Button';
4 | import Dialog from '@material-ui/core/Dialog';
5 | import DialogActions from '@material-ui/core/DialogActions';
6 | import DialogContent from '@material-ui/core/DialogContent';
7 | import DialogContentText from '@material-ui/core/DialogContentText';
8 | import DialogTitle from '@material-ui/core/DialogTitle';
9 | import PropTypes from 'prop-types';
10 |
11 | const DeleteConfirmDialog = ({ title, children, onConfirm, onAbort }) => {
12 | const { t } = useTranslation();
13 | const [open, setOpen] = useState(true);
14 |
15 | const handleAbort = () => {
16 | setOpen(false);
17 | onAbort();
18 | };
19 |
20 | const handleConfirm = () => {
21 | setOpen(false);
22 | onConfirm();
23 | };
24 |
25 | return (
26 |
32 | {title}
33 |
34 |
35 | {children}
36 |
37 |
38 |
39 |
40 | {t('ABORT')}
41 |
42 |
43 | {t('CONFIRM')}
44 |
45 |
46 |
47 | );
48 | };
49 |
50 | DeleteConfirmDialog.propTypes = {
51 | title: PropTypes.string,
52 | onConfirm: PropTypes.func.isRequired,
53 | onAbort: PropTypes.func.isRequired,
54 | children: PropTypes.node,
55 | };
56 |
57 | export default DeleteConfirmDialog;
58 |
--------------------------------------------------------------------------------
/src/components/Footer/Footer.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import { List, ListItem, withStyles } from '@material-ui/core';
4 |
5 | import footerStyle from '../../assets/jss/material-dashboard-react/footerStyle';
6 |
7 | const Footer = ({ classes }) => {
8 | return (
9 |
50 | );
51 | };
52 |
53 | Footer.propTypes = {
54 | classes: PropTypes.object.isRequired,
55 | };
56 |
57 | export default withStyles(footerStyle)(Footer);
58 |
--------------------------------------------------------------------------------
/src/components/Grid/GridItem.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { withStyles, Grid } from '@material-ui/core';
3 |
4 | const style = {
5 | grid: {
6 | padding: '0 15px !important',
7 | },
8 | };
9 |
10 | const GridItem = ({ classes, children, ...rest }) => {
11 | return (
12 |
13 | {children}
14 |
15 | );
16 | };
17 |
18 | export default withStyles(style)(GridItem);
19 |
--------------------------------------------------------------------------------
/src/components/Header/Header.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { matchPath, useLocation } from 'react-router-dom';
3 | import PropTypes from 'prop-types';
4 | import { Menu } from '@material-ui/icons';
5 | import {
6 | withStyles,
7 | AppBar,
8 | Toolbar,
9 | IconButton,
10 | Hidden,
11 | Button,
12 | } from '@material-ui/core';
13 | import { withTranslation } from 'react-i18next';
14 | import { compose } from 'redux';
15 |
16 | import headerStyle from '../../assets/jss/material-dashboard-react/headerStyle';
17 | import user from '../../services/user';
18 |
19 | import HeaderLinks from './HeaderLinks';
20 |
21 | const Header = (props) => {
22 | let location = useLocation();
23 | const makeBrand = () => {
24 | for (let i = 0; i < props.routes.length; i++) {
25 | if (matchPath(location.pathname, props.routes[i].path) !== null) {
26 | return props.t(props.routes[i].navbarName);
27 | }
28 | }
29 | return null;
30 | };
31 |
32 | const { classes, color, ...rest } = props;
33 |
34 | return (
35 |
41 |
42 |
43 | {/* Here we create navbar brand, based on route name */}
44 |
45 | {makeBrand()}
46 |
47 |
48 |
49 |
50 |
51 |
52 |
58 |
59 |
60 |
61 |
62 |
63 | );
64 | };
65 |
66 | Header.propTypes = {
67 | classes: PropTypes.object.isRequired,
68 | theme: PropTypes.object.isRequired,
69 | color: PropTypes.oneOf(['primary', 'info', 'success', 'warning', 'danger']),
70 | };
71 |
72 | export default compose(
73 | withTranslation(),
74 | withStyles(headerStyle, { withTheme: true })
75 | )(Header);
76 |
--------------------------------------------------------------------------------
/src/components/Notification/Notification.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import AddAlert from '@material-ui/icons/AddAlert';
3 | import { useSelector } from 'react-redux';
4 |
5 | import notification from '../../services/notification';
6 |
7 | import { Snackbar } from '../index';
8 | import { useTranslation } from 'react-i18next';
9 |
10 | export default function Notification(props) {
11 | const { t } = useTranslation();
12 |
13 | const messages = useSelector(state => state.notification.messages);
14 |
15 | return messages.map((message, index) => {
16 | let icon;
17 | let color;
18 | if (message.type === 'info') {
19 | icon = AddAlert;
20 | color = 'info';
21 | } else if (message.type === 'danger') {
22 | icon = AddAlert;
23 | color = 'danger';
24 | } else {
25 | console.log(message);
26 | // TODO add other notification types
27 | }
28 |
29 | return (
30 | {
38 | const new_messages = messages;
39 | new_messages.splice(index, 1);
40 | notification.set(new_messages);
41 | }}
42 | close
43 | />
44 | );
45 | }, this);
46 | }
47 |
--------------------------------------------------------------------------------
/src/components/Snackbar/Snackbar.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { withStyles, Snackbar as Snack, IconButton } from '@material-ui/core';
3 | import { Close } from '@material-ui/icons';
4 | import PropTypes from 'prop-types';
5 |
6 | import snackbarContentStyle from '../../assets/jss/material-dashboard-react/snackbarContentStyle';
7 |
8 | const Snackbar = ({
9 | classes,
10 | message,
11 | color,
12 | close,
13 | icon: Icon,
14 | place,
15 | open,
16 | closeNotification,
17 | }) => {
18 | const action = close
19 | ? [
20 |
27 |
28 | ,
29 | ]
30 | : [];
31 |
32 | return (
33 |
46 | {Icon ? : null}
47 |
48 | {message}
49 |
50 |
51 | }
52 | action={action}
53 | ContentProps={{
54 | classes: {
55 | root: `${classes.root} ${classes[color]}`,
56 | message: classes.message,
57 | },
58 | }}
59 | />
60 | );
61 | };
62 |
63 | Snackbar.propTypes = {
64 | classes: PropTypes.object.isRequired,
65 | message: PropTypes.node.isRequired,
66 | color: PropTypes.oneOf([
67 | 'warning',
68 | 'success',
69 | 'danger',
70 | 'info',
71 | 'primary',
72 | 'rose',
73 | ]),
74 | close: PropTypes.bool,
75 | icon: PropTypes.elementType,
76 | place: PropTypes.oneOf(['tl', 'tr', 'tc', 'br', 'bl', 'bc']),
77 | open: PropTypes.bool,
78 | closeNotification: PropTypes.func,
79 | };
80 |
81 | export default withStyles(snackbarContentStyle)(Snackbar);
82 |
--------------------------------------------------------------------------------
/src/components/Snackbar/SnackbarContent.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {
3 | withStyles,
4 | SnackbarContent as Snack,
5 | IconButton,
6 | } from '@material-ui/core';
7 | import { Close } from '@material-ui/icons';
8 | import PropTypes from 'prop-types';
9 |
10 | import snackbarContentStyle from '../../assets/jss/material-dashboard-react/snackbarContentStyle';
11 |
12 | const SnackbarContent = ({ classes, message, color, close, icon: Icon }) => {
13 | const action = [];
14 | if (close !== undefined) {
15 | action.push(
16 |
22 |
23 |
24 | );
25 | }
26 |
27 | return (
28 |
31 | {Icon !== undefined ? (
32 |
33 | ) : null}
34 |
39 | {message}
40 |
41 |
42 | }
43 | classes={{
44 | root: `${classes.root} ${classes[color]}`,
45 | message: classes.message,
46 | }}
47 | action={action}
48 | />
49 | );
50 | };
51 |
52 | SnackbarContent.propTypes = {
53 | classes: PropTypes.object.isRequired,
54 | message: PropTypes.node.isRequired,
55 | color: PropTypes.oneOf(['info', 'success', 'warning', 'danger', 'primary']),
56 | close: PropTypes.bool,
57 | icon: PropTypes.elementType,
58 | };
59 |
60 | export default withStyles(snackbarContentStyle)(SnackbarContent);
61 |
--------------------------------------------------------------------------------
/src/components/Table/Table.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {
3 | withStyles,
4 | Table,
5 | TableHead,
6 | TableRow,
7 | TableBody,
8 | TableCell,
9 | } from '@material-ui/core';
10 | import PropTypes from 'prop-types';
11 |
12 | import tableStyle from '../../assets/jss/material-dashboard-react/tableStyle';
13 |
14 | const CustomTable = ({ classes, tableHead, tableData, tableHeaderColor }) => {
15 | return (
16 |
17 |
18 | {tableHead !== undefined ? (
19 |
22 |
23 | {tableHead.map((prop, key) => (
24 |
28 | {prop}
29 |
30 | ))}
31 |
32 |
33 | ) : null}
34 |
35 | {tableData.map((row, key) => (
36 |
37 | {row.map((cell, cellKey) => (
38 |
42 | {cell}
43 |
44 | ))}
45 |
46 | ))}
47 |
48 |
49 |
50 | );
51 | };
52 |
53 | CustomTable.defaultProps = {
54 | tableHeaderColor: 'gray',
55 | };
56 |
57 | CustomTable.propTypes = {
58 | classes: PropTypes.object.isRequired,
59 | tableHeaderColor: PropTypes.oneOf([
60 | 'warning',
61 | 'primary',
62 | 'danger',
63 | 'success',
64 | 'info',
65 | 'rose',
66 | 'gray',
67 | ]),
68 | tableHead: PropTypes.arrayOf(PropTypes.string),
69 | tableData: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.string)),
70 | };
71 |
72 | export default withStyles(tableStyle)(CustomTable);
73 |
--------------------------------------------------------------------------------
/src/components/Typography/A.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { withStyles } from '@material-ui/core';
3 | import PropTypes from 'prop-types';
4 |
5 | import typographyStyle from '../../assets/jss/material-dashboard-react/typographyStyle';
6 |
7 | const A = ({ classes, children, ...rest }) => {
8 | return (
9 |
13 | {children}
14 |
15 | );
16 | };
17 |
18 | A.propTypes = {
19 | classes: PropTypes.object.isRequired,
20 | children: PropTypes.node.isRequired,
21 | };
22 |
23 | export default withStyles(typographyStyle)(A);
24 |
--------------------------------------------------------------------------------
/src/components/Typography/Danger.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import { withStyles } from '@material-ui/core';
4 |
5 | import typographyStyle from '../../assets/jss/material-dashboard-react/typographyStyle';
6 |
7 | const Danger = ({ classes, children }) => {
8 | return (
9 |
10 | {children}
11 |
12 | );
13 | };
14 |
15 | Danger.propTypes = {
16 | classes: PropTypes.object.isRequired,
17 | children: PropTypes.node.isRequired,
18 | };
19 |
20 | export default withStyles(typographyStyle)(Danger);
21 |
--------------------------------------------------------------------------------
/src/components/Typography/Info.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import { withStyles } from '@material-ui/core';
4 |
5 | import typographyStyle from '../../assets/jss/material-dashboard-react/typographyStyle';
6 |
7 | const Info = ({ classes, children }) => {
8 | return (
9 |
10 | {children}
11 |
12 | );
13 | };
14 |
15 | Info.propTypes = {
16 | classes: PropTypes.object.isRequired,
17 | children: PropTypes.node.isRequired,
18 | };
19 |
20 | export default withStyles(typographyStyle)(Info);
21 |
--------------------------------------------------------------------------------
/src/components/Typography/Muted.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import { withStyles } from '@material-ui/core';
4 |
5 | import typographyStyle from '../../assets/jss/material-dashboard-react/typographyStyle';
6 |
7 | const Muted = ({ classes, children }) => {
8 | return (
9 |
10 | {children}
11 |
12 | );
13 | };
14 |
15 | Muted.propTypes = {
16 | classes: PropTypes.object.isRequired,
17 | children: PropTypes.node.isRequired,
18 | };
19 |
20 | export default withStyles(typographyStyle)(Muted);
21 |
--------------------------------------------------------------------------------
/src/components/Typography/P.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { withStyles } from '@material-ui/core';
3 | import PropTypes from 'prop-types';
4 |
5 | import typographyStyle from '../../assets/jss/material-dashboard-react/typographyStyle';
6 |
7 | const P = ({ classes, children }) => {
8 | return (
9 |
10 | {children}
11 |
12 | );
13 | };
14 |
15 | P.propTypes = {
16 | classes: PropTypes.object.isRequired,
17 | children: PropTypes.node.isRequired,
18 | };
19 |
20 | export default withStyles(typographyStyle)(P);
21 |
--------------------------------------------------------------------------------
/src/components/Typography/Primary.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import { withStyles } from '@material-ui/core';
4 |
5 | import typographyStyle from '../../assets/jss/material-dashboard-react/typographyStyle';
6 |
7 | const Primary = ({ classes, children }) => {
8 | return (
9 |
10 | {children}
11 |
12 | );
13 | };
14 |
15 | Primary.propTypes = {
16 | classes: PropTypes.object.isRequired,
17 | children: PropTypes.node.isRequired,
18 | };
19 |
20 | export default withStyles(typographyStyle)(Primary);
21 |
--------------------------------------------------------------------------------
/src/components/Typography/Quote.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { withStyles } from '@material-ui/core';
3 | import PropTypes from 'prop-types';
4 |
5 | import typographyStyle from '../../assets/jss/material-dashboard-react/typographyStyle';
6 |
7 | const Quote = ({ classes, text, author }) => {
8 | return (
9 |
10 | {text}
11 | {author}
12 |
13 | );
14 | };
15 |
16 | Quote.propTypes = {
17 | classes: PropTypes.object.isRequired,
18 | text: PropTypes.node,
19 | author: PropTypes.node,
20 | };
21 |
22 | export default withStyles(typographyStyle)(Quote);
23 |
--------------------------------------------------------------------------------
/src/components/Typography/Small.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import { withStyles } from '@material-ui/core';
4 |
5 | import typographyStyle from '../../assets/jss/material-dashboard-react/typographyStyle';
6 |
7 | const Small = ({ classes, children }) => {
8 | return (
9 |
10 | {children}
11 |
12 | );
13 | };
14 |
15 | Small.propTypes = {
16 | classes: PropTypes.object.isRequired,
17 | children: PropTypes.node.isRequired,
18 | };
19 |
20 | export default withStyles(typographyStyle)(Small);
21 |
--------------------------------------------------------------------------------
/src/components/Typography/Success.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import { withStyles } from '@material-ui/core';
4 |
5 | import typographyStyle from '../../assets/jss/material-dashboard-react/typographyStyle';
6 |
7 | const Success = ({ classes, children }) => {
8 | return (
9 |
10 | {children}
11 |
12 | );
13 | };
14 |
15 | Success.propTypes = {
16 | classes: PropTypes.object.isRequired,
17 | children: PropTypes.node.isRequired,
18 | };
19 |
20 | export default withStyles(typographyStyle)(Success);
21 |
--------------------------------------------------------------------------------
/src/components/Typography/Warning.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import { withStyles } from '@material-ui/core';
4 |
5 | import typographyStyle from '../../assets/jss/material-dashboard-react/typographyStyle';
6 |
7 | const Warning = ({ classes, children }) => {
8 | return (
9 |
10 | {children}
11 |
12 | );
13 | };
14 |
15 | Warning.propTypes = {
16 | classes: PropTypes.object.isRequired,
17 | children: PropTypes.node.isRequired,
18 | };
19 |
20 | export default withStyles(typographyStyle)(Warning);
21 |
--------------------------------------------------------------------------------
/src/containers/App.js:
--------------------------------------------------------------------------------
1 | import React, { Suspense } from 'react';
2 | import { persistStore } from 'redux-persist';
3 | import { PersistGate } from 'redux-persist/integration/react';
4 | import { HashLoader } from 'react-spinners';
5 | import { createBrowserHistory } from 'history';
6 | import { withStyles } from '@material-ui/core';
7 | import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
8 |
9 | import store from '../services/store';
10 |
11 | import 'chartist/dist/chartist.min.css';
12 | import 'chartist/dist/chartist.min.js';
13 | import 'chartist-plugin-axistitle/dist/chartist-plugin-axistitle.min.js';
14 | import 'font-awesome/css/font-awesome.min.css';
15 |
16 | import 'clientjs/dist/client.min.js';
17 | import '../assets/css/material-dashboard-react.css';
18 | import Index from '../containers/Index/Index';
19 | import Login from '../containers/Login/Login';
20 | import logo from '../assets/img/logo.png';
21 | import image from '../assets/img/background.jpg';
22 |
23 | const hist = createBrowserHistory({
24 | basename: '/portal',
25 | });
26 |
27 | let persistor = persistStore(store);
28 |
29 | const style = {
30 | wrapper: {
31 | position: 'relative',
32 | top: '0',
33 | height: '100vh',
34 | backgroundImage: `url(${image})`,
35 | backgroundSize: 'cover',
36 | display: 'flex',
37 | justifyContent: 'center',
38 | alignItems: 'center',
39 | },
40 | content: {
41 | width: '100%',
42 | height: '100%',
43 | zIndex: '3',
44 | content: '',
45 | opacity: '.8',
46 | position: 'absolute',
47 | background: '#000',
48 | },
49 | };
50 |
51 | const Loader = ({ classes }) => (
52 |
53 |
54 |
55 |
loading...
56 |
57 | );
58 |
59 | const StyledLoader = withStyles(style)(Loader);
60 |
61 | const App = () => (
62 | }>
63 | } persistor={persistor}>
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 | );
83 |
84 | export default App;
85 |
--------------------------------------------------------------------------------
/src/containers/Index/SwitchRoutes.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {
3 | Switch,
4 | Route,
5 | Redirect,
6 | matchPath,
7 | useLocation,
8 | } from 'react-router-dom';
9 | import sidebarRoutes from '../../routes/sidebar';
10 | import eeRoutes from '../../routes/ee';
11 | import ldapRoutes from '../../routes/ldap';
12 | import samlRoutes from '../../routes/saml';
13 | import oidcRoutes from '../../routes/oidc';
14 | import otherRoutes from '../../routes/other';
15 |
16 | const SwitchRoutes = (props) => {
17 | let location = useLocation();
18 | const { actions, state, store, ...rest } = props;
19 |
20 | let variableLinks = [];
21 | if (state.server.type === 'EE') {
22 | eeRoutes.forEach(function (route) {
23 | variableLinks.push(route);
24 | });
25 | }
26 | if (
27 | state.server.type === 'EE' &&
28 | state.server.authentication_methods.indexOf('LDAP') !== -1
29 | ) {
30 | ldapRoutes.forEach(function (route) {
31 | variableLinks.push(route);
32 | });
33 | }
34 | if (
35 | state.server.type === 'EE' &&
36 | state.server.authentication_methods.indexOf('SAML') !== -1
37 | ) {
38 | samlRoutes.forEach(function (route) {
39 | variableLinks.push(route);
40 | });
41 | }
42 | if (
43 | state.server.type === 'EE' &&
44 | state.server.authentication_methods.indexOf('OIDC') !== -1
45 | ) {
46 | oidcRoutes.forEach(function (route) {
47 | variableLinks.push(route);
48 | });
49 | }
50 |
51 | const routes = otherRoutes.concat(variableLinks, sidebarRoutes);
52 |
53 | let match = null;
54 | for (let i = 0; i < routes.length; i++) {
55 | match = matchPath(location.pathname, routes[i].path);
56 | if (match !== null) {
57 | break;
58 | }
59 | }
60 |
61 | return (
62 |
63 | {routes.map((prop, key) => {
64 | if (prop.redirect)
65 | return (
66 |
72 | );
73 | return (
74 | (
77 |
83 | )}
84 | key={key}
85 | {...rest}
86 | />
87 | );
88 | })}
89 |
90 | );
91 | };
92 |
93 | export default SwitchRoutes;
94 |
--------------------------------------------------------------------------------
/src/containers/Login/Login.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { connect } from 'react-redux';
3 | import { bindActionCreators, compose } from 'redux';
4 | import { withStyles } from '@material-ui/core';
5 | import PropTypes from 'prop-types';
6 |
7 | import { LoginForm, Notification } from '../../components';
8 | import actionCreators from '../../actions/actionCreators';
9 | import user from '../../services/user';
10 | import host from '../../services/host';
11 | import browserClient from '../../services/browser-client';
12 |
13 | import image from '../../assets/img/background.jpg';
14 | import store from '../../services/store';
15 | import { Redirect } from 'react-router-dom';
16 |
17 | const style = {
18 | wrapper: {
19 | position: 'relative',
20 | top: '0',
21 | height: '100vh',
22 | backgroundImage: `url(${image})`,
23 | backgroundSize: 'cover',
24 | display: 'flex',
25 | justifyContent: 'center',
26 | alignItems: 'center',
27 | },
28 | content: {
29 | width: '100%',
30 | height: '100%',
31 | zIndex: '3',
32 | content: '',
33 | opacity: '.8',
34 | position: 'absolute',
35 | background: '#000',
36 | },
37 | };
38 |
39 | const Login = ({ classes, ...rest }) => {
40 | if (store.getState().user.isLoggedIn) {
41 | return ;
42 | }
43 |
44 | return (
45 |
68 | );
69 | };
70 |
71 | Login.propTypes = {
72 | classes: PropTypes.object.isRequired,
73 | };
74 |
75 | function mapStateToProps(state) {
76 | return { state: state };
77 | }
78 |
79 | function mapDispatchToProps(dispatch) {
80 | return { actions: bindActionCreators(actionCreators, dispatch) };
81 | }
82 |
83 | export default compose(
84 | withStyles(style),
85 | connect(mapStateToProps, mapDispatchToProps)
86 | )(Login);
87 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import { I18nextProvider } from 'react-i18next';
4 | import { Provider } from 'react-redux';
5 | import CssBaseline from '@material-ui/core/CssBaseline';
6 | import 'moment-timezone';
7 |
8 | import i18n from './i18n';
9 |
10 | import App from './containers/App';
11 | import worker from './services/worker';
12 | import store from './services/store';
13 |
14 | /**
15 | * @typedef {Object} PublicPrivateKeyPair
16 | * @property {string} public_key The public key (hex encoded)
17 | * @property {string} private_key The private key (hex encoded)
18 | *
19 | * @typedef {Object} EncryptedValue
20 | * @property {string} text The public key (hex encoded)
21 | * @property {string} nonce The private key (hex encoded)
22 | *
23 | * @typedef {string} uuid
24 | *
25 | * @typedef {Object} SplittedUrl
26 | * @property {string} scheme The scheme e.g. 'http' or 'ftps'
27 | * @property {string} authority The scheme e.g. 'test.example.com:6000'
28 | * @property {string} full_domain The full domain e.g. 'test.example.com'
29 | * @property {string} top_domain The top level domain e.g. 'example.com'
30 | * @property {string} port The port e.g. '6000'
31 | * @property {string} port The path e.g. '/url-part/'
32 | * @property {string} port The query, evething after '?' e.g. 'myFunnyParameter=test'
33 | * @property {string} port The query, evething after '#' e.g. 'anotherParameter=test'
34 | *
35 | * @typedef {Object} TreeObject
36 | * @property {uuid} [datastore_id] The datastore id if its the top
37 | * @property {uuid} [parent_datastore_id] The parent datastore id
38 | * @property {uuid} [parent_share_id] The parent share id
39 | * @property {object} [share_rights] All the share rights in an object
40 | * @property {boolean} [expanded] Is the folder expanded or not
41 | * @property {Array} [items] The items in the tree object
42 | * @property {Array} [folders] The folders in the tree object containing other TreeObject
43 | * @property {Object} [share_index] The share index
44 | *
45 | * @typedef {Object} RightObject
46 | * @property {boolean} read The read rights
47 | * @property {boolean} write The write rights
48 | * @property {boolean} grant The grant rights
49 | * @property {boolean} [delete] The delete rights
50 | *
51 | */
52 |
53 | import './assets/css/material-dashboard-react.css';
54 |
55 | ReactDOM.render(
56 |
57 |
58 |
59 |
60 |
61 | ,
62 | document.getElementById('root')
63 | );
64 | worker.register();
65 |
--------------------------------------------------------------------------------
/src/reducers/admin_client.js:
--------------------------------------------------------------------------------
1 | import { LOGOUT, SET_ADMIN_CLIENT_CONFIG } from '../actions/actionTypes';
2 |
3 | const default_config = {};
4 |
5 | function server(
6 | state = {
7 | config: default_config
8 | },
9 | action
10 | ) {
11 | switch (action.type) {
12 | case LOGOUT:
13 | return Object.assign({}, state, {
14 | config: default_config
15 | });
16 | case SET_ADMIN_CLIENT_CONFIG:
17 | return Object.assign({}, state, {
18 | config: action.config
19 | });
20 | default:
21 | return state;
22 | }
23 | }
24 |
25 | export default server;
26 |
--------------------------------------------------------------------------------
/src/reducers/client.js:
--------------------------------------------------------------------------------
1 | import { LOGOUT, SET_CLIENT_URL } from '../actions/actionTypes';
2 |
3 | const default_url = '';
4 |
5 | function server(
6 | state = {
7 | url: default_url,
8 | },
9 | action
10 | ) {
11 | switch (action.type) {
12 | case LOGOUT:
13 | return Object.assign({}, state, {
14 | url: default_url.toLowerCase(),
15 | });
16 | case SET_CLIENT_URL:
17 | return Object.assign({}, state, {
18 | url: action.url.toLowerCase(),
19 | });
20 | default:
21 | return state;
22 | }
23 | }
24 |
25 | export default server;
26 |
--------------------------------------------------------------------------------
/src/reducers/index.js:
--------------------------------------------------------------------------------
1 | import { combineReducers } from 'redux';
2 | import persistent from './persistent';
3 | import admin_client from './admin_client';
4 | import user from './user';
5 | import server from './server';
6 | import client from './client';
7 | import notification from './notification';
8 |
9 | const rootReducer = combineReducers({
10 | persistent,
11 | admin_client,
12 | user,
13 | server,
14 | client,
15 | notification,
16 | });
17 |
18 | export default rootReducer;
19 |
--------------------------------------------------------------------------------
/src/reducers/notification.js:
--------------------------------------------------------------------------------
1 | import { NOTIFICATION_SEND, NOTIFICATION_SET } from '../actions/actionTypes';
2 |
3 | function notification(
4 | state = {
5 | messages: [],
6 | },
7 | action
8 | ) {
9 | switch (action.type) {
10 | case NOTIFICATION_SEND:
11 | const new_messages = state.messages;
12 | new_messages.push({
13 | text: action.message,
14 | type: action.message_type,
15 | });
16 |
17 | return Object.assign({}, state, {
18 | messages: new_messages,
19 | });
20 | case NOTIFICATION_SET:
21 | return Object.assign({}, state, {
22 | messages: action.messages,
23 | });
24 | default:
25 | return state;
26 | }
27 | }
28 |
29 | export default notification;
30 |
--------------------------------------------------------------------------------
/src/reducers/persistent.js:
--------------------------------------------------------------------------------
1 | import { SET_KNOWN_HOSTS } from '../actions/actionTypes';
2 |
3 | const default_known_hosts = [
4 | {
5 | url: 'https://www.psono.pw/server',
6 | verify_key:
7 | 'a16301bd25e3a445a83b279e7091ea91d085901933f310fdb1b137db9676de59',
8 | },
9 | ];
10 |
11 | function persistent(
12 | state = {
13 | known_hosts: default_known_hosts,
14 | },
15 | action
16 | ) {
17 | switch (action.type) {
18 | case SET_KNOWN_HOSTS:
19 | return Object.assign({}, state, {
20 | known_hosts: action.known_hosts,
21 | });
22 | default:
23 | return state;
24 | }
25 | }
26 |
27 | export default persistent;
28 |
--------------------------------------------------------------------------------
/src/reducers/user.js:
--------------------------------------------------------------------------------
1 | import {
2 | SET_USER_USERNAME,
3 | SET_USER_INFO_1,
4 | SET_USER_INFO_2,
5 | SET_USER_INFO_3,
6 | SET_SERVER_SECRET_EXISTS,
7 | LOGOUT,
8 | } from '../actions/actionTypes';
9 |
10 | const default_username = '';
11 | const default_remember_me = false;
12 | const default_trust_device = false;
13 |
14 | function user(
15 | state = {
16 | isLoggedIn: false,
17 | username: default_username,
18 | remember_me: default_remember_me,
19 | trust_device: default_trust_device,
20 | authentication: '',
21 | user_secret_key: '',
22 | serverSecretExists: false,
23 | user_private_key: '',
24 | user_public_key: '',
25 | session_secret_key: '',
26 | token: '',
27 | user_sauce: '',
28 | user_email: '',
29 | user_id: '',
30 | },
31 | action
32 | ) {
33 | switch (action.type) {
34 | case SET_USER_USERNAME:
35 | return Object.assign({}, state, {
36 | username: action.username,
37 | });
38 | case SET_USER_INFO_1:
39 | return Object.assign({}, state, {
40 | remember_me: action.remember_me,
41 | trust_device: action.trust_device,
42 | authentication: action.authentication,
43 | });
44 | case SET_USER_INFO_2:
45 | return Object.assign({}, state, {
46 | user_private_key: action.user_private_key,
47 | user_public_key: action.user_public_key,
48 | session_secret_key: action.session_secret_key,
49 | token: action.token,
50 | user_sauce: action.user_sauce,
51 | authentication: action.authentication,
52 | });
53 | case SET_USER_INFO_3:
54 | return Object.assign({}, state, {
55 | isLoggedIn: true,
56 | user_id: action.user_id,
57 | user_email: action.user_email,
58 | user_secret_key: action.user_secret_key,
59 | serverSecretExists: action.serverSecretExists,
60 | });
61 | case SET_SERVER_SECRET_EXISTS:
62 | return Object.assign({}, state, {
63 | serverSecretExists: action.serverSecretExists,
64 | });
65 | case LOGOUT:
66 | return Object.assign({}, state, {
67 | isLoggedIn: false,
68 | username: state.remember_me ? state.username : default_username,
69 | remember_me: state.remember_me
70 | ? state.remember_me
71 | : default_remember_me,
72 | trust_device: state.remember_me
73 | ? state.trust_device
74 | : default_trust_device,
75 | authentication: '',
76 | user_secret_key: '',
77 | serverSecretExists: false,
78 | user_private_key: '',
79 | user_email: '',
80 | user_id: '',
81 | user_public_key: '',
82 | session_secret_key: '',
83 | token: '',
84 | user_sauce: '',
85 | });
86 | default:
87 | return state;
88 | }
89 | }
90 |
91 | export default user;
92 |
--------------------------------------------------------------------------------
/src/routes/ee.js:
--------------------------------------------------------------------------------
1 | import { Policy } from '@material-ui/icons';
2 |
3 | import Policies from '../views/Policies/Index';
4 |
5 | let routes = [
6 | {
7 | path: '/policies',
8 | sidebarName: 'POLICIES',
9 | navbarName: 'POLICIES',
10 | icon: Policy,
11 | component: Policies,
12 | },
13 | ];
14 |
15 | export default routes;
16 |
--------------------------------------------------------------------------------
/src/routes/ldap.js:
--------------------------------------------------------------------------------
1 | import LDAP from '../views/LDAP/Index';
2 |
3 | import { Business } from '@material-ui/icons';
4 |
5 | let routes = [
6 | {
7 | path: '/ldap',
8 | sidebarName: 'LDAP',
9 | navbarName: 'LDAP',
10 | icon: Business,
11 | component: LDAP,
12 | },
13 | ];
14 |
15 | export default routes;
16 |
--------------------------------------------------------------------------------
/src/routes/oidc.js:
--------------------------------------------------------------------------------
1 | import OIDC from '../views/OIDC/Index';
2 |
3 | import { Business } from '@material-ui/icons';
4 |
5 | let routes = [
6 | {
7 | path: '/oidc',
8 | sidebarName: 'OIDC',
9 | navbarName: 'OIDC',
10 | icon: Business,
11 | component: OIDC,
12 | },
13 | ];
14 |
15 | export default routes;
16 |
--------------------------------------------------------------------------------
/src/routes/other.js:
--------------------------------------------------------------------------------
1 | import SecurityReportEdit from '../views/SecurityReport/Edit';
2 | import UserEdit from '../views/User/Edit';
3 | import GroupEdit from '../views/Group/Edit';
4 | import GroupCreate from '../views/Group/Create';
5 | import GroupShareRightCreate from '../views/Group/ShareRightCreate';
6 | import PolicyCreate from '../views/Policies/Create';
7 | import PolicyEdit from '../views/Policies/Edit';
8 | import UserCreate from '../views/User/Create';
9 |
10 | import { Person, Group, Policy, Timeline } from '@material-ui/icons';
11 |
12 | let routes = [
13 | {
14 | path: '/user/:user_id',
15 | sidebarName: 'USER',
16 | navbarName: 'USER',
17 | icon: Person,
18 | component: UserEdit,
19 | },
20 | {
21 | path: '/security-report/:security_report_id',
22 | sidebarName: 'SECURITY_REPORT',
23 | navbarName: 'SECURITY_REPORT',
24 | icon: Timeline,
25 | component: SecurityReportEdit,
26 | },
27 | {
28 | path: '/policy/:policy_id',
29 | sidebarName: 'POLICY',
30 | navbarName: 'POLICY',
31 | icon: Policy,
32 | component: PolicyEdit,
33 | },
34 | {
35 | path: '/group/:group_id/create-share-right',
36 | sidebarName: 'CREATE_SHARE_RIGHT',
37 | navbarName: 'CREATE_SHARE_RIGHT',
38 | icon: Group,
39 | component: GroupShareRightCreate,
40 | },
41 | {
42 | path: '/group/:group_id',
43 | sidebarName: 'GROUP',
44 | navbarName: 'GROUP',
45 | icon: Group,
46 | component: GroupEdit,
47 | },
48 | {
49 | path: '/policies/create',
50 | sidebarName: 'CREATE_POLICY',
51 | navbarName: 'CREATE_POLICY',
52 | icon: Policy,
53 | component: PolicyCreate,
54 | },
55 | {
56 | path: '/groups/create',
57 | sidebarName: 'CREATE_GROUP',
58 | navbarName: 'CREATE_GROUP',
59 | icon: Group,
60 | component: GroupCreate,
61 | },
62 | {
63 | path: '/users/create',
64 | sidebarName: 'CREATE_USER',
65 | navbarName: 'CREATE_USER',
66 | icon: Person,
67 | component: UserCreate,
68 | },
69 | ];
70 |
71 | export default routes;
72 |
--------------------------------------------------------------------------------
/src/routes/saml.js:
--------------------------------------------------------------------------------
1 | import SAML from '../views/SAML/Index';
2 | import SCIM from '../views/SCIM/Index';
3 |
4 | import { Business } from '@material-ui/icons';
5 |
6 | let routes = [
7 | {
8 | path: '/saml',
9 | sidebarName: 'SAML',
10 | navbarName: 'SAML',
11 | icon: Business,
12 | component: SAML,
13 | },
14 | {
15 | path: '/scim',
16 | sidebarName: 'SCIM',
17 | navbarName: 'SCIM',
18 | icon: Business,
19 | component: SCIM,
20 | },
21 | ];
22 |
23 | export default routes;
24 |
--------------------------------------------------------------------------------
/src/routes/sidebar.js:
--------------------------------------------------------------------------------
1 | import DashboardPage from '../views/Dashboard/Index';
2 | import Users from '../views/Users/Index';
3 | import Groups from '../views/Groups/Index';
4 | import SecurityReports from '../views/SecurityReports/Index';
5 |
6 | import { Dashboard, Person, Timeline, Group } from '@material-ui/icons';
7 |
8 | let routes = [
9 | {
10 | path: '/dashboard',
11 | sidebarName: 'DASHBOARD',
12 | navbarName: 'DASHBOARD',
13 | icon: Dashboard,
14 | component: DashboardPage,
15 | },
16 | {
17 | path: '/users',
18 | sidebarName: 'USERS',
19 | navbarName: 'USERS',
20 | icon: Person,
21 | component: Users,
22 | },
23 | {
24 | path: '/groups',
25 | sidebarName: 'GROUPS',
26 | navbarName: 'GROUPS',
27 | icon: Group,
28 | component: Groups,
29 | },
30 | {
31 | path: '/security-reports',
32 | sidebarName: 'SECURITY_REPORTS',
33 | navbarName: 'SECURITY_REPORTS',
34 | icon: Timeline,
35 | component: SecurityReports,
36 | },
37 | ];
38 |
39 | if (!process.env.NODE_ENV || process.env.NODE_ENV === 'development') {
40 | //dev
41 | // preserve
42 | // routes = routes.concat([
43 | // {
44 | // path: '/profile',
45 | // sidebarName: 'Orig. User Profile',
46 | // navbarName: 'Original: Profile',
47 | // icon: Person,
48 | // component: UserProfile
49 | // },
50 | // {
51 | // path: '/table',
52 | // sidebarName: 'Orig. Table List',
53 | // navbarName: 'Original: Table List',
54 | // icon: ContentPaste,
55 | // component: TableList
56 | // },
57 | // {
58 | // path: '/typography',
59 | // sidebarName: 'Orig. Typography',
60 | // navbarName: 'Original: Typography',
61 | // icon: LibraryBooks,
62 | // component: Typography
63 | // },
64 | // {
65 | // path: '/icons',
66 | // sidebarName: 'Orig.I cons',
67 | // navbarName: 'Original: Icons',
68 | // icon: BubbleChart,
69 | // component: Icons
70 | // },
71 | // {
72 | // path: '/maps',
73 | // sidebarName: 'Orig. Maps',
74 | // navbarName: 'Original: Map',
75 | // icon: LocationOn,
76 | // component: Maps
77 | // },
78 | // {
79 | // path: '/notifications',
80 | // sidebarName: 'Orig. Notifications',
81 | // navbarName: 'Original: Notifications',
82 | // icon: Notifications,
83 | // component: NotificationsPage
84 | // }
85 | // ]);
86 | } else {
87 | // prod
88 | }
89 |
90 | routes = routes.concat([
91 | { redirect: true, path: '/', to: '/dashboard', navbarName: 'Redirect' },
92 | ]);
93 |
94 | export default routes;
95 |
--------------------------------------------------------------------------------
/src/services/api-client.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Client service for the psono web client
3 | */
4 |
5 | import store from './store';
6 |
7 | async function getVersion() {
8 | const client_url = store.getState().server.web_client;
9 | const response = await fetch(
10 | client_url + '/VERSION.txt?t=' + new Date().getTime()
11 | );
12 | return await response.text();
13 | }
14 |
15 | const service = {
16 | getVersion,
17 | };
18 |
19 | export default service;
20 |
--------------------------------------------------------------------------------
/src/services/api-static.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Gitlab service, that implements the Gitlab API
3 | */
4 |
5 | const BASE_URL = 'https://static.psono.com';
6 |
7 | /**
8 | *
9 | * Ajax GET request to download a ressource from static.psono.com
10 | *
11 | * @param {string} ressource The "url" part to return
12 | *
13 | * @returns {Promise} promise
14 | */
15 | async function get(ressource) {
16 | const response = await fetch(BASE_URL + ressource);
17 | return await response.json();
18 | }
19 |
20 | const service = {
21 | get,
22 | };
23 |
24 | export default service;
25 |
--------------------------------------------------------------------------------
/src/services/clientjs.js:
--------------------------------------------------------------------------------
1 | /**
2 | * clientjs service, a small wrapper for ClientJS
3 | */
4 |
5 | const service = new window.ClientJS();
6 | export default service;
7 |
--------------------------------------------------------------------------------
/src/services/device.js:
--------------------------------------------------------------------------------
1 | import client_js from './clientjs';
2 |
3 | let fingerprint;
4 |
5 | activate();
6 | function activate() {
7 | getDeviceFingerprintAsync().then(function (local_fingerprint) {
8 | fingerprint = local_fingerprint;
9 | });
10 | }
11 |
12 | /**
13 | * Returns the device fingerprint
14 | *
15 | * @returns Promise> Returns promise with the device fingerprint
16 | */
17 | function getDeviceFingerprintAsync() {
18 | return new Promise((resolve, reject) => {
19 | resolve(client_js.getFingerprint());
20 | });
21 | }
22 |
23 | /**
24 | * Returns the device fingerprint
25 | *
26 | * @returns {string} Fingerprint of the device
27 | */
28 | function getDeviceFingerprint() {
29 | if (fingerprint) {
30 | return fingerprint;
31 | }
32 | fingerprint = client_js.getFingerprint();
33 | return fingerprint;
34 | }
35 |
36 | /**
37 | * Returns weather we have an IE or not
38 | *
39 | * @returns {boolean} Is this an IE user
40 | */
41 | function is_ie() {
42 | return client_js.isIE();
43 | }
44 |
45 | /**
46 | * Returns weather we have a Chrome or not
47 | *
48 | * @returns {boolean} Is this an Chrome user
49 | */
50 | function is_chrome() {
51 | return client_js.isChrome();
52 | }
53 |
54 | /**
55 | * Returns weather we have a Firefox or not
56 | *
57 | * @returns {boolean} Is this an Firefox user
58 | */
59 | function is_firefox() {
60 | return client_js.isFirefox();
61 | }
62 |
63 | /**
64 | * Returns weather we have a Safari or not
65 | *
66 | * @returns {boolean} Is this an Safari user
67 | */
68 | function is_safari() {
69 | return client_js.isSafari();
70 | }
71 |
72 | /**
73 | * Returns weather we have a Opera or not
74 | *
75 | * @returns {boolean} Is this an Opera user
76 | */
77 | function is_opera() {
78 | return client_js.isOpera();
79 | }
80 |
81 | /**
82 | * Generates the Device description out of the Vendor, OS, Version and others
83 | *
84 | * @returns {string} Returns the device's description
85 | */
86 | function getDeviceDescription() {
87 | let description = '';
88 | if (typeof client_js.getDeviceVendor() !== 'undefined') {
89 | description = description + client_js.getDeviceVendor() + ' ';
90 | }
91 | if (typeof client_js.getDevice() !== 'undefined') {
92 | description = description + client_js.getDevice() + ' ';
93 | }
94 | if (typeof client_js.getOS() !== 'undefined') {
95 | description = description + client_js.getOS() + ' ';
96 | }
97 | if (typeof client_js.getOSVersion() !== 'undefined') {
98 | description = description + client_js.getOSVersion() + ' ';
99 | }
100 | if (typeof client_js.getBrowser() !== 'undefined') {
101 | description = description + client_js.getBrowser() + ' ';
102 | }
103 | if (typeof client_js.getBrowserVersion() !== 'undefined') {
104 | description = description + client_js.getBrowserVersion() + ' ';
105 | }
106 | return description;
107 | }
108 |
109 | const service = {
110 | getDeviceFingerprint: getDeviceFingerprint,
111 | is_ie: is_ie,
112 | is_chrome: is_chrome,
113 | is_firefox: is_firefox,
114 | is_safari: is_safari,
115 | is_opera: is_opera,
116 | getDeviceDescription: getDeviceDescription,
117 | };
118 |
119 | export default service;
120 |
--------------------------------------------------------------------------------
/src/services/ivalt.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Ivalt and all the functions to create / edit / delete it ...
3 | */
4 |
5 | import psono_server from './api-server';
6 | import store from './store';
7 |
8 | function sendTwoFactorNotification() {
9 | const token = store.getState().user.token;
10 | const sessionSecretKey = store.getState().user.session_secret_key;
11 | const onSuccess = function () {
12 | return true;
13 | };
14 | const onError = function () {
15 | return false;
16 | };
17 | return psono_server
18 | .ivaltVerify(token, sessionSecretKey, 'notification')
19 | .then(onSuccess, onError);
20 | }
21 |
22 | function validateIvaltTwoFactor() {
23 | const token = store.getState().user.token;
24 | const sessionSecretKey = store.getState().user.session_secret_key;
25 | const onSuccess = function (res) {
26 | return res;
27 | };
28 | const onError = function (res) {
29 | return res;
30 | };
31 | return psono_server
32 | .ivaltVerify(token, sessionSecretKey, 'verification')
33 | .then(onSuccess, onError);
34 | }
35 |
36 | const ivaltService = {
37 | sendTwoFactorNotification,
38 | validateIvaltTwoFactor,
39 | };
40 |
41 | export default ivaltService;
42 |
--------------------------------------------------------------------------------
/src/services/notification.js:
--------------------------------------------------------------------------------
1 | import action from '../actions/boundActionCreators';
2 |
3 | /**
4 | * Sends an info message
5 | *
6 | * @param {array} message The message to send
7 | */
8 | function infoSend(message) {
9 | action.sendNotification(message, 'info');
10 | }
11 |
12 | /**
13 | * Sends an info message
14 | *
15 | * @param {array} message The message to send
16 | */
17 | function errorSend(message) {
18 | action.sendNotification(message, 'danger');
19 | }
20 |
21 | /**
22 | * Resets messages
23 | */
24 | function reset() {
25 | action.setNotifications([]);
26 | }
27 |
28 | /**
29 | * Resets messages
30 | */
31 | function set(messages) {
32 | action.setNotifications(messages);
33 | }
34 |
35 | const service = {
36 | infoSend,
37 | errorSend,
38 | reset,
39 | set,
40 | };
41 |
42 | export default service;
43 |
--------------------------------------------------------------------------------
/src/services/store.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Store service
3 | */
4 |
5 | import { createStore, applyMiddleware } from 'redux';
6 | import thunkMiddleware from 'redux-thunk';
7 | import { createLogger } from 'redux-logger';
8 | import { persistReducer } from 'redux-persist';
9 | import storage from 'redux-persist/lib/storage';
10 |
11 | import rootReducer from '../reducers';
12 |
13 | const middlewares = [thunkMiddleware];
14 |
15 | if (!process.env.NODE_ENV || process.env.NODE_ENV === 'development') {
16 | const loggerMiddleware = createLogger();
17 | middlewares.push(loggerMiddleware);
18 | }
19 |
20 | const persistConfig = {
21 | key: 'root',
22 | blacklist: ['transient', 'notification'],
23 | storage,
24 | };
25 |
26 | const persistedReducer = persistReducer(persistConfig, rootReducer);
27 |
28 | let service = createStore(persistedReducer, applyMiddleware(...middlewares));
29 |
30 | export default service;
31 |
--------------------------------------------------------------------------------
/src/services/webauthn.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Fido / Webauthn and all the functions to create / edit / delete it ...
3 | */
4 |
5 | import psonoServer from './api-server';
6 | import store from './store';
7 | import helperService from './helper';
8 |
9 | /**
10 | * Returns the current origin
11 | *
12 | * @returns {string} Returns the current origin
13 | */
14 | function getOrigin() {
15 | const parsedUrl = helperService.parse_url(window.location.href);
16 | return parsedUrl.base_url;
17 | }
18 |
19 | /**
20 | * Initiate the second factor authentication with webauthn
21 | *
22 | * @returns {Promise} Returns a promise with the user information
23 | */
24 | function verifyWebauthnInit() {
25 | const token = store.getState().user.token;
26 | const sessionSecretKey = store.getState().user.session_secret_key;
27 |
28 | const onSuccess = function (request) {
29 | return request.data;
30 | };
31 | const onError = function (request) {
32 | return Promise.reject(request.data);
33 | };
34 | return psonoServer
35 | .webauthnVerifyInit(token, sessionSecretKey, getOrigin())
36 | .then(onSuccess, onError);
37 | }
38 |
39 | /**
40 | * Solve the second factor webauthn authentication
41 | *
42 | * @param {string} credential The credentials passed by the browser
43 | *
44 | * @returns {Promise} Returns a promise with the user information
45 | */
46 | function verifyWebauthn(credential) {
47 | const token = store.getState().user.token;
48 | const sessionSecretKey = store.getState().user.session_secret_key;
49 |
50 | const onSuccess = function (request) {
51 | return request.data;
52 | };
53 | const onError = function (request) {
54 | return Promise.reject(request.data);
55 | };
56 | return psonoServer
57 | .webauthnVerify(token, sessionSecretKey, credential)
58 | .then(onSuccess, onError);
59 | }
60 |
61 | const webauthnService = {
62 | verifyWebauthnInit,
63 | verifyWebauthn,
64 | };
65 |
66 | export default webauthnService;
67 |
--------------------------------------------------------------------------------
/src/setupTests.js:
--------------------------------------------------------------------------------
1 | const localStorageMock = {
2 | getItem: jest.fn(),
3 | setItem: jest.fn(),
4 | clear: jest.fn(),
5 | };
6 | global.localStorage = localStorageMock;
7 |
8 | jest.mock('./services/clientjs', () => {
9 | return {
10 | getFingerprint: () => {
11 | return 'dummy_fingerprint';
12 | },
13 | };
14 | });
15 |
--------------------------------------------------------------------------------
/src/variables/general.jsx:
--------------------------------------------------------------------------------
1 | // ##############################
2 | // // // Tasks for TasksCard - see Dashboard view
3 | // #############################
4 |
5 | export const bugs = [
6 | 'Sign contract for "What are conference organizers afraid of?"',
7 | 'Lines From Great Russian Literature? Or E-mails From My Boss?',
8 | 'Flooded: One year later, assessing what was lost and what was found when a ravaging rain swept through metro Detroit',
9 | 'Create 4 Invisible User Experiences you Never Knew About'
10 | ];
11 | export const website = [
12 | 'Flooded: One year later, assessing what was lost and what was found when a ravaging rain swept through metro Detroit',
13 | 'Sign contract for "What are conference organizers afraid of?"'
14 | ];
15 | export const server = [
16 | 'Lines From Great Russian Literature? Or E-mails From My Boss?',
17 | 'Flooded: One year later, assessing what was lost and what was found when a ravaging rain swept through metro Detroit',
18 | 'Sign contract for "What are conference organizers afraid of?"'
19 | ];
20 |
--------------------------------------------------------------------------------
/src/views/Dashboard/HealthCheck.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Grid } from '@material-ui/core';
3 | import { useTranslation } from 'react-i18next';
4 | import { HealthcheckCard } from '../../components';
5 | import { GridItem } from '../../components';
6 | import psono_server from '../../services/api-server';
7 |
8 | const HealthCheck = (props) => {
9 | const { t } = useTranslation();
10 | const [healthcheck, setHealthcheck] = React.useState({
11 | db_read: {},
12 | db_sync: {},
13 | time_sync: {},
14 | });
15 |
16 | React.useEffect(() => {
17 | psono_server.healthcheck().then(
18 | (response) => {
19 | //healthy is reported as 200
20 | setHealthcheck(response.data);
21 | },
22 | (response) => {
23 | if (response.hasOwnProperty('data')) {
24 | setHealthcheck(response.data);
25 | } else {
26 | console.log(response);
27 | }
28 | }
29 | );
30 | // eslint-disable-next-line react-hooks/exhaustive-deps
31 | }, []);
32 |
33 | return (
34 |
35 |
36 |
42 |
43 |
44 |
50 |
51 |
52 |
58 |
59 |
60 | );
61 | };
62 |
63 | export default HealthCheck;
64 |
--------------------------------------------------------------------------------
/src/views/Icons/Icons.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { withStyles, Grid, Hidden } from '@material-ui/core';
3 | import PropTypes from 'prop-types';
4 |
5 | import { RegularCard, P, A, GridItem } from '../../components';
6 | import iconsStyle from '../../assets/jss/material-dashboard-react/iconsStyle';
7 |
8 | const Icons = ({ classes }) => {
9 | return (
10 |
11 |
12 |
17 | Handcrafted by our friends from{' '}
18 |
23 | Google
24 |
25 |
26 | }
27 | content={
28 |
29 |
30 |
39 |
40 |
41 |
42 |
43 | The icons are visible on Desktop mode
44 | inside an iframe. Since the iframe is
45 | not working on Mobile and Tablets please
46 | visit the icons on their original page
47 | on Google. Check the{' '}
48 |
53 | Material Icons
54 |
55 |
56 |
57 |
58 |
59 | }
60 | />
61 |
62 |
63 | );
64 | };
65 |
66 | Icons.propTypes = {
67 | classes: PropTypes.object.isRequired,
68 | };
69 |
70 | export default withStyles(iconsStyle)(Icons);
71 |
--------------------------------------------------------------------------------
/src/views/OIDC/Index.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import { Grid } from '@material-ui/core';
3 |
4 | import { OIDCCard, GridItem } from '../../components';
5 | import psono_server from '../../services/api-server';
6 | import store from '../../services/store';
7 |
8 | const Users = () => {
9 | const [oidcGroups, setOidcGroups] = useState([]);
10 |
11 | const createGroupsNode = (oidc_group) => {
12 | oidc_group.groups = (
13 |
14 | {oidc_group.groups.map((group, key) => (
15 | <>
16 | {key !== 0 ? ', ' : ''}
17 |
18 | {group.name}
19 |
20 | >
21 | ))}
22 |
23 | );
24 | };
25 |
26 | const loadOidcGroups = () => {
27 | psono_server
28 | .admin_oidc_group(
29 | store.getState().user.token,
30 | store.getState().user.session_secret_key
31 | )
32 | .then((response) => {
33 | const { oidc_groups } = response.data;
34 |
35 | oidc_groups.forEach((oidc_group) => {
36 | oidc_group['name'] =
37 | oidc_group['display_name'] || oidc_group['oidc_name'];
38 | createGroupsNode(oidc_group);
39 | });
40 |
41 | setOidcGroups(oidc_groups);
42 | });
43 | };
44 |
45 | const onDeleteOidcGroups = (selectedGroups) => {
46 | selectedGroups.forEach((group) => {
47 | psono_server
48 | .admin_delete_oidc_group(
49 | store.getState().user.token,
50 | store.getState().user.session_secret_key,
51 | group.id
52 | )
53 | .then(() => {
54 | loadOidcGroups();
55 | });
56 | });
57 | };
58 |
59 | useEffect(() => {
60 | loadOidcGroups();
61 | }, []);
62 |
63 | return (
64 |
65 |
66 |
67 |
71 |
72 |
73 |
74 | );
75 | };
76 |
77 | export default Users;
78 |
--------------------------------------------------------------------------------
/src/views/SAML/Index.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import { Grid } from '@material-ui/core';
3 | import { Redirect } from 'react-router-dom';
4 |
5 | import { SAMLCard, GridItem } from '../../components';
6 | import psono_server from '../../services/api-server';
7 | import notification from '../../services/notification';
8 | import store from '../../services/store';
9 |
10 | const SAML = (props) => {
11 | const [redirectTo, setRedirectTo] = useState('');
12 | const [samlGroups, setSamlGroups] = useState([]);
13 |
14 | const createGroupsNode = (saml_group) => {
15 | saml_group.groups = (
16 |
17 | {saml_group.groups.map((group, key) => (
18 | <>
19 | {key !== 0 ? ', ' : ''}
20 |
21 | {group.name}
22 |
23 | >
24 | ))}
25 |
26 | );
27 | };
28 |
29 | const loadSamlGroups = () => {
30 | psono_server
31 | .admin_saml_group(
32 | store.getState().user.token,
33 | store.getState().user.session_secret_key
34 | )
35 | .then((response) => {
36 | const { saml_groups } = response.data;
37 |
38 | saml_groups.forEach((saml_group) => {
39 | saml_group['name'] =
40 | saml_group['display_name'] || saml_group['saml_name'];
41 | createGroupsNode(saml_group);
42 | });
43 |
44 | setSamlGroups(saml_groups);
45 | });
46 | };
47 |
48 | const onSyncGroupsSaml = () => {
49 | psono_server
50 | .admin_saml_group_sync(
51 | store.getState().user.token,
52 | store.getState().user.session_secret_key
53 | )
54 | .then(
55 | () => {
56 | loadSamlGroups();
57 | },
58 | (response) => {
59 | const { non_field_errors } = response.data;
60 | notification.errorSend(non_field_errors[0]);
61 | }
62 | );
63 | };
64 |
65 | const onDeleteSamlGroups = (selectedGroups) => {
66 | selectedGroups.forEach((group) => {
67 | psono_server
68 | .admin_delete_saml_group(
69 | store.getState().user.token,
70 | store.getState().user.session_secret_key,
71 | group.id
72 | )
73 | .then(() => {
74 | loadSamlGroups();
75 | });
76 | });
77 | };
78 |
79 | useEffect(() => {
80 | loadSamlGroups();
81 | }, []);
82 |
83 | if (redirectTo) {
84 | return ;
85 | }
86 |
87 | return (
88 |
89 |
90 |
91 |
96 |
97 |
98 |
99 | );
100 | };
101 |
102 | export default SAML;
103 |
--------------------------------------------------------------------------------
/src/views/SCIM/Index.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import { Grid } from '@material-ui/core';
3 |
4 | import { SCIMCard, GridItem } from '../../components';
5 | import psono_server from '../../services/api-server';
6 | import store from '../../services/store';
7 |
8 | const Users = () => {
9 | const [scimGroups, setScimGroups] = useState([]);
10 |
11 | const createGroupsNode = (scim_group) => {
12 | scim_group.groups = (
13 |
14 | {scim_group.groups.map((group, key) => (
15 | <>
16 | {key !== 0 ? ', ' : ''}
17 |
18 | {group.name}
19 |
20 | >
21 | ))}
22 |
23 | );
24 | };
25 |
26 | const loadScimGroups = () => {
27 | psono_server
28 | .admin_scim_group(
29 | store.getState().user.token,
30 | store.getState().user.session_secret_key
31 | )
32 | .then((response) => {
33 | const { scim_groups } = response.data;
34 | scim_groups.forEach(createGroupsNode);
35 | setScimGroups(
36 | scim_groups.map((scim_group) => ({
37 | ...scim_group,
38 | name: scim_group.display_name || scim_group.scim_name,
39 | }))
40 | );
41 | });
42 | };
43 |
44 | const onDeleteScimGroups = (selectedGroups) => {
45 | selectedGroups.forEach((group) => {
46 | psono_server
47 | .admin_delete_scim_group(
48 | store.getState().user.token,
49 | store.getState().user.session_secret_key,
50 | group.id
51 | )
52 | .then(() => {
53 | loadScimGroups();
54 | });
55 | });
56 | };
57 |
58 | useEffect(() => {
59 | loadScimGroups();
60 | }, []);
61 |
62 | return (
63 |
64 |
65 |
66 |
70 |
71 |
72 |
73 | );
74 | };
75 |
76 | export default Users;
77 |
--------------------------------------------------------------------------------
/var/build-ubuntu.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | apt-get update && \
3 | apt-get install -y ca-certificates curl gnupg apt-transport-https zip && \
4 | mkdir -p /etc/apt/keyrings && \
5 | curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg && \
6 | echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_22.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list && \
7 | apt-get update && \
8 | apt-get -y install nodejs && \
9 | npm --version && \
10 | npm config set registry https://psono.jfrog.io/psono/api/npm/npm/ && \
11 | npm config set @devexpress:registry https://psono.jfrog.io/psono/api/npm/npm/ && \
12 | npm config set @types:registry https://psono.jfrog.io/psono/api/npm/npm/ && \
13 | npm ci && \
14 | npm install -g karma-cli && \
15 | INLINE_RUNTIME_CHUNK=false npm run build && \
16 | ./var/update_version.sh && \
17 | cp LICENSE.md build/LICENSE.md
18 |
19 |
--------------------------------------------------------------------------------
/var/deploy-docker.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | apk upgrade --no-cache
3 | apk add --update curl skopeo
4 |
5 | # Deploy to Docker Hub
6 | skopeo copy --all docker://$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG docker://docker.io/psono/psono-admin-client:latest
7 |
8 | export docker_version_tag=$(echo $CI_COMMIT_TAG | awk '{ string=substr($0, 2, 100); print string; }' )
9 | skopeo copy --all docker://$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG docker://docker.io/psono/psono-admin-client:$docker_version_tag
10 |
11 | echo "Trigger psono combo rebuild"
12 | curl -X POST -F token=$PSONO_COMBO_TRIGGER_TOKEN -F ref=master https://gitlab.com/api/v4/projects/16086547/trigger/pipeline
13 | curl -X POST -F token=$PSONO_COMBO_EE_TRIGGER_TOKEN -F ref=master https://gitlab.com/api/v4/projects/16127995/trigger/pipeline
14 |
--------------------------------------------------------------------------------
/var/deploy-github.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | echo "Clonging gitlab.com/psono/psono-admin-client.git"
3 | git clone https://gitlab.com/psono/psono-admin-client.git
4 | cd psono-admin-client
5 | git branch --track develop origin/develop
6 | git fetch --all
7 | git pull --all
8 |
9 | echo "Empty .ssh folder"
10 | if [ -d "/root/.ssh" ]; then
11 | rm -Rf /root/.ssh;
12 | fi
13 | mkdir -p /root/.ssh
14 |
15 | echo "Fill .ssh folder"
16 | echo "$github_deploy_key" > /root/.ssh/id_rsa
17 | cat > /root/.ssh/known_hosts <<- "EOF"
18 | |1|AuV+6vt2c6yHKSBI3cGlgiQgBw0=|oReK12ycO4x62cIfNqNIvclb2Ao= ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg=
19 | |1|rLMxkb3I+R6GmInBad4kitV0ZTk=|c7GxoZTzebOPBENzRmPEylRcgtY= ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg=
20 | EOF
21 | chmod 600 /root/.ssh/id_rsa
22 | chmod 600 /root/.ssh/known_hosts
23 |
24 | echo "Push to github.com/psono/psono-admin-client.git"
25 | git remote set-url origin git@github.com:psono/psono-admin-client.git
26 | git push --all origin
27 |
--------------------------------------------------------------------------------
/var/deploy_changelog.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | apt-get update && \
3 | apt-get install -y curl python3 && \
4 | curl -fSL "https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-cli-392.0.0-linux-x86_64.tar.gz" -o google-cloud-cli.tar.gz && echo "a7e88856a07ed75cf310ebe5415c922c9b516021a6c7e66b3eb8f2859b9351bc google-cloud-cli.tar.gz" | sha256sum -c - && tar -xzvf google-cloud-cli.tar.gz && \
5 | ./google-cloud-sdk/install.sh -q && \
6 | echo "$GOOGLE_APPLICATION_CREDENTIALS" > "/root/key.json" && \
7 | ./google-cloud-sdk/bin/gcloud auth activate-service-account --key-file=/root/key.json && \
8 | curl -H "PRIVATE-TOKEN: $GITLAB_PERSONAL_ACCESS_TOKEN" "https://gitlab.com/api/v4/projects/$CI_PROJECT_ID/repository/tags" --output changelog.json && \
9 | ./google-cloud-sdk/bin/gsutil cp changelog.json gs://static.psono.com/gitlab.com/$CI_PROJECT_PATH/changelog.json
--------------------------------------------------------------------------------
/var/deploy_nightlyartifacts.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | apt-get update && \
3 | apt-get install -y lsb-release curl gnupg && \
4 | echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] http://packages.cloud.google.com/apt cloud-sdk main" | tee -a /etc/apt/sources.list.d/google-cloud-sdk.list && \
5 | curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key --keyring /usr/share/keyrings/cloud.google.gpg add - && \
6 | apt-get update -y && apt-get install google-cloud-cli -y && \
7 | echo "$GOOGLE_APPLICATION_CREDENTIALS" > "/root/key.json" && \
8 | gcloud auth activate-service-account --key-file=/root/key.json && \
9 | curl -fL https://getcli.jfrog.io | sh && \
10 | ./jfrog config add rt-server-1 --artifactory-url=https://psono.jfrog.io/psono --user=gitlab --password=$artifactory_credentials --interactive=false && \
11 | ./jfrog rt dl psono/client/$CI_COMMIT_REF_NAME/webclient.zip --flat && \
12 | gsutil cp webclient.zip gs://get.psono.com/$CI_PROJECT_PATH/nightly/adminclient.zip && \
13 | gsutil cp sbom.json gs://get.psono.com/$CI_PROJECT_PATH/nightly/sbom.json
14 |
--------------------------------------------------------------------------------
/var/deploy_releaseartifacts.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | apt-get update && \
3 | apt-get install -y lsb-release curl gnupg && \
4 | echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] http://packages.cloud.google.com/apt cloud-sdk main" | tee -a /etc/apt/sources.list.d/google-cloud-sdk.list && \
5 | curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key --keyring /usr/share/keyrings/cloud.google.gpg add - && \
6 | apt-get update -y && apt-get install google-cloud-cli -y && \
7 | echo "$GOOGLE_APPLICATION_CREDENTIALS" > "/root/key.json" && \
8 | gcloud auth activate-service-account --key-file=/root/key.json && \
9 | curl -fL https://getcli.jfrog.io | sh && \
10 | ./jfrog config add rt-server-1 --artifactory-url=https://psono.jfrog.io/psono --user=gitlab --password=$artifactory_credentials --interactive=false && \
11 | ./jfrog rt dl psono/admin-client/$CI_COMMIT_REF_NAME/webclient.zip --flat && \
12 | gsutil cp webclient.zip gs://get.psono.com/$CI_PROJECT_PATH/latest/adminclient.zip && \
13 | gsutil cp webclient.zip gs://get.psono.com/$CI_PROJECT_PATH/$CI_COMMIT_REF_NAME/adminclient.zip && \
14 | gsutil cp sbom.json gs://get.psono.com/$CI_PROJECT_PATH/$CI_COMMIT_REF_NAME/sbom.json && \
15 | gsutil cp sbom.json gs://get.psono.com/$CI_PROJECT_PATH/latest/sbom.json
16 |
--------------------------------------------------------------------------------
/var/download_translations_from_artifactory.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -e
3 |
4 | # poeditor language codes: https://poeditor.com/docs/languages
5 |
6 | apt-get update && \
7 | apt-get install -y curl && \
8 | curl -f -o public/locales/locale-da.json https://psono.jfrog.io/psono/psono/admin-client/languages/locale-da.json && \
9 | curl -f -o public/locales/locale-ca.json https://psono.jfrog.io/psono/psono/admin-client/languages/locale-ca.json && \
10 | curl -f -o public/locales/locale-sv.json https://psono.jfrog.io/psono/psono/admin-client/languages/locale-sv.json && \
11 | curl -f -o public/locales/locale-no.json https://psono.jfrog.io/psono/psono/admin-client/languages/locale-no.json && \
12 | curl -f -o public/locales/locale-he.json https://psono.jfrog.io/psono/psono/admin-client/languages/locale-he.json && \
13 | curl -f -o public/locales/locale-ar.json https://psono.jfrog.io/psono/psono/admin-client/languages/locale-ar.json && \
14 | curl -f -o public/locales/locale-hi.json https://psono.jfrog.io/psono/psono/admin-client/languages/locale-hi.json && \
15 | curl -f -o public/locales/locale-hu.json https://psono.jfrog.io/psono/psono/admin-client/languages/locale-hu.json && \
16 | curl -f -o public/locales/locale-bn.json https://psono.jfrog.io/psono/psono/admin-client/languages/locale-bn.json && \
17 | curl -f -o public/locales/locale-cs.json https://psono.jfrog.io/psono/psono/admin-client/languages/locale-cs.json && \
18 | curl -f -o public/locales/locale-de.json https://psono.jfrog.io/psono/psono/admin-client/languages/locale-de.json && \
19 | curl -f -o public/locales/locale-en.json https://psono.jfrog.io/psono/psono/admin-client/languages/locale-en.json && \
20 | curl -f -o public/locales/locale-es.json https://psono.jfrog.io/psono/psono/admin-client/languages/locale-es.json && \
21 | curl -f -o public/locales/locale-fi.json https://psono.jfrog.io/psono/psono/admin-client/languages/locale-fi.json && \
22 | curl -f -o public/locales/locale-fr.json https://psono.jfrog.io/psono/psono/admin-client/languages/locale-fr.json && \
23 | curl -f -o public/locales/locale-hr.json https://psono.jfrog.io/psono/psono/admin-client/languages/locale-hr.json && \
24 | curl -f -o public/locales/locale-it.json https://psono.jfrog.io/psono/psono/admin-client/languages/locale-it.json && \
25 | curl -f -o public/locales/locale-ja.json https://psono.jfrog.io/psono/psono/admin-client/languages/locale-ja.json && \
26 | curl -f -o public/locales/locale-ko.json https://psono.jfrog.io/psono/psono/admin-client/languages/locale-ko.json && \
27 | curl -f -o public/locales/locale-nl.json https://psono.jfrog.io/psono/psono/admin-client/languages/locale-nl.json && \
28 | curl -f -o public/locales/locale-pt.json https://psono.jfrog.io/psono/psono/admin-client/languages/locale-pt.json && \
29 | curl -f -o public/locales/locale-pt-BR.json https://psono.jfrog.io/psono/psono/admin-client/languages/locale-pt-br.json && \
30 | curl -f -o public/locales/locale-pl.json https://psono.jfrog.io/psono/psono/admin-client/languages/locale-pl.json && \
31 | curl -f -o public/locales/locale-ru.json https://psono.jfrog.io/psono/psono/admin-client/languages/locale-ru.json && \
32 | curl -f -o public/locales/locale-sk.json https://psono.jfrog.io/psono/psono/admin-client/languages/locale-sk.json && \
33 | curl -f -o public/locales/locale-vi.json https://psono.jfrog.io/psono/psono/admin-client/languages/locale-vi.json && \
34 | curl -f -o public/locales/locale-zh-Hant.json https://psono.jfrog.io/psono/psono/admin-client/languages/locale-zh-Hant.json && \
35 | curl -f -o public/locales/locale-zh-Hans.json https://psono.jfrog.io/psono/psono/admin-client/languages/locale-zh-Hans.json
36 |
--------------------------------------------------------------------------------
/var/package-webclient.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | cd /builds/psono/psono-admin-client/build/
3 | zip -r /builds/psono/psono-admin-client/build/psono.webclient.zip *
4 | cd /builds/psono/psono-admin-client/
--------------------------------------------------------------------------------
/var/update_version.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | if [ -z "$CI_COMMIT_TAG" ]; then
4 | exit 0
5 | fi
6 |
7 | if [ -z "$CI_COMMIT_SHA" ]; then
8 | exit 0
9 | fi
10 |
11 | if ! echo "$CI_COMMIT_TAG" | egrep -q ^v[0-9]+\.[0-9]+\.[0-9]+$; then
12 | exit 0
13 | fi
14 |
15 | version="$(echo $CI_COMMIT_TAG | awk '{ string=substr($0, 2, 100); print string; }' ) (Build $(echo $CI_COMMIT_SHA | awk '{ string=substr($0, 1, 8); print string; }' ))"
16 |
17 | echo $version > ./build/VERSION.txt
18 |
19 |
--------------------------------------------------------------------------------
/var/upload_translations.py:
--------------------------------------------------------------------------------
1 | import requests
2 | import os
3 | import json
4 | import time
5 |
6 | POEDITOR_API_KEY = os.environ['POEDITOR_API_KEY']
7 | POEDITOR_PROJECT_ID = os.environ['POEDITOR_PROJECT_ID']
8 |
9 |
10 | FILE_PATHS = {
11 | 'en': 'public/locales/locale-en.json',
12 | }
13 |
14 |
15 | def upload_language(lang, updating):
16 |
17 | if lang in FILE_PATHS:
18 | data = {
19 | 'id': POEDITOR_PROJECT_ID,
20 | 'api_token': POEDITOR_API_KEY,
21 | 'updating': updating,
22 | 'language': lang,
23 | 'overwrite': 1,
24 | 'sync_terms ': 1,
25 | }
26 | with open(FILE_PATHS[lang], 'rb') as file:
27 | r = requests.post('https://api.poeditor.com/v2/projects/upload', data=data, files={'file': file})
28 |
29 | else:
30 | print("Error: upload_language " + lang + " No webhook configured for this language")
31 | # params = (
32 | # ('api_token', POEDITOR_API_KEY),
33 | # ('id_project', POEDITOR_PROJECT_ID),
34 | # ('language', lang),
35 | # ('operation', 'import_terms_and_translations'),
36 | # )
37 | #
38 | # r = requests.post('https://poeditor.com/api/webhooks/gitlab', params=params)
39 | if not r.ok:
40 | print("Error: upload_language " + lang)
41 | print(r.text)
42 | exit(1)
43 | content = json.loads(r.content)
44 | if "response" not in content or "status" not in content["response"] or content["response"]["status"] != 'success':
45 | print("Error: upload_language " + lang)
46 | print(r.text)
47 | exit(1)
48 | print("Success: upload_language " + lang)
49 |
50 |
51 | def main():
52 | # Upload
53 | upload_language('en', 'terms_translations')
54 |
55 | print("Success")
56 |
57 | if __name__ == "__main__":
58 | main()
59 |
--------------------------------------------------------------------------------
/webpack.common.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const HtmlWebpackPlugin = require('html-webpack-plugin');
3 | const CopyWebpackPlugin = require('copy-webpack-plugin');
4 | const { CleanWebpackPlugin } = require('clean-webpack-plugin');
5 | const webpack = require('webpack');
6 | const paths = {
7 | publicUrlOrPath: '/portal/',
8 | };
9 |
10 | module.exports = {
11 | entry: './src/index.js',
12 | output: {
13 | filename: 'static/js/[name].[contenthash:8].js',
14 | chunkFilename: 'static/js/[name].[contenthash:8].chunk.js',
15 | path: path.resolve(__dirname, 'build'),
16 | publicPath: '/portal/',
17 | },
18 | plugins: [
19 | new CleanWebpackPlugin(),
20 | new CopyWebpackPlugin({
21 | patterns: [
22 | {
23 | from: 'public',
24 | to: '',
25 | globOptions: {
26 | ignore: ['**/index.html'],
27 | },
28 | },
29 | ],
30 | }),
31 | new webpack.ProvidePlugin({
32 | process: 'process/browser',
33 | Buffer: ['buffer', 'Buffer'],
34 | }),
35 | ],
36 | module: {
37 | rules: [
38 | {
39 | test: /\.(js|jsx)$/,
40 | exclude: /node_modules/,
41 | use: {
42 | loader: 'babel-loader',
43 | options: {
44 | presets: [
45 | ['@babel/preset-env', { targets: { node: 'current' } }],
46 | '@babel/preset-react',
47 | ],
48 | plugins: [
49 | '@babel/plugin-proposal-class-properties',
50 | '@babel/plugin-transform-runtime',
51 | ],
52 | },
53 | },
54 | },
55 | {
56 | test: /\.css$/,
57 | use: ['style-loader', 'css-loader'],
58 | },
59 | {
60 | test: /\.(png|svg|jpg|jpeg|gif|ico)$/i,
61 | type: 'asset/resource',
62 | generator: {
63 | filename: 'static/media/[name].[hash:8][ext]',
64 | },
65 | },
66 | {
67 | test: /\.(woff|woff2|eot|ttf|otf)$/i,
68 | type: 'asset/resource',
69 | generator: {
70 | filename: 'static/media/[name].[hash:8][ext]',
71 | },
72 | },
73 | ],
74 | },
75 | resolve: {
76 | extensions: ['.js', '.jsx'],
77 | fallback: {
78 | "crypto": false,
79 | "buffer": require.resolve("buffer/"),
80 | "path": require.resolve("path-browserify"),
81 | "process": require.resolve("process/browser"),
82 | },
83 | },
84 | };
--------------------------------------------------------------------------------
/webpack.dev.js:
--------------------------------------------------------------------------------
1 | const { merge } = require('webpack-merge');
2 | const common = require('./webpack.common.js');
3 | const path = require('path');
4 | const webpack = require('webpack');
5 | const HtmlWebpackPlugin = require('html-webpack-plugin');
6 |
7 | module.exports = merge(common, {
8 | mode: 'development',
9 | devtool: 'inline-source-map',
10 | devServer: {
11 | static: {
12 | directory: path.join(__dirname, 'public'),
13 | },
14 | hot: true,
15 | historyApiFallback: {
16 | disableDotRule: true,
17 | index: '/portal/',
18 | },
19 | port: 3000,
20 | client: {
21 | overlay: {
22 | errors: true,
23 | warnings: false,
24 | },
25 | },
26 | },
27 | plugins: [
28 | new webpack.DefinePlugin({
29 | 'process.env.NODE_ENV': JSON.stringify('development'),
30 | 'process.env.PUBLIC_URL': JSON.stringify('/portal'),
31 | }),
32 | // Replace HtmlWebpackPlugin to use template processing
33 | new HtmlWebpackPlugin({
34 | inject: true,
35 | template: path.resolve(__dirname, 'public/index.html'),
36 | templateParameters: {
37 | PUBLIC_URL: '/portal',
38 | },
39 | }),
40 | ],
41 | });
--------------------------------------------------------------------------------
/webpack.prod.js:
--------------------------------------------------------------------------------
1 | const { merge } = require('webpack-merge');
2 | const common = require('./webpack.common.js');
3 | const TerserPlugin = require('terser-webpack-plugin');
4 | const MiniCssExtractPlugin = require('mini-css-extract-plugin');
5 | const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
6 | const webpack = require('webpack');
7 | const HtmlWebpackPlugin = require('html-webpack-plugin');
8 | const path = require('path');
9 |
10 | module.exports = merge(common, {
11 | mode: 'production',
12 | devtool: 'source-map',
13 | output: {
14 | filename: 'static/js/[name].[contenthash:8].js',
15 | chunkFilename: 'static/js/[name].[contenthash:8].chunk.js',
16 | },
17 | optimization: {
18 | minimize: true,
19 | minimizer: [
20 | new TerserPlugin({
21 | terserOptions: {
22 | compress: {
23 | comparisons: false,
24 | },
25 | mangle: {
26 | safari10: true,
27 | },
28 | output: {
29 | comments: false,
30 | ascii_only: true,
31 | },
32 | },
33 | }),
34 | new CssMinimizerPlugin(),
35 | ],
36 | splitChunks: {
37 | chunks: 'all',
38 | name: false,
39 | },
40 | runtimeChunk: {
41 | name: (entrypoint) => `runtime-${entrypoint.name}`,
42 | },
43 | },
44 | plugins: [
45 | new webpack.DefinePlugin({
46 | 'process.env.NODE_ENV': JSON.stringify('production'),
47 | 'process.env.PUBLIC_URL': JSON.stringify('/portal'),
48 | }),
49 | new MiniCssExtractPlugin({
50 | filename: 'static/css/[name].[contenthash:8].css',
51 | chunkFilename: 'static/css/[name].[contenthash:8].chunk.css',
52 | }),
53 | // Replace HtmlWebpackPlugin to use template processing
54 | new HtmlWebpackPlugin({
55 | inject: true,
56 | template: path.resolve(__dirname, 'public/index.html'),
57 | templateParameters: {
58 | PUBLIC_URL: '/portal',
59 | },
60 | minify: {
61 | removeComments: true,
62 | collapseWhitespace: true,
63 | removeRedundantAttributes: true,
64 | useShortDoctype: true,
65 | removeEmptyAttributes: true,
66 | removeStyleLinkTypeAttributes: true,
67 | keepClosingSlash: true,
68 | minifyJS: true,
69 | minifyCSS: true,
70 | minifyURLs: true,
71 | },
72 | }),
73 | ],
74 | module: {
75 | rules: [
76 | {
77 | test: /\.css$/,
78 | use: [
79 | MiniCssExtractPlugin.loader,
80 | 'css-loader',
81 | ],
82 | },
83 | ],
84 | },
85 | });
--------------------------------------------------------------------------------