├── .env
├── .eslintrc
├── .gitignore
├── LICENSE
├── README.md
├── config.js
├── logs
└── .gitignore
├── package-lock.json
├── package.json
├── public
├── favicon.ico
├── index.html
├── manifest.json
└── robots.txt
├── save-commands.json
├── server
└── index.js
└── src
├── App.css
├── App.js
├── App.style.js
├── change-pass
├── actions
│ ├── onDone.js
│ └── post.js
├── components
│ └── ChangePass.js
├── fetchers
│ └── post.js
└── reducer.js
├── colors.js
├── config.js
├── contacts
├── actions
│ ├── onDone.js
│ └── post.js
├── components
│ └── Contacts.js
├── fetchers
│ └── post.js
└── reducer.js
├── email-confirm
├── actions
│ ├── onConfirm.js
│ └── post.js
├── components
│ └── EmailConfirm.js
├── fetchers
│ └── post.js
└── reducer.js
├── entries
├── actions
│ ├── delete.js
│ ├── onAddDialogDone.js
│ ├── onAddEntry.js
│ ├── onConfirmDialogConfirm.js
│ ├── onDeleteEntry.js
│ ├── onDialogClose.js
│ ├── onDialogExited.js
│ ├── onEditDialogDone.js
│ ├── onEditEntry.js
│ ├── post.js
│ └── put.js
├── components
│ ├── Entries.js
│ ├── basic
│ │ └── EntryStringValue.js
│ ├── cards
│ │ ├── ArrayCard.js
│ │ ├── ArrayCard.style.js
│ │ ├── ArraySubcard.js
│ │ ├── ArraySubcard.style.js
│ │ ├── BasicTypeCard.js
│ │ ├── BasicTypeSubcard.js
│ │ ├── CardFactory.js
│ │ ├── ObjectCard.js
│ │ ├── ObjectCard.style.js
│ │ ├── ObjectSubcard.js
│ │ ├── ObjectSubcard.style.js
│ │ └── SubcardFactory.js
│ └── dialogs
│ │ ├── ControlContainer.js
│ │ ├── ControlContainer.style.js
│ │ ├── ControlFactory.js
│ │ ├── EntryDialog.js
│ │ ├── EntryDialogInner.js
│ │ └── controls
│ │ ├── ArrayControl.js
│ │ ├── ArrayControl.style.js
│ │ ├── AssetControl.js
│ │ ├── BooleanControl.js
│ │ ├── EnumControl.js
│ │ ├── HtmlControl.js
│ │ ├── MarkdownControl.js
│ │ ├── NumberControl.js
│ │ ├── ObjectControl.js
│ │ ├── ObjectControl.style.js
│ │ ├── ReferenceControl.js
│ │ ├── StringLineControl.js
│ │ └── StringMultilineControl.js
├── fetchers
│ ├── delete.js
│ ├── post.js
│ ├── postFileFetcher.js
│ └── put.js
├── helpers
│ └── isEmptyObject.js
└── reducer.js
├── explorer
└── components
│ ├── Explorer.js
│ └── config.js
├── global
├── actions
│ ├── errorSet.js
│ ├── fetchingEnd.js
│ ├── fetchingStart.js
│ ├── getData.js
│ ├── projectIdSet.js
│ └── redirectSet.js
├── components
│ ├── Container.js
│ ├── Content.js
│ ├── Content.style.js
│ ├── ErrorContainer.js
│ ├── ErrorContainer.style.js
│ ├── Header.js
│ ├── Header.style.js
│ ├── Loader.js
│ ├── Loader.style.js
│ ├── Menu.js
│ ├── Menu.style.js
│ ├── Redirect.js
│ └── RedirectContainer.js
├── fetchers
│ ├── getEntries.js
│ ├── getModels.js
│ └── getProjects.js
└── reducer.js
├── index.js
├── index
└── components
│ ├── Index.js
│ └── Index.style.js
├── landing
└── components
│ ├── GithubCorner.js
│ ├── GithubCorner.style.js
│ ├── Landing.js
│ └── Landing.style.js
├── lib
├── components
│ ├── Button.js
│ ├── Button.style.js
│ ├── Card.js
│ ├── Card.style.js
│ ├── CircledIcon.js
│ ├── CircularProgress.js
│ ├── CircularProgress.style.js
│ ├── ConfirmDialog.js
│ ├── Dialog.js
│ ├── Dialog.style.js
│ ├── DialogActions.js
│ ├── DialogActions.style.js
│ ├── DialogContent.js
│ ├── DialogContent.style.js
│ ├── Icon.js
│ ├── LinearProgress.js
│ ├── LinearProgress.style.js
│ ├── MessageBlock.js
│ ├── MessageBlock.style.js
│ ├── PageContainer.js
│ ├── PageContainer.style.js
│ ├── Subcard.js
│ ├── Subcard.style.js
│ ├── SubcardDivider.js
│ ├── SubcardDivider.style.js
│ ├── Typography.js
│ ├── Typography.style.js
│ ├── controls
│ │ ├── Checkbox.js
│ │ ├── Checkbox.style.js
│ │ ├── CodeEditor.js
│ │ ├── CodeEditor.style.js
│ │ ├── FileInput.js
│ │ ├── Select.js
│ │ ├── SelectInner.js
│ │ ├── SelectInner.style.js
│ │ ├── Switch.js
│ │ ├── Switch.style.js
│ │ ├── TextInput.js
│ │ └── TextInput.style.js
│ └── fields
│ │ ├── Checkbox.js
│ │ ├── Checkbox.style.js
│ │ ├── Select.js
│ │ ├── Switch.js
│ │ ├── Switch.style.js
│ │ ├── TextField.js
│ │ └── TextField.style.js
├── helpers
│ ├── createEntry.js
│ ├── createModel.js
│ ├── createSubentry.js
│ ├── createSubmodel.js
│ ├── getAssetControlsWithFile.js
│ ├── isEntryConsistencyConflict.js
│ ├── isEntryRefConflict.js
│ ├── isModelRefConflict.js
│ ├── isNumber.js
│ ├── logout.js
│ ├── sortKeys.js
│ └── valueAsNumber.js
├── services
│ ├── Auth.js
│ ├── Fetcher.js
│ ├── Jss.js
│ ├── Promise.js
│ ├── Routes.js
│ └── Validator.js
├── styles
│ ├── margins.css
│ ├── paddings.css
│ └── texts.css
└── types
│ ├── entries
│ ├── ArrayEntryType.js
│ ├── ArraySubentryType.js
│ ├── AssetEntryType.js
│ ├── AssetSubentryType.js
│ ├── BooleanEntryType.js
│ ├── BooleanSubentryType.js
│ ├── EntryType.js
│ ├── EnumEntryType.js
│ ├── EnumSubentryType.js
│ ├── NumberEntryType.js
│ ├── NumberSubentryType.js
│ ├── ObjectEntryType.js
│ ├── ObjectSubentryType.js
│ ├── ReferenceEntryType.js
│ ├── ReferenceSubentryType.js
│ ├── StringEntryType.js
│ ├── StringSubentryType.js
│ └── SubentryType.js
│ └── models
│ ├── AbstractType.js
│ ├── ArrayModelType.js
│ ├── ArraySubmodelType.js
│ ├── AssetModelType.js
│ ├── AssetSubmodelType.js
│ ├── BooleanModelType.js
│ ├── BooleanSubmodelType.js
│ ├── EnumModelType.js
│ ├── EnumSubmodelType.js
│ ├── ModelType.js
│ ├── NumberModelType.js
│ ├── NumberSubmodelType.js
│ ├── ObjectModelType.js
│ ├── ObjectSubmodelType.js
│ ├── ReferenceModelType.js
│ ├── ReferenceSubmodelType.js
│ ├── StringModelType.js
│ ├── StringSubmodelType.js
│ └── SubmodelType.js
├── login
├── actions
│ ├── onDone.js
│ └── post.js
├── components
│ ├── Login.js
│ └── Login.style.js
├── fetchers
│ └── post.js
└── reducer.js
├── mocks
├── getArray.js
├── getAsset.js
├── getBoolean.js
├── getEnum.js
├── getId.js
├── getNumber.js
├── getObject.js
├── getReference.js
├── getStringHtml.js
├── getStringLine.js
├── getStringMarkdown.js
├── getStringMultiline.js
├── index.js
└── stringMarkdownValue.js
├── models
├── actions
│ ├── delete.js
│ ├── onAddItem.js
│ ├── onAddModel.js
│ ├── onAddProp.js
│ ├── onDeleteItem.js
│ ├── onDeleteModel.js
│ ├── onDeleteProp.js
│ ├── onDialogAddDoneItem.js
│ ├── onDialogAddDoneModel.js
│ ├── onDialogAddDoneProp.js
│ ├── onDialogClose.js
│ ├── onDialogConfirmConfirmItem.js
│ ├── onDialogConfirmConfirmModel.js
│ ├── onDialogConfirmConfirmProp.js
│ ├── onDialogEditDoneItem.js
│ ├── onDialogEditDoneModel.js
│ ├── onDialogEditDoneProp.js
│ ├── onDialogExited.js
│ ├── onEditItem.js
│ ├── onEditModel.js
│ ├── onEditProp.js
│ ├── post.js
│ └── put.js
├── components
│ ├── Models.js
│ ├── basic
│ │ ├── TypeBlock.js
│ │ └── TypeBlock.style.js
│ ├── cards
│ │ ├── ArrayCard.js
│ │ ├── BasicTypeCard.js
│ │ ├── CardFactory.js
│ │ ├── ObjectCard.js
│ │ └── ObjectCard.style.js
│ └── dialogs
│ │ ├── AddDialog.js
│ │ ├── ConfirmDialog.js
│ │ ├── EditDialog.js
│ │ ├── SelectType.js
│ │ ├── Step.js
│ │ ├── Steps.js
│ │ ├── array-type
│ │ ├── ArrayItem.js
│ │ ├── ArrayModel.js
│ │ └── ArrayProp.js
│ │ ├── asset-type
│ │ ├── AssetItem.js
│ │ ├── AssetModel.js
│ │ └── AssetProp.js
│ │ ├── boolean-type
│ │ ├── BooleanItem.js
│ │ ├── BooleanModel.js
│ │ └── BooleanProp.js
│ │ ├── enum-type
│ │ ├── EnumControl.js
│ │ ├── EnumControl.style.js
│ │ ├── EnumControlSmart.js
│ │ ├── EnumItem.js
│ │ ├── EnumModel.js
│ │ └── EnumProp.js
│ │ ├── number-type
│ │ ├── NumberItem.js
│ │ ├── NumberModel.js
│ │ └── NumberProp.js
│ │ ├── object-type
│ │ ├── ObjectItem.js
│ │ ├── ObjectModel.js
│ │ └── ObjectProp.js
│ │ ├── reference-type
│ │ ├── ReferenceItem.js
│ │ ├── ReferenceItem.style.js
│ │ ├── ReferenceModel.js
│ │ ├── ReferenceModel.style.js
│ │ ├── ReferenceProp.js
│ │ └── ReferenceProp.style.js
│ │ └── string-type
│ │ ├── StringItem.js
│ │ ├── StringModel.js
│ │ ├── StringProp.js
│ │ └── Subtype.js
├── fetchers
│ ├── delete.js
│ ├── post.js
│ └── put.js
├── helpers
│ ├── dialogConstructor.js
│ ├── dialogTypeOnBlur.js
│ ├── dialogTypeOnDone.js
│ ├── onBooleanChange.js
│ ├── onNumberChange.js
│ ├── onStringChange.js
│ └── validatePropertyName.js
└── reducer.js
├── not-found
└── components
│ └── NotFound.js
├── projects
├── actions
│ ├── deleteAction.js
│ ├── getAction.js
│ ├── onAddDialogDone.js
│ ├── onAddProject.js
│ ├── onConfirmDialogConfirm.js
│ ├── onDeleteProject.js
│ ├── onDialogClose.js
│ ├── onDialogExited.js
│ ├── onEditDialogDone.js
│ ├── onEditProject.js
│ ├── onLogoutClick.js
│ ├── postAction.js
│ └── putAction.js
├── components
│ ├── ConfirmDialog.js
│ ├── ProjectDialog.js
│ ├── ProjectDialogInner.js
│ ├── Projects.js
│ └── Projects.style.js
├── fetchers
│ ├── deleteFetcher.js
│ ├── postFetcher.js
│ └── putFetcher.js
└── reducer.js
├── recover-pass
├── actions
│ ├── onDone.js
│ └── post.js
├── components
│ └── RecoverPass.js
├── fetchers
│ └── post.js
└── reducer.js
├── reducer.js
├── registration
├── actions
│ ├── onDone.js
│ └── post.js
├── components
│ ├── Registration.js
│ └── Registration.style.js
├── fetchers
│ └── post.js
└── reducer.js
├── serviceWorker.js
├── state.js
├── store.js
└── tokens
├── actions
├── deleteAction.js
├── getAction.js
├── onAdd.js
├── onAddDialogDone.js
├── onConfirmDialogConfirm.js
├── onDelete.js
├── onDialogClose.js
├── onDialogExited.js
├── onEdit.js
├── onEditDialogDone.js
├── postAction.js
└── putAction.js
├── components
├── ConfirmDialog.js
├── TokenDialog.js
├── TokenDialogInner.js
├── Tokens.js
└── basic
│ ├── Card.js
│ └── Card.style.js
├── fetchers
├── deleteFetcher.js
├── getFetcher.js
├── postFetcher.js
└── putFetcher.js
└── reducer.js
/.env:
--------------------------------------------------------------------------------
1 | NODE_PATH=./
2 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "react-app",
3 | "rules": {
4 | # "lines-between-class-members": [1, "always"], # added in eslint 4.9.0
5 | "arrow-parens": [1, "as-needed"],
6 | "comma-dangle": [1,"always-multiline"],
7 | "no-console": 1,
8 | "react/require-default-props": 1,
9 | "react/prop-types": 1,
10 | "react/default-props-match-prop-types": 1,
11 | "react/no-unused-prop-types": 1,
12 | "prefer-template": 1,
13 | "no-useless-concat": 1
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/.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 | yarn-debug.log*
21 | yarn-error.log*
22 |
23 | /public/vs
24 | /public/cookieconsent
25 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Any JSON CMS - Admin application server
2 |
3 | If you want to read general information about Any JSON CMS go [here](https://github.com/evmizulin/any-json-cms).
4 |
5 | Any JSON CMS consists of two parts. Admin application server and [API server](https://github.com/evmizulin/cms-api). It is Admin application server.
6 |
7 | ### Installation
8 |
9 | #### Step 1. Install the required dependencies.
10 | - [Node.js](https://nodejs.org/) v8+;
11 |
12 | #### Step 2. Install the Admin application server.
13 | ```sh
14 | git clone git@github.com:evmizulin/cms-admin.git
15 | cd cms-admin
16 | npm install
17 | ```
18 |
19 | #### Step 3. Update configuration file.
20 | In project root folder there are configuration file ```config.js```. Update it for your needs.
21 | ```js
22 | module.exports = {
23 | config: {
24 | isDemo: true,
25 | prodAppServerHost: 'localhost',
26 | prodAppServerPort: 8081,
27 | devApiProtocol: 'http',
28 | prodApiProtocol: 'https',
29 | devApiHost: 'localhost:8080',
30 | prodApiHost: 'some-domain',
31 | },
32 | }
33 | ```
34 | All parameters that have ```dev``` and ```prod``` prefixes, will be used for development and production environments respectively.
35 |
36 | - ```isDemo``` - there are several messages on the landing page informing that it is a demo server, set flag to ```false``` and it will hide messages;
37 | - ```prodAppServerHost``` - this parameter will be passed as ```host``` to run Node.js server;
38 | - ```prodAppServerPort``` - this parameter will be passed as ```port``` to run Node.js server;
39 | - ```apiProtocol``` - protocol of [API server](https://github.com/evmizulin/cms-api);
40 | - ```apiHost``` - host of [API server](https://github.com/evmizulin/cms-api);
41 |
42 | #### Step 4. Run Admin application server.
43 | To run Admin application server in development environment:
44 | ```sh
45 | npm start
46 | ```
47 | And open ```http://localhost:3000``` in your browser.
48 |
49 | To run Admin application server in production environment:
50 | ```sh
51 | npm run build && npm run start.prod
52 | ```
53 | You could see the logs in ```/logs``` folder.
54 |
--------------------------------------------------------------------------------
/config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | config: {
3 | isDemo: true,
4 | prodAppServerHost: 'localhost',
5 | prodAppServerPort: 8081,
6 | devApiProtocol: 'http',
7 | prodApiProtocol: 'https',
8 | devApiHost: 'localhost:8080',
9 | prodApiHost: 'some-domain',
10 | },
11 | }
12 |
--------------------------------------------------------------------------------
/logs/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cms-admin",
3 | "version": "1.3.2",
4 | "description": "",
5 | "scripts": {
6 | "pre": "npm run pre-monaco && npm run pre-cookie",
7 | "pre-monaco": "rm -rf public/vs && cp -a node_modules/monaco-editor/min/vs public/",
8 | "pre-cookie": "rm -rf public/cookieconsent && cp -a node_modules/cookieconsent/build/. public/cookieconsent",
9 | "build": "npm run pre && react-scripts build",
10 | "start": "npm run pre && react-scripts start",
11 | "test": "react-scripts test --env=jsdom",
12 | "start.prod": "NODE_ENV=production forever start -a -p logs -l console.log server/index.js",
13 | "stop": "forever stop server/index.js"
14 | },
15 | "repository": {
16 | "type": "git",
17 | "url": "git+ssh://git@bitbucket.org/evmizulin/cms-admin.git"
18 | },
19 | "author": "Evgeny Mizulin",
20 | "license": "GNU General Public License v3.0",
21 | "engines": {
22 | "node": "8.11.2"
23 | },
24 | "dependencies": {
25 | "bootstrap-grid": "^2.0.1",
26 | "clone": "2.1.1",
27 | "cookieconsent": "^3.1.0",
28 | "deep-freeze": "0.0.1",
29 | "express": "^4.16.4",
30 | "forever": "^0.15.3",
31 | "jss": "9.3.3",
32 | "jss-preset-default": "4.0.1",
33 | "lodash.uniq": "^4.5.0",
34 | "material-ui": "1.0.0-beta.23",
35 | "monaco-editor": "^0.10.1",
36 | "morgan": "^1.9.1",
37 | "prettier": "^1.14.3",
38 | "react": "16.0.0",
39 | "react-dom": "16.0.0",
40 | "react-icons": "^3.1.0",
41 | "react-redux": "5.0.6",
42 | "react-router-dom": "4.2.2",
43 | "react-scripts": "1.0.14",
44 | "react-select": "^2.1.1",
45 | "react-youtube": "^7.8.0",
46 | "redux": "3.7.2",
47 | "redux-thunk": "2.2.0",
48 | "reset-css": "^2.2.1",
49 | "rotating-file-stream": "^1.3.9",
50 | "showdown": "^1.8.5",
51 | "store": "^2.0.12",
52 | "swagger-ui": "^3.10.0",
53 | "tvalidator": "2.0.3",
54 | "xhr": "^2.5.0"
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evmizulin/cms-admin/16534d05fe187608af4b329ad1e7cb02794d09b0/public/favicon.ico
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "Any JSON CMS",
3 | "name": "Any JSON CMS",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "192x192",
8 | "type": "image/png"
9 | }
10 | ],
11 | "start_url": "./index.html",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | User-agent: *
2 | Allow: /
3 |
--------------------------------------------------------------------------------
/save-commands.json:
--------------------------------------------------------------------------------
1 | {
2 | "commands": [
3 | "src/**/*.js : ./node_modules/.bin/prettier --print-width 110 --no-semi --single-quote --trailing-comma es5 --write {absPath}{filename}",
4 | "src/**/*.js : ./node_modules/.bin/eslint --fix {absPath}{filename}",
5 | "server/**/*.js : ./node_modules/.bin/prettier --print-width 110 --no-semi --single-quote --trailing-comma es5 --write {absPath}{filename}",
6 | "server/**/*.js : ./node_modules/.bin/eslint --fix {absPath}{filename}"
7 | ]
8 | }
9 |
--------------------------------------------------------------------------------
/server/index.js:
--------------------------------------------------------------------------------
1 | const express = require('express')
2 | const fs = require('fs')
3 | const morgan = require('morgan')
4 | const path = require('path')
5 | const rfs = require('rotating-file-stream')
6 | const indexHtml = fs.readFileSync('./build/index.html', 'utf8')
7 | const { config } = require('../config')
8 |
9 | const accessLogStream = rfs('access.log', {
10 | interval: '1d',
11 | path: path.join(__dirname, '../logs'),
12 | })
13 | const format =
14 | ':date[iso] :remote-addr :remote-user :method :url :status :res[content-length] - :response-time ms'
15 |
16 | const app = express()
17 |
18 | app.use(morgan(format, { stream: accessLogStream }))
19 | app.use(express.static('build'))
20 |
21 | app.get('*', (req, res) => {
22 | res.status(200).send(indexHtml)
23 | })
24 |
25 | app.listen(config.prodAppServerPort, config.prodAppServerHost, () => {
26 | // eslint-disable-next-line no-console
27 | console.log(
28 | `${new Date().toISOString()} listening on ${config.prodAppServerHost}:${config.prodAppServerPort}`
29 | )
30 | // eslint-disable-next-line no-console
31 | console.log(`${new Date().toISOString()} NODE_ENV=${process.env.NODE_ENV}`)
32 | })
33 |
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | @import "./lib/styles/paddings.css";
2 | @import "./lib/styles/margins.css";
3 | @import "./lib/styles/texts.css";
4 | @import "~bootstrap-grid/dist/grid.css";
5 | @import "~swagger-ui/dist/swagger-ui.css";
6 |
7 | html,
8 | body {
9 | height: 100%;
10 | margin: 0;
11 | padding: 0;
12 | font-family: "Roboto", "Helvetica", "Arial", sans-serif;
13 | font-size: 16px;
14 | }
15 |
16 | #root {
17 | margin: 0;
18 | padding: 0;
19 | height: 100%;
20 | position: relative; }
21 |
22 | .row > div {
23 | box-sizing: border-box;
24 | }
25 |
26 | .github-corner:hover .octo-arm {
27 | animation: octocat-wave 560ms ease-in-out
28 | }
29 | @keyframes octocat-wave {
30 | 0%,
31 | 100% {
32 | transform: rotate(0)
33 | }
34 | 20%,
35 | 60% {
36 | transform: rotate(-25deg)
37 | }
38 | 40%,
39 | 80% {
40 | transform: rotate(10deg)
41 | }
42 | }
43 | @media (max-width:500px) {
44 | .github-corner:hover .octo-arm {
45 | animation: none
46 | }
47 | .github-corner .octo-arm {
48 | animation: octocat-wave 560ms ease-in-out
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/App.style.js:
--------------------------------------------------------------------------------
1 | import jss from 'src/lib/services/Jss'
2 | import { colors } from 'src/colors'
3 |
4 | jss
5 | .createStyleSheet({
6 | '@global': {
7 | '.text-error': {
8 | color: colors.error.main,
9 | },
10 | '.text-disabled': {
11 | color: colors.black.t4,
12 | },
13 | '.loader-page-container': {
14 | background: colors.tertiary.main,
15 | minHeight: 'calc(100% - 50px)',
16 | paddingTop: '50px',
17 | textAlign: 'center',
18 | },
19 | 'a:link': {
20 | color: colors.primary.main,
21 | },
22 | 'a:visited': {
23 | color: colors.primary.main,
24 | },
25 | 'a:hover': {
26 | color: colors.primary.d5,
27 | },
28 | 'a:active': {
29 | color: colors.primary.l3,
30 | },
31 | },
32 | })
33 | .attach()
34 |
--------------------------------------------------------------------------------
/src/change-pass/actions/onDone.js:
--------------------------------------------------------------------------------
1 | export const onDone = creds => ({
2 | widget: 'changePass',
3 | type: 'onDone',
4 | payload: { creds },
5 | })
6 |
--------------------------------------------------------------------------------
/src/change-pass/actions/post.js:
--------------------------------------------------------------------------------
1 | import { postFetcher } from 'src/change-pass/fetchers/post'
2 |
3 | export function postAction(creds) {
4 | return function(dispatch, getState) {
5 | dispatch({
6 | widget: 'changePass',
7 | type: 'postStart',
8 | })
9 | postFetcher(creds)
10 | .then(() => {
11 | dispatch({
12 | widget: 'changePass',
13 | type: 'postEnd',
14 | })
15 | })
16 | .catch(error => {
17 | dispatch({
18 | widget: 'changePass',
19 | type: 'postError',
20 | payload: error,
21 | })
22 | })
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/change-pass/fetchers/post.js:
--------------------------------------------------------------------------------
1 | import { fetch } from 'src/lib/services/Fetcher'
2 |
3 | export function postFetcher(creds) {
4 | return fetch({ method: 'POST', url: `change-pass`, body: creds })
5 | }
6 |
--------------------------------------------------------------------------------
/src/change-pass/reducer.js:
--------------------------------------------------------------------------------
1 | import { errorSet, fetchingStart, fetchingEnd } from 'src/global/reducer'
2 | import { postAction } from 'src/change-pass/actions/post'
3 | import { dispatch } from 'src/store'
4 |
5 | export function postStart(state) {
6 | fetchingStart(state)
7 | state.changePass.loading.post = true
8 | }
9 |
10 | export function postEnd(state) {
11 | fetchingEnd(state)
12 | state.changePass.loading.post = false
13 | state.changePass.showMessage = true
14 | }
15 |
16 | export function postError(state, error) {
17 | fetchingEnd(state)
18 | state.changePass.loading.post = false
19 | errorSet(state, { show: true, error })
20 | }
21 |
22 | export function onDone(state, { creds }) {
23 | setTimeout(() => dispatch(postAction(creds)), 0)
24 | }
25 |
26 | const modifiers = {
27 | postStart,
28 | postEnd,
29 | postError,
30 | onDone,
31 | }
32 |
33 | export const changePassReducer = (state, action) => {
34 | const modifier = modifiers[action.type]
35 | modifier(state, action.payload)
36 | }
37 |
--------------------------------------------------------------------------------
/src/config.js:
--------------------------------------------------------------------------------
1 | import { config as globalConfig } from 'config'
2 |
3 | const IS_DEV = process.env.NODE_ENV === 'development'
4 |
5 | export const config = {
6 | isDemo: globalConfig.isDemo,
7 | apiUrl: IS_DEV
8 | ? `${globalConfig.devApiProtocol}://${globalConfig.devApiHost}`
9 | : `${globalConfig.prodApiProtocol}://${globalConfig.prodApiHost}`,
10 | apiHost: IS_DEV ? globalConfig.devApiHost : globalConfig.prodApiHost,
11 | apiProtocol: IS_DEV ? globalConfig.devApiProtocol : globalConfig.prodApiProtocol,
12 | }
13 |
--------------------------------------------------------------------------------
/src/contacts/actions/onDone.js:
--------------------------------------------------------------------------------
1 | export const onDone = contact => ({
2 | widget: 'contacts',
3 | type: 'onDone',
4 | payload: { contact },
5 | })
6 |
--------------------------------------------------------------------------------
/src/contacts/actions/post.js:
--------------------------------------------------------------------------------
1 | import { postFetcher } from 'src/contacts/fetchers/post'
2 |
3 | export function postAction(contact) {
4 | return function(dispatch, getState) {
5 | dispatch({
6 | widget: 'contacts',
7 | type: 'postStart',
8 | })
9 | postFetcher(contact)
10 | .then(() => {
11 | dispatch({
12 | widget: 'contacts',
13 | type: 'postEnd',
14 | })
15 | })
16 | .catch(error => {
17 | dispatch({
18 | widget: 'contacts',
19 | type: 'postError',
20 | payload: error,
21 | })
22 | })
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/contacts/fetchers/post.js:
--------------------------------------------------------------------------------
1 | import { fetch } from 'src/lib/services/Fetcher'
2 |
3 | export function postFetcher(contact) {
4 | return fetch({ method: 'POST', url: `tmp/contacts`, body: contact })
5 | }
6 |
--------------------------------------------------------------------------------
/src/contacts/reducer.js:
--------------------------------------------------------------------------------
1 | import { errorSet, fetchingStart, fetchingEnd } from 'src/global/reducer'
2 | import { postAction } from 'src/contacts/actions/post'
3 | import { dispatch } from 'src/store'
4 |
5 | export function postStart(state) {
6 | fetchingStart(state)
7 | state.contacts.loading.post = true
8 | }
9 |
10 | export function postEnd(state) {
11 | fetchingEnd(state)
12 | state.contacts.loading.post = false
13 | state.contacts.status = 'success'
14 | }
15 |
16 | export function postError(state, error) {
17 | fetchingEnd(state)
18 | state.contacts.loading.post = false
19 | errorSet(state, { show: true, error })
20 | }
21 |
22 | export function onDone(state, { contact }) {
23 | setTimeout(() => dispatch(postAction(contact)), 0)
24 | }
25 |
26 | const modifiers = {
27 | postStart,
28 | postEnd,
29 | postError,
30 | onDone,
31 | }
32 |
33 | export const contactsReducer = (state, action) => {
34 | const modifier = modifiers[action.type]
35 | modifier(state, action.payload)
36 | }
37 |
--------------------------------------------------------------------------------
/src/email-confirm/actions/onConfirm.js:
--------------------------------------------------------------------------------
1 | export const onConfirm = activationToken => ({
2 | widget: 'emailConfirm',
3 | type: 'onConfirm',
4 | payload: { activationToken },
5 | })
6 |
--------------------------------------------------------------------------------
/src/email-confirm/actions/post.js:
--------------------------------------------------------------------------------
1 | import { postFetcher } from 'src/email-confirm/fetchers/post'
2 |
3 | export function postAction(activationToken) {
4 | return function(dispatch, getState) {
5 | dispatch({
6 | widget: 'emailConfirm',
7 | type: 'postStart',
8 | })
9 | postFetcher(activationToken)
10 | .then(() => {
11 | dispatch({
12 | widget: 'emailConfirm',
13 | type: 'postEnd',
14 | })
15 | })
16 | .catch(error => {
17 | dispatch({
18 | widget: 'emailConfirm',
19 | type: 'postError',
20 | payload: error,
21 | })
22 | })
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/email-confirm/fetchers/post.js:
--------------------------------------------------------------------------------
1 | import { fetch } from 'src/lib/services/Fetcher'
2 |
3 | export function postFetcher(activationToken) {
4 | return fetch({ method: 'POST', url: `email-confirm`, body: { activationToken } })
5 | }
6 |
--------------------------------------------------------------------------------
/src/email-confirm/reducer.js:
--------------------------------------------------------------------------------
1 | import { errorSet, fetchingStart, fetchingEnd } from 'src/global/reducer'
2 | import { postAction } from 'src/email-confirm/actions/post'
3 | import { dispatch } from 'src/store'
4 |
5 | export function postStart(state) {
6 | fetchingStart(state)
7 | state.emailConfirm.status = 'loading'
8 | }
9 |
10 | export function postEnd(state) {
11 | fetchingEnd(state)
12 | state.emailConfirm.status = 'success'
13 | }
14 |
15 | export function postError(state, error) {
16 | fetchingEnd(state)
17 | state.emailConfirm.status = 'fail'
18 | errorSet(state, { show: true, error })
19 | }
20 |
21 | export function onConfirm(state, { activationToken }) {
22 | setTimeout(() => dispatch(postAction(activationToken)), 0)
23 | }
24 |
25 | const modifiers = {
26 | postStart,
27 | postEnd,
28 | postError,
29 | onConfirm,
30 | }
31 |
32 | export const emailConfirmReducer = (state, action) => {
33 | const modifier = modifiers[action.type]
34 | modifier(state, action.payload)
35 | }
36 |
--------------------------------------------------------------------------------
/src/entries/actions/delete.js:
--------------------------------------------------------------------------------
1 | import { deleteFetcher } from 'src/entries/fetchers/delete'
2 | import { getDataAction } from 'src/global/actions/getData'
3 |
4 | export function deleteAction(entry) {
5 | return function(dispatch, getState) {
6 | const { projectId } = getState().global
7 | dispatch({
8 | widget: 'entries',
9 | type: 'deleteStart',
10 | })
11 | deleteFetcher(projectId, entry.id)
12 | .then(() => {
13 | dispatch({
14 | widget: 'entries',
15 | type: 'deleteEnd',
16 | })
17 | dispatch(getDataAction())
18 | })
19 | .catch(error => {
20 | dispatch({
21 | widget: 'entries',
22 | type: 'deleteError',
23 | payload: error,
24 | })
25 | dispatch(getDataAction())
26 | })
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/entries/actions/onAddDialogDone.js:
--------------------------------------------------------------------------------
1 | export const onAddDialogDone = entry => ({
2 | widget: 'entries',
3 | type: 'onAddDialogDone',
4 | payload: { entry },
5 | })
6 |
--------------------------------------------------------------------------------
/src/entries/actions/onAddEntry.js:
--------------------------------------------------------------------------------
1 | export const onAddEntry = model => ({
2 | widget: 'entries',
3 | type: 'onAddEntry',
4 | payload: { model },
5 | })
6 |
--------------------------------------------------------------------------------
/src/entries/actions/onConfirmDialogConfirm.js:
--------------------------------------------------------------------------------
1 | export const onConfirmDialogConfirm = () => ({
2 | widget: 'entries',
3 | type: 'onConfirmDialogConfirm',
4 | payload: {},
5 | })
6 |
--------------------------------------------------------------------------------
/src/entries/actions/onDeleteEntry.js:
--------------------------------------------------------------------------------
1 | export const onDeleteEntry = id => ({
2 | widget: 'entries',
3 | type: 'onDeleteEntry',
4 | payload: { id },
5 | })
6 |
--------------------------------------------------------------------------------
/src/entries/actions/onDialogClose.js:
--------------------------------------------------------------------------------
1 | export const onDialogClose = dialogType => ({
2 | widget: 'entries',
3 | type: 'onDialogClose',
4 | payload: { dialogType },
5 | })
6 |
--------------------------------------------------------------------------------
/src/entries/actions/onDialogExited.js:
--------------------------------------------------------------------------------
1 | export const onDialogExited = dialogType => ({
2 | widget: 'entries',
3 | type: 'onDialogExited',
4 | payload: { dialogType },
5 | })
6 |
--------------------------------------------------------------------------------
/src/entries/actions/onEditDialogDone.js:
--------------------------------------------------------------------------------
1 | export const onEditDialogDone = entry => ({
2 | widget: 'entries',
3 | type: 'onEditDialogDone',
4 | payload: { entry },
5 | })
6 |
--------------------------------------------------------------------------------
/src/entries/actions/onEditEntry.js:
--------------------------------------------------------------------------------
1 | export const onEditEntry = (entry, model) => ({
2 | widget: 'entries',
3 | type: 'onEditEntry',
4 | payload: { entry, model },
5 | })
6 |
--------------------------------------------------------------------------------
/src/entries/actions/post.js:
--------------------------------------------------------------------------------
1 | import { postFetcher } from 'src/entries/fetchers/post'
2 | import { getDataAction } from 'src/global/actions/getData'
3 | import { getAssetControlsWithFile } from 'src/lib/helpers/getAssetControlsWithFile'
4 | import { postFileFetcher } from 'src/entries/fetchers/postFileFetcher'
5 |
6 | export function postAction(entry) {
7 | return function(dispatch, getState) {
8 | const { projectId } = getState().global
9 | const errorHandler = error => {
10 | dispatch({
11 | widget: 'entries',
12 | type: 'postError',
13 | payload: error,
14 | })
15 | dispatch(getDataAction())
16 | }
17 | dispatch({
18 | widget: 'entries',
19 | type: 'postStart',
20 | })
21 | Promise.all(
22 | getAssetControlsWithFile(entry).map(assetControl => {
23 | return postFileFetcher(projectId, assetControl.value).then(fileUrl => {
24 | assetControl.value = fileUrl
25 | })
26 | })
27 | )
28 | .then(() => {
29 | postFetcher(projectId, entry)
30 | .then(() => {
31 | dispatch({
32 | widget: 'entries',
33 | type: 'postEnd',
34 | })
35 | dispatch(getDataAction())
36 | })
37 | .catch(errorHandler)
38 | })
39 | .catch(errorHandler)
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/entries/actions/put.js:
--------------------------------------------------------------------------------
1 | import { putFetcher } from 'src/entries/fetchers/put'
2 | import { getDataAction } from 'src/global/actions/getData'
3 | import { getAssetControlsWithFile } from 'src/lib/helpers/getAssetControlsWithFile'
4 | import { postFileFetcher } from 'src/entries/fetchers/postFileFetcher'
5 |
6 | export function putAction(oldEntry, newEntry) {
7 | return function(dispatch, getState) {
8 | const { projectId } = getState().global
9 | const errorHandler = error => {
10 | dispatch({
11 | widget: 'entries',
12 | type: 'putError',
13 | payload: error,
14 | })
15 | dispatch(getDataAction())
16 | }
17 | dispatch({
18 | widget: 'entries',
19 | type: 'putStart',
20 | })
21 | Promise.all(
22 | getAssetControlsWithFile(newEntry).map(assetControl => {
23 | return postFileFetcher(projectId, assetControl.value).then(fileUrl => {
24 | assetControl.value = fileUrl
25 | })
26 | })
27 | )
28 | .then(() => {
29 | putFetcher(projectId, newEntry)
30 | .then(() => {
31 | dispatch({
32 | widget: 'entries',
33 | type: 'putEnd',
34 | })
35 | dispatch(getDataAction())
36 | })
37 | .catch(errorHandler)
38 | })
39 | .catch(errorHandler)
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/entries/components/basic/EntryStringValue.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { string } from 'prop-types'
3 |
4 | export class EntryStringValue extends Component {
5 | static propTypes = {
6 | value: string,
7 | }
8 |
9 | static defaultProps = {
10 | value: '',
11 | }
12 |
13 | render() {
14 | const { value } = this.props
15 | return !value ? (
16 |
Empty string
17 | ) : (
18 | {`${value.slice(0, 350)}${value.length > 350 ? '...' : ''}`}
19 | )
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/entries/components/cards/ArrayCard.style.js:
--------------------------------------------------------------------------------
1 | import jss from 'src/lib/services/Jss'
2 | import { colors } from 'src/colors'
3 |
4 | const { classes } = jss
5 | .createStyleSheet({
6 | dividerContainer: {
7 | '&:last-child > $divider': {
8 | display: 'none',
9 | },
10 | },
11 | divider: {},
12 | error: {
13 | color: colors.error.main,
14 | },
15 | })
16 | .attach()
17 |
18 | export const cn = classes
19 |
--------------------------------------------------------------------------------
/src/entries/components/cards/ArraySubcard.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { Icon } from 'src/lib/components/Icon'
3 | import { instanceOf, arrayOf } from 'prop-types'
4 | import { Subcard } from 'src/lib/components/Subcard'
5 | import { colors } from 'src/colors'
6 | import { ArraySubmodelType } from 'src/lib/types/models/ArraySubmodelType'
7 | import { SubcardFactory } from 'src/entries/components/cards/SubcardFactory'
8 | import { SubcardDivider } from 'src/lib/components/SubcardDivider'
9 | import { EntryType } from 'src/lib/types/entries/EntryType'
10 | import { ArraySubentryType } from 'src/lib/types/entries/ArraySubentryType'
11 |
12 | import { cn } from './ArraySubcard.style'
13 |
14 | export class ArraySubcard extends Component {
15 | static propTypes = {
16 | model: instanceOf(ArraySubmodelType).isRequired,
17 | entries: arrayOf(instanceOf(EntryType)).isRequired,
18 | value: instanceOf(ArraySubentryType).isRequired,
19 | }
20 |
21 | render() {
22 | const { model, value, entries } = this.props
23 | return (
24 | }
29 | labels={[model.type]}
30 | noDivider={!value.value.length}
31 | >
32 | {value.value.length ? null : Empty array
}
33 | {value.value.map((item, index) => (
34 |
35 |
36 |
37 |
38 | ))}
39 |
40 | )
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/entries/components/cards/ArraySubcard.style.js:
--------------------------------------------------------------------------------
1 | import jss from 'src/lib/services/Jss'
2 |
3 | const { classes } = jss
4 | .createStyleSheet({
5 | dividerContainer: {
6 | '&:last-child > $divider': {
7 | display: 'none',
8 | },
9 | },
10 | divider: {},
11 | })
12 | .attach()
13 |
14 | export const cn = classes
15 |
--------------------------------------------------------------------------------
/src/entries/components/cards/CardFactory.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { instanceOf } from 'prop-types'
3 | import { ObjectCard } from 'src/entries/components/cards/ObjectCard'
4 | import { ModelType } from 'src/lib/types/models/ModelType'
5 | import { BasicTypeCard } from 'src/entries/components/cards/BasicTypeCard'
6 | import { ArrayCard } from 'src/entries/components/cards/ArrayCard'
7 |
8 | export class CardFactory extends Component {
9 | static propTypes = {
10 | model: instanceOf(ModelType).isRequired,
11 | }
12 |
13 | render() {
14 | const { model, ...props } = this.props
15 | const MAP = {
16 | 'string-line': BasicTypeCard,
17 | 'string-multiline': BasicTypeCard,
18 | 'string-markdown': BasicTypeCard,
19 | 'string-html': BasicTypeCard,
20 | number: BasicTypeCard,
21 | boolean: BasicTypeCard,
22 | object: ObjectCard,
23 | array: ArrayCard,
24 | enum: BasicTypeCard,
25 | reference: BasicTypeCard,
26 | asset: BasicTypeCard,
27 | }
28 | const Component = MAP[model.type] || (() => unknown type
)
29 | return
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/entries/components/cards/ObjectCard.style.js:
--------------------------------------------------------------------------------
1 | import jss from 'src/lib/services/Jss'
2 | import { colors } from 'src/colors'
3 |
4 | const { classes } = jss
5 | .createStyleSheet({
6 | dividerContainer: {
7 | '&:last-child > $divider': {
8 | display: 'none',
9 | },
10 | },
11 | divider: {},
12 | error: {
13 | color: colors.error.main,
14 | },
15 | })
16 | .attach()
17 |
18 | export const cn = classes
19 |
--------------------------------------------------------------------------------
/src/entries/components/cards/ObjectSubcard.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { Icon } from 'src/lib/components/Icon'
3 | import { instanceOf, arrayOf } from 'prop-types'
4 | import { Subcard } from 'src/lib/components/Subcard'
5 | import { colors } from 'src/colors'
6 | import { ObjectSubmodelType } from 'src/lib/types/models/ObjectSubmodelType'
7 | import { SubcardFactory } from 'src/entries/components/cards/SubcardFactory'
8 | import { SubcardDivider } from 'src/lib/components/SubcardDivider'
9 | import { cn } from './ObjectSubcard.style'
10 | import { isEmptyObject } from 'src/entries/helpers/isEmptyObject'
11 | import { sortKeys } from 'src/lib/helpers/sortKeys'
12 | import { EntryType } from 'src/lib/types/entries/EntryType'
13 | import { ObjectSubentryType } from 'src/lib/types/entries/ObjectSubentryType'
14 |
15 | export class ObjectSubcard extends Component {
16 | static propTypes = {
17 | model: instanceOf(ObjectSubmodelType).isRequired,
18 | entries: arrayOf(instanceOf(EntryType)).isRequired,
19 | value: instanceOf(ObjectSubentryType).isRequired,
20 | }
21 |
22 | render() {
23 | const { model, value, entries } = this.props
24 | return (
25 | }
30 | labels={[model.type]}
31 | noDivider={isEmptyObject(model, value.value)}
32 | >
33 | {!isEmptyObject(model, value.value) ? null : Empty object
}
34 | {sortKeys(model.properties).map(
35 | (key, i, keys) =>
36 | !value.value.hasOwnProperty(key) ? null : (
37 |
38 |
39 |
40 |
41 | )
42 | )}
43 |
44 | )
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/entries/components/cards/ObjectSubcard.style.js:
--------------------------------------------------------------------------------
1 | import jss from 'src/lib/services/Jss'
2 |
3 | const { classes } = jss
4 | .createStyleSheet({
5 | dividerContainer: {
6 | '&:last-child > $divider': {
7 | display: 'none',
8 | },
9 | },
10 | divider: {},
11 | })
12 | .attach()
13 |
14 | export const cn = classes
15 |
--------------------------------------------------------------------------------
/src/entries/components/cards/SubcardFactory.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { instanceOf } from 'prop-types'
3 | import { ObjectSubcard } from 'src/entries/components/cards/ObjectSubcard'
4 | import { SubmodelType } from 'src/lib/types/models/SubmodelType'
5 | import { BasicTypeSubcard } from 'src/entries/components/cards/BasicTypeSubcard'
6 | import { ArraySubcard } from 'src/entries/components/cards/ArraySubcard'
7 |
8 | export class SubcardFactory extends Component {
9 | static propTypes = {
10 | model: instanceOf(SubmodelType).isRequired,
11 | }
12 |
13 | render() {
14 | const { model, ...props } = this.props
15 | const MAP = {
16 | 'string-line': BasicTypeSubcard,
17 | 'string-multiline': BasicTypeSubcard,
18 | 'string-markdown': BasicTypeSubcard,
19 | 'string-html': BasicTypeSubcard,
20 | number: BasicTypeSubcard,
21 | boolean: BasicTypeSubcard,
22 | object: ObjectSubcard,
23 | array: ArraySubcard,
24 | enum: BasicTypeSubcard,
25 | reference: BasicTypeSubcard,
26 | asset: BasicTypeSubcard,
27 | }
28 | const Component = MAP[model.type] || (() => unknown subtype
)
29 | return
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/entries/components/dialogs/ControlContainer.style.js:
--------------------------------------------------------------------------------
1 | import jss from 'src/lib/services/Jss'
2 | import { colors } from 'src/colors'
3 |
4 | const { classes } = jss
5 | .createStyleSheet({
6 | container: {
7 | borderLeft: `3px solid`,
8 | borderLeftColor: colors.secondary.main,
9 | '&.error': {
10 | borderLeftColor: colors.error.main,
11 | },
12 | '&.disabled': {
13 | borderLeftColor: `${colors.black.t4} !important`,
14 | },
15 | },
16 | head: {
17 | position: 'relative',
18 | minHeight: 40,
19 | },
20 | left: {
21 | position: 'absolute',
22 | left: '0px',
23 | top: '0px',
24 | bottom: '0px',
25 | width: '60px',
26 | display: 'flex',
27 | alignItems: 'center',
28 | '& > div': {
29 | margin: 'auto',
30 | },
31 | },
32 | right: {
33 | marginLeft: '60px',
34 | },
35 | buttons: {
36 | display: 'inline-block',
37 | },
38 | body: {
39 | padding: '30px 0 0 32px',
40 | '&.noBodyPedding': {
41 | padding: '20px 0 0 10px',
42 | },
43 | },
44 | label: {
45 | minWidth: 50,
46 | minHeight: 20,
47 | fontSize: '0.62rem',
48 | },
49 | errorMsg: {
50 | color: colors.error.main,
51 | },
52 | })
53 | .attach()
54 |
55 | export const cn = classes
56 |
--------------------------------------------------------------------------------
/src/entries/components/dialogs/ControlFactory.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { instanceOf, oneOfType } from 'prop-types'
3 | import { ModelType } from 'src/lib/types/models/ModelType'
4 | import { StringLineControl } from 'src/entries/components/dialogs/controls/StringLineControl'
5 | import { BooleanControl } from 'src/entries/components/dialogs/controls/BooleanControl'
6 | import { NumberControl } from 'src/entries/components/dialogs/controls/NumberControl'
7 | import { StringMultilineControl } from 'src/entries/components/dialogs/controls/StringMultilineControl'
8 | import { HtmlControl } from 'src/entries/components/dialogs/controls/HtmlControl'
9 | import { MarkdownControl } from 'src/entries/components/dialogs/controls/MarkdownControl'
10 | import { ObjectControl } from 'src/entries/components/dialogs/controls/ObjectControl'
11 | import { SubmodelType } from 'src/lib/types/models/SubmodelType'
12 | import { ArrayControl } from 'src/entries/components/dialogs/controls/ArrayControl'
13 | import { EnumControl } from 'src/entries/components/dialogs/controls/EnumControl'
14 | import { ReferenceControl } from 'src/entries/components/dialogs/controls/ReferenceControl'
15 | import { AssetControl } from 'src/entries/components/dialogs/controls/AssetControl'
16 |
17 | export class ControlFactory extends Component {
18 | static propTypes = {
19 | model: oneOfType([instanceOf(ModelType), instanceOf(SubmodelType)]).isRequired,
20 | }
21 |
22 | render() {
23 | const { model, ...props } = this.props
24 | const MAP = {
25 | 'string-line': StringLineControl,
26 | 'string-multiline': StringMultilineControl,
27 | 'string-html': HtmlControl,
28 | 'string-markdown': MarkdownControl,
29 | boolean: BooleanControl,
30 | number: NumberControl,
31 | object: ObjectControl,
32 | array: ArrayControl,
33 | enum: EnumControl,
34 | reference: ReferenceControl,
35 | asset: AssetControl,
36 | }
37 | const Component = MAP[model.type]
38 | return
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/entries/components/dialogs/EntryDialog.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { func, bool, string, instanceOf, arrayOf } from 'prop-types'
3 | import { ModelType } from 'src/lib/types/models/ModelType'
4 | import { EntryType } from 'src/lib/types/entries/EntryType'
5 | import { Dialog } from 'src/lib/components/Dialog'
6 | import { EntryDialogInner } from 'src/entries/components/dialogs/EntryDialogInner'
7 |
8 | export class EntryDialog extends Component {
9 | static propTypes = {
10 | open: bool.isRequired,
11 | onDone: func.isRequired,
12 | onClose: func.isRequired,
13 | model: instanceOf(ModelType),
14 | entry: instanceOf(EntryType),
15 | title: string.isRequired,
16 | onExited: func.isRequired,
17 | entries: arrayOf(instanceOf(EntryType)).isRequired,
18 | }
19 |
20 | static defaultProps = {
21 | model: null,
22 | entry: null,
23 | }
24 |
25 | render() {
26 | const { open, onClose, onDone, model, entry, title, onExited, entries } = this.props
27 | if (!model) return null
28 | return (
29 |
32 | )
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/entries/components/dialogs/controls/ArrayControl.style.js:
--------------------------------------------------------------------------------
1 | import jss from 'src/lib/services/Jss'
2 | import { colors } from 'src/colors'
3 |
4 | const { classes } = jss
5 | .createStyleSheet({
6 | controlContainer: {
7 | marginBottom: '24px',
8 | '&:last-child': {
9 | marginBottom: '0',
10 | },
11 | },
12 | disabled: {
13 | color: `${colors.black.t4}`,
14 | },
15 | addBtnContainer: {
16 | marginTop: '24px',
17 | borderLeft: `3px solid ${colors.secondary.main}`,
18 | '&.disabled': {
19 | borderLeftColor: `${colors.black.t4} !important`,
20 | },
21 | },
22 | })
23 | .attach()
24 |
25 | export const cn = classes
26 |
--------------------------------------------------------------------------------
/src/entries/components/dialogs/controls/BooleanControl.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { func, string, bool, oneOfType, instanceOf } from 'prop-types'
3 | import { Switch } from 'src/lib/components/controls/Switch'
4 | import { ControlContainer } from 'src/entries/components/dialogs/ControlContainer'
5 | import { BooleanModelType } from 'src/lib/types/models/BooleanModelType'
6 | import { BooleanSubmodelType } from 'src/lib/types/models/BooleanSubmodelType'
7 |
8 | export class BooleanControl extends Component {
9 | static propTypes = {
10 | model: oneOfType([instanceOf(BooleanModelType), instanceOf(BooleanSubmodelType)]).isRequired,
11 | value: bool.isRequired,
12 | onBooleanChange: func.isRequired,
13 | disabled: bool,
14 | propBtnStatus: string,
15 | onPropBtnStatusChange: func,
16 | onItemDelete: func,
17 | onItemUp: func,
18 | onItemDown: func,
19 | }
20 |
21 | static defaultProps = {
22 | /* if it is object prop */
23 | disabled: false,
24 | onPropBtnStatusChange: null,
25 | propBtnStatus: null,
26 | /* if it is array item */
27 | onItemDelete: null,
28 | onItemUp: null,
29 | onItemDown: null,
30 | }
31 |
32 | render() {
33 | const {
34 | model,
35 | value,
36 | onBooleanChange,
37 | disabled,
38 | propBtnStatus,
39 | onPropBtnStatusChange,
40 | onItemDelete,
41 | onItemUp,
42 | onItemDown,
43 | } = this.props
44 | return (
45 |
58 |
59 |
60 | )
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/entries/components/dialogs/controls/ObjectControl.style.js:
--------------------------------------------------------------------------------
1 | import jss from 'src/lib/services/Jss'
2 | import { colors } from 'src/colors'
3 |
4 | const { classes } = jss
5 | .createStyleSheet({
6 | controlContainer: {
7 | marginBottom: '24px',
8 | '&:last-child': {
9 | marginBottom: '0',
10 | },
11 | },
12 | disabled: {
13 | color: `${colors.black.t4}`,
14 | },
15 | })
16 | .attach()
17 |
18 | export const cn = classes
19 |
--------------------------------------------------------------------------------
/src/entries/components/dialogs/controls/StringLineControl.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { func, string, bool, oneOfType, instanceOf } from 'prop-types'
3 | import { ControlContainer } from 'src/entries/components/dialogs/ControlContainer'
4 | import { StringModelType } from 'src/lib/types/models/StringModelType'
5 | import { StringSubmodelType } from 'src/lib/types/models/StringSubmodelType'
6 | import { TextInput } from 'src/lib/components/controls/TextInput'
7 |
8 | export class StringLineControl extends Component {
9 | static propTypes = {
10 | model: oneOfType([instanceOf(StringModelType), instanceOf(StringSubmodelType)]).isRequired,
11 | value: string.isRequired,
12 | error: string.isRequired,
13 | onStringChange: func.isRequired,
14 | onBlur: func.isRequired,
15 | disabled: bool,
16 | propBtnStatus: string,
17 | onPropBtnStatusChange: func,
18 | onItemDelete: func,
19 | onItemUp: func,
20 | onItemDown: func,
21 | }
22 |
23 | static defaultProps = {
24 | /* if it is object prop */
25 | disabled: false,
26 | onPropBtnStatusChange: null,
27 | propBtnStatus: null,
28 | /* if it is array item */
29 | onItemDelete: null,
30 | onItemUp: null,
31 | onItemDown: null,
32 | }
33 |
34 | render() {
35 | const {
36 | model,
37 | value,
38 | error,
39 | onStringChange,
40 | onBlur,
41 | disabled,
42 | propBtnStatus,
43 | onPropBtnStatusChange,
44 | onItemDelete,
45 | onItemUp,
46 | onItemDown,
47 | } = this.props
48 | return (
49 |
63 |
64 |
65 | )
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/entries/fetchers/delete.js:
--------------------------------------------------------------------------------
1 | import { fetch } from 'src/lib/services/Fetcher'
2 |
3 | export function deleteFetcher(projectId, id) {
4 | return fetch({ method: 'DELETE', url: `projects/${projectId}/entries/${id}` })
5 | }
6 |
--------------------------------------------------------------------------------
/src/entries/fetchers/post.js:
--------------------------------------------------------------------------------
1 | import { fetch } from 'src/lib/services/Fetcher'
2 |
3 | export function postFetcher(projectId, entry) {
4 | return fetch({ method: 'POST', url: `projects/${projectId}/entries`, body: entry })
5 | }
6 |
--------------------------------------------------------------------------------
/src/entries/fetchers/postFileFetcher.js:
--------------------------------------------------------------------------------
1 | import { fetch } from 'src/lib/services/Fetcher'
2 |
3 | export function postFileFetcher(projectId, file) {
4 | return fetch({ method: 'POST', url: `projects/${projectId}/files`, file }).then(({ name, id }) => {
5 | return `/files/${id}/${name}`
6 | })
7 | }
8 |
--------------------------------------------------------------------------------
/src/entries/fetchers/put.js:
--------------------------------------------------------------------------------
1 | import { fetch } from 'src/lib/services/Fetcher'
2 |
3 | export function putFetcher(projectId, entry) {
4 | return fetch({ method: 'PUT', url: `projects/${projectId}/entries/${entry.id}`, body: entry })
5 | }
6 |
--------------------------------------------------------------------------------
/src/entries/helpers/isEmptyObject.js:
--------------------------------------------------------------------------------
1 | export const isEmptyObject = (model, value) =>
2 | !Object.keys(model.properties).some(key => Object.keys(value).some(item => item === key))
3 |
--------------------------------------------------------------------------------
/src/explorer/components/Explorer.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | // import { arrayOf, func, bool, object } from 'prop-types'
3 | import { connect } from 'react-redux'
4 | import SwaggerUI from 'swagger-ui'
5 | // import { exampleConfig } from './exampleConfig'
6 | import { config } from './config'
7 |
8 | class AExplorer extends Component {
9 | static propTypes = {}
10 |
11 | id = `swagger-id-${Math.round(Math.random() * 1e9)}`
12 |
13 | componentDidMount() {
14 | const { id } = this
15 | SwaggerUI({
16 | dom_id: `#${id}`,
17 | spec: config,
18 | })
19 | }
20 |
21 | render() {
22 | const { id } = this
23 | return (
24 |
27 | )
28 | }
29 | }
30 |
31 | export const Explorer = connect(
32 | state => ({}),
33 | dispatch => ({})
34 | )(AExplorer)
35 |
--------------------------------------------------------------------------------
/src/global/actions/errorSet.js:
--------------------------------------------------------------------------------
1 | export const setErrorAction = (show, error) => ({
2 | widget: 'global',
3 | type: 'errorSet',
4 | payload: {
5 | show,
6 | error,
7 | },
8 | })
9 |
--------------------------------------------------------------------------------
/src/global/actions/fetchingEnd.js:
--------------------------------------------------------------------------------
1 | export const fetchingEndAction = () => ({
2 | widget: 'global',
3 | type: 'fetchingEnd',
4 | payload: {},
5 | })
6 |
--------------------------------------------------------------------------------
/src/global/actions/fetchingStart.js:
--------------------------------------------------------------------------------
1 | export const fetchingStartAction = () => ({
2 | widget: 'global',
3 | type: 'fetchingStart',
4 | payload: {},
5 | })
6 |
--------------------------------------------------------------------------------
/src/global/actions/getData.js:
--------------------------------------------------------------------------------
1 | import { getEntriesFetcher } from 'src/global/fetchers/getEntries'
2 | import { getModelsFetcher } from 'src/global/fetchers/getModels'
3 | import { getProjectsFetcher } from 'src/global/fetchers/getProjects'
4 | import Promise from 'src/lib/services/Promise'
5 | import { createEntry } from 'src/lib/helpers/createEntry'
6 | import { createModel } from 'src/lib/helpers/createModel'
7 |
8 | export const getDataAction = function(projectId) {
9 | return function(dispatch, getState) {
10 | const state = getState()
11 | const { projectId: stateProjectId } = state.global
12 | if (state.models.loading.get && state.entries.loading.get) return
13 | dispatch({
14 | widget: 'global',
15 | type: 'getStart',
16 | })
17 | Promise.all([
18 | getProjectsFetcher(),
19 | getEntriesFetcher(projectId || stateProjectId),
20 | getModelsFetcher(projectId || stateProjectId),
21 | ])
22 | .then(([projects, entries, models]) => {
23 | dispatch({
24 | widget: 'global',
25 | type: 'getEnd',
26 | payload: {
27 | projects: projects,
28 | models: models.map(model => createModel(model)),
29 | entries: entries.map(entry => createEntry(entry)),
30 | },
31 | })
32 | })
33 | .catch(error => {
34 | dispatch({
35 | widget: 'global',
36 | type: 'getError',
37 | payload: error,
38 | })
39 | })
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/global/actions/projectIdSet.js:
--------------------------------------------------------------------------------
1 | export const projectIdSet = projectId => ({
2 | widget: 'global',
3 | type: 'projectIdSet',
4 | payload: { projectId },
5 | })
6 |
--------------------------------------------------------------------------------
/src/global/actions/redirectSet.js:
--------------------------------------------------------------------------------
1 | export const redirectSetAction = url => ({
2 | widget: 'global',
3 | type: 'redirectSet',
4 | payload: url,
5 | })
6 |
--------------------------------------------------------------------------------
/src/global/components/Content.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { node } from 'prop-types'
3 |
4 | import { cn } from './Content.style.js'
5 |
6 | export class Content extends React.Component {
7 | static propTypes = {
8 | children: node.isRequired,
9 | }
10 |
11 | render() {
12 | const { children } = this.props
13 | return {children}
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/global/components/Content.style.js:
--------------------------------------------------------------------------------
1 | import jss from 'src/lib/services/Jss'
2 |
3 | const { classes } = jss
4 | .createStyleSheet({
5 | content: {
6 | padding: '20px',
7 | },
8 | })
9 | .attach()
10 |
11 | export const cn = classes
12 |
--------------------------------------------------------------------------------
/src/global/components/ErrorContainer.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { func, string, shape, bool } from 'prop-types'
3 | import Snackbar from 'material-ui/Snackbar'
4 | import { connect } from 'react-redux'
5 | import { setErrorAction } from 'src/global/actions/errorSet'
6 |
7 | import { cn } from './ErrorContainer.style.js'
8 |
9 | class AErrorContainer extends Component {
10 | static propTypes = {
11 | errorSet: func.isRequired,
12 | error: shape({
13 | show: bool.isRequired,
14 | message: string.isRequired,
15 | }).isRequired,
16 | }
17 |
18 | render() {
19 | const { error, errorSet } = this.props
20 | return (
21 | errorSet(false)}
26 | message={{error.message}}
27 | />
28 | )
29 | }
30 | }
31 |
32 | export const ErrorContainer = connect(
33 | state => ({
34 | error: state.global.error,
35 | }),
36 | dispatch => ({
37 | errorSet: (...props) => dispatch(setErrorAction(...props)),
38 | })
39 | )(AErrorContainer)
40 |
--------------------------------------------------------------------------------
/src/global/components/ErrorContainer.style.js:
--------------------------------------------------------------------------------
1 | import jss from 'src/lib/services/Jss'
2 | import { colors } from 'src/colors'
3 |
4 | const { classes } = jss
5 | .createStyleSheet({
6 | errorAlert: {
7 | '& > div': {
8 | 'background-color': colors.error.main,
9 | },
10 | },
11 | })
12 | .attach()
13 |
14 | export const cn = classes
15 |
--------------------------------------------------------------------------------
/src/global/components/Header.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { node } from 'prop-types'
3 | import { cn } from './Header.style'
4 |
5 | export class Header extends Component {
6 | static propTypes = {
7 | children: node.isRequired,
8 | }
9 |
10 | render() {
11 | const { children } = this.props
12 | return {children}
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/global/components/Header.style.js:
--------------------------------------------------------------------------------
1 | import jss from 'src/lib/services/Jss'
2 | import { colors } from 'src/colors'
3 |
4 | const { classes } = jss
5 | .createStyleSheet({
6 | header: {
7 | height: '36px',
8 | background: colors.tertiary.d2,
9 | display: 'flex',
10 | alignItems: 'center',
11 | justifyContent: 'flex-end',
12 | padding: '20px',
13 | borderBottom: `1px solid ${colors.grey.l3t5}`,
14 | },
15 | })
16 | .attach()
17 |
18 | export const cn = classes
19 |
--------------------------------------------------------------------------------
/src/global/components/Loader.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { cn } from 'src/global/components/Loader.style'
3 | import { LinearProgress } from 'src/lib/components/LinearProgress'
4 | import { connect } from 'react-redux'
5 | import { arrayOf, bool } from 'prop-types'
6 |
7 | export class ALoader extends Component {
8 | static propTypes = {
9 | loading: arrayOf(bool).isRequired,
10 | }
11 |
12 | render() {
13 | const { loading } = this.props
14 | return loading.some(bool => bool) ? (
15 |
16 |
17 |
18 | ) : null
19 | }
20 | }
21 |
22 | export const Loader = connect(
23 | state => ({
24 | loading: state.global.loading,
25 | }),
26 | dispatch => ({})
27 | )(ALoader)
28 |
--------------------------------------------------------------------------------
/src/global/components/Loader.style.js:
--------------------------------------------------------------------------------
1 | import jss from 'src/lib/services/Jss'
2 |
3 | const { classes } = jss
4 | .createStyleSheet({
5 | loader: {
6 | width: '100%',
7 | background: 'white',
8 | position: 'fixed',
9 | top: '0',
10 | zIndex: 1,
11 | },
12 | })
13 | .attach()
14 |
15 | export const cn = classes
16 |
--------------------------------------------------------------------------------
/src/global/components/Redirect.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { func } from 'prop-types'
3 | import { Redirect as ReactRedirect } from 'react-router'
4 | import { connect } from 'react-redux'
5 | import { redirectSetAction } from 'src/global/actions/redirectSet'
6 |
7 | class ARedirect extends Component {
8 | static propTypes = {
9 | redirectSet: func.isRequired,
10 | }
11 |
12 | componentDidMount() {
13 | const { redirectSet } = this.props
14 | redirectSet('')
15 | }
16 |
17 | render() {
18 | const { redirectSet, ...props } = this.props
19 | return
20 | }
21 | }
22 |
23 | export const Redirect = connect(
24 | state => ({}),
25 | dispatch => ({
26 | redirectSet: (...props) => dispatch(redirectSetAction(...props)),
27 | })
28 | )(ARedirect)
29 |
--------------------------------------------------------------------------------
/src/global/components/RedirectContainer.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { string } from 'prop-types'
3 | import { Redirect } from 'src/global/components/Redirect'
4 | import { connect } from 'react-redux'
5 |
6 | class ARedirectContainer extends Component {
7 | static propTypes = {
8 | redirect: string.isRequired,
9 | }
10 |
11 | render() {
12 | const { redirect } = this.props
13 | return !redirect ? null :
14 | }
15 | }
16 |
17 | export const RedirectContainer = connect(
18 | state => ({
19 | redirect: state.global.redirect,
20 | }),
21 | dispatch => ({})
22 | )(ARedirectContainer)
23 |
--------------------------------------------------------------------------------
/src/global/fetchers/getEntries.js:
--------------------------------------------------------------------------------
1 | import { fetch } from 'src/lib/services/Fetcher'
2 |
3 | export const getEntriesFetcher = projectId => {
4 | return fetch({ method: 'GET', url: `projects/${projectId}/entries` })
5 | }
6 |
--------------------------------------------------------------------------------
/src/global/fetchers/getModels.js:
--------------------------------------------------------------------------------
1 | import { fetch } from 'src/lib/services/Fetcher'
2 |
3 | export const getModelsFetcher = projectId => {
4 | return fetch({ method: 'GET', url: `projects/${projectId}/models` })
5 | }
6 |
--------------------------------------------------------------------------------
/src/global/fetchers/getProjects.js:
--------------------------------------------------------------------------------
1 | import { fetch } from 'src/lib/services/Fetcher'
2 |
3 | export const getProjectsFetcher = () => {
4 | return fetch({ method: 'GET', url: `projects` })
5 | }
6 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import { App } from './App'
4 | import * as serviceWorker from './serviceWorker'
5 |
6 | ReactDOM.render(, document.getElementById('root'))
7 |
8 | // If you want your app to work offline and load faster, you can change
9 | // unregister() to register() below. Note this comes with some pitfalls.
10 | // Learn more about service workers: https://bit.ly/CRA-PWA
11 | serviceWorker.unregister()
12 |
--------------------------------------------------------------------------------
/src/index/components/Index.style.js:
--------------------------------------------------------------------------------
1 | import jss from 'src/lib/services/Jss'
2 | import { colors } from 'src/colors'
3 |
4 | const { classes } = jss
5 | .createStyleSheet({
6 | card: {
7 | padding: '20px',
8 | background: colors.white.main,
9 | boxShadow:
10 | '0px 1px 5px 0px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 3px 1px -2px rgba(0, 0, 0, 0.12)',
11 | borderRadius: '2px',
12 | },
13 | container: {
14 | position: 'relative',
15 | },
16 | left: {
17 | position: 'absolute',
18 | },
19 | right: {
20 | marginLeft: '68px',
21 | },
22 | })
23 | .attach()
24 |
25 | export const cn = classes
26 |
--------------------------------------------------------------------------------
/src/landing/components/GithubCorner.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | import { cn } from './GithubCorner.style'
4 |
5 | export class GithubCorner extends React.Component {
6 | render() {
7 | return (
8 |
13 |
39 |
40 | )
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/landing/components/GithubCorner.style.js:
--------------------------------------------------------------------------------
1 | import jss from 'src/lib/services/Jss'
2 |
3 | const { classes } = jss
4 | .createStyleSheet({
5 | svg: {
6 | fill: '#151513',
7 | color: '#fff',
8 | position: 'absolute',
9 | top: 0,
10 | border: 0,
11 | left: 0,
12 | transform: 'scale(-1, 1)',
13 | },
14 | path: {
15 | transformOrigin: '130px 106px',
16 | },
17 | })
18 | .attach()
19 |
20 | export const cn = classes
21 |
--------------------------------------------------------------------------------
/src/landing/components/Landing.style.js:
--------------------------------------------------------------------------------
1 | import jss from 'src/lib/services/Jss'
2 | import { colors } from 'src/colors'
3 |
4 | const { classes } = jss
5 | .createStyleSheet({
6 | header: {
7 | background: colors.white.main,
8 | boxShadow: '0px 1px 4px 0px rgba(13,26,44,.23)',
9 | padding: 22,
10 | },
11 | body: {
12 | width: 760,
13 | margin: 'auto',
14 | padding: '0 4px',
15 | },
16 | messages: {
17 | marginTop: 60,
18 | },
19 | message: {
20 | background: colors.primary.l5t5,
21 | padding: 15,
22 | borderRadius: 2,
23 | marginTop: 15,
24 | },
25 | title: {
26 | paddingTop: 40,
27 | fontSize: 40,
28 | fontWeight: 300,
29 | lineHeight: '52px',
30 | },
31 | explanation: {
32 | fontSize: 14,
33 | lineHeight: 1.7,
34 | },
35 | })
36 | .attach()
37 |
38 | export const cn = classes
39 |
--------------------------------------------------------------------------------
/src/lib/components/Button.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { node, bool, oneOf, func } from 'prop-types'
3 | import { Button as AButton } from 'material-ui'
4 |
5 | import { cn } from './Button.style'
6 |
7 | export class Button extends Component {
8 | static propTypes = {
9 | onClick: func.isRequired,
10 | children: node.isRequired,
11 | color: oneOf(['primary', 'secondary', 'accent']),
12 | size: oneOf(['lg', 'md', 'sm', 'xs']),
13 | filled: bool,
14 | outlined: bool,
15 | disabled: bool,
16 | }
17 |
18 | static defaultProps = {
19 | color: 'primary',
20 | size: 'lg',
21 | filled: false,
22 | outlined: false,
23 | disabled: false,
24 | }
25 |
26 | render() {
27 | const { onClick, children, size, color, filled, outlined, disabled } = this.props
28 | const MAP_COLORS = {
29 | primary: cn.primary,
30 | secondary: cn.secondary,
31 | accent: cn.accent,
32 | }
33 | const MAP_SIZE = {
34 | lg: cn.lg,
35 | md: cn.md,
36 | sm: cn.sm,
37 | xs: cn.xs,
38 | }
39 | const colorClasses = disabled ? cn.disabled : `${MAP_COLORS[color]} ${filled ? 'filled' : ''}`
40 | const sizeClasses = MAP_SIZE[size]
41 | const outlineClasses = outlined ? 'outlined' : ''
42 | return (
43 |
50 | {children}
51 |
52 | )
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/lib/components/Card.style.js:
--------------------------------------------------------------------------------
1 | import jss from 'src/lib/services/Jss'
2 |
3 | const { classes } = jss
4 | .createStyleSheet({
5 | container: {
6 | background: '#fff',
7 | boxShadow:
8 | '0px 2px 4px -1px rgba(0, 0, 0, 0.2), 0px 4px 5px 0px rgba(0, 0, 0, 0.14), 0px 1px 10px 0px rgba(0, 0, 0, 0.12)',
9 | borderRadius: '2px',
10 | marginBottom: '15px',
11 | position: 'relative',
12 | '&:hover $cardButtons': {
13 | visibility: 'visible !important',
14 | },
15 | },
16 | cardButtons: {
17 | display: 'inline-block',
18 | visibility: 'hidden',
19 | },
20 | left: {
21 | borderRadius: '2px 0 0 2px',
22 | position: 'absolute',
23 | left: '0px',
24 | top: '0px',
25 | bottom: '0px',
26 | width: '80px',
27 | display: 'flex',
28 | alignItems: 'center',
29 | '& > div': {
30 | margin: 'auto',
31 | },
32 | },
33 | right: {
34 | marginLeft: '80px',
35 | },
36 | head: {
37 | padding: '10px',
38 | },
39 | body: {
40 | padding: '10px',
41 | },
42 | exclamationIcon: {
43 | display: 'inline-block',
44 | position: 'relative',
45 | top: '4px',
46 | },
47 | })
48 | .attach()
49 |
50 | export const cn = classes
51 |
--------------------------------------------------------------------------------
/src/lib/components/CircledIcon.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { string, node, number } from 'prop-types'
3 | import { Avatar } from 'material-ui'
4 |
5 | export class CircledIcon extends Component {
6 | static propTypes = {
7 | children: node.isRequired,
8 | size: number,
9 | color: string,
10 | className: string,
11 | }
12 |
13 | static defaultProps = {
14 | size: 50,
15 | color: '#fff',
16 | className: '',
17 | }
18 |
19 | render() {
20 | const { children, size, color, className } = this.props
21 | return (
22 |
23 | {children}
24 |
25 | )
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/lib/components/CircularProgress.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { number } from 'prop-types'
3 | import { CircularProgress as ACircularProgress } from 'material-ui/Progress'
4 |
5 | import { cn } from './CircularProgress.style'
6 |
7 | export class CircularProgress extends Component {
8 | static propTypes = {
9 | size: number,
10 | }
11 |
12 | static defaultProps = {
13 | size: 100,
14 | }
15 |
16 | render() {
17 | const { size } = this.props
18 | return
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/lib/components/CircularProgress.style.js:
--------------------------------------------------------------------------------
1 | import jss from 'src/lib/services/Jss'
2 | import { colors } from 'src/colors'
3 |
4 | const { classes } = jss
5 | .createStyleSheet({
6 | container: {
7 | color: colors.primary.main,
8 | },
9 | })
10 | .attach()
11 |
12 | export const cn = classes
13 |
--------------------------------------------------------------------------------
/src/lib/components/ConfirmDialog.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { func, bool, string } from 'prop-types'
3 | import { Dialog } from 'src/lib/components/Dialog'
4 | import { DialogActions } from 'src/lib/components/DialogActions'
5 | import { DialogContent } from 'src/lib/components/DialogContent'
6 | import { Typography } from 'src/lib/components/Typography'
7 | import { Button } from 'src/lib/components/Button'
8 |
9 | export class ConfirmDialog extends Component {
10 | static propTypes = {
11 | title: string.isRequired,
12 | text: string.isRequired,
13 | open: bool.isRequired,
14 | onClose: func.isRequired,
15 | onDone: func.isRequired,
16 | onExited: func,
17 | }
18 |
19 | static defaultProps = {
20 | onExited: () => {},
21 | }
22 |
23 | render() {
24 | const { title, text, onClose, onDone, onExited, open } = this.props
25 | return (
26 |
36 | )
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/lib/components/Dialog.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import ADialog from 'material-ui/Dialog'
3 | import { Divider } from 'material-ui'
4 | import { DialogTitle } from 'material-ui/Dialog'
5 | import { func, node, bool, number, string } from 'prop-types'
6 | import { LinearProgress } from 'src/lib/components/LinearProgress'
7 |
8 | import { cn } from './Dialog.style'
9 |
10 | export class Dialog extends Component {
11 | static propTypes = {
12 | open: bool.isRequired,
13 | onClose: func.isRequired,
14 | onExited: func,
15 | onEnter: func,
16 | children: node.isRequired,
17 | progress: number,
18 | title: string.isRequired,
19 | maxWidth: string,
20 | }
21 |
22 | static defaultProps = {
23 | progress: null,
24 | onEnter: () => {},
25 | onExited: () => {},
26 | maxWidth: 'md',
27 | }
28 |
29 | render() {
30 | const { onEnter, open, onClose, children, onExited, progress, title, maxWidth } = this.props
31 | return (
32 |
45 | {title}
46 | {progress === null ? (
47 |
48 | ) : (
49 |
50 |
51 |
52 | )}
53 | {children}
54 |
55 | )
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/lib/components/Dialog.style.js:
--------------------------------------------------------------------------------
1 | import jss from 'src/lib/services/Jss'
2 |
3 | const { classes } = jss
4 | .createStyleSheet({
5 | dialog: {
6 | 'align-items': 'flex-start !important',
7 | },
8 | })
9 | .attach()
10 |
11 | export const cn = classes
12 |
--------------------------------------------------------------------------------
/src/lib/components/DialogActions.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { Grid } from 'material-ui'
3 | import { func, node } from 'prop-types'
4 | import { Button } from 'src/lib/components/Button'
5 | import { DialogActions as ADialogActions } from 'material-ui/Dialog'
6 |
7 | import { cn } from './DialogActions.style'
8 |
9 | export class DialogActions extends Component {
10 | static propTypes = {
11 | onClose: func.isRequired,
12 | children: node,
13 | }
14 |
15 | static defaultProps = {
16 | children: null,
17 | }
18 |
19 | render() {
20 | const { onClose, children } = this.props
21 | return (
22 |
23 |
24 |
25 |
26 |
29 |
30 |
31 |
32 | {children}
33 |
34 |
35 |
36 | )
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/lib/components/DialogActions.style.js:
--------------------------------------------------------------------------------
1 | import jss from 'src/lib/services/Jss'
2 |
3 | const { classes } = jss
4 | .createStyleSheet({
5 | dialogActions: {
6 | padding: '5px',
7 | },
8 | actionsLeft: {
9 | 'justify-content': 'flex-start',
10 | },
11 | })
12 | .attach()
13 |
14 | export const cn = classes
15 |
--------------------------------------------------------------------------------
/src/lib/components/DialogContent.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { node } from 'prop-types'
3 | import { DialogContent as ADialogContent } from 'material-ui/Dialog'
4 |
5 | import { cn } from './DialogContent.style'
6 |
7 | export class DialogContent extends Component {
8 | static propTypes = {
9 | children: node.isRequired,
10 | }
11 |
12 | render() {
13 | const { children } = this.props
14 | return {children}
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/lib/components/DialogContent.style.js:
--------------------------------------------------------------------------------
1 | import jss from 'src/lib/services/Jss'
2 |
3 | const { classes } = jss
4 | .createStyleSheet({
5 | dialogContent: {
6 | 'padding-top': '24px !important',
7 | overflowY: 'inherit',
8 | },
9 | })
10 | .attach()
11 |
12 | export const cn = classes
13 |
--------------------------------------------------------------------------------
/src/lib/components/LinearProgress.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { bool } from 'prop-types'
3 | import { LinearProgress as ALinearProgress } from 'material-ui/Progress'
4 | import { cn } from './LinearProgress.style'
5 |
6 | export class LinearProgress extends Component {
7 | static propTypes = {
8 | noHeight: bool,
9 | light: bool,
10 | }
11 |
12 | static defaultProps = {
13 | noHeight: false,
14 | light: false,
15 | }
16 |
17 | render() {
18 | const { noHeight, light, ...props } = this.props
19 | return (
20 |
28 | )
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/lib/components/LinearProgress.style.js:
--------------------------------------------------------------------------------
1 | import jss from 'src/lib/services/Jss'
2 | import { colors } from 'src/colors'
3 |
4 | const { classes } = jss
5 | .createStyleSheet({
6 | progressBg: {
7 | backgroundColor: colors.primary.d2t4,
8 | },
9 | progressColor: {
10 | backgroundColor: colors.primary.d2,
11 | },
12 | progressColorLight: {
13 | backgroundColor: colors.secondary.d5t2,
14 | },
15 | progressNoHeight: {
16 | marginBottom: -5,
17 | },
18 | })
19 | .attach()
20 |
21 | export const cn = classes
22 |
--------------------------------------------------------------------------------
/src/lib/components/MessageBlock.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { node, number } from 'prop-types'
3 |
4 | import { cn } from './MessageBlock.style'
5 |
6 | export class MessageBlock extends Component {
7 | static propTypes = {
8 | children: node.isRequired,
9 | minWidth: number,
10 | maxWidth: number,
11 | }
12 |
13 | static defaultProps = {
14 | minWidth: 300,
15 | maxWidth: 300,
16 | }
17 |
18 | render() {
19 | const { children, minWidth, maxWidth } = this.props
20 | return (
21 |
22 | {children}
23 |
24 | )
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/lib/components/MessageBlock.style.js:
--------------------------------------------------------------------------------
1 | import jss from 'src/lib/services/Jss'
2 | import { colors } from 'src/colors'
3 |
4 | const { classes } = jss
5 | .createStyleSheet({
6 | card: {
7 | padding: '20px',
8 | display: 'inline-block',
9 | background: colors.white.main,
10 | boxShadow:
11 | '0px 1px 5px 0px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 3px 1px -2px rgba(0, 0, 0, 0.12)',
12 | borderRadius: '2px',
13 | },
14 | })
15 | .attach()
16 |
17 | export const cn = classes
18 |
--------------------------------------------------------------------------------
/src/lib/components/PageContainer.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { node } from 'prop-types'
3 |
4 | import { cn } from './PageContainer.style'
5 |
6 | export class PageContainer extends Component {
7 | static propTypes = {
8 | children: node.isRequired,
9 | }
10 |
11 | render() {
12 | const { children } = this.props
13 | return {children}
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/lib/components/PageContainer.style.js:
--------------------------------------------------------------------------------
1 | import jss from 'src/lib/services/Jss'
2 | import { colors } from 'src/colors'
3 |
4 | const { classes } = jss
5 | .createStyleSheet({
6 | container: {
7 | minHeight: '100%',
8 | background: colors.tertiary.main,
9 | },
10 | })
11 | .attach()
12 |
13 | export const cn = classes
14 |
--------------------------------------------------------------------------------
/src/lib/components/Subcard.style.js:
--------------------------------------------------------------------------------
1 | import jss from 'src/lib/services/Jss'
2 |
3 | const { classes } = jss
4 | .createStyleSheet({
5 | container: {
6 | background: '#fff',
7 | borderRadius: '2px',
8 | position: 'relative',
9 | minHeight: 40,
10 | },
11 | left: {
12 | borderLeft: `4px solid`,
13 | position: 'absolute',
14 | left: '0px',
15 | top: '0px',
16 | bottom: '0px',
17 | width: '60px',
18 | display: 'flex',
19 | alignItems: 'center',
20 | '& > div': {
21 | margin: 'auto',
22 | },
23 | },
24 | right: {
25 | marginLeft: '64px',
26 | },
27 | head: {
28 | padding: '0',
29 | },
30 | body: {
31 | padding: '10px 0 0',
32 | fontSize: '12px',
33 | },
34 | label: {
35 | minWidth: 50,
36 | minHeight: 20,
37 | fontSize: '0.62rem',
38 | },
39 | exclamationIcon: {
40 | display: 'inline-block',
41 | position: 'relative',
42 | top: '3px',
43 | },
44 | })
45 | .attach()
46 |
47 | export const cnHoverTrick = () => {
48 | const { classes } = jss
49 | .createStyleSheet({
50 | hoverContainer: {
51 | '&:hover $cardButtons': {
52 | visibility: 'visible !important',
53 | },
54 | },
55 | cardButtons: {
56 | display: 'inline-block',
57 | visibility: 'hidden',
58 | },
59 | })
60 | .attach()
61 |
62 | return classes
63 | }
64 |
65 | export const cn = classes
66 |
--------------------------------------------------------------------------------
/src/lib/components/SubcardDivider.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { string } from 'prop-types'
3 | import { Divider } from 'material-ui'
4 | import { cn } from './SubcardDivider.style'
5 |
6 | export class SubcardDivider extends Component {
7 | static propTypes = {
8 | className: string,
9 | }
10 |
11 | static defaultProps = {
12 | className: '',
13 | }
14 |
15 | render() {
16 | const { className } = this.props
17 | return
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/lib/components/SubcardDivider.style.js:
--------------------------------------------------------------------------------
1 | import jss from 'src/lib/services/Jss'
2 |
3 | const { classes } = jss
4 | .createStyleSheet({
5 | divider: {
6 | margin: '8px 0',
7 | },
8 | })
9 | .attach()
10 |
11 | export const cn = classes
12 |
--------------------------------------------------------------------------------
/src/lib/components/Typography.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { string, node, bool } from 'prop-types'
3 |
4 | import { cn } from './Typography.style'
5 |
6 | export class Typography extends Component {
7 | static propTypes = {
8 | className: string,
9 | type: string.isRequired,
10 | children: node.isRequired,
11 | inline: bool,
12 | disabled: bool,
13 | }
14 |
15 | static defaultProps = {
16 | className: '',
17 | inline: false,
18 | disabled: false,
19 | }
20 |
21 | render() {
22 | const { type, children, className, inline, disabled } = this.props
23 | const MAP = {
24 | bigTransperent: cn.bigTransperent,
25 | light: cn.light,
26 | lg: cn.lg,
27 | md: cn.md,
28 | sm: cn.sm,
29 | xs: cn.xs,
30 | label: cn.label,
31 | }
32 | return (
33 |
37 | {children}
38 |
39 | )
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/lib/components/Typography.style.js:
--------------------------------------------------------------------------------
1 | import jss from 'src/lib/services/Jss'
2 | import { colors } from 'src/colors'
3 |
4 | const { classes } = jss
5 | .createStyleSheet({
6 | bigTransperent: {
7 | color: 'rgba(0, 0, 0, 0.54)',
8 | fontSize: '34px',
9 | },
10 | light: {
11 | color: 'rgba(0, 0, 0, 0.87)',
12 | fontSize: '14px',
13 | },
14 | lg: {
15 | color: 'rgba(0, 0, 0, 0.87)',
16 | fontSize: '22px',
17 | },
18 | md: {
19 | color: 'rgba(0, 0, 0, 0.87)',
20 | fontSize: '18px',
21 | },
22 | sm: {
23 | color: 'rgba(0, 0, 0, 0.87)',
24 | fontSize: '14px',
25 | },
26 | xs: {
27 | color: 'rgba(0, 0, 0, 0.54)',
28 | fontSize: '12px',
29 | },
30 | label: {
31 | boxSizing: 'border-box',
32 | color: colors.black.l2t2,
33 | fontSize: '0.8125rem',
34 | lineHeight: '1.4em',
35 | background: colors.grey.l5t3,
36 | borderRadius: '2px',
37 | padding: '3px 4px',
38 | minWidth: 56,
39 | minHeight: 24,
40 | textAlign: 'center',
41 | '&$disabled': {
42 | background: colors.white.d5t2,
43 | },
44 | },
45 | disabled: {
46 | color: colors.black.t3,
47 | },
48 | })
49 | .attach()
50 |
51 | export const cn = classes
52 |
--------------------------------------------------------------------------------
/src/lib/components/controls/Checkbox.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { bool, func } from 'prop-types'
3 | import ACheckbox from 'material-ui/Checkbox'
4 |
5 | import { cn } from './Checkbox.style'
6 |
7 | export class Checkbox extends Component {
8 | static propTypes = {
9 | checked: bool.isRequired,
10 | onChange: func.isRequired,
11 | disabled: bool,
12 | }
13 |
14 | static defaultProps = {
15 | disabled: false,
16 | }
17 |
18 | render() {
19 | const { checked, onChange, disabled } = this.props
20 | return (
21 | onChange(!checked)}
25 | value=""
26 | classes={{ checked: cn.checked }}
27 | />
28 | )
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/lib/components/controls/Checkbox.style.js:
--------------------------------------------------------------------------------
1 | import jss from 'src/lib/services/Jss'
2 | import { colors } from 'src/colors'
3 |
4 | const { classes } = jss
5 | .createStyleSheet({
6 | checked: {
7 | color: colors.primary.main,
8 | },
9 | })
10 | .attach()
11 |
12 | export const cn = classes
13 |
--------------------------------------------------------------------------------
/src/lib/components/controls/CodeEditor.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { func, string, oneOf, bool } from 'prop-types'
3 | import { cn } from './CodeEditor.style'
4 | const monaco = window.monaco
5 |
6 | class CodeEditorInner extends Component {
7 | static propTypes = {
8 | language: oneOf(['html', 'markdown']).isRequired,
9 | initialValue: string.isRequired,
10 | onChange: func.isRequired,
11 | onBlur: func.isRequired,
12 | }
13 |
14 | id = `editor-container-${Math.round(Math.random() * 1e9)}`
15 |
16 | componentDidMount() {
17 | const { initialValue, onChange, language } = this.props
18 | const { id } = this
19 | const editor = monaco.editor.create(document.getElementById(id), {
20 | value: initialValue,
21 | language: language,
22 | })
23 | editor.onDidChangeModelContent(event => {
24 | const value = editor.getValue()
25 | onChange(value)
26 | })
27 | }
28 |
29 | render() {
30 | const { onBlur } = this.props
31 | const { id } = this
32 | return
33 | }
34 | }
35 |
36 | export class CodeEditor extends Component {
37 | static propTypes = {
38 | disabled: bool,
39 | }
40 |
41 | static defaultProps = {
42 | disabled: false,
43 | }
44 |
45 | render() {
46 | const { disabled, ...props } = this.props
47 | return disabled ? :
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/lib/components/controls/CodeEditor.style.js:
--------------------------------------------------------------------------------
1 | import jss from 'src/lib/services/Jss'
2 |
3 | const { classes } = jss
4 | .createStyleSheet({
5 | container: {
6 | height: 150,
7 | },
8 | })
9 | .attach()
10 |
11 | export const cn = classes
12 |
--------------------------------------------------------------------------------
/src/lib/components/controls/Select.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { func, string, arrayOf, bool, shape, oneOfType, number } from 'prop-types'
3 | import SelectInner from 'src/lib/components/controls/SelectInner'
4 |
5 | export class Select extends Component {
6 | static propTypes = {
7 | options: arrayOf(
8 | shape({
9 | label: string.isRequired,
10 | value: oneOfType([number, string, bool]).isRequired,
11 | })
12 | ).isRequired,
13 | onChange: func.isRequired,
14 | onMenuOpen: func,
15 | onMenuClose: func,
16 | onBlur: func.isRequired,
17 | value: shape({
18 | label: string.isRequired,
19 | value: oneOfType([number, string, bool]).isRequired,
20 | }),
21 | placeholder: string,
22 | isField: bool,
23 | disabled: bool,
24 | isError: bool,
25 | }
26 |
27 | static defaultProps = {
28 | value: null,
29 | placeholder: '',
30 | isField: false,
31 | disabled: false,
32 | isError: false,
33 | onMenuOpen: () => {},
34 | onMenuClose: () => {},
35 | }
36 |
37 | render() {
38 | const { ...props } = this.props
39 | return
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/lib/components/controls/SelectInner.style.js:
--------------------------------------------------------------------------------
1 | import jss from 'src/lib/services/Jss'
2 | import { colors } from 'src/colors'
3 |
4 | const { classes } = jss
5 | .createStyleSheet({
6 | inkbar: {
7 | '&:after': {
8 | backgroundColor: colors.primary.main,
9 | },
10 | },
11 | inkbarError: {
12 | '&:after': {
13 | backgroundColor: colors.error.main,
14 | },
15 | },
16 | })
17 | .attach()
18 |
19 | export const cn = classes
20 |
--------------------------------------------------------------------------------
/src/lib/components/controls/Switch.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import ASwitch from 'material-ui/Switch'
3 | import { bool, func } from 'prop-types'
4 |
5 | import { cn } from './Switch.style'
6 |
7 | export class Switch extends Component {
8 | static propTypes = {
9 | checked: bool.isRequired,
10 | onChange: func.isRequired,
11 | disabled: bool,
12 | }
13 |
14 | static defaultProps = {
15 | disabled: false,
16 | }
17 |
18 | render() {
19 | const { checked, onChange, disabled } = this.props
20 | return (
21 | onChange(!checked)}
25 | value=""
26 | classes={{
27 | checked: cn.checked,
28 | disabled: cn.disabled,
29 | bar: cn.bar,
30 | }}
31 | />
32 | )
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/lib/components/controls/Switch.style.js:
--------------------------------------------------------------------------------
1 | import jss from 'src/lib/services/Jss'
2 | import { colors } from 'src/colors'
3 |
4 | const { classes } = jss
5 | .createStyleSheet({
6 | checked: {
7 | color: colors.primary.main,
8 | },
9 | disabled: {
10 | color: colors.grey.l5t2,
11 | },
12 | bar: {
13 | 'background-color': `${colors.primary.main} !important`,
14 | },
15 | })
16 | .attach()
17 |
18 | export const cn = classes
19 |
--------------------------------------------------------------------------------
/src/lib/components/controls/TextInput.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { func, string, bool, oneOf } from 'prop-types'
3 | import Input from 'material-ui/Input'
4 |
5 | import { cn } from './TextInput.style'
6 |
7 | export class TextInput extends Component {
8 | static propTypes = {
9 | onChange: func.isRequired,
10 | onBlur: func.isRequired,
11 | value: string.isRequired,
12 | type: oneOf(['text', 'password']),
13 | placeholder: string,
14 | multiline: bool,
15 | disabled: bool,
16 | }
17 |
18 | static defaultProps = {
19 | type: 'text',
20 | placeholder: '',
21 | multiline: false,
22 | disabled: false,
23 | }
24 |
25 | render() {
26 | const { type, disabled, value, onChange, onBlur, placeholder, multiline } = this.props
27 | return (
28 | onChange(event.target.value)}
36 | onBlur={onBlur}
37 | value={disabled ? '' : value}
38 | classes={{ inkbar: cn.inkbar, error: cn.inkbarError }}
39 | />
40 | )
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/lib/components/controls/TextInput.style.js:
--------------------------------------------------------------------------------
1 | import jss from 'src/lib/services/Jss'
2 | import { colors } from 'src/colors'
3 |
4 | const { classes } = jss
5 | .createStyleSheet({
6 | inkbar: {
7 | '&:after': {
8 | backgroundColor: colors.primary.main,
9 | },
10 | },
11 | inkbarError: {
12 | '&:after': {
13 | backgroundColor: colors.error.main,
14 | },
15 | },
16 | })
17 | .attach()
18 |
19 | export const cn = classes
20 |
--------------------------------------------------------------------------------
/src/lib/components/fields/Checkbox.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { bool, func, string } from 'prop-types'
3 | import { FormControlLabel } from 'material-ui/Form'
4 | import { FormControl, FormHelperText } from 'material-ui/Form'
5 | import { Checkbox as ACheckbox } from 'src/lib/components/controls/Checkbox'
6 |
7 | import { cn } from './Checkbox.style'
8 |
9 | export class Checkbox extends Component {
10 | static propTypes = {
11 | checked: bool.isRequired,
12 | onChange: func.isRequired,
13 | label: string.isRequired,
14 | disabled: bool,
15 | helperText: string,
16 | dirtyAlign: bool,
17 | }
18 |
19 | static defaultProps = {
20 | disabled: false,
21 | dirtyAlign: false,
22 | helperText: '',
23 | }
24 |
25 | render() {
26 | const { checked, onChange, label, disabled, helperText, dirtyAlign } = this.props
27 | return (
28 |
29 | }
36 | label={label}
37 | />
38 | {helperText}
39 |
40 | )
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/lib/components/fields/Checkbox.style.js:
--------------------------------------------------------------------------------
1 | import jss from 'src/lib/services/Jss'
2 | import { colors } from 'src/colors'
3 |
4 | const { classes } = jss
5 | .createStyleSheet({
6 | label: {
7 | 'font-size': '1rem',
8 | },
9 | dirtyAlign: {
10 | marginTop: 6,
11 | marginBottom: -6,
12 | },
13 | disabled: {
14 | '& $label': {
15 | color: colors.black.l2t3,
16 | },
17 | },
18 | })
19 | .attach()
20 |
21 | export const cn = classes
22 |
--------------------------------------------------------------------------------
/src/lib/components/fields/Select.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { string, bool, shape, oneOfType, number } from 'prop-types'
3 | import { FormControl, FormHelperText } from 'material-ui/Form'
4 | import { InputLabel } from 'material-ui/Input'
5 | import { Select as ASelect } from 'src/lib/components/controls/Select'
6 |
7 | import { cn } from './TextField.style'
8 |
9 | export class Select extends Component {
10 | static propTypes = {
11 | label: string.isRequired,
12 | required: bool,
13 | error: bool.isRequired,
14 | helperText: string.isRequired,
15 | disabled: bool,
16 | value: shape({
17 | label: string.isRequired,
18 | value: oneOfType([number, string, bool]).isRequired,
19 | }),
20 | }
21 |
22 | state = {
23 | open: false,
24 | }
25 |
26 | onMenuOpen() {
27 | this.setState({ open: true })
28 | }
29 |
30 | onMenuClose() {
31 | this.setState({ open: false })
32 | }
33 |
34 | static defaultProps = {
35 | required: false,
36 | disabled: false,
37 | value: null,
38 | }
39 |
40 | render() {
41 | const { disabled, label, error, helperText, required, value, ...props } = this.props
42 | const { open } = this.state
43 | return (
44 |
45 |
50 | {label}
51 |
52 | this.onMenuOpen()}
59 | onMenuClose={() => this.onMenuClose()}
60 | />
61 | {helperText}
62 |
63 | )
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/lib/components/fields/Switch.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { Switch as ASwitch } from 'src/lib/components/controls/Switch'
3 | import { bool, func, string } from 'prop-types'
4 | import { FormControlLabel, FormHelperText, FormControl } from 'material-ui/Form'
5 |
6 | import { cn } from './Switch.style'
7 |
8 | export class Switch extends Component {
9 | static propTypes = {
10 | checked: bool.isRequired,
11 | onChange: func.isRequired,
12 | label: string.isRequired,
13 | helperText: string,
14 | disabled: bool,
15 | dirtyAlign: bool,
16 | }
17 |
18 | static defaultProps = {
19 | helperText: ' ',
20 | disabled: false,
21 | dirtyAlign: false,
22 | }
23 |
24 | render() {
25 | const { checked, onChange, label, helperText, disabled, dirtyAlign } = this.props
26 | return (
27 |
28 | }
35 | label={label}
36 | />
37 | {helperText}
38 |
39 | )
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/lib/components/fields/Switch.style.js:
--------------------------------------------------------------------------------
1 | import jss from 'src/lib/services/Jss'
2 | import { colors } from 'src/colors'
3 |
4 | const { classes } = jss
5 | .createStyleSheet({
6 | label: {
7 | 'font-size': '1rem',
8 | },
9 | dirtyAlign: {
10 | marginTop: 6,
11 | marginBottom: -6,
12 | },
13 | disabled: {
14 | '& $label': {
15 | color: colors.black.l2t3,
16 | },
17 | },
18 | })
19 | .attach()
20 |
21 | export const cn = classes
22 |
--------------------------------------------------------------------------------
/src/lib/components/fields/TextField.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { func, string, bool, oneOf } from 'prop-types'
3 | import { FormControl, FormHelperText } from 'material-ui/Form'
4 | import { InputLabel } from 'material-ui/Input'
5 | import { TextInput } from 'src/lib/components/controls/TextInput'
6 |
7 | import { cn } from './TextField.style'
8 |
9 | export class TextField extends Component {
10 | static propTypes = {
11 | label: string.isRequired,
12 | required: bool,
13 | shrink: bool,
14 | onChange: func.isRequired,
15 | onBlur: func.isRequired,
16 | value: string.isRequired,
17 | error: bool.isRequired,
18 | helperText: string.isRequired,
19 | placeholder: string,
20 | multiline: bool,
21 | disabled: bool,
22 | type: oneOf(['text', 'password']),
23 | }
24 |
25 | static defaultProps = {
26 | required: false,
27 | shrink: undefined,
28 | placeholder: '',
29 | multiline: false,
30 | disabled: false,
31 | type: 'text',
32 | }
33 |
34 | render() {
35 | const {
36 | disabled,
37 | label,
38 | value,
39 | error,
40 | onChange,
41 | onBlur,
42 | helperText,
43 | required,
44 | shrink,
45 | placeholder,
46 | multiline,
47 | type,
48 | } = this.props
49 | return (
50 |
51 |
56 | {label}
57 |
58 |
67 | {helperText}
68 |
69 | )
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/lib/components/fields/TextField.style.js:
--------------------------------------------------------------------------------
1 | import jss from 'src/lib/services/Jss'
2 | import { colors } from 'src/colors'
3 |
4 | const { classes } = jss
5 | .createStyleSheet({
6 | label: {
7 | color: colors.primary.main,
8 | },
9 | labelError: {
10 | color: colors.error.main,
11 | },
12 | textError: {
13 | color: colors.error.main,
14 | },
15 | })
16 | .attach()
17 |
18 | export const cn = classes
19 |
--------------------------------------------------------------------------------
/src/lib/helpers/createEntry.js:
--------------------------------------------------------------------------------
1 | import { NumberEntryType } from 'src/lib/types/entries/NumberEntryType'
2 | import { StringEntryType } from 'src/lib/types/entries/StringEntryType'
3 | import { BooleanEntryType } from 'src/lib/types/entries/BooleanEntryType'
4 | import { ObjectEntryType } from 'src/lib/types/entries/ObjectEntryType'
5 | import { ArrayEntryType } from 'src/lib/types/entries/ArrayEntryType'
6 | import { EnumEntryType } from 'src/lib/types/entries/EnumEntryType'
7 | import { ReferenceEntryType } from 'src/lib/types/entries/ReferenceEntryType'
8 | import { AssetEntryType } from 'src/lib/types/entries/AssetEntryType'
9 |
10 | export function createEntry(entry) {
11 | const map = {
12 | 'string-line': StringEntryType,
13 | 'string-html': StringEntryType,
14 | 'string-markdown': StringEntryType,
15 | 'string-multiline': StringEntryType,
16 | number: NumberEntryType,
17 | boolean: BooleanEntryType,
18 | object: ObjectEntryType,
19 | array: ArrayEntryType,
20 | enum: EnumEntryType,
21 | reference: ReferenceEntryType,
22 | asset: AssetEntryType,
23 | }
24 |
25 | if (!entry || !entry.value || !entry.value.type || !map[entry.value.type]) {
26 | throw new Error('Unvalid entry: unknown type of entry')
27 | }
28 |
29 | return new map[entry.value.type](entry)
30 | }
31 |
--------------------------------------------------------------------------------
/src/lib/helpers/createModel.js:
--------------------------------------------------------------------------------
1 | import { NumberModelType } from 'src/lib/types/models/NumberModelType'
2 | import { StringModelType } from 'src/lib/types/models/StringModelType'
3 | import { BooleanModelType } from 'src/lib/types/models/BooleanModelType'
4 | import { ObjectModelType } from 'src/lib/types/models/ObjectModelType'
5 | import { ArrayModelType } from 'src/lib/types/models/ArrayModelType'
6 | import { EnumModelType } from 'src/lib/types/models/EnumModelType'
7 | import { ReferenceModelType } from 'src/lib/types/models/ReferenceModelType'
8 | import { AssetModelType } from 'src/lib/types/models/AssetModelType'
9 |
10 | export function createModel(model) {
11 | const map = {
12 | 'string-line': StringModelType,
13 | 'string-html': StringModelType,
14 | 'string-markdown': StringModelType,
15 | 'string-multiline': StringModelType,
16 | number: NumberModelType,
17 | boolean: BooleanModelType,
18 | object: ObjectModelType,
19 | array: ArrayModelType,
20 | enum: EnumModelType,
21 | reference: ReferenceModelType,
22 | asset: AssetModelType,
23 | }
24 |
25 | if (!model || !model.type || !map[model.type]) {
26 | throw new Error('unknown type of model')
27 | }
28 |
29 | return new map[model.type](model)
30 | }
31 |
--------------------------------------------------------------------------------
/src/lib/helpers/createSubentry.js:
--------------------------------------------------------------------------------
1 | import { NumberSubentryType } from 'src/lib/types/entries/NumberSubentryType'
2 | import { StringSubentryType } from 'src/lib/types/entries/StringSubentryType'
3 | import { BooleanSubentryType } from 'src/lib/types/entries/BooleanSubentryType'
4 | import { ObjectSubentryType } from 'src/lib/types/entries/ObjectSubentryType'
5 | import { ArraySubentryType } from 'src/lib/types/entries/ArraySubentryType'
6 | import { EnumSubentryType } from 'src/lib/types/entries/EnumSubentryType'
7 | import { ReferenceSubentryType } from 'src/lib/types/entries/ReferenceSubentryType'
8 | import { AssetSubentryType } from 'src/lib/types/entries/AssetSubentryType'
9 |
10 | export function createSubentry(subentry) {
11 | const map = {
12 | 'string-line': StringSubentryType,
13 | 'string-html': StringSubentryType,
14 | 'string-markdown': StringSubentryType,
15 | 'string-multiline': StringSubentryType,
16 | number: NumberSubentryType,
17 | boolean: BooleanSubentryType,
18 | object: ObjectSubentryType,
19 | array: ArraySubentryType,
20 | enum: EnumSubentryType,
21 | reference: ReferenceSubentryType,
22 | asset: AssetSubentryType,
23 | }
24 |
25 | if (!subentry || !subentry.type || !map[subentry.type]) {
26 | throw new Error('Unvalid subentry: unknown type of subentry')
27 | }
28 |
29 | return new map[subentry.type](subentry)
30 | }
31 |
--------------------------------------------------------------------------------
/src/lib/helpers/createSubmodel.js:
--------------------------------------------------------------------------------
1 | import { StringSubmodelType } from 'src/lib/types/models/StringSubmodelType'
2 | import { NumberSubmodelType } from 'src/lib/types/models/NumberSubmodelType'
3 | import { BooleanSubmodelType } from 'src/lib/types/models/BooleanSubmodelType'
4 | import { ObjectSubmodelType } from 'src/lib/types/models/ObjectSubmodelType'
5 | import { ArraySubmodelType } from 'src/lib/types/models/ArraySubmodelType'
6 | import { EnumSubmodelType } from 'src/lib/types/models/EnumSubmodelType'
7 | import { ReferenceSubmodelType } from 'src/lib/types/models/ReferenceSubmodelType'
8 | import { AssetSubmodelType } from 'src/lib/types/models/AssetSubmodelType'
9 |
10 | export function createSubmodel(submodel) {
11 | const map = {
12 | 'string-line': StringSubmodelType,
13 | 'string-html': StringSubmodelType,
14 | 'string-markdown': StringSubmodelType,
15 | 'string-multiline': StringSubmodelType,
16 | number: NumberSubmodelType,
17 | boolean: BooleanSubmodelType,
18 | object: ObjectSubmodelType,
19 | array: ArraySubmodelType,
20 | enum: EnumSubmodelType,
21 | reference: ReferenceSubmodelType,
22 | asset: AssetSubmodelType,
23 | }
24 |
25 | if (!submodel || !submodel.type || !map[submodel.type]) {
26 | throw new Error('unknown type of submodel')
27 | }
28 |
29 | return new map[submodel.type](submodel)
30 | }
31 |
--------------------------------------------------------------------------------
/src/lib/helpers/getAssetControlsWithFile.js:
--------------------------------------------------------------------------------
1 | export const getAssetControlsWithFile = entry => {
2 | const res = []
3 | inAny(res, entry.value)
4 | return res
5 | }
6 |
7 | const inSimple = () => []
8 |
9 | const inAny = (res, value) => {
10 | const MAP = {
11 | 'string-line': inSimple,
12 | 'string-multiline': inSimple,
13 | 'string-html': inSimple,
14 | 'string-markdown': inSimple,
15 | boolean: inSimple,
16 | number: inSimple,
17 | object: isObject,
18 | array: inArray,
19 | enum: inSimple,
20 | reference: inSimple,
21 | asset: inAsset,
22 | }
23 | MAP[value.type](res, value)
24 | }
25 |
26 | const isObject = (res, value) => {
27 | Object.keys(value.value).forEach(propName => {
28 | inAny(res, value.value[propName])
29 | })
30 | }
31 |
32 | const inArray = (res, value) => {
33 | value.value.forEach(item => inAny(res, item))
34 | }
35 |
36 | const inAsset = (res, value) => {
37 | if (value.value instanceof File) {
38 | res.push(value)
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/lib/helpers/isEntryConsistencyConflict.js:
--------------------------------------------------------------------------------
1 | export const isEntryConsistencyConflict = (entry, model) => {
2 | return !validate(model, entry.value)
3 | }
4 |
5 | const isValid = (model, value) => model.type === value.type
6 |
7 | const isValidObject = (model, value) => {
8 | if (!isValid(model, value)) return false
9 | return Object.keys(model.properties).every(propName => {
10 | const subModel = model.properties[propName]
11 | const isValue = value.value.hasOwnProperty(propName)
12 | return isValue ? validate(subModel, value.value[propName]) : true
13 | })
14 | }
15 |
16 | const isValidArray = (model, value) => {
17 | if (!isValid(model, value)) return false
18 | return !model.items ? true : value.value.every(item => validate(model.items, item))
19 | }
20 |
21 | const validate = (model, value, entries) => {
22 | const MAP = {
23 | 'string-line': isValid,
24 | 'string-multiline': isValid,
25 | 'string-html': isValid,
26 | 'string-markdown': isValid,
27 | boolean: isValid,
28 | number: isValid,
29 | object: isValidObject,
30 | array: isValidArray,
31 | enum: isValid,
32 | reference: isValid,
33 | asset: isValid,
34 | }
35 | return MAP[model.type].call(this, model, value, entries)
36 | }
37 |
--------------------------------------------------------------------------------
/src/lib/helpers/isEntryRefConflict.js:
--------------------------------------------------------------------------------
1 | export const isEntryRefConflict = (model, entry, entries) => {
2 | return init(model, entry.value, entries)
3 | }
4 |
5 | const initObject = (model, value, entries) => {
6 | return Object.keys(model.properties)
7 | .map(propName => {
8 | const subModel = model.properties[propName]
9 | const isValue = value.value.hasOwnProperty(propName)
10 | return isValue ? init(subModel, value.value[propName], entries) : false
11 | })
12 | .some(item => item === true)
13 | }
14 |
15 | const initArray = (model, value, entries) => {
16 | return !model.items
17 | ? false
18 | : value.value.map(item => init(model.items, item, entries)).some(item => item === true)
19 | }
20 |
21 | const initReference = (model, value, entries) => {
22 | return !entries.filter(entry => entry.modelId === model.reference).some(entry => entry.id === value.value)
23 | }
24 |
25 | const init = (model, value, entries) => {
26 | const MAP = {
27 | 'string-line': () => false,
28 | 'string-multiline': () => false,
29 | 'string-html': () => false,
30 | 'string-markdown': () => false,
31 | boolean: () => false,
32 | number: () => false,
33 | object: initObject,
34 | array: initArray,
35 | enum: () => false,
36 | reference: initReference,
37 | asset: () => false,
38 | }
39 | return MAP[model.type].call(this, model, value, entries)
40 | }
41 |
--------------------------------------------------------------------------------
/src/lib/helpers/isModelRefConflict.js:
--------------------------------------------------------------------------------
1 | export const isModelRefConflict = (model, models) => {
2 | return init(model, models)
3 | }
4 |
5 | const initObject = (model, models) => {
6 | return Object.keys(model.properties)
7 | .map(propName => {
8 | const subModel = model.properties[propName]
9 | return init(subModel, models)
10 | })
11 | .some(item => item === true)
12 | }
13 |
14 | const initArray = (model, models) => {
15 | return !model.items ? false : init(model.items, models)
16 | }
17 |
18 | const initReference = (model, models) => {
19 | return !models.some(item => item.id === model.reference)
20 | }
21 |
22 | const init = (model, models) => {
23 | const MAP = {
24 | 'string-line': () => false,
25 | 'string-multiline': () => false,
26 | 'string-html': () => false,
27 | 'string-markdown': () => false,
28 | boolean: () => false,
29 | number: () => false,
30 | object: initObject,
31 | array: initArray,
32 | enum: () => false,
33 | reference: initReference,
34 | asset: () => false,
35 | }
36 | return MAP[model.type].call(this, model, models)
37 | }
38 |
--------------------------------------------------------------------------------
/src/lib/helpers/isNumber.js:
--------------------------------------------------------------------------------
1 | export const isNumber = value => {
2 | const regs = [
3 | /^-[1-9]{1}[0-9]*$/,
4 | /^0{1}$/,
5 | /^[1-9]{1}[0-9]*$/,
6 | /^-[1-9]{1}[0-9]*\.[0-9]*[1-9]{1}$/,
7 | /^-0\.[0-9]*[1-9]{1}$/,
8 | /^0\.[0-9]*[1-9]{1}$/,
9 | /^[1-9]{1}[0-9]*\.[0-9]*[1-9]{1}$/,
10 | ]
11 | const isNumber = regs.some(item => item.test(value) && !isNaN(Number(value)))
12 | return isNumber
13 | }
14 |
--------------------------------------------------------------------------------
/src/lib/helpers/logout.js:
--------------------------------------------------------------------------------
1 | import { auth } from 'src/lib/services/Auth'
2 |
3 | export const logout = () => {
4 | auth.set(false)
5 | window.location.href = '/'
6 | }
7 |
--------------------------------------------------------------------------------
/src/lib/helpers/sortKeys.js:
--------------------------------------------------------------------------------
1 | export const sortKeys = obj => {
2 | return Object.keys(obj).sort((a, b) => (a > b ? 1 : -1))
3 | }
4 |
--------------------------------------------------------------------------------
/src/lib/helpers/valueAsNumber.js:
--------------------------------------------------------------------------------
1 | export function valueAsNumber(value) {
2 | return typeof value === 'number' ? `${value}` : value ? value : ''
3 | }
4 |
--------------------------------------------------------------------------------
/src/lib/services/Auth.js:
--------------------------------------------------------------------------------
1 | import store from 'store'
2 |
3 | class Auth {
4 | set(isSet) {
5 | store.set('isAuthSet', isSet)
6 | }
7 |
8 | isSet() {
9 | return store.get('isAuthSet') || false
10 | }
11 | }
12 |
13 | export const auth = new Auth()
14 |
--------------------------------------------------------------------------------
/src/lib/services/Fetcher.js:
--------------------------------------------------------------------------------
1 | import xhr from 'xhr'
2 | import { config } from 'src/config'
3 | import { logout } from 'src/lib/helpers/logout'
4 |
5 | export const fetch = ({ method, url, body, file, withCredentials = true }) => {
6 | return new Promise((resolve, reject) => {
7 | xhr(
8 | {
9 | withCredentials: withCredentials,
10 | json: !file,
11 | method: method,
12 | url: `${config.apiUrl}/${url}`,
13 | body: !file
14 | ? body
15 | : (() => {
16 | const formData = new FormData()
17 | formData.append('file', file)
18 | return formData
19 | })(),
20 | },
21 | (err, resp, body) => {
22 | try {
23 | body = JSON.parse(body)
24 | } catch (err) {}
25 | if (err) {
26 | reject(err.message === '[object ProgressEvent]' ? new Error('Network error') : err)
27 | return
28 | }
29 | if (resp.statusCode === 401) {
30 | logout()
31 | return
32 | }
33 | if (resp.statusCode < 200 || resp.statusCode > 299) {
34 | reject({
35 | statusCode: resp.statusCode,
36 | message: body && body.message ? body.message : body,
37 | })
38 | return
39 | }
40 | resolve(body)
41 | }
42 | )
43 | })
44 | }
45 |
--------------------------------------------------------------------------------
/src/lib/services/Jss.js:
--------------------------------------------------------------------------------
1 | import jss from 'jss'
2 | import preset from 'jss-preset-default'
3 |
4 | jss.setup(preset())
5 |
6 | export default jss
7 |
--------------------------------------------------------------------------------
/src/lib/services/Promise.js:
--------------------------------------------------------------------------------
1 | // import Promise from 'bluebird'
2 |
3 | // Promise.config({ cancellation: true })
4 |
5 | export default Promise
6 |
--------------------------------------------------------------------------------
/src/lib/services/Routes.js:
--------------------------------------------------------------------------------
1 | class Routes {
2 | home() {
3 | return `/`
4 | }
5 |
6 | projects() {
7 | return `/projects`
8 | }
9 |
10 | index(projectId) {
11 | return `/projects/${projectId}`
12 | }
13 |
14 | isIndex(projectId) {
15 | const { pathname } = window.location
16 | return pathname === `/projects/${projectId}`
17 | }
18 |
19 | models(projectId) {
20 | return `/projects/${projectId}/models`
21 | }
22 |
23 | isModels(projectId) {
24 | const { pathname } = window.location
25 | return pathname === `/projects/${projectId}/models`
26 | }
27 |
28 | entries(projectId, modelId) {
29 | return `/projects/${projectId}/models/${modelId}/entries`
30 | }
31 |
32 | isEntries(projectId) {
33 | const { pathname } = window.location
34 | return pathname.indexOf('entries') > -1 && pathname.indexOf(`/projects/${projectId}`) > -1
35 | }
36 |
37 | isExactEntry(projectId, modelId) {
38 | const { pathname } = window.location
39 | return pathname === `/projects/${projectId}/models/${modelId}/entries`
40 | }
41 |
42 | tokens(projectId) {
43 | return `/projects/${projectId}/keys`
44 | }
45 |
46 | isTokens(projectId) {
47 | const { pathname } = window.location
48 | return pathname === `/projects/${projectId}/keys`
49 | }
50 |
51 | explorer(projectId) {
52 | return `/projects/${projectId}/explorer`
53 | }
54 |
55 | isExplorer(projectId) {
56 | const { pathname } = window.location
57 | return pathname === `/projects/${projectId}/explorer`
58 | }
59 |
60 | notFound() {
61 | return `/not-found`
62 | }
63 |
64 | login() {
65 | return `/login`
66 | }
67 |
68 | registration() {
69 | return `/registration`
70 | }
71 |
72 | recoverPass() {
73 | return '/recover-pass'
74 | }
75 |
76 | contacts() {
77 | return '/contacts'
78 | }
79 | }
80 |
81 | export const routes = new Routes()
82 |
--------------------------------------------------------------------------------
/src/lib/services/Validator.js:
--------------------------------------------------------------------------------
1 | import validator from 'tvalidator'
2 |
3 | const v = validator()
4 |
5 | export const validate = (...props) => {
6 | const { valid, errors } = v(...props)
7 | return {
8 | valid,
9 | errors: errors.map(error => {
10 | return {
11 | field: error.dataPath[0] || error.params.key,
12 | message: error.message,
13 | }
14 | }),
15 | originalErrors: errors,
16 | }
17 | }
18 |
19 | /*
20 | validator(
21 | // value
22 | { name: '12345678901' },
23 | // schema
24 | {
25 | type: 'object',
26 | required: ['name'],
27 | properties: {
28 | name: {
29 | type: 'string',
30 | maxLength: 10,
31 | minLength: 1,
32 | },
33 | },
34 | },
35 | // errors
36 | {
37 | properties: {
38 | name: {
39 | maxLength: 'Name too long',
40 | },
41 | },
42 | }
43 | )
44 |
45 | {
46 | valid: false,
47 | errors: [
48 | {
49 | params: {
50 | length: 11,
51 | maximum: 10,
52 | },
53 | code: 'STRING_LENGTH_LONG',
54 | dataPath: ['name'],
55 | schemaPath: ['properties', 'name', 'maxLength'],
56 | message: 'Name too long',
57 | },
58 | ],
59 | }
60 | */
61 |
--------------------------------------------------------------------------------
/src/lib/styles/margins.css:
--------------------------------------------------------------------------------
1 | .mt-xxs { margin-top: 3px !important; }
2 | .mt-xs { margin-top: 5px !important; }
3 | .mt-sm { margin-top: 10px !important; }
4 | .mt-md { margin-top: 15px !important; }
5 | .mt-lg { margin-top: 20px !important; }
6 | .mt-xl { margin-top: 30px !important; }
7 | .mt-xxl { margin-top: 50px !important; }
8 |
9 | .mr-xxs { margin-right: 3px !important; }
10 | .mr-xs { margin-right: 5px !important; }
11 | .mr-sm { margin-right: 10px !important; }
12 | .mr-md { margin-right: 15px !important; }
13 | .mr-lg { margin-right: 20px !important; }
14 | .mr-xl { margin-right: 30px !important; }
15 | .mr-xxl { margin-right: 50px !important; }
16 |
17 | .mb-xxs { margin-bottom: 3px !important; }
18 | .mb-xs { margin-bottom: 5px !important; }
19 | .mb-sm { margin-bottom: 10px !important; }
20 | .mb-md { margin-bottom: 15px !important; }
21 | .mb-lg { margin-bottom: 20px !important; }
22 | .mb-xl { margin-bottom: 30px !important; }
23 | .mb-xxl { margin-bottom: 50px !important; }
24 |
25 | .ml-xxs { margin-left: 3px !important; }
26 | .ml-xs { margin-left: 5px !important; }
27 | .ml-sm { margin-left: 10px !important; }
28 | .ml-md { margin-left: 15px !important; }
29 | .ml-lg { margin-left: 20px !important; }
30 | .ml-xl { margin-left: 30px !important; }
31 | .ml-xxl { margin-left: 50px !important; }
32 |
33 | .m-xxs { margin: 3px !important; }
34 | .m-xs { margin: 5px !important; }
35 | .m-sm { margin: 10px !important; }
36 | .m-md { margin: 15px !important; }
37 | .m-lg { margin: 20px !important; }
38 | .m-xl { margin: 30px !important; }
39 | .m-xxl { margin: 50px !important; }
40 |
--------------------------------------------------------------------------------
/src/lib/styles/paddings.css:
--------------------------------------------------------------------------------
1 | .pt-xxs { padding-top: 3px !important; }
2 | .pt-xs { padding-top: 5px !important; }
3 | .pt-sm { padding-top: 10px !important; }
4 | .pt-md { padding-top: 15px !important; }
5 | .pt-lg { padding-top: 20px !important; }
6 | .pt-xl { padding-top: 30px !important; }
7 | .pt-xxl { padding-top: 50px !important; }
8 |
9 | .pr-xxs { padding-right: 3px !important; }
10 | .pr-xs { padding-right: 5px !important; }
11 | .pr-sm { padding-right: 10px !important; }
12 | .pr-md { padding-right: 15px !important; }
13 | .pr-lg { padding-right: 20px !important; }
14 | .pr-xl { padding-right: 30px !important; }
15 | .pr-xxl { padding-right: 50px !important; }
16 |
17 | .pb-xxs { padding-bottom: 3px !important; }
18 | .pb-xs { padding-bottom: 5px !important; }
19 | .pb-sm { padding-bottom: 10px !important; }
20 | .pb-md { padding-bottom: 15px !important; }
21 | .pb-lg { padding-bottom: 20px !important; }
22 | .pb-xl { padding-bottom: 30px !important; }
23 | .pb-xxl { padding-bottom: 50px !important; }
24 |
25 | .pl-xxs { padding-left: 3px !important; }
26 | .pl-xs { padding-left: 5px !important; }
27 | .pl-sm { padding-left: 10px !important; }
28 | .pl-md { padding-left: 15px !important; }
29 | .pl-lg { padding-left: 20px !important; }
30 | .pl-xl { padding-left: 30px !important; }
31 | .pl-xxl { padding-left: 50px !important; }
32 |
33 | .p-xxs { padding: 3px !important; }
34 | .p-xs { padding: 5px !important; }
35 | .p-sm { padding: 10px !important; }
36 | .p-md { padding: 15px !important; }
37 | .p-lg { padding: 20px !important; }
38 | .p-xl { padding: 30px !important; }
39 | .p-xxl { padding: 50px !important; }
40 |
--------------------------------------------------------------------------------
/src/lib/styles/texts.css:
--------------------------------------------------------------------------------
1 | .text-center {
2 | text-align: center; }
3 |
4 | .text-right {
5 | text-align: right; }
6 |
7 | .text-left {
8 | text-align: left; }
9 |
10 | .text-italic {
11 | font-style: italic; }
12 |
13 | .text-one-line {
14 | overflow: hidden;
15 | white-space: nowrap;
16 | text-overflow: ellipsis;
17 | }
18 |
19 | .text-smaller-xs { font-size: 0.9em; }
20 |
21 | .text-no-underline {
22 | text-decoration: none;
23 | }
24 |
--------------------------------------------------------------------------------
/src/lib/types/entries/ArrayEntryType.js:
--------------------------------------------------------------------------------
1 | import { EntryType } from 'src/lib/types/entries/EntryType'
2 | import deepFreeze from 'deep-freeze'
3 | import { createSubentry } from 'src/lib/helpers/createSubentry'
4 |
5 | export class ArrayEntryType extends EntryType {
6 | constructor(entry) {
7 | super(entry)
8 | entry.value.value.forEach((subentry, i) => {
9 | this.value.value[i] = createSubentry(subentry)
10 | })
11 | deepFreeze(this)
12 | }
13 |
14 | _getBasicSchema() {
15 | const schema = super._getBasicSchema()
16 | schema.properties.value.properties.type = { enum: ['array'] }
17 | schema.properties.value.properties.value = { type: 'array' }
18 | return schema
19 | }
20 |
21 | toValue() {
22 | return this.value.value.map(item => item.toValue())
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/lib/types/entries/ArraySubentryType.js:
--------------------------------------------------------------------------------
1 | import { SubentryType } from 'src/lib/types/entries/SubentryType'
2 | import { createSubentry } from 'src/lib/helpers/createSubentry'
3 |
4 | export class ArraySubentryType extends SubentryType {
5 | constructor(subentry) {
6 | super(subentry)
7 | subentry.value.forEach((subentry, i) => {
8 | this.value[i] = createSubentry(subentry)
9 | })
10 | }
11 |
12 | _getBasicSchema() {
13 | const schema = super._getBasicSchema()
14 | schema.properties.type = { enum: ['array'] }
15 | schema.properties.value = { type: 'array' }
16 | return schema
17 | }
18 |
19 | toValue() {
20 | return this.value.map(item => item.toValue())
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/lib/types/entries/AssetEntryType.js:
--------------------------------------------------------------------------------
1 | import { EntryType } from 'src/lib/types/entries/EntryType'
2 | import deepFreeze from 'deep-freeze'
3 |
4 | export class AssetEntryType extends EntryType {
5 | constructor(entry) {
6 | super(entry)
7 | deepFreeze(this)
8 | }
9 |
10 | _getBasicSchema() {
11 | const schema = super._getBasicSchema()
12 | schema.properties.value.properties.type = { enum: ['asset'] }
13 | schema.properties.value.properties.value = { type: 'string', minLength: 1 }
14 |
15 | return schema
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/lib/types/entries/AssetSubentryType.js:
--------------------------------------------------------------------------------
1 | import { SubentryType } from 'src/lib/types/entries/SubentryType'
2 |
3 | export class AssetSubentryType extends SubentryType {
4 | _getBasicSchema() {
5 | const schema = super._getBasicSchema()
6 | schema.properties.type = { enum: ['asset'] }
7 | schema.properties.value = { type: 'string', minLength: 1 }
8 | return schema
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/lib/types/entries/BooleanEntryType.js:
--------------------------------------------------------------------------------
1 | import { EntryType } from 'src/lib/types/entries/EntryType'
2 | import deepFreeze from 'deep-freeze'
3 |
4 | export class BooleanEntryType extends EntryType {
5 | constructor(entry) {
6 | super(entry)
7 | deepFreeze(this)
8 | }
9 |
10 | _getBasicSchema() {
11 | const schema = super._getBasicSchema()
12 | schema.properties.value.properties.type = { enum: ['boolean'] }
13 | schema.properties.value.properties.value = { type: 'boolean' }
14 | return schema
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/lib/types/entries/BooleanSubentryType.js:
--------------------------------------------------------------------------------
1 | import { SubentryType } from 'src/lib/types/entries/SubentryType'
2 |
3 | export class BooleanSubentryType extends SubentryType {
4 | _getBasicSchema() {
5 | const schema = super._getBasicSchema()
6 | schema.properties.type = { enum: ['boolean'] }
7 | schema.properties.value = { type: 'boolean' }
8 | return schema
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/lib/types/entries/EntryType.js:
--------------------------------------------------------------------------------
1 | import { validate } from 'src/lib/services/Validator'
2 |
3 | // abstract class
4 | export class EntryType {
5 | constructor(entry) {
6 | const { valid, errors } = this._validate(entry)
7 | if (!valid) {
8 | throw new Error(`Unvalid entry: ${entry.id}, message: ${errors[0].message}`)
9 | }
10 | Object.keys(entry).forEach(key => {
11 | this[key] = entry[key]
12 | })
13 | }
14 |
15 | _validate(entry) {
16 | return validate(entry, this._getBasicSchema())
17 | }
18 |
19 | _getBasicSchema() {
20 | return {
21 | type: 'object',
22 | additionalProperties: false,
23 | required: ['id', 'modelId', 'value', 'identificator'],
24 | properties: {
25 | id: { type: 'string', minLength: 1 },
26 | modelId: { type: 'string', minLength: 1 },
27 | identificator: { type: 'string' },
28 | value: {
29 | type: 'object',
30 | additionalProperties: false,
31 | required: ['type', 'value'],
32 | properties: {
33 | type: {},
34 | value: {},
35 | },
36 | },
37 | },
38 | }
39 | }
40 |
41 | toValue() {
42 | return this.value.value
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/lib/types/entries/EnumEntryType.js:
--------------------------------------------------------------------------------
1 | import { EntryType } from 'src/lib/types/entries/EntryType'
2 | import deepFreeze from 'deep-freeze'
3 |
4 | export class EnumEntryType extends EntryType {
5 | constructor(entry) {
6 | super(entry)
7 | deepFreeze(this)
8 | }
9 |
10 | _getBasicSchema() {
11 | const schema = super._getBasicSchema()
12 | schema.properties.value.properties.type = { enum: ['enum'] }
13 | schema.properties.value.properties.value = {
14 | anyOf: [{ type: 'boolean' }, { type: 'string' }, { type: 'number' }],
15 | }
16 |
17 | return schema
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/lib/types/entries/EnumSubentryType.js:
--------------------------------------------------------------------------------
1 | import { SubentryType } from 'src/lib/types/entries/SubentryType'
2 |
3 | export class EnumSubentryType extends SubentryType {
4 | _getBasicSchema() {
5 | const schema = super._getBasicSchema()
6 | schema.properties.type = { enum: ['enum'] }
7 | schema.properties.value = {
8 | anyOf: [{ type: 'boolean' }, { type: 'string' }, { type: 'number' }],
9 | }
10 | return schema
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/lib/types/entries/NumberEntryType.js:
--------------------------------------------------------------------------------
1 | import { EntryType } from 'src/lib/types/entries/EntryType'
2 | import deepFreeze from 'deep-freeze'
3 |
4 | export class NumberEntryType extends EntryType {
5 | constructor(entry) {
6 | super(entry)
7 | deepFreeze(this)
8 | }
9 |
10 | _getBasicSchema() {
11 | const schema = super._getBasicSchema()
12 | schema.properties.value.properties.type = { enum: ['number'] }
13 | schema.properties.value.properties.value = { type: 'number' }
14 |
15 | return schema
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/lib/types/entries/NumberSubentryType.js:
--------------------------------------------------------------------------------
1 | import { SubentryType } from 'src/lib/types/entries/SubentryType'
2 |
3 | export class NumberSubentryType extends SubentryType {
4 | _getBasicSchema() {
5 | const schema = super._getBasicSchema()
6 | schema.properties.type = { enum: ['number'] }
7 | schema.properties.value = { type: 'number' }
8 | return schema
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/lib/types/entries/ObjectEntryType.js:
--------------------------------------------------------------------------------
1 | import { EntryType } from 'src/lib/types/entries/EntryType'
2 | import deepFreeze from 'deep-freeze'
3 | import { createSubentry } from 'src/lib/helpers/createSubentry'
4 |
5 | export class ObjectEntryType extends EntryType {
6 | constructor(entry) {
7 | super(entry)
8 | Object.keys(entry.value.value).forEach(key => {
9 | this.value.value[key] = createSubentry(entry.value.value[key])
10 | })
11 | deepFreeze(this)
12 | }
13 |
14 | _getBasicSchema() {
15 | const schema = super._getBasicSchema()
16 | schema.properties.value.properties.type = { enum: ['object'] }
17 | schema.properties.value.properties.value = { type: 'object' }
18 | return schema
19 | }
20 |
21 | toValue() {
22 | return Object.keys(this.value.value).reduce((res, key) => {
23 | res[key] = this.value.value[key].toValue()
24 | return res
25 | }, {})
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/lib/types/entries/ObjectSubentryType.js:
--------------------------------------------------------------------------------
1 | import { SubentryType } from 'src/lib/types/entries/SubentryType'
2 | import { createSubentry } from 'src/lib/helpers/createSubentry'
3 |
4 | export class ObjectSubentryType extends SubentryType {
5 | constructor(subentry) {
6 | super(subentry)
7 | Object.keys(subentry.value).forEach(key => {
8 | this.value[key] = createSubentry(subentry.value[key])
9 | })
10 | }
11 |
12 | _getBasicSchema() {
13 | const schema = super._getBasicSchema()
14 | schema.properties.type = { enum: ['object'] }
15 | schema.properties.value = { type: 'object' }
16 | return schema
17 | }
18 |
19 | toValue() {
20 | return Object.keys(this.value).reduce((res, key) => {
21 | res[key] = this.value[key].toValue()
22 | return res
23 | }, {})
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/lib/types/entries/ReferenceEntryType.js:
--------------------------------------------------------------------------------
1 | import { EntryType } from 'src/lib/types/entries/EntryType'
2 | import deepFreeze from 'deep-freeze'
3 |
4 | export class ReferenceEntryType extends EntryType {
5 | constructor(entry) {
6 | super(entry)
7 | deepFreeze(this)
8 | }
9 |
10 | _getBasicSchema() {
11 | const schema = super._getBasicSchema()
12 | schema.properties.value.properties.type = { enum: ['reference'] }
13 | schema.properties.value.properties.value = { type: 'string', minLength: 1 }
14 |
15 | return schema
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/lib/types/entries/ReferenceSubentryType.js:
--------------------------------------------------------------------------------
1 | import { SubentryType } from 'src/lib/types/entries/SubentryType'
2 |
3 | export class ReferenceSubentryType extends SubentryType {
4 | _getBasicSchema() {
5 | const schema = super._getBasicSchema()
6 | schema.properties.type = { enum: ['reference'] }
7 | schema.properties.value = { type: 'string', minLength: 1 }
8 | return schema
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/lib/types/entries/StringEntryType.js:
--------------------------------------------------------------------------------
1 | import { EntryType } from 'src/lib/types/entries/EntryType'
2 | import deepFreeze from 'deep-freeze'
3 |
4 | export class StringEntryType extends EntryType {
5 | constructor(entry) {
6 | super(entry)
7 | deepFreeze(this)
8 | }
9 |
10 | _getBasicSchema() {
11 | const schema = super._getBasicSchema()
12 | schema.properties.value.properties.type = {
13 | enum: ['string-line', 'string-multiline', 'string-html', 'string-markdown'],
14 | }
15 | schema.properties.value.properties.value = { type: 'string' }
16 |
17 | return schema
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/lib/types/entries/StringSubentryType.js:
--------------------------------------------------------------------------------
1 | import { SubentryType } from 'src/lib/types/entries/SubentryType'
2 |
3 | export class StringSubentryType extends SubentryType {
4 | _getBasicSchema() {
5 | const schema = super._getBasicSchema()
6 | schema.properties.type = {
7 | enum: ['string-line', 'string-multiline', 'string-html', 'string-markdown'],
8 | }
9 | schema.properties.value = { type: 'string' }
10 | return schema
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/lib/types/entries/SubentryType.js:
--------------------------------------------------------------------------------
1 | import { validate } from 'src/lib/services/Validator'
2 |
3 | // abstract class
4 | export class SubentryType {
5 | constructor(entry) {
6 | const { valid, errors } = this._validate(entry)
7 | if (!valid) {
8 | throw new Error(`Unvalid subentry: ${entry.id}, message: ${errors[0].message}`)
9 | }
10 | Object.keys(entry).forEach(key => {
11 | this[key] = entry[key]
12 | })
13 | }
14 |
15 | _validate(entry) {
16 | return validate(entry, this._getBasicSchema())
17 | }
18 |
19 | _getBasicSchema() {
20 | return {
21 | type: 'object',
22 | additionalProperties: false,
23 | required: ['type', 'value'],
24 | properties: {
25 | type: {},
26 | value: {},
27 | },
28 | }
29 | }
30 |
31 | toValue() {
32 | return this.value
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/lib/types/models/AbstractType.js:
--------------------------------------------------------------------------------
1 | import { validate } from 'src/lib/services/Validator'
2 |
3 | // abstract class
4 | export class AbstractType {
5 | constructor(model) {
6 | const { valid, errors } = this._validate(model)
7 | if (!valid) {
8 | throw new Error(`Unvalid model/submodel: ${model.type}, message: ${errors[0].message}`)
9 | }
10 | Object.keys(model).forEach(key => {
11 | this[key] = model[key]
12 | })
13 | }
14 |
15 | _validate(model) {
16 | return validate(model, this._getBasicSchema())
17 | }
18 |
19 | _getBasicSchema() {
20 | throw new Error('method _getBasicSchema must be implemented')
21 | }
22 |
23 | toSchema() {
24 | throw new Error('method toSchema must be implemented')
25 | }
26 |
27 | validateExactFields(model, fields) {
28 | const { errors } = this._validate(model)
29 | const filtredErrors = errors.filter(error => fields.some(field => field === error.field))
30 | return { valid: !filtredErrors.length, errors: filtredErrors }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/lib/types/models/ArrayModelType.js:
--------------------------------------------------------------------------------
1 | import { ModelType } from 'src/lib/types/models/ModelType'
2 | import { createSubmodel } from 'src/lib/helpers/createSubmodel'
3 | import deepFreeze from 'deep-freeze'
4 |
5 | export class ArrayModelType extends ModelType {
6 | constructor(model) {
7 | super(model)
8 | if (model.items) {
9 | this.items = createSubmodel(model.items)
10 | }
11 | deepFreeze(this)
12 | }
13 |
14 | _getBasicSchema() {
15 | return {
16 | type: 'object',
17 | additionalProperties: false,
18 | required: ['id', 'title', 'apiId', 'type', 'uniqueItems'],
19 | properties: {
20 | id: { type: 'string', minLength: 1 },
21 | title: { type: 'string', minLength: 1 },
22 | apiId: { type: 'string', minLength: 1 },
23 | type: { enum: ['array'] },
24 | description: { type: 'string', minLength: 1 },
25 | minItems: { type: 'integer', minimum: 0 },
26 | maxItems: { type: 'integer', minimum: 0 },
27 | uniqueItems: { enum: [false] },
28 | items: { type: 'object' },
29 | },
30 | }
31 | }
32 |
33 | toSchema() {
34 | const model = this
35 | const schema = { type: 'array' }
36 | const props = ['minItems', 'maxItems', 'uniqueItems']
37 | props.forEach(item => {
38 | if (model.hasOwnProperty(item)) {
39 | schema[item] = model[item]
40 | }
41 | })
42 | if (model.items) {
43 | schema.items = model.items.toSchema()
44 | } else {
45 | /* app could work only with strict values, if model.items not set in enrty could be only empty array */
46 | schema.maxItems = 0
47 | schema.minItems = 0
48 | }
49 | return schema
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/lib/types/models/ArraySubmodelType.js:
--------------------------------------------------------------------------------
1 | import { SubmodelType } from 'src/lib/types/models/SubmodelType'
2 | import { ArrayModelType } from 'src/lib/types/models/ArrayModelType'
3 | import { createSubmodel } from 'src/lib/helpers/createSubmodel'
4 |
5 | export class ArraySubmodelType extends SubmodelType {
6 | constructor(submodel) {
7 | super(submodel)
8 | if (submodel.items) {
9 | this.items = createSubmodel(submodel.items)
10 | }
11 | }
12 |
13 | _getBasicSchema() {
14 | const schema = ArrayModelType.prototype._getBasicSchema()
15 | schema.required = schema.required.filter(field => field !== 'apiId' && field !== 'id')
16 | delete schema.properties.id
17 | delete schema.properties.apiId
18 | return schema
19 | }
20 |
21 | toSchema() {
22 | return ArrayModelType.prototype.toSchema.call(this)
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/lib/types/models/AssetModelType.js:
--------------------------------------------------------------------------------
1 | import { ModelType } from 'src/lib/types/models/ModelType'
2 | import deepFreeze from 'deep-freeze'
3 |
4 | export class AssetModelType extends ModelType {
5 | constructor(model) {
6 | super(model)
7 | deepFreeze(this)
8 | }
9 |
10 | _getBasicSchema() {
11 | return {
12 | type: 'object',
13 | additionalProperties: false,
14 | required: ['id', 'title', 'apiId', 'type'],
15 | properties: {
16 | id: { type: 'string', minLength: 1 },
17 | title: { type: 'string', minLength: 1 },
18 | apiId: { type: 'string', minLength: 1 },
19 | type: {
20 | enum: ['asset'],
21 | },
22 | description: { type: 'string', minLength: 1 },
23 | },
24 | }
25 | }
26 |
27 | toSchema() {
28 | const schema = { type: 'string', minLength: 1 }
29 | return schema
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/lib/types/models/AssetSubmodelType.js:
--------------------------------------------------------------------------------
1 | import { SubmodelType } from 'src/lib/types/models/SubmodelType'
2 | import { AssetModelType } from 'src/lib/types/models/AssetModelType'
3 |
4 | export class AssetSubmodelType extends SubmodelType {
5 | _getBasicSchema() {
6 | const schema = AssetModelType.prototype._getBasicSchema()
7 | schema.required = schema.required.filter(field => field !== 'apiId' && field !== 'id')
8 | delete schema.properties.id
9 | delete schema.properties.apiId
10 | return schema
11 | }
12 |
13 | toSchema() {
14 | return AssetModelType.prototype.toSchema.call(this)
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/lib/types/models/BooleanModelType.js:
--------------------------------------------------------------------------------
1 | import { ModelType } from 'src/lib/types/models/ModelType'
2 | import deepFreeze from 'deep-freeze'
3 |
4 | export class BooleanModelType extends ModelType {
5 | constructor(model) {
6 | super(model)
7 | deepFreeze(this)
8 | }
9 |
10 | _getBasicSchema() {
11 | return {
12 | type: 'object',
13 | additionalProperties: false,
14 | required: ['id', 'title', 'apiId', 'type', 'default'],
15 | properties: {
16 | id: { type: 'string', minLength: 1 },
17 | title: { type: 'string', minLength: 1 },
18 | apiId: { type: 'string', minLength: 1 },
19 | type: {
20 | enum: ['boolean'],
21 | },
22 | description: { type: 'string', minLength: 1 },
23 | default: { type: 'boolean' },
24 | },
25 | }
26 | }
27 |
28 | toSchema() {
29 | const schema = { type: 'boolean' }
30 | return schema
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/lib/types/models/BooleanSubmodelType.js:
--------------------------------------------------------------------------------
1 | import { SubmodelType } from 'src/lib/types/models/SubmodelType'
2 | import { BooleanModelType } from 'src/lib/types/models/BooleanModelType'
3 |
4 | export class BooleanSubmodelType extends SubmodelType {
5 | _getBasicSchema() {
6 | const schema = BooleanModelType.prototype._getBasicSchema()
7 | schema.required = schema.required.filter(field => field !== 'apiId' && field !== 'id')
8 | delete schema.properties.id
9 | delete schema.properties.apiId
10 | return schema
11 | }
12 |
13 | toSchema() {
14 | return BooleanModelType.prototype.toSchema.call(this)
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/lib/types/models/EnumSubmodelType.js:
--------------------------------------------------------------------------------
1 | import { SubmodelType } from 'src/lib/types/models/SubmodelType'
2 | import { EnumModelType } from 'src/lib/types/models/EnumModelType'
3 |
4 | export class EnumSubmodelType extends SubmodelType {
5 | _getBasicSchema() {
6 | const schema = EnumModelType.prototype._getBasicSchema()
7 | schema.required = schema.required.filter(field => field !== 'apiId' && field !== 'id')
8 | delete schema.properties.id
9 | delete schema.properties.apiId
10 | return schema
11 | }
12 |
13 | _validate(model) {
14 | const { valid, errors } = super._validate(model)
15 | const {
16 | valid: validByUniqueness,
17 | errors: uniquenessErrors,
18 | } = EnumModelType.prototype._validateUniqueness(model)
19 | const { valid: defaultFieldValid, errors: defaultFieldErrors } = EnumModelType.prototype._validateDefault(
20 | model
21 | )
22 | return {
23 | valid: valid && validByUniqueness && defaultFieldValid,
24 | errors: errors.concat(uniquenessErrors, defaultFieldErrors),
25 | }
26 | }
27 |
28 | toSchema() {
29 | return EnumModelType.prototype.toSchema.call(this)
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/lib/types/models/ModelType.js:
--------------------------------------------------------------------------------
1 | import { AbstractType } from 'src/lib/types/models/AbstractType'
2 |
3 | // abstract class
4 | export class ModelType extends AbstractType {}
5 |
--------------------------------------------------------------------------------
/src/lib/types/models/NumberModelType.js:
--------------------------------------------------------------------------------
1 | import { ModelType } from 'src/lib/types/models/ModelType'
2 | import deepFreeze from 'deep-freeze'
3 |
4 | export class NumberModelType extends ModelType {
5 | constructor(model) {
6 | super(model)
7 | deepFreeze(this)
8 | }
9 |
10 | _getBasicSchema() {
11 | return {
12 | type: 'object',
13 | additionalProperties: false,
14 | required: ['id', 'title', 'apiId', 'type'],
15 | properties: {
16 | id: { type: 'string', minLength: 1 },
17 | title: { type: 'string', minLength: 1 },
18 | apiId: { type: 'string', minLength: 1 },
19 | type: {
20 | enum: ['number'],
21 | },
22 | description: { type: 'string', minLength: 1 },
23 | default: { type: 'number' },
24 | minimum: { type: 'number' },
25 | maximum: { type: 'number' },
26 | // TODO: exist if exist min and max
27 | exclusiveMaximum: { type: 'boolean' },
28 | exclusiveMinimum: { type: 'boolean' },
29 | multipleOf: { type: 'number', minimum: 0, exclusiveMinimum: true },
30 | },
31 | }
32 | }
33 |
34 | toSchema() {
35 | const model = this
36 | const schema = { type: 'number' }
37 | const props = ['minimum', 'maximum', 'exclusiveMaximum', 'exclusiveMinimum', 'multipleOf']
38 | props.forEach(item => {
39 | if (model.hasOwnProperty(item)) {
40 | schema[item] = model[item]
41 | }
42 | })
43 | return schema
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/lib/types/models/NumberSubmodelType.js:
--------------------------------------------------------------------------------
1 | import { SubmodelType } from 'src/lib/types/models/SubmodelType'
2 | import { NumberModelType } from 'src/lib/types/models/NumberModelType'
3 |
4 | export class NumberSubmodelType extends SubmodelType {
5 | _getBasicSchema() {
6 | const schema = NumberModelType.prototype._getBasicSchema()
7 | schema.required = schema.required.filter(field => field !== 'apiId' && field !== 'id')
8 | delete schema.properties.id
9 | delete schema.properties.apiId
10 | return schema
11 | }
12 |
13 | toSchema() {
14 | return NumberModelType.prototype.toSchema.call(this)
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/lib/types/models/ObjectSubmodelType.js:
--------------------------------------------------------------------------------
1 | import { SubmodelType } from 'src/lib/types/models/SubmodelType'
2 | import { ObjectModelType } from 'src/lib/types/models/ObjectModelType'
3 | import { createSubmodel } from 'src/lib/helpers/createSubmodel'
4 |
5 | export class ObjectSubmodelType extends SubmodelType {
6 | constructor(submodel) {
7 | super(submodel)
8 | Object.keys(submodel.properties).forEach(propName => {
9 | this.properties[propName] = createSubmodel(submodel.properties[propName])
10 | })
11 | }
12 |
13 | _validate(model) {
14 | const { valid, errors } = super._validate(model)
15 | const {
16 | valid: requiredFieldsValid,
17 | errors: requiredFieldsErrors,
18 | } = ObjectModelType.prototype._validateRequireqFields(model)
19 | return { valid: valid && requiredFieldsValid, errors: errors.concat(requiredFieldsErrors) }
20 | }
21 |
22 | _getBasicSchema() {
23 | const schema = ObjectModelType.prototype._getBasicSchema()
24 | schema.required = schema.required.filter(field => field !== 'apiId' && field !== 'id')
25 | delete schema.properties.id
26 | delete schema.properties.apiId
27 | return schema
28 | }
29 |
30 | toSchema() {
31 | return ObjectModelType.prototype.toSchema.call(this)
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/lib/types/models/ReferenceModelType.js:
--------------------------------------------------------------------------------
1 | import { ModelType } from 'src/lib/types/models/ModelType'
2 | import deepFreeze from 'deep-freeze'
3 |
4 | export class ReferenceModelType extends ModelType {
5 | constructor(model) {
6 | super(model)
7 | deepFreeze(this)
8 | }
9 |
10 | _getBasicSchema() {
11 | return {
12 | type: 'object',
13 | additionalProperties: false,
14 | required: ['id', 'title', 'apiId', 'type', 'reference'],
15 | properties: {
16 | id: { type: 'string', minLength: 1 },
17 | title: { type: 'string', minLength: 1 },
18 | apiId: { type: 'string', minLength: 1 },
19 | type: {
20 | enum: ['reference'],
21 | },
22 | description: { type: 'string', minLength: 1 },
23 | reference: { type: 'string', minLength: 1 },
24 | },
25 | }
26 | }
27 |
28 | toSchema() {
29 | const schema = { type: 'string', minLength: 1 }
30 | return schema
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/lib/types/models/ReferenceSubmodelType.js:
--------------------------------------------------------------------------------
1 | import { SubmodelType } from 'src/lib/types/models/SubmodelType'
2 | import { ReferenceModelType } from 'src/lib/types/models/ReferenceModelType'
3 |
4 | export class ReferenceSubmodelType extends SubmodelType {
5 | _getBasicSchema() {
6 | const schema = ReferenceModelType.prototype._getBasicSchema()
7 | schema.required = schema.required.filter(field => field !== 'apiId' && field !== 'id')
8 | delete schema.properties.id
9 | delete schema.properties.apiId
10 | return schema
11 | }
12 |
13 | toSchema() {
14 | return ReferenceModelType.prototype.toSchema.call(this)
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/lib/types/models/StringModelType.js:
--------------------------------------------------------------------------------
1 | import { ModelType } from 'src/lib/types/models/ModelType'
2 | import deepFreeze from 'deep-freeze'
3 |
4 | export class StringModelType extends ModelType {
5 | constructor(model) {
6 | super(model)
7 | deepFreeze(this)
8 | }
9 |
10 | _validate(model) {
11 | const { valid, errors } = super._validate(model)
12 | const { valid: patternValid, errors: patternErrors } = this._validatePattern(model)
13 | return { valid: valid && patternValid, errors: errors.concat(patternErrors) }
14 | }
15 |
16 | _validatePattern(model) {
17 | if (model.pattern) {
18 | try {
19 | RegExp(model.pattern)
20 | } catch (error) {
21 | return { valid: false, errors: [{ field: 'pattern', message: error.message }] }
22 | }
23 | }
24 | return { valid: true, errors: [] }
25 | }
26 |
27 | _getBasicSchema() {
28 | return {
29 | type: 'object',
30 | additionalProperties: false,
31 | required: ['apiId', 'type', 'title', 'id'],
32 | properties: {
33 | id: { type: 'string', minLength: 1 },
34 | apiId: { type: 'string', minLength: 1 },
35 | type: {
36 | enum: ['string-line', 'string-multiline', 'string-html', 'string-markdown'],
37 | },
38 | title: { type: 'string', minLength: 1 },
39 | description: { type: 'string', minLength: 1 },
40 | default: { type: 'string', minLength: 1 },
41 | minLength: { type: 'integer', minimum: 0 },
42 | maxLength: { type: 'integer', minimum: 0 },
43 | pattern: { type: 'string', minLength: 1 },
44 | },
45 | }
46 | }
47 |
48 | toSchema() {
49 | const model = this
50 | const schema = { type: 'string' }
51 | const props = ['minLength', 'maxLength', 'pattern']
52 | props.forEach(item => {
53 | if (model.hasOwnProperty(item)) {
54 | schema[item] = model[item]
55 | }
56 | })
57 | return schema
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/lib/types/models/StringSubmodelType.js:
--------------------------------------------------------------------------------
1 | import { SubmodelType } from 'src/lib/types/models/SubmodelType'
2 | import { StringModelType } from 'src/lib/types/models/StringModelType'
3 |
4 | export class StringSubmodelType extends SubmodelType {
5 | _validate(model) {
6 | const { valid, errors } = super._validate(model)
7 | const { valid: patternValid, errors: patternErrors } = StringModelType.prototype._validatePattern(model)
8 | return { valid: valid && patternValid, errors: errors.concat(patternErrors) }
9 | }
10 |
11 | _getBasicSchema() {
12 | const schema = StringModelType.prototype._getBasicSchema()
13 | schema.required = schema.required.filter(field => field !== 'apiId' && field !== 'id')
14 | delete schema.properties.id
15 | delete schema.properties.apiId
16 | return schema
17 | }
18 |
19 | toSchema() {
20 | return StringModelType.prototype.toSchema.call(this)
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/lib/types/models/SubmodelType.js:
--------------------------------------------------------------------------------
1 | import { AbstractType } from 'src/lib/types/models/AbstractType'
2 |
3 | // abstract class
4 | export class SubmodelType extends AbstractType {}
5 |
--------------------------------------------------------------------------------
/src/login/actions/onDone.js:
--------------------------------------------------------------------------------
1 | export const onDone = creds => ({
2 | widget: 'login',
3 | type: 'onDone',
4 | payload: { creds },
5 | })
6 |
--------------------------------------------------------------------------------
/src/login/actions/post.js:
--------------------------------------------------------------------------------
1 | import { postFetcher } from 'src/login/fetchers/post'
2 |
3 | export function postAction(creds) {
4 | return function(dispatch, getState) {
5 | dispatch({
6 | widget: 'login',
7 | type: 'postStart',
8 | })
9 | postFetcher(creds)
10 | .then(() => {
11 | dispatch({
12 | widget: 'login',
13 | type: 'postEnd',
14 | })
15 | })
16 | .catch(error => {
17 | dispatch({
18 | widget: 'login',
19 | type: 'postError',
20 | payload: error,
21 | })
22 | })
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/login/components/Login.style.js:
--------------------------------------------------------------------------------
1 | import jss from 'src/lib/services/Jss'
2 |
3 | const { classes } = jss
4 | .createStyleSheet({
5 | link: {
6 | fontSize: '0.9em',
7 | },
8 | })
9 | .attach()
10 |
11 | export const cn = classes
12 |
--------------------------------------------------------------------------------
/src/login/fetchers/post.js:
--------------------------------------------------------------------------------
1 | import { fetch } from 'src/lib/services/Fetcher'
2 |
3 | export function postFetcher(creds) {
4 | return fetch({ method: 'POST', url: `login`, body: creds })
5 | }
6 |
--------------------------------------------------------------------------------
/src/login/reducer.js:
--------------------------------------------------------------------------------
1 | import { redirectSet, errorSet, fetchingStart, fetchingEnd } from 'src/global/reducer'
2 | import { routes } from 'src/lib/services/Routes'
3 | import { auth } from 'src/lib/services/Auth'
4 | import { postAction } from 'src/login/actions/post'
5 | import { dispatch } from 'src/store'
6 |
7 | export function postStart(state) {
8 | fetchingStart(state)
9 | state.login.loading.post = true
10 | }
11 |
12 | export function postEnd(state) {
13 | fetchingEnd(state)
14 | state.login.loading.post = false
15 | auth.set(true)
16 | redirectSet(state, routes.projects())
17 | }
18 |
19 | export function postError(state, error) {
20 | fetchingEnd(state)
21 | state.login.loading.post = false
22 | errorSet(state, { show: true, error })
23 | }
24 |
25 | export function onDone(state, { creds }) {
26 | setTimeout(() => dispatch(postAction(creds)), 0)
27 | }
28 |
29 | const modifiers = {
30 | postStart,
31 | postEnd,
32 | postError,
33 | onDone,
34 | }
35 |
36 | export const loginReducer = (state, action) => {
37 | const modifier = modifiers[action.type]
38 | modifier(state, action.payload)
39 | }
40 |
--------------------------------------------------------------------------------
/src/mocks/getArray.js:
--------------------------------------------------------------------------------
1 | import { getId } from 'src/mocks/getId'
2 |
3 | export const getArray = ({ max, sub, item }) => {
4 | const id = getId()
5 | const mock = {
6 | model: {
7 | id: id,
8 | apiId: `api-id-${id}`,
9 | type: 'array',
10 | title: `Array ${max ? 'max' : 'min'} ${sub ? 'subtype' : 'type'} title`,
11 | uniqueItems: false,
12 | },
13 | entry: {
14 | id: getId(),
15 | modelId: id,
16 | identificator: getId(),
17 | value: { type: 'array', value: max ? [item.entry] : [] },
18 | },
19 | }
20 | if (max) {
21 | mock.model.description = 'Array max description'
22 | mock.model.minItems = 1
23 | mock.model.maxItems = 3
24 | mock.model.items = item.model
25 | }
26 | if (sub) {
27 | delete mock.model.id
28 | delete mock.model.apiId
29 | mock.entry = mock.entry.value
30 | }
31 | return mock
32 | }
33 |
--------------------------------------------------------------------------------
/src/mocks/getAsset.js:
--------------------------------------------------------------------------------
1 | import { getId } from 'src/mocks/getId'
2 |
3 | export const getAsset = ({ max, sub } = {}) => {
4 | const id = getId()
5 | const mock = {
6 | model: {
7 | id: id,
8 | apiId: `api-id-${id}`,
9 | type: 'asset',
10 | title: `Asset ${max ? 'max' : 'min'} ${sub ? 'subtype' : 'type'} title`,
11 | },
12 | entry: {
13 | id: getId(),
14 | modelId: id,
15 | identificator: getId(),
16 | value: {
17 | type: 'asset',
18 | value: `http://localhost:3000/1.jpg`,
19 | },
20 | },
21 | }
22 | if (max) {
23 | mock.model.description = 'Asset max description'
24 | }
25 | if (sub) {
26 | delete mock.model.id
27 | delete mock.model.apiId
28 | mock.entry = mock.entry.value
29 | }
30 | return mock
31 | }
32 |
--------------------------------------------------------------------------------
/src/mocks/getBoolean.js:
--------------------------------------------------------------------------------
1 | import { getId } from 'src/mocks/getId'
2 |
3 | export const getBoolean = ({ max, sub } = {}) => {
4 | const id = getId()
5 | const mock = {
6 | model: {
7 | id: id,
8 | apiId: `api-id-${id}`,
9 | type: 'boolean',
10 | title: `Boolean ${max ? 'max' : 'min'} ${sub ? 'subtype' : 'type'} title`,
11 | default: !!max,
12 | },
13 | entry: {
14 | id: getId(),
15 | modelId: id,
16 | identificator: getId(),
17 | value: { type: 'boolean', value: false },
18 | },
19 | }
20 | if (max) {
21 | mock.entry.value.value = true
22 | mock.model.description = 'Boolean max description'
23 | }
24 | if (sub) {
25 | delete mock.model.id
26 | delete mock.model.apiId
27 | mock.entry = mock.entry.value
28 | }
29 | return mock
30 | }
31 |
--------------------------------------------------------------------------------
/src/mocks/getEnum.js:
--------------------------------------------------------------------------------
1 | import { getId } from 'src/mocks/getId'
2 |
3 | export const getEnum = ({ max, sub } = {}) => {
4 | const id = getId()
5 | const mock = {
6 | model: {
7 | id: id,
8 | apiId: `api-id-${id}`,
9 | type: 'enum',
10 | title: `Enum ${max ? 'max' : 'min'} ${sub ? 'subtype' : 'type'} title`,
11 | enum: [
12 | {
13 | label: 'True',
14 | value: true,
15 | },
16 | ],
17 | },
18 | entry: {
19 | id: getId(),
20 | modelId: id,
21 | identificator: getId(),
22 | value: { type: 'enum', value: true },
23 | },
24 | }
25 | if (max) {
26 | mock.model.enum.push({ label: 'first', value: 'first' })
27 | mock.entry.value.value = 'first'
28 | mock.model.description = 'Enum max description'
29 | mock.model.default = true
30 | }
31 | if (sub) {
32 | delete mock.model.id
33 | delete mock.model.apiId
34 | mock.entry = mock.entry.value
35 | }
36 | return mock
37 | }
38 |
--------------------------------------------------------------------------------
/src/mocks/getId.js:
--------------------------------------------------------------------------------
1 | export const getId = () => `${Math.round(Math.random() * 1e9)}`
2 |
--------------------------------------------------------------------------------
/src/mocks/getNumber.js:
--------------------------------------------------------------------------------
1 | import { getId } from 'src/mocks/getId'
2 |
3 | export const getNumber = ({ max, sub } = {}) => {
4 | const id = getId()
5 | const mock = {
6 | model: {
7 | id: id,
8 | apiId: `api-id-${id}`,
9 | type: 'number',
10 | title: `Number ${max ? 'max' : 'min'} ${sub ? 'subtype' : 'type'} title`,
11 | },
12 | entry: {
13 | id: getId(),
14 | modelId: id,
15 | identificator: getId(),
16 | value: { type: 'number', value: 0 },
17 | },
18 | }
19 | if (max) {
20 | mock.entry.value.value = 2.8 // 1.4
21 | mock.model.description = 'Number max description'
22 | mock.model.default = 1.4
23 | mock.model.minimum = 0.1
24 | mock.model.maximum = 9.8
25 | mock.model.multipleOf = 1.4 // 0.2
26 | mock.model.exclusiveMinimum = true
27 | mock.model.exclusiveMaximum = true
28 | }
29 | if (sub) {
30 | delete mock.model.id
31 | delete mock.model.apiId
32 | mock.entry = mock.entry.value
33 | }
34 | return mock
35 | }
36 |
--------------------------------------------------------------------------------
/src/mocks/getObject.js:
--------------------------------------------------------------------------------
1 | import { getId } from 'src/mocks/getId'
2 |
3 | export const getObject = ({ max, sub, props }) => {
4 | const id = getId()
5 | const mock = {
6 | model: {
7 | id: id,
8 | apiId: `api-id-${id}`,
9 | type: 'object',
10 | title: `Object ${max ? 'max' : 'min'} ${sub ? 'subtype' : 'type'} title`,
11 | required: max ? Object.keys(props) : [],
12 | additionalProperties: false,
13 | properties: Object.keys(props).reduce((res, key) => {
14 | res[key] = props[key].model
15 | return res
16 | }, {}),
17 | },
18 | entry: {
19 | id: getId(),
20 | modelId: id,
21 | identificator: getId(),
22 | value: { type: 'object', value: {} },
23 | },
24 | }
25 | if (max) {
26 | mock.model.description = 'Object max description'
27 | mock.entry.value.value = Object.keys(props).reduce((res, key) => {
28 | res[key] = props[key].entry
29 | return res
30 | }, {})
31 | }
32 | if (sub) {
33 | delete mock.model.id
34 | delete mock.model.apiId
35 | mock.entry = mock.entry.value
36 | }
37 | return mock
38 | }
39 |
--------------------------------------------------------------------------------
/src/mocks/getReference.js:
--------------------------------------------------------------------------------
1 | import { getId } from 'src/mocks/getId'
2 |
3 | export const getReference = ({ max, sub, model, entry } = {}) => {
4 | const id = getId()
5 | const mock = {
6 | model: {
7 | id: id,
8 | apiId: `api-id-${id}`,
9 | type: 'reference',
10 | title: `Reference ${max ? 'max' : 'min'} ${sub ? 'subtype' : 'type'} title`,
11 | reference: model.id,
12 | },
13 | entry: {
14 | id: getId(),
15 | modelId: id,
16 | identificator: getId(),
17 | value: { type: 'reference', value: entry.id },
18 | },
19 | }
20 | if (max) {
21 | mock.model.description = 'Reference max description'
22 | }
23 | if (sub) {
24 | delete mock.model.id
25 | delete mock.model.apiId
26 | mock.entry = mock.entry.value
27 | }
28 | return mock
29 | }
30 |
--------------------------------------------------------------------------------
/src/mocks/getStringHtml.js:
--------------------------------------------------------------------------------
1 | import { getId } from 'src/mocks/getId'
2 |
3 | export const getStringHtml = ({ max, sub } = {}) => {
4 | const id = getId()
5 | const mock = {
6 | model: {
7 | id: id,
8 | apiId: `api-id-${id}`,
9 | type: 'string-html',
10 | title: `StringHtml ${max ? 'max' : 'min'} ${sub ? 'subtype' : 'type'} title`,
11 | },
12 | entry: {
13 | id: getId(),
14 | modelId: id,
15 | identificator: getId(),
16 | value: { type: 'string-html', value: '' },
17 | },
18 | }
19 | if (max) {
20 | mock.entry.value.value = 'a
'
21 | mock.model.description = 'StringHtml max description'
22 | mock.model.default = 'b'
23 | mock.model.minLength = 2
24 | mock.model.maxLength = 20
25 | // mock.model.pattern = '^([0-9]+)$'
26 | }
27 | if (sub) {
28 | delete mock.model.id
29 | delete mock.model.apiId
30 | mock.entry = mock.entry.value
31 | }
32 | return mock
33 | }
34 |
--------------------------------------------------------------------------------
/src/mocks/getStringLine.js:
--------------------------------------------------------------------------------
1 | import { getId } from 'src/mocks/getId'
2 |
3 | export const getStringLine = ({ max, sub } = {}) => {
4 | const id = getId()
5 | const mock = {
6 | model: {
7 | id: id,
8 | apiId: `api-id-${id}`,
9 | type: 'string-line',
10 | title: `StringLine ${max ? 'max' : 'min'} ${sub ? 'subtype' : 'type'} title`,
11 | },
12 | entry: {
13 | id: getId(),
14 | modelId: id,
15 | identificator: getId(),
16 | value: { type: 'string-line', value: '' },
17 | },
18 | }
19 | if (max) {
20 | mock.entry.value.value = 'lada'
21 | mock.model.description = 'StringLine max description'
22 | mock.model.default = 'bmw'
23 | mock.model.minLength = 2
24 | mock.model.maxLength = 20
25 | mock.model.pattern = '^([a-z]+)$'
26 | }
27 | if (sub) {
28 | delete mock.model.id
29 | delete mock.model.apiId
30 | mock.entry = mock.entry.value
31 | }
32 | return mock
33 | }
34 |
--------------------------------------------------------------------------------
/src/mocks/getStringMarkdown.js:
--------------------------------------------------------------------------------
1 | import { stringMarkdownValue } from 'src/mocks/stringMarkdownValue'
2 | import { getId } from 'src/mocks/getId'
3 |
4 | export const getStringMarkdown = ({ max, sub } = {}) => {
5 | const id = getId()
6 | const mock = {
7 | model: {
8 | id: id,
9 | apiId: `api-id-${id}`,
10 | type: 'string-markdown',
11 | title: `StringMarkdown ${max ? 'max' : 'min'} ${sub ? 'subtype' : 'type'} title`,
12 | },
13 | entry: {
14 | id: getId(),
15 | modelId: id,
16 | identificator: getId(),
17 | value: { type: 'string-markdown', value: '' },
18 | },
19 | }
20 | if (max) {
21 | mock.entry.value.value = stringMarkdownValue
22 | mock.model.description = 'StringMarkdown max description'
23 | mock.model.default = '## StringMarkdown'
24 | mock.model.minLength = 2
25 | mock.model.maxLength = 100
26 | // mock.model.pattern = '^([a-z]+)$'
27 | }
28 | if (sub) {
29 | delete mock.model.id
30 | delete mock.model.apiId
31 | mock.entry = mock.entry.value
32 | }
33 | return mock
34 | }
35 |
--------------------------------------------------------------------------------
/src/mocks/getStringMultiline.js:
--------------------------------------------------------------------------------
1 | import { getId } from 'src/mocks/getId'
2 |
3 | export const getStringMultiline = ({ max, sub } = {}) => {
4 | const id = getId()
5 | const mock = {
6 | model: {
7 | id: id,
8 | apiId: `api-id-${id}`,
9 | type: 'string-multiline',
10 | title: `StringMultiline ${max ? 'max' : 'min'} ${sub ? 'subtype' : 'type'} title`,
11 | },
12 | entry: {
13 | id: getId(),
14 | modelId: id,
15 | identificator: getId(),
16 | value: { type: 'string-multiline', value: '' },
17 | },
18 | }
19 | if (max) {
20 | mock.entry.value.value = 'aaabbb'
21 | mock.model.description = 'StringMultiline max description'
22 | mock.model.default = 'aaa'
23 | mock.model.minLength = 2
24 | mock.model.maxLength = 20
25 | mock.model.pattern = '^([a-z]+)$'
26 | }
27 | if (sub) {
28 | delete mock.model.id
29 | delete mock.model.apiId
30 | mock.entry = mock.entry.value
31 | }
32 | return mock
33 | }
34 |
--------------------------------------------------------------------------------
/src/mocks/stringMarkdownValue.js:
--------------------------------------------------------------------------------
1 | export const stringMarkdownValue = `You`
2 | // `
3 | // ## Medium Editor
4 | //
5 | // You know, the **Medium Editor** library is awesome. Just great. But there is a missing feature that some people would like to have.
6 | //
7 | // It's called _Markdown_. [@IonicaBizau](https://github.com/IonicaBizau) created a Medium Editor extension that adds this missing feature.
8 | //
9 | // > Walking on water and developing software from a specification are easy if both are frozen. _Edward Berard_
10 | //
11 | // Let's test up the elements.
12 | //
13 | // > ## First Computer Bug
14 | // >
15 | // > In 1947, Grace Murray Hopper was working on the Harvard University Mark II Aiken Relay Calculator (a primitive computer).
16 | // >
17 | // > On the 9th of September, 1947, when the machine was experiencing problems, an investigation showed that there was a moth trapped between the points of Relay #70, in Panel F.
18 | // >
19 | // > The operators removed the moth and affixed it to the log. The entry reads: "First actual case of bug being found."
20 | // >
21 | // > _[Read the whole story »](http://www.jamesshuggins.com/h/tek1/first_computer_bug.htm)_
22 | //
23 | // # Heading 1
24 | //
25 | // ## Heading 2
26 | //
27 | // ### Heading 3
28 | //
29 | // #### Heading 4
30 | //
31 | // ##### Heading 5
32 | //
33 | // ###### Heading 6
34 | //
35 | // * I am
36 | // * a list
37 | // * with 3 items
38 | //
39 | // 1. I am
40 | // 2. a numbered list
41 | // 3. with 3 items
42 | //
43 | // **bold**
44 | //
45 | // _italic_
46 | //
47 | // underline
48 | //
49 | // awesome
50 | //
51 | // elements1
52 | //
53 | // elements1
54 | //
55 | // [Read the whole story »](http://www.jamesshuggins.com/h/tek1/first_computer_bug.htm)
56 | //
57 | // > quote
58 | // `
59 |
--------------------------------------------------------------------------------
/src/models/actions/delete.js:
--------------------------------------------------------------------------------
1 | import { deleteFetcher } from 'src/models/fetchers/delete'
2 | import { getDataAction } from 'src/global/actions/getData'
3 |
4 | export function deleteAction(modelId, entries) {
5 | return function(dispatch, getState) {
6 | const { projectId } = getState().global
7 | dispatch({
8 | widget: 'models',
9 | type: 'deleteStart',
10 | })
11 | deleteFetcher(projectId, modelId)
12 | .then(() => {
13 | dispatch({
14 | widget: 'models',
15 | type: 'deleteEnd',
16 | })
17 | dispatch(getDataAction())
18 | })
19 | .catch(error => {
20 | dispatch({
21 | widget: 'models',
22 | type: 'deleteError',
23 | payload: error,
24 | })
25 | dispatch(getDataAction())
26 | })
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/models/actions/onAddItem.js:
--------------------------------------------------------------------------------
1 | export const onAddItem = (id, dist) => ({
2 | widget: 'models',
3 | type: 'onAddItem',
4 | payload: { id, dist },
5 | })
6 |
--------------------------------------------------------------------------------
/src/models/actions/onAddModel.js:
--------------------------------------------------------------------------------
1 | export const onAddModel = () => ({
2 | widget: 'models',
3 | type: 'onAddModel',
4 | payload: {},
5 | })
6 |
--------------------------------------------------------------------------------
/src/models/actions/onAddProp.js:
--------------------------------------------------------------------------------
1 | export const onAddProp = (id, dist) => ({
2 | widget: 'models',
3 | type: 'onAddProp',
4 | payload: { id, dist },
5 | })
6 |
--------------------------------------------------------------------------------
/src/models/actions/onDeleteItem.js:
--------------------------------------------------------------------------------
1 | export const onDeleteItem = (id, dist) => ({
2 | widget: 'models',
3 | type: 'onDeleteItem',
4 | payload: { id, dist },
5 | })
6 |
--------------------------------------------------------------------------------
/src/models/actions/onDeleteModel.js:
--------------------------------------------------------------------------------
1 | export const onDeleteModel = id => ({
2 | widget: 'models',
3 | type: 'onDeleteModel',
4 | payload: { id },
5 | })
6 |
--------------------------------------------------------------------------------
/src/models/actions/onDeleteProp.js:
--------------------------------------------------------------------------------
1 | export const onDeleteProp = (id, dist) => ({
2 | widget: 'models',
3 | type: 'onDeleteProp',
4 | payload: { id, dist },
5 | })
6 |
--------------------------------------------------------------------------------
/src/models/actions/onDialogAddDoneItem.js:
--------------------------------------------------------------------------------
1 | export const onDialogAddDoneItem = item => ({
2 | widget: 'models',
3 | type: 'onDialogAddDoneItem',
4 | payload: { item },
5 | })
6 |
--------------------------------------------------------------------------------
/src/models/actions/onDialogAddDoneModel.js:
--------------------------------------------------------------------------------
1 | export const onDialogAddDoneModel = model => ({
2 | widget: 'models',
3 | type: 'onDialogAddDoneModel',
4 | payload: { model },
5 | })
6 |
--------------------------------------------------------------------------------
/src/models/actions/onDialogAddDoneProp.js:
--------------------------------------------------------------------------------
1 | export const onDialogAddDoneProp = property => ({
2 | widget: 'models',
3 | type: 'onDialogAddDoneProp',
4 | payload: { property },
5 | })
6 |
--------------------------------------------------------------------------------
/src/models/actions/onDialogClose.js:
--------------------------------------------------------------------------------
1 | export const onDialogClose = dialogType => ({
2 | widget: 'models',
3 | type: 'onDialogClose',
4 | payload: { dialogType },
5 | })
6 |
--------------------------------------------------------------------------------
/src/models/actions/onDialogConfirmConfirmItem.js:
--------------------------------------------------------------------------------
1 | export const onDialogConfirmConfirmItem = () => ({
2 | widget: 'models',
3 | type: 'onDialogConfirmConfirmItem',
4 | payload: {},
5 | })
6 |
--------------------------------------------------------------------------------
/src/models/actions/onDialogConfirmConfirmModel.js:
--------------------------------------------------------------------------------
1 | export const onDialogConfirmConfirmModel = () => ({
2 | widget: 'models',
3 | type: 'onDialogConfirmConfirmModel',
4 | payload: {},
5 | })
6 |
--------------------------------------------------------------------------------
/src/models/actions/onDialogConfirmConfirmProp.js:
--------------------------------------------------------------------------------
1 | export const onDialogConfirmConfirmProp = () => ({
2 | widget: 'models',
3 | type: 'onDialogConfirmConfirmProp',
4 | payload: {},
5 | })
6 |
--------------------------------------------------------------------------------
/src/models/actions/onDialogEditDoneItem.js:
--------------------------------------------------------------------------------
1 | export const onDialogEditDoneItem = item => ({
2 | widget: 'models',
3 | type: 'onDialogEditDoneItem',
4 | payload: { item },
5 | })
6 |
--------------------------------------------------------------------------------
/src/models/actions/onDialogEditDoneModel.js:
--------------------------------------------------------------------------------
1 | export const onDialogEditDoneModel = model => ({
2 | widget: 'models',
3 | type: 'onDialogEditDoneModel',
4 | payload: { model },
5 | })
6 |
--------------------------------------------------------------------------------
/src/models/actions/onDialogEditDoneProp.js:
--------------------------------------------------------------------------------
1 | export const onDialogEditDoneProp = property => ({
2 | widget: 'models',
3 | type: 'onDialogEditDoneProp',
4 | payload: { property },
5 | })
6 |
--------------------------------------------------------------------------------
/src/models/actions/onDialogExited.js:
--------------------------------------------------------------------------------
1 | export const onDialogExited = dialogType => ({
2 | widget: 'models',
3 | type: 'onDialogExited',
4 | payload: { dialogType },
5 | })
6 |
--------------------------------------------------------------------------------
/src/models/actions/onEditItem.js:
--------------------------------------------------------------------------------
1 | export const onEditItem = (id, dist, item) => ({
2 | widget: 'models',
3 | type: 'onEditItem',
4 | payload: { id, dist, item },
5 | })
6 |
--------------------------------------------------------------------------------
/src/models/actions/onEditModel.js:
--------------------------------------------------------------------------------
1 | export const onEditModel = model => ({
2 | widget: 'models',
3 | type: 'onEditModel',
4 | payload: { model },
5 | })
6 |
--------------------------------------------------------------------------------
/src/models/actions/onEditProp.js:
--------------------------------------------------------------------------------
1 | export const onEditProp = (id, dist, property) => ({
2 | widget: 'models',
3 | type: 'onEditProp',
4 | payload: { id, dist, property },
5 | })
6 |
--------------------------------------------------------------------------------
/src/models/actions/post.js:
--------------------------------------------------------------------------------
1 | import { postFetcher } from 'src/models/fetchers/post'
2 | import { getDataAction } from 'src/global/actions/getData'
3 |
4 | export function postAction(model) {
5 | return function(dispatch, getState) {
6 | const { projectId } = getState().global
7 | dispatch({
8 | widget: 'models',
9 | type: 'postStart',
10 | })
11 | postFetcher(projectId, model)
12 | .then(() => {
13 | dispatch({
14 | widget: 'models',
15 | type: 'postEnd',
16 | })
17 | dispatch(getDataAction())
18 | })
19 | .catch(error => {
20 | dispatch({
21 | widget: 'models',
22 | type: 'postError',
23 | payload: error,
24 | })
25 | dispatch(getDataAction())
26 | })
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/models/actions/put.js:
--------------------------------------------------------------------------------
1 | import { putFetcher } from 'src/models/fetchers/put'
2 | import { getDataAction } from 'src/global/actions/getData'
3 |
4 | export function putAction(model) {
5 | return function(dispatch, getState) {
6 | const { projectId } = getState().global
7 | dispatch({
8 | widget: 'models',
9 | type: 'putStart',
10 | })
11 | putFetcher(projectId, model)
12 | .then(() => {
13 | dispatch({
14 | widget: 'models',
15 | type: 'putEnd',
16 | })
17 | dispatch(getDataAction())
18 | })
19 | .catch(error => {
20 | dispatch({
21 | widget: 'models',
22 | type: 'putError',
23 | payload: error,
24 | })
25 | dispatch(getDataAction())
26 | })
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/models/components/basic/TypeBlock.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { Grid, Typography } from 'material-ui'
3 | import { func, string, node } from 'prop-types'
4 | import { CircledIcon } from 'src/lib/components/CircledIcon'
5 | import { colors } from 'src/colors'
6 |
7 | import { cn } from './TypeBlock.style'
8 |
9 | export class TypeBlock extends Component {
10 | static propTypes = {
11 | onClick: func.isRequired,
12 | icon: node.isRequired,
13 | title: string.isRequired,
14 | description: string.isRequired,
15 | }
16 |
17 | render() {
18 | const { onClick, icon, title, description } = this.props
19 | return (
20 | onClick()}>
21 |
22 |
23 | {icon}
24 |
25 |
26 |
27 | {title}
28 | {description}
29 |
30 |
31 | )
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/models/components/basic/TypeBlock.style.js:
--------------------------------------------------------------------------------
1 | import jss from 'src/lib/services/Jss'
2 | import { colors } from 'src/colors'
3 |
4 | const { classes } = jss
5 | .createStyleSheet({
6 | typeBlock: {
7 | cursor: 'pointer',
8 | '& .avatar > div': {
9 | margin: 'auto',
10 | },
11 | '&:hover .avatar > div': {
12 | 'background-color': `${colors.primary.d2} !important`,
13 | },
14 | },
15 | })
16 | .attach()
17 |
18 | export const cn = classes
19 |
--------------------------------------------------------------------------------
/src/models/components/cards/ObjectCard.style.js:
--------------------------------------------------------------------------------
1 | import jss from 'src/lib/services/Jss'
2 | import { colors } from 'src/colors'
3 |
4 | const { classes } = jss
5 | .createStyleSheet({
6 | add: {
7 | borderLeft: `4px solid ${colors.primary.main}`,
8 | },
9 | })
10 | .attach()
11 |
12 | export const cn = classes
13 |
--------------------------------------------------------------------------------
/src/models/components/dialogs/ConfirmDialog.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { func, oneOf, bool } from 'prop-types'
3 | import { ConfirmDialog as AConfirmDialog } from 'src/lib/components/ConfirmDialog'
4 |
5 | export class ConfirmDialog extends Component {
6 | static propTypes = {
7 | mod: oneOf(['model', 'prop', 'item']),
8 | open: bool.isRequired,
9 | onConfirmItem: func.isRequired,
10 | onConfirmModel: func.isRequired,
11 | onConfirmProp: func.isRequired,
12 | onClose: func.isRequired,
13 | onExited: func.isRequired,
14 | }
15 |
16 | static defaultProps = {
17 | mod: null,
18 | }
19 |
20 | render() {
21 | const { mod, open, onConfirmItem, onConfirmModel, onConfirmProp, onClose, onExited } = this.props
22 | if (!mod) return null
23 | const MAP_TITLE = {
24 | model: 'Delete model?',
25 | prop: 'Delete property?',
26 | item: 'Delete item?',
27 | }
28 | const MAP_TEXT = {
29 | model: 'Are you sure you want to delete model? All entries related to this model will be lost.',
30 | prop:
31 | 'Are you sure you want to delete property? All data of entries related to this property will be lost.',
32 | item: 'Are you sure you want to delete item? All data of entries related to this item will be lost.',
33 | }
34 | const MAP_ACTIONS = {
35 | model: onConfirmModel,
36 | prop: onConfirmProp,
37 | item: onConfirmItem,
38 | }
39 | return (
40 |
48 | )
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/models/components/dialogs/Steps.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { number, array, arrayOf } from 'prop-types'
3 | import { Step } from 'src/models/components/dialogs/Step'
4 |
5 | export class Steps extends Component {
6 | static propTypes = {
7 | step: number.isRequired,
8 | steps: arrayOf(array).isRequired,
9 | }
10 |
11 | render() {
12 | const { step, steps, ...props } = this.props
13 | return
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/models/components/dialogs/enum-type/EnumControl.style.js:
--------------------------------------------------------------------------------
1 | import jss from 'src/lib/services/Jss'
2 | import { colors } from 'src/colors'
3 |
4 | const { classes } = jss
5 | .createStyleSheet({
6 | container: {
7 | paddingBottom: 42,
8 | },
9 | deleteButton: {
10 | marginTop: 16,
11 | },
12 | textError: {
13 | color: colors.error.main,
14 | },
15 | })
16 | .attach()
17 |
18 | export const cn = classes
19 |
--------------------------------------------------------------------------------
/src/models/components/dialogs/reference-type/ReferenceItem.style.js:
--------------------------------------------------------------------------------
1 | import jss from 'src/lib/services/Jss'
2 |
3 | const { classes } = jss
4 | .createStyleSheet({
5 | contentContainer: {
6 | paddingBottom: 210,
7 | },
8 | })
9 | .attach()
10 |
11 | export const cn = classes
12 |
--------------------------------------------------------------------------------
/src/models/components/dialogs/reference-type/ReferenceModel.style.js:
--------------------------------------------------------------------------------
1 | import jss from 'src/lib/services/Jss'
2 |
3 | const { classes } = jss
4 | .createStyleSheet({
5 | contentContainer: {
6 | paddingBottom: 210,
7 | },
8 | })
9 | .attach()
10 |
11 | export const cn = classes
12 |
--------------------------------------------------------------------------------
/src/models/components/dialogs/reference-type/ReferenceProp.style.js:
--------------------------------------------------------------------------------
1 | import jss from 'src/lib/services/Jss'
2 |
3 | const { classes } = jss
4 | .createStyleSheet({
5 | contentContainer: {
6 | paddingBottom: 210 - 76,
7 | },
8 | })
9 | .attach()
10 |
11 | export const cn = classes
12 |
--------------------------------------------------------------------------------
/src/models/fetchers/delete.js:
--------------------------------------------------------------------------------
1 | import { fetch } from 'src/lib/services/Fetcher'
2 |
3 | export const deleteFetcher = (projectId, id) => {
4 | return fetch({ method: 'DELETE', url: `projects/${projectId}/models/${id}` })
5 | }
6 |
--------------------------------------------------------------------------------
/src/models/fetchers/post.js:
--------------------------------------------------------------------------------
1 | import { fetch } from 'src/lib/services/Fetcher'
2 |
3 | export const postFetcher = (projectId, model) => {
4 | return fetch({ method: 'POST', url: `projects/${projectId}/models`, body: model })
5 | }
6 |
--------------------------------------------------------------------------------
/src/models/fetchers/put.js:
--------------------------------------------------------------------------------
1 | import { fetch } from 'src/lib/services/Fetcher'
2 |
3 | export const putFetcher = (projectId, model) => {
4 | return fetch({ method: 'PUT', url: `projects/${projectId}/models/${model.id}`, body: model })
5 | }
6 |
--------------------------------------------------------------------------------
/src/models/helpers/dialogConstructor.js:
--------------------------------------------------------------------------------
1 | export function dialogConstructor(props, initialModel) {
2 | const clearState = this.getClearState()
3 | if (initialModel) {
4 | Object.keys(initialModel).forEach(key => {
5 | clearState.model[key] = initialModel[key]
6 | })
7 | }
8 | this.state = clearState
9 | }
10 |
--------------------------------------------------------------------------------
/src/models/helpers/dialogTypeOnBlur.js:
--------------------------------------------------------------------------------
1 | import { validatePropertyName } from 'src/models/helpers/validatePropertyName'
2 |
3 | export function dialogTypeOnBlur({ Type, field }) {
4 | const { state } = this
5 | const { model } = state
6 |
7 | const { errors } =
8 | field !== 'propertyName'
9 | ? Type.prototype.validateExactFields(model, [field])
10 | : validatePropertyName(model)
11 | state.errors[field] = errors.length ? errors[0].message : ''
12 |
13 | this.setState(state)
14 | }
15 |
--------------------------------------------------------------------------------
/src/models/helpers/dialogTypeOnDone.js:
--------------------------------------------------------------------------------
1 | import clone from 'clone'
2 | import { validatePropertyName } from 'src/models/helpers/validatePropertyName'
3 |
4 | export function dialogTypeOnDone({ Type, fields, onDone }) {
5 | const { state } = this
6 | const { model } = state
7 |
8 | const { valid, errors } = Type.prototype.validateExactFields(
9 | model,
10 | fields.filter(item => item !== 'propertyName')
11 | )
12 | fields.forEach(field => {
13 | const fieldErrors = errors.filter(error => error.field === field)
14 | state.errors[field] = fieldErrors.length ? fieldErrors[0].message : ''
15 | })
16 |
17 | let propertyNameValid = true
18 | if (fields.some(item => item === 'propertyName')) {
19 | const { valid, errors } = validatePropertyName(model)
20 | propertyNameValid = valid
21 | state.errors.propertyName = errors.length ? errors[0].message : ''
22 | }
23 |
24 | if (valid && propertyNameValid) {
25 | onDone(clone(model))
26 | } else {
27 | this.setState(state)
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/models/helpers/onBooleanChange.js:
--------------------------------------------------------------------------------
1 | export function onBooleanChange(field, value) {
2 | const { state } = this
3 | const { model } = state
4 |
5 | model[field] = value
6 |
7 | this.setState(state)
8 | }
9 |
--------------------------------------------------------------------------------
/src/models/helpers/onNumberChange.js:
--------------------------------------------------------------------------------
1 | import { isNumber } from 'src/lib/helpers/isNumber'
2 |
3 | export function onNumberChange(field, value) {
4 | const { state } = this
5 | const { model, errors } = state
6 |
7 | model[field] = isNumber(value) ? +value : value
8 | errors[field] = ''
9 |
10 | if (model[field] === '') {
11 | delete model[field]
12 | }
13 |
14 | this.setState(state)
15 | }
16 |
--------------------------------------------------------------------------------
/src/models/helpers/onStringChange.js:
--------------------------------------------------------------------------------
1 | export function onStringChange(field, value) {
2 | const { state } = this
3 | const { model, errors } = state
4 |
5 | model[field] = value
6 | errors[field] = ''
7 |
8 | if (!model[field]) {
9 | delete model[field]
10 | }
11 |
12 | this.setState(state)
13 | }
14 |
--------------------------------------------------------------------------------
/src/models/helpers/validatePropertyName.js:
--------------------------------------------------------------------------------
1 | import { validate } from 'src/lib/services/Validator'
2 |
3 | export function validatePropertyName(model) {
4 | return validate(model.propertyName, { type: 'string', minLength: 1 })
5 | }
6 |
--------------------------------------------------------------------------------
/src/not-found/components/NotFound.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { func } from 'prop-types'
3 | import { connect } from 'react-redux'
4 | import { Typography } from 'src/lib/components/Typography'
5 | import { Button } from 'src/lib/components/Button'
6 | import { redirectSetAction } from 'src/global/actions/redirectSet'
7 | import { routes } from 'src/lib/services/Routes'
8 | import { RedirectContainer } from 'src/global/components/RedirectContainer'
9 | import { ErrorContainer } from 'src/global/components/ErrorContainer'
10 | import { PageContainer } from 'src/lib/components/PageContainer'
11 |
12 | class ANotFound extends Component {
13 | static propTypes = {
14 | redirectSet: func.isRequired,
15 | }
16 |
17 | render() {
18 | const { redirectSet } = this.props
19 | return (
20 |
21 |
22 |
23 |
24 |
25 | Look like this page doesn't exist
26 |
27 |
30 |
31 |
32 |
33 |
34 | )
35 | }
36 | }
37 |
38 | export const NotFound = connect(
39 | state => ({}),
40 | dispatch => ({
41 | redirectSet: (...props) => dispatch(redirectSetAction(...props)),
42 | })
43 | )(ANotFound)
44 |
--------------------------------------------------------------------------------
/src/projects/actions/deleteAction.js:
--------------------------------------------------------------------------------
1 | import { deleteFetcher } from 'src/projects/fetchers/deleteFetcher'
2 | import { getAction } from 'src/projects/actions/getAction'
3 |
4 | export function deleteAction(project) {
5 | return function(dispatch, getState) {
6 | dispatch({
7 | widget: 'projects',
8 | type: 'deleteStart',
9 | })
10 | deleteFetcher(project.id)
11 | .then(() => {
12 | dispatch({
13 | widget: 'projects',
14 | type: 'deleteEnd',
15 | })
16 | dispatch(getAction())
17 | })
18 | .catch(error => {
19 | dispatch({
20 | widget: 'projects',
21 | type: 'deleteError',
22 | payload: error,
23 | })
24 | dispatch(getAction())
25 | })
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/projects/actions/getAction.js:
--------------------------------------------------------------------------------
1 | import { getProjectsFetcher } from 'src/global/fetchers/getProjects'
2 |
3 | export function getAction() {
4 | return function(dispatch, getState) {
5 | dispatch({
6 | widget: 'projects',
7 | type: 'getStart',
8 | })
9 | getProjectsFetcher()
10 | .then(projects => {
11 | dispatch({
12 | widget: 'projects',
13 | type: 'getEnd',
14 | payload: { projects },
15 | })
16 | })
17 | .catch(error => {
18 | dispatch({
19 | widget: 'projects',
20 | type: 'getError',
21 | payload: error,
22 | })
23 | })
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/projects/actions/onAddDialogDone.js:
--------------------------------------------------------------------------------
1 | export const onAddDialogDone = project => ({
2 | widget: 'projects',
3 | type: 'onAddDialogDone',
4 | payload: { project },
5 | })
6 |
--------------------------------------------------------------------------------
/src/projects/actions/onAddProject.js:
--------------------------------------------------------------------------------
1 | export const onAddProject = () => ({
2 | widget: 'projects',
3 | type: 'onAddProject',
4 | payload: {},
5 | })
6 |
--------------------------------------------------------------------------------
/src/projects/actions/onConfirmDialogConfirm.js:
--------------------------------------------------------------------------------
1 | export const onConfirmDialogConfirm = () => ({
2 | widget: 'projects',
3 | type: 'onConfirmDialogConfirm',
4 | payload: {},
5 | })
6 |
--------------------------------------------------------------------------------
/src/projects/actions/onDeleteProject.js:
--------------------------------------------------------------------------------
1 | export const onDeleteProject = id => ({
2 | widget: 'projects',
3 | type: 'onDeleteProject',
4 | payload: { id },
5 | })
6 |
--------------------------------------------------------------------------------
/src/projects/actions/onDialogClose.js:
--------------------------------------------------------------------------------
1 | export const onDialogClose = dialogType => ({
2 | widget: 'projects',
3 | type: 'onDialogClose',
4 | payload: { dialogType },
5 | })
6 |
--------------------------------------------------------------------------------
/src/projects/actions/onDialogExited.js:
--------------------------------------------------------------------------------
1 | export const onDialogExited = dialogType => ({
2 | widget: 'projects',
3 | type: 'onDialogExited',
4 | payload: { dialogType },
5 | })
6 |
--------------------------------------------------------------------------------
/src/projects/actions/onEditDialogDone.js:
--------------------------------------------------------------------------------
1 | export const onEditDialogDone = project => ({
2 | widget: 'projects',
3 | type: 'onEditDialogDone',
4 | payload: { project },
5 | })
6 |
--------------------------------------------------------------------------------
/src/projects/actions/onEditProject.js:
--------------------------------------------------------------------------------
1 | export const onEditProject = project => ({
2 | widget: 'projects',
3 | type: 'onEditProject',
4 | payload: { project },
5 | })
6 |
--------------------------------------------------------------------------------
/src/projects/actions/onLogoutClick.js:
--------------------------------------------------------------------------------
1 | export const onLogoutClick = () => ({
2 | widget: 'projects',
3 | type: 'onLogoutClick',
4 | payload: {},
5 | })
6 |
--------------------------------------------------------------------------------
/src/projects/actions/postAction.js:
--------------------------------------------------------------------------------
1 | import { postFetcher } from 'src/projects/fetchers/postFetcher'
2 | import { getAction } from 'src/projects/actions/getAction'
3 |
4 | export function postAction(project) {
5 | return function(dispatch, getState) {
6 | dispatch({
7 | widget: 'projects',
8 | type: 'postStart',
9 | })
10 | postFetcher(project)
11 | .then(() => {
12 | dispatch({
13 | widget: 'projects',
14 | type: 'postEnd',
15 | })
16 | dispatch(getAction())
17 | })
18 | .catch(error => {
19 | dispatch({
20 | widget: 'projects',
21 | type: 'postError',
22 | payload: error,
23 | })
24 | dispatch(getAction())
25 | })
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/projects/actions/putAction.js:
--------------------------------------------------------------------------------
1 | import { putFetcher } from 'src/projects/fetchers/putFetcher'
2 | import { getAction } from 'src/projects/actions/getAction'
3 |
4 | export function putAction(oldProject, newProject) {
5 | return function(dispatch, getState) {
6 | dispatch({
7 | widget: 'projects',
8 | type: 'putStart',
9 | })
10 | putFetcher(newProject)
11 | .then(() => {
12 | dispatch({
13 | widget: 'projects',
14 | type: 'putEnd',
15 | })
16 | dispatch(getAction())
17 | })
18 | .catch(error => {
19 | dispatch({
20 | widget: 'projects',
21 | type: 'putError',
22 | payload: error,
23 | })
24 | dispatch(getAction())
25 | })
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/projects/components/ConfirmDialog.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { bool } from 'prop-types'
3 | import { ConfirmDialog as AConfirmDialog } from 'src/lib/components/ConfirmDialog'
4 |
5 | export class ConfirmDialog extends Component {
6 | static propTypes = {
7 | mount: bool.isRequired,
8 | }
9 |
10 | render() {
11 | const { mount, ...props } = this.props
12 | return !mount ? null :
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/projects/components/ProjectDialog.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { func, bool, string, object } from 'prop-types'
3 | import { Dialog } from 'src/lib/components/Dialog'
4 | import { ProjectDialogInner } from 'src/projects/components/ProjectDialogInner'
5 |
6 | export class ProjectDialog extends Component {
7 | static propTypes = {
8 | project: object,
9 | title: string.isRequired,
10 | mount: bool.isRequired,
11 | open: bool.isRequired,
12 | onDone: func.isRequired,
13 | onClose: func.isRequired,
14 | onExited: func.isRequired,
15 | }
16 |
17 | static defaultProps = {
18 | project: null,
19 | }
20 |
21 | render() {
22 | const { mount, project, open, onClose, onDone, title, onExited } = this.props
23 | if (!mount) return null
24 | return (
25 |
28 | )
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/projects/components/Projects.style.js:
--------------------------------------------------------------------------------
1 | import jss from 'src/lib/services/Jss'
2 | import { colors } from 'src/colors'
3 |
4 | const { classes } = jss
5 | .createStyleSheet({
6 | card: {
7 | boxShadow:
8 | '0px 1px 5px 0px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 3px 1px -2px rgba(0, 0, 0, 0.12)',
9 | textAlign: 'center',
10 | borderRadius: '2px',
11 | },
12 | newProjectCard: {
13 | boxShadow:
14 | '0px 1px 5px 0px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 3px 1px -2px rgba(0, 0, 0, 0.12)',
15 | textAlign: 'center',
16 | borderRadius: '2px',
17 | cursor: 'pointer',
18 | height: '100%',
19 | background: colors.white.t3,
20 | '&:hover': {
21 | background: colors.white.t5,
22 | },
23 | },
24 | newProjectCardInner: {
25 | padding: '60px 25px',
26 | },
27 | newProjectText: {
28 | color: 'rgba(0, 0, 0, 0.54)',
29 | fontSize: '30px',
30 | },
31 | avatar: {
32 | margin: 'auto',
33 | width: '100%',
34 | height: '100%',
35 | },
36 | cardBody: {
37 | cursor: 'pointer',
38 | borderRadius: '2px 2px 0 0',
39 | padding: '25px 25px',
40 | background: colors.white.main,
41 | transition: '0.2s',
42 | '&:hover': {
43 | background: colors.white.t4,
44 | },
45 | },
46 | cardFooter: {
47 | cursor: 'default',
48 | padding: '20px 25px',
49 | borderRadius: '0 0 2px 2px',
50 | background: colors.white.main,
51 | },
52 | })
53 | .attach()
54 |
55 | export const cn = classes
56 |
--------------------------------------------------------------------------------
/src/projects/fetchers/deleteFetcher.js:
--------------------------------------------------------------------------------
1 | import { fetch } from 'src/lib/services/Fetcher'
2 |
3 | export const deleteFetcher = projectId => {
4 | return fetch({ method: 'DELETE', url: `projects/${projectId}` })
5 | }
6 |
--------------------------------------------------------------------------------
/src/projects/fetchers/postFetcher.js:
--------------------------------------------------------------------------------
1 | import { fetch } from 'src/lib/services/Fetcher'
2 |
3 | export const postFetcher = project => {
4 | return fetch({ method: 'POST', url: `projects`, body: project })
5 | }
6 |
--------------------------------------------------------------------------------
/src/projects/fetchers/putFetcher.js:
--------------------------------------------------------------------------------
1 | import { fetch } from 'src/lib/services/Fetcher'
2 |
3 | export const putFetcher = project => {
4 | return fetch({ method: 'PUT', url: `projects/${project.id}`, body: project })
5 | }
6 |
--------------------------------------------------------------------------------
/src/recover-pass/actions/onDone.js:
--------------------------------------------------------------------------------
1 | export const onDone = creds => ({
2 | widget: 'recoverPass',
3 | type: 'onDone',
4 | payload: { creds },
5 | })
6 |
--------------------------------------------------------------------------------
/src/recover-pass/actions/post.js:
--------------------------------------------------------------------------------
1 | import { postFetcher } from 'src/recover-pass/fetchers/post'
2 |
3 | export function postAction(creds) {
4 | return function(dispatch, getState) {
5 | dispatch({
6 | widget: 'recoverPass',
7 | type: 'postStart',
8 | })
9 | postFetcher(creds)
10 | .then(() => {
11 | dispatch({
12 | widget: 'recoverPass',
13 | type: 'postEnd',
14 | })
15 | })
16 | .catch(error => {
17 | dispatch({
18 | widget: 'recoverPass',
19 | type: 'postError',
20 | payload: error,
21 | })
22 | })
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/recover-pass/fetchers/post.js:
--------------------------------------------------------------------------------
1 | import { fetch } from 'src/lib/services/Fetcher'
2 |
3 | export function postFetcher(creds) {
4 | return fetch({ method: 'POST', url: `recover`, body: creds })
5 | }
6 |
--------------------------------------------------------------------------------
/src/recover-pass/reducer.js:
--------------------------------------------------------------------------------
1 | import { errorSet, fetchingStart, fetchingEnd } from 'src/global/reducer'
2 | import { postAction } from 'src/recover-pass/actions/post'
3 | import { dispatch } from 'src/store'
4 |
5 | export function postStart(state) {
6 | fetchingStart(state)
7 | state.recoverPass.loading.post = true
8 | }
9 |
10 | export function postEnd(state) {
11 | fetchingEnd(state)
12 | state.recoverPass.loading.post = false
13 | state.recoverPass.showMessage = true
14 | }
15 |
16 | export function postError(state, error) {
17 | fetchingEnd(state)
18 | state.recoverPass.loading.post = false
19 | errorSet(state, { show: true, error })
20 | }
21 |
22 | export function onDone(state, { creds }) {
23 | setTimeout(() => dispatch(postAction(creds)), 0)
24 | }
25 |
26 | const modifiers = {
27 | postStart,
28 | postEnd,
29 | postError,
30 | onDone,
31 | }
32 |
33 | export const recoverPassReducer = (state, action) => {
34 | const modifier = modifiers[action.type]
35 | modifier(state, action.payload)
36 | }
37 |
--------------------------------------------------------------------------------
/src/reducer.js:
--------------------------------------------------------------------------------
1 | import clone from 'clone'
2 | import { state } from './state'
3 | import { globalReducer } from 'src/global/reducer'
4 | import { modelsReducer } from 'src/models/reducer'
5 | import { entriesReducer } from 'src/entries/reducer'
6 | import { projectsReducer } from 'src/projects/reducer'
7 | import { loginReducer } from 'src/login/reducer'
8 | import { registrationReducer } from 'src/registration/reducer'
9 | import { emailConfirmReducer } from 'src/email-confirm/reducer'
10 | import { recoverPassReducer } from 'src/recover-pass/reducer'
11 | import { changePassReducer } from 'src/change-pass/reducer'
12 | import { tokensReducer } from 'src/tokens/reducer'
13 | import { contactsReducer } from 'src/contacts/reducer'
14 |
15 | const initialState = state()
16 |
17 | const MAP = {
18 | global: globalReducer,
19 | models: modelsReducer,
20 | entries: entriesReducer,
21 | projects: projectsReducer,
22 | login: loginReducer,
23 | registration: registrationReducer,
24 | emailConfirm: emailConfirmReducer,
25 | recoverPass: recoverPassReducer,
26 | changePass: changePassReducer,
27 | tokens: tokensReducer,
28 | contacts: contactsReducer,
29 | }
30 |
31 | export const reducer = (oldState = initialState, action) => {
32 | const state = clone(oldState)
33 | const widget = action.widget
34 | if (widget) {
35 | MAP[widget](state, action)
36 | }
37 | return state
38 | }
39 |
--------------------------------------------------------------------------------
/src/registration/actions/onDone.js:
--------------------------------------------------------------------------------
1 | export const onDone = creds => ({
2 | widget: 'registration',
3 | type: 'onDone',
4 | payload: { creds },
5 | })
6 |
--------------------------------------------------------------------------------
/src/registration/actions/post.js:
--------------------------------------------------------------------------------
1 | import { postFetcher } from 'src/registration/fetchers/post'
2 |
3 | export function postAction(creds) {
4 | return function(dispatch, getState) {
5 | dispatch({
6 | widget: 'registration',
7 | type: 'postStart',
8 | })
9 | postFetcher(creds)
10 | .then(() => {
11 | dispatch({
12 | widget: 'registration',
13 | type: 'postEnd',
14 | })
15 | })
16 | .catch(error => {
17 | dispatch({
18 | widget: 'registration',
19 | type: 'postError',
20 | payload: error,
21 | })
22 | })
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/registration/components/Registration.style.js:
--------------------------------------------------------------------------------
1 | import jss from 'src/lib/services/Jss'
2 |
3 | const { classes } = jss
4 | .createStyleSheet({
5 | link: {
6 | fontSize: '0.9em',
7 | },
8 | })
9 | .attach()
10 |
11 | export const cn = classes
12 |
--------------------------------------------------------------------------------
/src/registration/fetchers/post.js:
--------------------------------------------------------------------------------
1 | import { fetch } from 'src/lib/services/Fetcher'
2 |
3 | export function postFetcher(creds) {
4 | return fetch({ method: 'POST', url: `register`, body: creds })
5 | }
6 |
--------------------------------------------------------------------------------
/src/registration/reducer.js:
--------------------------------------------------------------------------------
1 | import { errorSet, fetchingStart, fetchingEnd } from 'src/global/reducer'
2 | import { postAction } from 'src/registration/actions/post'
3 | import { dispatch } from 'src/store'
4 |
5 | export function postStart(state) {
6 | fetchingStart(state)
7 | state.registration.loading.post = true
8 | }
9 |
10 | export function postEnd(state) {
11 | fetchingEnd(state)
12 | state.registration.loading.post = false
13 | state.registration.showMessage = true
14 | }
15 |
16 | export function postError(state, error) {
17 | fetchingEnd(state)
18 | state.registration.loading.post = false
19 | errorSet(state, { show: true, error })
20 | }
21 |
22 | export function onDone(state, { creds }) {
23 | setTimeout(() => dispatch(postAction(creds)), 0)
24 | }
25 |
26 | const modifiers = {
27 | postStart,
28 | postEnd,
29 | postError,
30 | onDone,
31 | }
32 |
33 | export const registrationReducer = (state, action) => {
34 | const modifier = modifiers[action.type]
35 | modifier(state, action.payload)
36 | }
37 |
--------------------------------------------------------------------------------
/src/store.js:
--------------------------------------------------------------------------------
1 | import { createStore, applyMiddleware } from 'redux'
2 | import thunk from 'redux-thunk'
3 | import { reducer } from './reducer'
4 |
5 | export const store = createStore(reducer, applyMiddleware(thunk))
6 |
7 | export const dispatch = store.dispatch
8 |
--------------------------------------------------------------------------------
/src/tokens/actions/deleteAction.js:
--------------------------------------------------------------------------------
1 | import { deleteFetcher } from 'src/tokens/fetchers/deleteFetcher'
2 | import { getAction } from 'src/tokens/actions/getAction'
3 |
4 | export function deleteAction(token) {
5 | return function(dispatch, getState) {
6 | const { projectId } = getState().global
7 | dispatch({
8 | widget: 'tokens',
9 | type: 'deleteStart',
10 | })
11 | deleteFetcher(projectId, token.id)
12 | .then(() => {
13 | dispatch({
14 | widget: 'tokens',
15 | type: 'deleteEnd',
16 | })
17 | dispatch(getAction())
18 | })
19 | .catch(error => {
20 | dispatch({
21 | widget: 'tokens',
22 | type: 'deleteError',
23 | payload: error,
24 | })
25 | dispatch(getAction())
26 | })
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/tokens/actions/getAction.js:
--------------------------------------------------------------------------------
1 | import { getFetcher } from 'src/tokens/fetchers/getFetcher'
2 |
3 | export function getAction() {
4 | return function(dispatch, getState) {
5 | const { projectId } = getState().global
6 | dispatch({
7 | widget: 'tokens',
8 | type: 'getStart',
9 | })
10 | getFetcher(projectId)
11 | .then(tokens => {
12 | dispatch({
13 | widget: 'tokens',
14 | type: 'getEnd',
15 | payload: { tokens },
16 | })
17 | })
18 | .catch(error => {
19 | dispatch({
20 | widget: 'tokens',
21 | type: 'getError',
22 | payload: error,
23 | })
24 | })
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/tokens/actions/onAdd.js:
--------------------------------------------------------------------------------
1 | export const onAdd = () => ({
2 | widget: 'tokens',
3 | type: 'onAdd',
4 | payload: {},
5 | })
6 |
--------------------------------------------------------------------------------
/src/tokens/actions/onAddDialogDone.js:
--------------------------------------------------------------------------------
1 | export const onAddDialogDone = token => ({
2 | widget: 'tokens',
3 | type: 'onAddDialogDone',
4 | payload: { token },
5 | })
6 |
--------------------------------------------------------------------------------
/src/tokens/actions/onConfirmDialogConfirm.js:
--------------------------------------------------------------------------------
1 | export const onConfirmDialogConfirm = () => ({
2 | widget: 'tokens',
3 | type: 'onConfirmDialogConfirm',
4 | payload: {},
5 | })
6 |
--------------------------------------------------------------------------------
/src/tokens/actions/onDelete.js:
--------------------------------------------------------------------------------
1 | export const onDelete = id => ({
2 | widget: 'tokens',
3 | type: 'onDelete',
4 | payload: { id },
5 | })
6 |
--------------------------------------------------------------------------------
/src/tokens/actions/onDialogClose.js:
--------------------------------------------------------------------------------
1 | export const onDialogClose = dialogType => ({
2 | widget: 'tokens',
3 | type: 'onDialogClose',
4 | payload: { dialogType },
5 | })
6 |
--------------------------------------------------------------------------------
/src/tokens/actions/onDialogExited.js:
--------------------------------------------------------------------------------
1 | export const onDialogExited = dialogType => ({
2 | widget: 'tokens',
3 | type: 'onDialogExited',
4 | payload: { dialogType },
5 | })
6 |
--------------------------------------------------------------------------------
/src/tokens/actions/onEdit.js:
--------------------------------------------------------------------------------
1 | export const onEdit = token => ({
2 | widget: 'tokens',
3 | type: 'onEdit',
4 | payload: { token },
5 | })
6 |
--------------------------------------------------------------------------------
/src/tokens/actions/onEditDialogDone.js:
--------------------------------------------------------------------------------
1 | export const onEditDialogDone = token => ({
2 | widget: 'tokens',
3 | type: 'onEditDialogDone',
4 | payload: { token },
5 | })
6 |
--------------------------------------------------------------------------------
/src/tokens/actions/postAction.js:
--------------------------------------------------------------------------------
1 | import { postFetcher } from 'src/tokens/fetchers/postFetcher'
2 | import { getAction } from 'src/tokens/actions/getAction'
3 |
4 | export function postAction(token) {
5 | return function(dispatch, getState) {
6 | const { projectId } = getState().global
7 | dispatch({
8 | widget: 'tokens',
9 | type: 'postStart',
10 | })
11 | postFetcher(projectId, token)
12 | .then(() => {
13 | dispatch({
14 | widget: 'tokens',
15 | type: 'postEnd',
16 | })
17 | dispatch(getAction())
18 | })
19 | .catch(error => {
20 | dispatch({
21 | widget: 'tokens',
22 | type: 'postError',
23 | payload: error,
24 | })
25 | dispatch(getAction())
26 | })
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/tokens/actions/putAction.js:
--------------------------------------------------------------------------------
1 | import { putFetcher } from 'src/tokens/fetchers/putFetcher'
2 | import { getAction } from 'src/tokens/actions/getAction'
3 |
4 | export function putAction(token) {
5 | return function(dispatch, getState) {
6 | const { projectId } = getState().global
7 | dispatch({
8 | widget: 'tokens',
9 | type: 'putStart',
10 | })
11 | putFetcher(projectId, token)
12 | .then(() => {
13 | dispatch({
14 | widget: 'tokens',
15 | type: 'putEnd',
16 | })
17 | dispatch(getAction())
18 | })
19 | .catch(error => {
20 | dispatch({
21 | widget: 'tokens',
22 | type: 'putError',
23 | payload: error,
24 | })
25 | dispatch(getAction())
26 | })
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/tokens/components/ConfirmDialog.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { bool } from 'prop-types'
3 | import { ConfirmDialog as AConfirmDialog } from 'src/lib/components/ConfirmDialog'
4 |
5 | export class ConfirmDialog extends Component {
6 | static propTypes = {
7 | mount: bool.isRequired,
8 | }
9 |
10 | render() {
11 | const { mount, ...props } = this.props
12 | return !mount ? null :
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/tokens/components/TokenDialog.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { func, bool, string, object } from 'prop-types'
3 | import { Dialog } from 'src/lib/components/Dialog'
4 | import { TokenDialogInner } from 'src/tokens/components/TokenDialogInner'
5 |
6 | export class TokenDialog extends Component {
7 | static propTypes = {
8 | token: object,
9 | title: string.isRequired,
10 | mount: bool.isRequired,
11 | open: bool.isRequired,
12 | onDone: func.isRequired,
13 | onClose: func.isRequired,
14 | onExited: func.isRequired,
15 | }
16 |
17 | static defaultProps = {
18 | token: null,
19 | }
20 |
21 | render() {
22 | const { mount, token, open, onClose, onDone, title, onExited } = this.props
23 | if (!mount) return null
24 | return (
25 |
28 | )
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/tokens/components/basic/Card.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { string, func, arrayOf } from 'prop-types'
3 | import { Button } from 'src/lib/components/Button'
4 | import { Typography } from 'src/lib/components/Typography'
5 |
6 | import { cn } from './Card.style'
7 |
8 | export class Card extends Component {
9 | static propTypes = {
10 | title: string.isRequired,
11 | onEdit: func.isRequired,
12 | onDelete: func.isRequired,
13 | labels: arrayOf(string).isRequired,
14 | }
15 |
16 | render() {
17 | const { title, onEdit, onDelete, labels } = this.props
18 | return (
19 |
20 |
21 | {title}
22 |
23 |
24 | {labels.map((label, key) => (
25 |
26 | {label}
27 |
28 | ))}
29 |
30 |
31 |
34 |
35 |
38 |
39 |
40 |
41 | )
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/tokens/components/basic/Card.style.js:
--------------------------------------------------------------------------------
1 | import jss from 'src/lib/services/Jss'
2 |
3 | const { classes } = jss
4 | .createStyleSheet({
5 | container: {
6 | background: '#fff',
7 | boxShadow:
8 | '0px 2px 4px -1px rgba(0, 0, 0, 0.2), 0px 4px 5px 0px rgba(0, 0, 0, 0.14), 0px 1px 10px 0px rgba(0, 0, 0, 0.12)',
9 | borderRadius: '2px',
10 | marginBottom: '15px',
11 | '&:hover $cardButtons': {
12 | visibility: 'visible !important',
13 | },
14 | },
15 | cardButtons: {
16 | display: 'inline-block',
17 | visibility: 'hidden',
18 | },
19 | })
20 | .attach()
21 |
22 | export const cn = classes
23 |
--------------------------------------------------------------------------------
/src/tokens/fetchers/deleteFetcher.js:
--------------------------------------------------------------------------------
1 | import { fetch } from 'src/lib/services/Fetcher'
2 |
3 | export const deleteFetcher = (projectId, tokenId) => {
4 | return fetch({ method: 'DELETE', url: `projects/${projectId}/tokens/${tokenId}` })
5 | }
6 |
--------------------------------------------------------------------------------
/src/tokens/fetchers/getFetcher.js:
--------------------------------------------------------------------------------
1 | import { fetch } from 'src/lib/services/Fetcher'
2 |
3 | export const getFetcher = projectId => {
4 | return fetch({ method: 'GET', url: `projects/${projectId}/tokens` })
5 | }
6 |
--------------------------------------------------------------------------------
/src/tokens/fetchers/postFetcher.js:
--------------------------------------------------------------------------------
1 | import { fetch } from 'src/lib/services/Fetcher'
2 |
3 | export const postFetcher = (projectId, token) => {
4 | return fetch({ method: 'POST', url: `projects/${projectId}/tokens`, body: token })
5 | }
6 |
--------------------------------------------------------------------------------
/src/tokens/fetchers/putFetcher.js:
--------------------------------------------------------------------------------
1 | import { fetch } from 'src/lib/services/Fetcher'
2 |
3 | export const putFetcher = (projectId, token) => {
4 | return fetch({ method: 'PUT', url: `projects/${projectId}/tokens/${token.id}`, body: token })
5 | }
6 |
--------------------------------------------------------------------------------