HM-134. Добавлен редактор кода Ace и внедрен для работы с хранилищами (#66)
This commit is contained in:
@ -58,6 +58,7 @@
|
|||||||
"webpack-dev-server": "^3.11.0"
|
"webpack-dev-server": "^3.11.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"ace-builds": "^1.4.12",
|
||||||
"axios": "^0.19.2",
|
"axios": "^0.19.2",
|
||||||
"bootstrap": "^5.0.0-alpha1",
|
"bootstrap": "^5.0.0-alpha1",
|
||||||
"moment": "^2.27.0",
|
"moment": "^2.27.0",
|
||||||
|
|||||||
20
src/app.html
20
src/app.html
@ -32,6 +32,26 @@
|
|||||||
</nav>
|
</nav>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<!-- Шаблон для CodeEditor -->
|
||||||
|
<template id="code-editor">
|
||||||
|
<div class="CodeEditor">
|
||||||
|
<div class="CodeEditor__editor form-control"></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- Шаблон для FormCodeEditor -->
|
||||||
|
<template id="form-code-editor">
|
||||||
|
<div class="mb-3 FormCodeEditor">
|
||||||
|
<label class="form-label">
|
||||||
|
<span class="FormCodeEditor__label"></span>
|
||||||
|
<span class="FormCodeEditor__star text-danger"></span>
|
||||||
|
</label>
|
||||||
|
<input type="text" class="FormCodeEditor__input" />
|
||||||
|
<div class="FormCodeEditor__editor"></div>
|
||||||
|
<div class="FormCodeEditor__errorText form-text invalid-feedback"></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
<!-- Шаблон карточек на главной-->
|
<!-- Шаблон карточек на главной-->
|
||||||
<template id="main-statistic">
|
<template id="main-statistic">
|
||||||
<div class="h-100">
|
<div class="h-100">
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import authServiceApi from './api/AuthServiceAPI';
|
|||||||
import userInfoService from './services/UserInfoService';
|
import userInfoService from './services/UserInfoService';
|
||||||
import {EVENTS, ROUTES} from './core/consts';
|
import {EVENTS, ROUTES} from './core/consts';
|
||||||
import UsersPage from './pages/users/components/page/Page';
|
import UsersPage from './pages/users/components/page/Page';
|
||||||
|
import {DocumentationPage} from './pages/documentation/components/page/Page';
|
||||||
|
|
||||||
const initAppComponents = () => {
|
const initAppComponents = () => {
|
||||||
const mainMenu = new MainMenu();
|
const mainMenu = new MainMenu();
|
||||||
@ -40,6 +41,7 @@ const initAppComponents = () => {
|
|||||||
{url: ROUTES.USERS, pageComponent: UsersPage},
|
{url: ROUTES.USERS, pageComponent: UsersPage},
|
||||||
{url: ROUTES.LOGIN, pageComponent: LoginPage},
|
{url: ROUTES.LOGIN, pageComponent: LoginPage},
|
||||||
{url: ROUTES.PROFILE, pageComponent: ProfilePage},
|
{url: ROUTES.PROFILE, pageComponent: ProfilePage},
|
||||||
|
{url: ROUTES.DOCUMENTATION, pageComponent: DocumentationPage},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
3
src/core/components/code-editor/CodeEditor.css
Normal file
3
src/core/components/code-editor/CodeEditor.css
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
.CodeEditor__editor {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
43
src/core/components/code-editor/CodeEditor.js
Normal file
43
src/core/components/code-editor/CodeEditor.js
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import ace from 'ace-builds/src-noconflict/ace';
|
||||||
|
import theme from 'ace-builds/src-noconflict/theme-github';
|
||||||
|
import {Mode as JSONMode} from 'ace-builds/src-noconflict/mode-json';
|
||||||
|
import Component from '../component/Component';
|
||||||
|
import {CODE_EDITOR_MODE} from '../../consts';
|
||||||
|
import './CodeEditor.css';
|
||||||
|
|
||||||
|
const Modes = {
|
||||||
|
[CODE_EDITOR_MODE.JSON]: JSONMode,
|
||||||
|
};
|
||||||
|
|
||||||
|
export class CodeEditor extends Component {
|
||||||
|
constructor ({
|
||||||
|
parentNode,
|
||||||
|
id,
|
||||||
|
mode,
|
||||||
|
rows = 5,
|
||||||
|
} = {}) {
|
||||||
|
super('#code-editor', parentNode);
|
||||||
|
|
||||||
|
this.editorContainer = this.mainNode.querySelector('.CodeEditor__editor');
|
||||||
|
this.editorContainer.setAttribute('id', id);
|
||||||
|
|
||||||
|
this.editorContainer.style.minHeight = `${Math.round(rows * 24.33)}px`;
|
||||||
|
|
||||||
|
this.editor = ace.edit(id);
|
||||||
|
this.editor.session.setMode(new Modes[mode]());
|
||||||
|
|
||||||
|
this.editor.setTheme(theme);
|
||||||
|
}
|
||||||
|
|
||||||
|
setValue = (value) => {
|
||||||
|
this.editor.setValue(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
getValue = () => {
|
||||||
|
return this.editor.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
disabled = (value) => {
|
||||||
|
this.editor.setReadOnly(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
13
src/core/components/form-code-editor/FormCodeEditor.css
Normal file
13
src/core/components/form-code-editor/FormCodeEditor.css
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
.FormCodeEditor {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.FormCodeEditor__input {
|
||||||
|
position: absolute;
|
||||||
|
z-index: -1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.FormCodeEditor__input:invalid + .FormCodeEditor__editor {
|
||||||
|
border: 1px solid var(--bs-red);
|
||||||
|
border-radius: .25rem;
|
||||||
|
}
|
||||||
69
src/core/components/form-code-editor/FormCodeEditor.js
Normal file
69
src/core/components/form-code-editor/FormCodeEditor.js
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import Component from '../component/Component';
|
||||||
|
import {CodeEditor} from '../code-editor/CodeEditor';
|
||||||
|
import './FormCodeEditor.css';
|
||||||
|
import {EVENTS} from '../../consts';
|
||||||
|
|
||||||
|
export class FormCodeEditor extends Component {
|
||||||
|
constructor (parentNode, {
|
||||||
|
id,
|
||||||
|
mode,
|
||||||
|
label,
|
||||||
|
required = false,
|
||||||
|
initValue = '',
|
||||||
|
className = '',
|
||||||
|
rows,
|
||||||
|
} = {}) {
|
||||||
|
super('#form-code-editor', parentNode);
|
||||||
|
|
||||||
|
this.label = this.mainNode.querySelector('.form-label');
|
||||||
|
this.labelText = this.mainNode.querySelector('.FormCodeEditor__label');
|
||||||
|
this.star = this.mainNode.querySelector('.FormCodeEditor__star');
|
||||||
|
this.editorContainer = this.mainNode.querySelector('.FormCodeEditor__editor');
|
||||||
|
this.errorText = this.mainNode.querySelector('.FormCodeEditor__errorText');
|
||||||
|
this.input = this.mainNode.querySelector('.FormCodeEditor__input');
|
||||||
|
|
||||||
|
this.addEventListener(this.editorContainer, EVENTS.CLICK, this.clearError);
|
||||||
|
this.addEventListener(this.editorContainer, EVENTS.KEYDOWN, this.clearError);
|
||||||
|
|
||||||
|
this.labelText.textContent = label;
|
||||||
|
|
||||||
|
this.editor = this.createComponent(CodeEditor, {
|
||||||
|
parentNode: this.editorContainer,
|
||||||
|
id,
|
||||||
|
mode,
|
||||||
|
rows,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (className) {
|
||||||
|
this.editorContainer.classList.add(className);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (required) {
|
||||||
|
this.star.textContent = ' *';
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setValue(initValue);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
disabled = (value) => {
|
||||||
|
this.editor.disabled(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
getValue = () => {
|
||||||
|
return this.editor.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
setValue = (value) => {
|
||||||
|
this.editor.setValue(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
setError = (errorMessage) => {
|
||||||
|
this.errorText.textContent = errorMessage;
|
||||||
|
this.input.setCustomValidity(errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
clearError = () => {
|
||||||
|
this.setError('');
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -88,7 +88,7 @@ class FormControl extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
clearError = () => {
|
clearError = () => {
|
||||||
this.errorText.textContent = '';
|
this.setError('');
|
||||||
}
|
}
|
||||||
|
|
||||||
getInputTagName = (type) => {
|
getInputTagName = (type) => {
|
||||||
|
|||||||
@ -22,6 +22,10 @@ const NAV_MENU = [
|
|||||||
title: 'Пользователи',
|
title: 'Пользователи',
|
||||||
url: ROUTES.USERS,
|
url: ROUTES.USERS,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: 'Документация',
|
||||||
|
url: ROUTES.DOCUMENTATION,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: 'Личный кабинет',
|
title: 'Личный кабинет',
|
||||||
url: ROUTES.PROFILE,
|
url: ROUTES.PROFILE,
|
||||||
|
|||||||
@ -69,4 +69,9 @@ export const ROUTES = {
|
|||||||
USERS: '/users',
|
USERS: '/users',
|
||||||
LOGIN: '/login',
|
LOGIN: '/login',
|
||||||
PROFILE: '/profile',
|
PROFILE: '/profile',
|
||||||
|
DOCUMENTATION: '/documentation',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const CODE_EDITOR_MODE = {
|
||||||
|
JSON: 'json',
|
||||||
};
|
};
|
||||||
|
|||||||
16
src/pages/documentation/components/page/Page.js
Normal file
16
src/pages/documentation/components/page/Page.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import Component from '../../../../core/components/component/Component';
|
||||||
|
import {TAG_NAME} from '../../../../core/consts';
|
||||||
|
|
||||||
|
export class DocumentationPage extends Component {
|
||||||
|
constructor (mainNodeSelector, parentNode) {
|
||||||
|
super(mainNodeSelector, parentNode);
|
||||||
|
|
||||||
|
this.createElement({
|
||||||
|
tagName: TAG_NAME.DIV,
|
||||||
|
parentNode: this.mainNode,
|
||||||
|
options: {
|
||||||
|
textContent: 'Документация',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,3 @@
|
|||||||
.Api__value-input {
|
|
||||||
height: 200px;
|
|
||||||
}
|
|
||||||
.Api__view-controls {
|
.Api__view-controls {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
|||||||
@ -1,11 +1,12 @@
|
|||||||
import Component from '../../../../core/components/component/Component';
|
import Component from '../../../../core/components/component/Component';
|
||||||
import ModalSidebar from '../../../../core/components/modal-sidebar/ModalSibebar';
|
import ModalSidebar from '../../../../core/components/modal-sidebar/ModalSibebar';
|
||||||
import FormControl from '../../../../core/components/form-control/FormControl';
|
import FormControl from '../../../../core/components/form-control/FormControl';
|
||||||
import {FORM_TYPES, EVENTS, MODES} from '../../../../core/consts';
|
import {EVENTS, MODES, CODE_EDITOR_MODE} from '../../../../core/consts';
|
||||||
import './ApiTableViewForm.css';
|
import './ApiTableViewForm.css';
|
||||||
import storageApi from '../../api/StorageServiceAPI';
|
import storageApi from '../../api/StorageServiceAPI';
|
||||||
import routeService from '../../../../services/RouteService';
|
import routeService from '../../../../services/RouteService';
|
||||||
import {HooksComponent} from '../hooks-component/HooksComponent';
|
import {HooksComponent} from '../hooks-component/HooksComponent';
|
||||||
|
import {FormCodeEditor} from '../../../../core/components/form-code-editor/FormCodeEditor';
|
||||||
|
|
||||||
const TITLE_MODES = {
|
const TITLE_MODES = {
|
||||||
[MODES.Create]: 'Создание нового хранилища',
|
[MODES.Create]: 'Создание нового хранилища',
|
||||||
@ -52,11 +53,11 @@ class ApiTableViewForm extends Component {
|
|||||||
label: 'Краткое описание',
|
label: 'Краткое описание',
|
||||||
required: true,
|
required: true,
|
||||||
}),
|
}),
|
||||||
this.valueInput = this.createComponent(FormControl, this.form, {
|
this.valueInput = this.createComponent(FormCodeEditor, this.form, {
|
||||||
id: 'api-value-input',
|
id: 'api-value-input',
|
||||||
type: FORM_TYPES.TEXTAREA,
|
|
||||||
className: 'Api__value-input',
|
className: 'Api__value-input',
|
||||||
label: 'Содержимое хранилища',
|
label: 'Содержимое хранилища',
|
||||||
|
mode: CODE_EDITOR_MODE.JSON,
|
||||||
required: true,
|
required: true,
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
|
|||||||
Reference in New Issue
Block a user