@maxisoft/instantcms-mcp 1.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +308 -0
- package/dist/__tests__/artifact-tool.test.js +196 -0
- package/dist/__tests__/db-tool.test.js +152 -0
- package/dist/__tests__/define-tool.test.js +106 -0
- package/dist/__tests__/find-tool.test.js +185 -0
- package/dist/__tests__/get-component-api.test.js +144 -0
- package/dist/__tests__/hardening.test.js +73 -0
- package/dist/__tests__/hooks-tool.test.js +173 -0
- package/dist/__tests__/mcp-integration-extra.test.js +166 -0
- package/dist/__tests__/mcp-integration.test.js +53 -0
- package/dist/__tests__/pagination.test.js +114 -0
- package/dist/__tests__/performance-baseline.test.js +56 -0
- package/dist/__tests__/project-patch.test.js +144 -0
- package/dist/__tests__/project-source.test.js +44 -0
- package/dist/__tests__/project-workflows-extra.test.js +165 -0
- package/dist/__tests__/project-workflows.test.js +51 -0
- package/dist/__tests__/scaffold-addon-roundtrip.test.js +287 -0
- package/dist/__tests__/serialization.test.js +170 -0
- package/dist/__tests__/source-knowledge-parsers.test.js +42 -0
- package/dist/__tests__/template-development.test.js +78 -0
- package/dist/__tests__/template-productivity.test.js +87 -0
- package/dist/__tests__/tools.test.js +2143 -0
- package/dist/data/components.js +2818 -0
- package/dist/data/controllers-map.js +7571 -0
- package/dist/data/core-api.js +9356 -0
- package/dist/data/database-schema.js +4555 -0
- package/dist/data/events-map.js +1339 -0
- package/dist/data/fields-map.js +3692 -0
- package/dist/data/hooks.js +2257 -0
- package/dist/data/js-api.js +123 -0
- package/dist/data/libs-api.js +264 -0
- package/dist/data/routes-map.js +203 -0
- package/dist/data/schemas-validation.js +255 -0
- package/dist/data/schemas.js +1404 -0
- package/dist/data/traits-map.js +1004 -0
- package/dist/data/version-profiles.js +41 -0
- package/dist/data/widgets-map.js +131 -0
- package/dist/data/wysiwyg-map.js +486 -0
- package/dist/generated/components-source.js +14748 -0
- package/dist/generated/hooks-source.js +3399 -0
- package/dist/generated/knowledge-meta.js +101 -0
- package/dist/index.js +13 -0
- package/dist/registry/database-tools.js +112 -0
- package/dist/registry/extension-tools.js +473 -0
- package/dist/registry/generator-tools.js +506 -0
- package/dist/registry/knowledge-tools.js +441 -0
- package/dist/registry/language-tools.js +99 -0
- package/dist/registry/meta-tools.js +152 -0
- package/dist/registry/project-tools.js +48 -0
- package/dist/registry/resources.js +98 -0
- package/dist/registry/source-tools.js +211 -0
- package/dist/registry/template-development-tools.js +79 -0
- package/dist/server.js +32 -0
- package/dist/tools/addon-tool.js +1437 -0
- package/dist/tools/admin-partial-tool.js +498 -0
- package/dist/tools/api-tool.js +294 -0
- package/dist/tools/artifact-tool.js +95 -0
- package/dist/tools/cache-tool.js +360 -0
- package/dist/tools/component-tool.js +415 -0
- package/dist/tools/controllers-tool.js +125 -0
- package/dist/tools/cron-tool.js +197 -0
- package/dist/tools/crud-tool.js +659 -0
- package/dist/tools/db-tool.js +198 -0
- package/dist/tools/email-tool.js +222 -0
- package/dist/tools/external-api-tool.js +596 -0
- package/dist/tools/filter-tool.js +341 -0
- package/dist/tools/form-tool.js +275 -0
- package/dist/tools/grid-tool.js +189 -0
- package/dist/tools/hooks-tool.js +104 -0
- package/dist/tools/import-export-tool.js +548 -0
- package/dist/tools/lang-tool.js +251 -0
- package/dist/tools/layout-override-tool.js +125 -0
- package/dist/tools/layout-tool.js +548 -0
- package/dist/tools/maria-tool.js +127 -0
- package/dist/tools/mariadb.js +201 -0
- package/dist/tools/migration-tool.js +329 -0
- package/dist/tools/oauth-tool.js +520 -0
- package/dist/tools/parser/components-parser.js +76 -0
- package/dist/tools/parser/controllers-parser.js +313 -0
- package/dist/tools/parser/core-parser.js +294 -0
- package/dist/tools/parser/coverage-generator.js +424 -0
- package/dist/tools/parser/events-parser.js +127 -0
- package/dist/tools/parser/fields-parser.js +382 -0
- package/dist/tools/parser/hooks-parser.js +106 -0
- package/dist/tools/parser/sql-parser.js +197 -0
- package/dist/tools/parser/traits-parser.js +161 -0
- package/dist/tools/parser/widgets-parser.js +150 -0
- package/dist/tools/permission-tool.js +348 -0
- package/dist/tools/project-patch-tool.js +73 -0
- package/dist/tools/project-source-tool.js +188 -0
- package/dist/tools/project-workflow-tool.js +186 -0
- package/dist/tools/requirement-tool.js +212 -0
- package/dist/tools/scaffold-tool.js +815 -0
- package/dist/tools/seo-tool.js +412 -0
- package/dist/tools/source-tool.js +155 -0
- package/dist/tools/template-development-tool.js +271 -0
- package/dist/tools/template-overrides-tool.js +294 -0
- package/dist/tools/template-productivity-tool.js +319 -0
- package/dist/tools/template-tool.js +665 -0
- package/dist/tools/test-tool.js +183 -0
- package/dist/tools/webhook-tool.js +427 -0
- package/dist/tools/widget-tool.js +331 -0
- package/dist/tools/wysiwyg-tool.js +137 -0
- package/dist/types/scaffold.js +68 -0
- package/dist/utils/define-tool.js +37 -0
- package/dist/utils/find-tool.js +97 -0
- package/dist/utils/mcp-result.js +18 -0
- package/dist/utils/pagination.js +27 -0
- package/dist/utils/serialization.js +27 -0
- package/package.json +94 -0
|
@@ -0,0 +1,548 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* InstantCMS Layout Scheme Generator
|
|
4
|
+
*
|
|
5
|
+
* Generates YAML import files for the "modern" template widget layout scheme.
|
|
6
|
+
* Based on Bootstrap 4 grid system (modern template uses Bootstrap 4).
|
|
7
|
+
*
|
|
8
|
+
* YAML format: layout.rows + layout.cols + widgets sections.
|
|
9
|
+
* Compatible with InstantCMS v2.x export/import via Admin → Templates → Layout.
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.layoutPresets = void 0;
|
|
13
|
+
exports.scaffoldLayoutScheme = scaffoldLayoutScheme;
|
|
14
|
+
exports.listLayoutPresets = listLayoutPresets;
|
|
15
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
16
|
+
// HELPERS
|
|
17
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
18
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
19
|
+
function _yamlNull() {
|
|
20
|
+
return 'null';
|
|
21
|
+
}
|
|
22
|
+
/** Wrap value in YAML double quotes */
|
|
23
|
+
function yamlQ(s) {
|
|
24
|
+
if (s === null || s === undefined)
|
|
25
|
+
return 'null';
|
|
26
|
+
return (0, serialization_js_1.quoteYaml)(s);
|
|
27
|
+
}
|
|
28
|
+
/** YAML unquoted scalar (for simple strings without special chars) */
|
|
29
|
+
function yamlBare(s) {
|
|
30
|
+
if (s === null || s === undefined)
|
|
31
|
+
return 'null';
|
|
32
|
+
return (0, serialization_js_1.quoteYaml)(s);
|
|
33
|
+
}
|
|
34
|
+
/** Serialize JSON options as single-quoted YAML string */
|
|
35
|
+
function yamlJsonOpts(obj) {
|
|
36
|
+
const json = JSON.stringify(obj);
|
|
37
|
+
return (0, serialization_js_1.quoteYaml)(json);
|
|
38
|
+
}
|
|
39
|
+
/** YAML literal block scalar for multiline strings (wrapper field) */
|
|
40
|
+
function yamlLiteral(s, indent) {
|
|
41
|
+
const lines = s
|
|
42
|
+
.split('\n')
|
|
43
|
+
.map(l => `${indent} ${l}`)
|
|
44
|
+
.join('\n');
|
|
45
|
+
return `|\n${lines}`;
|
|
46
|
+
}
|
|
47
|
+
function indent(level) {
|
|
48
|
+
return ' '.repeat(level);
|
|
49
|
+
}
|
|
50
|
+
function scaffoldLayoutScheme(opts) {
|
|
51
|
+
const template = opts.template || 'modern';
|
|
52
|
+
const rows = opts.rows || [];
|
|
53
|
+
// ── Pass 1: assign IDs and collect all positions ──────────────────────────
|
|
54
|
+
let rowIdCounter = 1;
|
|
55
|
+
let colIdCounter = 1;
|
|
56
|
+
let rowOrderCounter = 1;
|
|
57
|
+
let colOrderCounter = 1;
|
|
58
|
+
const rowMetas = [];
|
|
59
|
+
// Map from position_name → col meta (for parent_col resolution)
|
|
60
|
+
const positionToCol = new Map();
|
|
61
|
+
for (const rowDef of rows) {
|
|
62
|
+
const rowId = rowIdCounter++;
|
|
63
|
+
const ordering = rowOrderCounter++;
|
|
64
|
+
const colMetas = [];
|
|
65
|
+
for (const colDef of rowDef.cols || []) {
|
|
66
|
+
const colId = colIdCounter++;
|
|
67
|
+
const colOrder = colOrderCounter++;
|
|
68
|
+
const position = colDef.position || `pos_${colId}`;
|
|
69
|
+
const cm = {
|
|
70
|
+
id: colId,
|
|
71
|
+
rowId,
|
|
72
|
+
def: colDef,
|
|
73
|
+
ordering: colOrder,
|
|
74
|
+
position,
|
|
75
|
+
};
|
|
76
|
+
colMetas.push(cm);
|
|
77
|
+
positionToCol.set(position, cm);
|
|
78
|
+
}
|
|
79
|
+
rowMetas.push({ id: rowId, def: rowDef, ordering, cols: colMetas });
|
|
80
|
+
}
|
|
81
|
+
// ── Pass 2: generate YAML ─────────────────────────────────────────────────
|
|
82
|
+
const lines = ['---'];
|
|
83
|
+
// layout:
|
|
84
|
+
lines.push('layout:');
|
|
85
|
+
// layout.rows:
|
|
86
|
+
lines.push(`${indent(1)}rows:`);
|
|
87
|
+
for (const rm of rowMetas) {
|
|
88
|
+
const rd = rm.def;
|
|
89
|
+
// Resolve parent_id: look up position → col → id
|
|
90
|
+
let parentId = 'null';
|
|
91
|
+
if (rd.parent_col) {
|
|
92
|
+
const parentCol = positionToCol.get(rd.parent_col);
|
|
93
|
+
if (parentCol) {
|
|
94
|
+
parentId = `"${parentCol.id}"`;
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
parentId = 'null'; // unresolved reference
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// Build options JSON
|
|
101
|
+
const rowOptions = {
|
|
102
|
+
no_gutters: rd.no_gutters ? 1 : null,
|
|
103
|
+
vertical_align: '',
|
|
104
|
+
horizontal_align: '',
|
|
105
|
+
container: rd.container !== undefined ? rd.container : 'container',
|
|
106
|
+
container_tag: rd.container_tag || 'div',
|
|
107
|
+
container_tag_class: rd.container_class || '',
|
|
108
|
+
parrent_tag: rd.outer_tag || '',
|
|
109
|
+
parrent_tag_class: rd.outer_class || '',
|
|
110
|
+
};
|
|
111
|
+
// row tag
|
|
112
|
+
const rowTag = rd.tag !== undefined ? rd.tag : null;
|
|
113
|
+
lines.push(`${indent(2)}${rm.id}:`);
|
|
114
|
+
lines.push(`${indent(3)}id: ${yamlQ(rm.id)}`);
|
|
115
|
+
lines.push(`${indent(3)}parent_id: ${parentId}`);
|
|
116
|
+
// Title: simple bare string (YAML handles spaces)
|
|
117
|
+
lines.push(`${indent(3)}title: ${yamlBare(rd.title)}`);
|
|
118
|
+
lines.push(`${indent(3)}tag: ${rowTag === null ? 'null' : yamlBare(String(rowTag))}`);
|
|
119
|
+
lines.push(`${indent(3)}template: ${yamlBare(template)}`);
|
|
120
|
+
lines.push(`${indent(3)}ordering: ${yamlQ(rm.ordering)}`);
|
|
121
|
+
lines.push(`${indent(3)}nested_position: ${rd.parent_col ? yamlBare(rd.nested_position || 'after') : 'null'}`);
|
|
122
|
+
const rowClass = rd.class !== undefined ? rd.class : null;
|
|
123
|
+
lines.push(`${indent(3)}class: ${rowClass === null ? 'null' : yamlBare(rowClass)}`);
|
|
124
|
+
lines.push(`${indent(3)}options: ${yamlJsonOpts(rowOptions)}`);
|
|
125
|
+
}
|
|
126
|
+
// layout.cols:
|
|
127
|
+
lines.push(`${indent(1)}cols:`);
|
|
128
|
+
for (const rm of rowMetas) {
|
|
129
|
+
for (const cm of rm.cols) {
|
|
130
|
+
const cd = cm.def;
|
|
131
|
+
const colType = cd.type || 'typical';
|
|
132
|
+
// Build options JSON
|
|
133
|
+
const colOptions = {
|
|
134
|
+
cut_before: cd.cut_before ? 1 : null,
|
|
135
|
+
default_col_class: cd.col || '',
|
|
136
|
+
md_col_class: cd.col_md || '',
|
|
137
|
+
lg_col_class: cd.col_lg || '',
|
|
138
|
+
xl_col_class: cd.col_xl || '',
|
|
139
|
+
col_class: cd.col_class || '',
|
|
140
|
+
default_order: cd.order || 0,
|
|
141
|
+
sm_order: cd.sm_order || 0,
|
|
142
|
+
md_order: cd.md_order || 0,
|
|
143
|
+
lg_order: cd.lg_order || 0,
|
|
144
|
+
xl_order: cd.xl_order || 0,
|
|
145
|
+
};
|
|
146
|
+
lines.push(`${indent(2)}${cm.id}:`);
|
|
147
|
+
lines.push(`${indent(3)}id: ${yamlQ(cm.id)}`);
|
|
148
|
+
lines.push(`${indent(3)}row_id: ${yamlQ(rm.id)}`);
|
|
149
|
+
lines.push(`${indent(3)}title: ${yamlBare(cd.title)}`);
|
|
150
|
+
lines.push(`${indent(3)}name: ${yamlBare(cm.position)}`);
|
|
151
|
+
lines.push(`${indent(3)}type: ${yamlBare(colType)}`);
|
|
152
|
+
lines.push(`${indent(3)}ordering: ${yamlQ(cm.ordering)}`);
|
|
153
|
+
lines.push(`${indent(3)}tag: ${yamlBare(cd.tag || 'div')}`);
|
|
154
|
+
const colClass = cd.class !== undefined ? cd.class : null;
|
|
155
|
+
lines.push(`${indent(3)}class: ${colClass === null ? 'null' : yamlBare(colClass)}`);
|
|
156
|
+
// wrapper: null or block literal
|
|
157
|
+
if (cd.wrapper && cd.wrapper !== 'null') {
|
|
158
|
+
lines.push(`${indent(3)}wrapper: ${yamlLiteral(cd.wrapper, indent(3))}`);
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
lines.push(`${indent(3)}wrapper: null`);
|
|
162
|
+
}
|
|
163
|
+
lines.push(`${indent(3)}options: ${yamlJsonOpts(colOptions)}`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
// widgets:
|
|
167
|
+
lines.push('widgets:');
|
|
168
|
+
lines.push(`${indent(1)}widgets_bind_pages: [ ]`);
|
|
169
|
+
lines.push(`${indent(1)}widgets_bind: [ ]`);
|
|
170
|
+
lines.push('');
|
|
171
|
+
const yaml = lines.join('\n');
|
|
172
|
+
// ── Summary ───────────────────────────────────────────────────────────────
|
|
173
|
+
const allPositions = rowMetas.flatMap(r => r.cols.map(c => c.position));
|
|
174
|
+
const notes = [];
|
|
175
|
+
// Detect unresolved parent_col refs
|
|
176
|
+
for (const rm of rowMetas) {
|
|
177
|
+
const rd = rm.def;
|
|
178
|
+
if (rd.parent_col && !positionToCol.has(rd.parent_col)) {
|
|
179
|
+
notes.push(`⚠ Строка "${rd.title}": parent_col "${rd.parent_col}" не найдена среди позиций`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
if (notes.length === 0) {
|
|
183
|
+
notes.push('✓ Схема сгенерирована без ошибок');
|
|
184
|
+
}
|
|
185
|
+
const usageNotes = `
|
|
186
|
+
ИМПОРТ СХЕМЫ В INSTANTCMS
|
|
187
|
+
===========================
|
|
188
|
+
1. Откройте: Панель управления → Оформление → Шаблоны → Modern → Схема
|
|
189
|
+
2. Нажмите кнопку "Импорт"
|
|
190
|
+
3. Вставьте или загрузите YAML файл
|
|
191
|
+
4. Подтвердите импорт — схема заменит текущую
|
|
192
|
+
|
|
193
|
+
СТРУКТУРА ПОЗИЦИЙ
|
|
194
|
+
=================
|
|
195
|
+
${allPositions.map(p => ` • ${p}`).join('\n')}
|
|
196
|
+
|
|
197
|
+
BOOTSTRAP 4 КЛАССЫ (шаблон modern)
|
|
198
|
+
=====================================
|
|
199
|
+
Контейнеры: container, container-fluid
|
|
200
|
+
Колонки: col, col-sm-6, col-md-4, col-lg-3, col-xl-2, col-auto
|
|
201
|
+
Флекс: d-flex, flex-nowrap, align-items-center, justify-content-between
|
|
202
|
+
Отступы: py-3, mt-auto, mb-0
|
|
203
|
+
Порядок: order-1, order-md-2
|
|
204
|
+
|
|
205
|
+
ВЛОЖЕННЫЕ РЯДЫ
|
|
206
|
+
===============
|
|
207
|
+
Для вложения ряда внутрь колонки используйте parent_col = position_name колонки.
|
|
208
|
+
Вложенный ряд будет выведен ВНУТРИ позиции этой колонки (после виджетов).
|
|
209
|
+
nested_position: "after" — после виджетов позиции.
|
|
210
|
+
`.trim();
|
|
211
|
+
return {
|
|
212
|
+
yaml,
|
|
213
|
+
summary: {
|
|
214
|
+
template,
|
|
215
|
+
rows_count: rowMetas.length,
|
|
216
|
+
cols_count: rowMetas.reduce((n, r) => n + r.cols.length, 0),
|
|
217
|
+
positions: allPositions,
|
|
218
|
+
notes,
|
|
219
|
+
},
|
|
220
|
+
usage_notes: usageNotes,
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
224
|
+
// PRESETS — готовые шаблоны типовых схем
|
|
225
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
226
|
+
exports.layoutPresets = {
|
|
227
|
+
simple: {
|
|
228
|
+
description: 'Простая схема: шапка, контент (основной + правый сайдбар), подвал',
|
|
229
|
+
scheme: {
|
|
230
|
+
template: 'modern',
|
|
231
|
+
rows: [
|
|
232
|
+
{
|
|
233
|
+
title: 'Шапка',
|
|
234
|
+
outer_tag: 'header',
|
|
235
|
+
outer_class: '',
|
|
236
|
+
container: 'container',
|
|
237
|
+
cols: [
|
|
238
|
+
{
|
|
239
|
+
title: 'Шапка',
|
|
240
|
+
position: 'pos_header',
|
|
241
|
+
tag: 'div',
|
|
242
|
+
col: 'col-sm-12',
|
|
243
|
+
},
|
|
244
|
+
],
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
title: 'Контент',
|
|
248
|
+
tag: 'main',
|
|
249
|
+
outer_tag: '',
|
|
250
|
+
container: 'container',
|
|
251
|
+
cols: [
|
|
252
|
+
{
|
|
253
|
+
title: 'Тело страницы',
|
|
254
|
+
position: 'pos_content',
|
|
255
|
+
tag: 'article',
|
|
256
|
+
class: 'mb-3 mb-md-4',
|
|
257
|
+
col_lg: 'col-lg',
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
title: 'Правая колонка',
|
|
261
|
+
position: 'pos_sidebar_right',
|
|
262
|
+
tag: 'aside',
|
|
263
|
+
class: 'mb-3 mb-md-4',
|
|
264
|
+
col_lg: 'col-lg-4',
|
|
265
|
+
},
|
|
266
|
+
],
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
title: 'Футер',
|
|
270
|
+
tag: 'div',
|
|
271
|
+
outer_tag: 'footer',
|
|
272
|
+
outer_class: '',
|
|
273
|
+
container: 'container',
|
|
274
|
+
cols: [
|
|
275
|
+
{
|
|
276
|
+
title: 'Футер',
|
|
277
|
+
position: 'pos_footer',
|
|
278
|
+
tag: 'div',
|
|
279
|
+
col: 'col-sm-12',
|
|
280
|
+
},
|
|
281
|
+
],
|
|
282
|
+
},
|
|
283
|
+
],
|
|
284
|
+
},
|
|
285
|
+
},
|
|
286
|
+
with_sidebar_left: {
|
|
287
|
+
description: 'Схема с левым сайдбаром: шапка, три колонки (лево / контент / право), подвал',
|
|
288
|
+
scheme: {
|
|
289
|
+
template: 'modern',
|
|
290
|
+
rows: [
|
|
291
|
+
{
|
|
292
|
+
title: 'Шапка',
|
|
293
|
+
outer_tag: 'header',
|
|
294
|
+
container: 'container',
|
|
295
|
+
cols: [{ title: 'Шапка', position: 'pos_header', tag: 'div', col: 'col-sm-12' }],
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
title: 'Контент',
|
|
299
|
+
tag: 'main',
|
|
300
|
+
container: 'container',
|
|
301
|
+
cols: [
|
|
302
|
+
{
|
|
303
|
+
title: 'Левая колонка',
|
|
304
|
+
position: 'pos_sidebar_left',
|
|
305
|
+
tag: 'aside',
|
|
306
|
+
class: 'mb-3 mb-md-4',
|
|
307
|
+
col_lg: 'col-lg-3',
|
|
308
|
+
order: 1,
|
|
309
|
+
},
|
|
310
|
+
{
|
|
311
|
+
title: 'Тело страницы',
|
|
312
|
+
position: 'pos_content',
|
|
313
|
+
tag: 'article',
|
|
314
|
+
class: 'mb-3 mb-md-4',
|
|
315
|
+
col_lg: 'col-lg',
|
|
316
|
+
order: 2,
|
|
317
|
+
},
|
|
318
|
+
{
|
|
319
|
+
title: 'Правая колонка',
|
|
320
|
+
position: 'pos_sidebar_right',
|
|
321
|
+
tag: 'aside',
|
|
322
|
+
class: 'mb-3 mb-md-4',
|
|
323
|
+
col_lg: 'col-lg-4',
|
|
324
|
+
order: 3,
|
|
325
|
+
},
|
|
326
|
+
],
|
|
327
|
+
},
|
|
328
|
+
{
|
|
329
|
+
title: 'Футер',
|
|
330
|
+
tag: 'div',
|
|
331
|
+
outer_tag: 'footer',
|
|
332
|
+
container: 'container',
|
|
333
|
+
cols: [
|
|
334
|
+
{
|
|
335
|
+
title: 'Футер левый',
|
|
336
|
+
position: 'pos_footer_left',
|
|
337
|
+
tag: 'div',
|
|
338
|
+
col_md: 'col-md-6',
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
title: 'Футер правый',
|
|
342
|
+
position: 'pos_footer_right',
|
|
343
|
+
tag: 'div',
|
|
344
|
+
col_md: 'col-md-6',
|
|
345
|
+
},
|
|
346
|
+
],
|
|
347
|
+
},
|
|
348
|
+
],
|
|
349
|
+
},
|
|
350
|
+
},
|
|
351
|
+
modern_full: {
|
|
352
|
+
description: 'Полная схема modern: хедер (топ бар + лого/меню + навбар), блок-баннер, контент (лево/тело/право), перед футером, футер',
|
|
353
|
+
scheme: {
|
|
354
|
+
template: 'modern',
|
|
355
|
+
rows: [
|
|
356
|
+
{
|
|
357
|
+
title: 'Хедер',
|
|
358
|
+
outer_tag: 'header',
|
|
359
|
+
outer_class: '',
|
|
360
|
+
container: '',
|
|
361
|
+
cols: [
|
|
362
|
+
{
|
|
363
|
+
title: 'Верхний ряд',
|
|
364
|
+
position: 'pos_header_top',
|
|
365
|
+
tag: 'div',
|
|
366
|
+
type: 'custom',
|
|
367
|
+
wrapper: '<div class="icms-header__top">\n <div class="container d-flex justify-content-end flex-nowrap align-items-center">\n {position}\n </div>\n</div>',
|
|
368
|
+
},
|
|
369
|
+
],
|
|
370
|
+
},
|
|
371
|
+
{
|
|
372
|
+
title: 'Лого и меню пользователя',
|
|
373
|
+
parent_col: 'pos_header_top',
|
|
374
|
+
nested_position: 'after',
|
|
375
|
+
outer_tag: 'div',
|
|
376
|
+
outer_class: 'icms-header__middle',
|
|
377
|
+
container: 'container',
|
|
378
|
+
container_class: 'd-flex justify-content-between align-items-center flex-nowrap',
|
|
379
|
+
cols: [
|
|
380
|
+
{
|
|
381
|
+
title: 'Лого, поиск, меню',
|
|
382
|
+
position: 'pos_logo',
|
|
383
|
+
tag: 'div',
|
|
384
|
+
type: 'custom',
|
|
385
|
+
wrapper: '{position}',
|
|
386
|
+
col: 'col',
|
|
387
|
+
},
|
|
388
|
+
{
|
|
389
|
+
title: 'Меню пользователя',
|
|
390
|
+
position: 'pos_user_menu',
|
|
391
|
+
tag: 'div',
|
|
392
|
+
type: 'custom',
|
|
393
|
+
wrapper: '<div class="ml-auto d-flex align-items-center">\n {position}\n</div>',
|
|
394
|
+
},
|
|
395
|
+
],
|
|
396
|
+
},
|
|
397
|
+
{
|
|
398
|
+
title: 'Навбар',
|
|
399
|
+
parent_col: 'pos_header_top',
|
|
400
|
+
nested_position: 'after',
|
|
401
|
+
outer_tag: 'div',
|
|
402
|
+
outer_class: 'icms-header__bottom border-bottom icms-navbar',
|
|
403
|
+
container: 'container',
|
|
404
|
+
cols: [
|
|
405
|
+
{
|
|
406
|
+
title: 'Позиция меню',
|
|
407
|
+
position: 'pos_nav',
|
|
408
|
+
tag: 'div',
|
|
409
|
+
type: 'custom',
|
|
410
|
+
wrapper: '{position}',
|
|
411
|
+
col: 'col',
|
|
412
|
+
},
|
|
413
|
+
],
|
|
414
|
+
},
|
|
415
|
+
{
|
|
416
|
+
title: 'Ряд во всю ширину',
|
|
417
|
+
outer_tag: 'section',
|
|
418
|
+
outer_class: '',
|
|
419
|
+
container: '',
|
|
420
|
+
no_gutters: true,
|
|
421
|
+
cols: [
|
|
422
|
+
{
|
|
423
|
+
title: 'Позиция во всю ширину',
|
|
424
|
+
position: 'con_wide',
|
|
425
|
+
tag: 'div',
|
|
426
|
+
type: 'custom',
|
|
427
|
+
wrapper: '{position}',
|
|
428
|
+
col: 'col-sm',
|
|
429
|
+
},
|
|
430
|
+
],
|
|
431
|
+
},
|
|
432
|
+
{
|
|
433
|
+
title: 'Перед контентом',
|
|
434
|
+
tag: 'div',
|
|
435
|
+
container: 'container',
|
|
436
|
+
no_gutters: true,
|
|
437
|
+
cols: [
|
|
438
|
+
{
|
|
439
|
+
title: 'Перед телом страницы',
|
|
440
|
+
position: 'pos_before_content',
|
|
441
|
+
tag: 'div',
|
|
442
|
+
class: 'mb-3 mb-md-4',
|
|
443
|
+
col: 'col-sm-12',
|
|
444
|
+
},
|
|
445
|
+
],
|
|
446
|
+
},
|
|
447
|
+
{
|
|
448
|
+
title: 'Контент',
|
|
449
|
+
tag: 'main',
|
|
450
|
+
container: 'container',
|
|
451
|
+
cols: [
|
|
452
|
+
{
|
|
453
|
+
title: 'Левая колонка',
|
|
454
|
+
position: 'pos_sidebar_left',
|
|
455
|
+
tag: 'aside',
|
|
456
|
+
class: 'mb-3 mb-md-4',
|
|
457
|
+
col_lg: 'col-lg-3',
|
|
458
|
+
order: 1,
|
|
459
|
+
},
|
|
460
|
+
{
|
|
461
|
+
title: 'Тело страницы',
|
|
462
|
+
position: 'pos_content',
|
|
463
|
+
tag: 'article',
|
|
464
|
+
class: 'mb-3 mb-md-4',
|
|
465
|
+
col_lg: 'col-lg',
|
|
466
|
+
order: 2,
|
|
467
|
+
},
|
|
468
|
+
{
|
|
469
|
+
title: 'Правая колонка',
|
|
470
|
+
position: 'pos_sidebar_right',
|
|
471
|
+
tag: 'aside',
|
|
472
|
+
class: 'mb-3 mb-md-4',
|
|
473
|
+
col_lg: 'col-lg-4',
|
|
474
|
+
order: 3,
|
|
475
|
+
},
|
|
476
|
+
],
|
|
477
|
+
},
|
|
478
|
+
{
|
|
479
|
+
title: 'Над футером',
|
|
480
|
+
tag: 'div',
|
|
481
|
+
class: 'py-5 mb-n3',
|
|
482
|
+
outer_tag: 'section',
|
|
483
|
+
outer_class: 'icms-footer__middle mt-auto',
|
|
484
|
+
container: 'container',
|
|
485
|
+
container_class: 'border-bottom',
|
|
486
|
+
cols: [
|
|
487
|
+
{
|
|
488
|
+
title: 'Левый',
|
|
489
|
+
position: 'pos_prefooter_left',
|
|
490
|
+
tag: 'div',
|
|
491
|
+
class: 'mb-3',
|
|
492
|
+
col_md: 'col-md-3',
|
|
493
|
+
},
|
|
494
|
+
{
|
|
495
|
+
title: 'Средний',
|
|
496
|
+
position: 'pos_prefooter_center',
|
|
497
|
+
tag: 'div',
|
|
498
|
+
class: 'mb-3',
|
|
499
|
+
col_md: 'col-md',
|
|
500
|
+
},
|
|
501
|
+
{
|
|
502
|
+
title: 'Правый',
|
|
503
|
+
position: 'pos_prefooter_right',
|
|
504
|
+
tag: 'div',
|
|
505
|
+
class: 'mb-3',
|
|
506
|
+
col_md: 'col-md',
|
|
507
|
+
},
|
|
508
|
+
],
|
|
509
|
+
},
|
|
510
|
+
{
|
|
511
|
+
title: 'Футер',
|
|
512
|
+
tag: 'div',
|
|
513
|
+
class: 'align-items-center flex-wrap',
|
|
514
|
+
outer_tag: 'footer',
|
|
515
|
+
outer_class: 'icms-footer__bottom',
|
|
516
|
+
container: 'container',
|
|
517
|
+
container_class: 'py-2',
|
|
518
|
+
no_gutters: true,
|
|
519
|
+
cols: [
|
|
520
|
+
{
|
|
521
|
+
title: 'Футер',
|
|
522
|
+
position: 'pos_footer',
|
|
523
|
+
tag: 'div',
|
|
524
|
+
class: 'mt-2 mt-sm-0 mb-1 mb-sm-0',
|
|
525
|
+
col_md: 'col-md-6',
|
|
526
|
+
},
|
|
527
|
+
{
|
|
528
|
+
title: 'Меню',
|
|
529
|
+
position: 'pos_footer_menu',
|
|
530
|
+
tag: 'div',
|
|
531
|
+
col_md: 'col-md-6',
|
|
532
|
+
},
|
|
533
|
+
],
|
|
534
|
+
},
|
|
535
|
+
],
|
|
536
|
+
},
|
|
537
|
+
},
|
|
538
|
+
};
|
|
539
|
+
/** Returns a list of available preset names with descriptions */
|
|
540
|
+
function listLayoutPresets() {
|
|
541
|
+
return Object.entries(exports.layoutPresets).map(([name, preset]) => ({
|
|
542
|
+
name,
|
|
543
|
+
description: preset.description,
|
|
544
|
+
rows_count: preset.scheme.rows.length,
|
|
545
|
+
positions: preset.scheme.rows.flatMap(r => (r.cols || []).map(c => c.position || '(auto)')),
|
|
546
|
+
}));
|
|
547
|
+
}
|
|
548
|
+
const serialization_js_1 = require("../utils/serialization.js");
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.mariaExecuteQuery = mariaExecuteQuery;
|
|
4
|
+
exports.mariaListTables = mariaListTables;
|
|
5
|
+
exports.mariaDescribeTable = mariaDescribeTable;
|
|
6
|
+
exports.mariaGetDatabaseInfo = mariaGetDatabaseInfo;
|
|
7
|
+
exports.mariaShowIndexes = mariaShowIndexes;
|
|
8
|
+
exports.mariaSearchTables = mariaSearchTables;
|
|
9
|
+
exports.mariaGetTableData = mariaGetTableData;
|
|
10
|
+
const mariadb_js_1 = require("./mariadb.js");
|
|
11
|
+
async function mariaExecuteQuery(sql) {
|
|
12
|
+
const result = await (0, mariadb_js_1.executeQuery)(sql);
|
|
13
|
+
if (result.error) {
|
|
14
|
+
return {
|
|
15
|
+
success: false,
|
|
16
|
+
error: result.error,
|
|
17
|
+
query: result.query,
|
|
18
|
+
executionTime: result.executionTime,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
return {
|
|
22
|
+
success: true,
|
|
23
|
+
columns: result.columns,
|
|
24
|
+
rows: result.rows,
|
|
25
|
+
rowCount: result.rowCount,
|
|
26
|
+
query: result.query,
|
|
27
|
+
executionTime: result.executionTime,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
async function mariaListTables() {
|
|
31
|
+
const tables = await (0, mariadb_js_1.listTables)();
|
|
32
|
+
return {
|
|
33
|
+
tables,
|
|
34
|
+
count: tables.length,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
async function mariaDescribeTable(tableName) {
|
|
38
|
+
const info = await (0, mariadb_js_1.getTableInfo)(tableName);
|
|
39
|
+
if (!info) {
|
|
40
|
+
return {
|
|
41
|
+
error: `Table "${tableName}" not found`,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
name: info.name,
|
|
46
|
+
comment: info.comment,
|
|
47
|
+
rowCount: info.rowCount,
|
|
48
|
+
columns: info.columns.map(c => ({
|
|
49
|
+
name: c.name,
|
|
50
|
+
type: c.type,
|
|
51
|
+
nullable: c.nullable,
|
|
52
|
+
key: c.key,
|
|
53
|
+
default: c.default,
|
|
54
|
+
extra: c.extra,
|
|
55
|
+
comment: c.comment,
|
|
56
|
+
})),
|
|
57
|
+
indexes: info.indexes.map(i => ({
|
|
58
|
+
name: i.name,
|
|
59
|
+
type: i.type,
|
|
60
|
+
columns: i.columns,
|
|
61
|
+
unique: i.unique,
|
|
62
|
+
})),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
async function mariaGetDatabaseInfo() {
|
|
66
|
+
return await (0, mariadb_js_1.getDatabaseInfo)();
|
|
67
|
+
}
|
|
68
|
+
async function mariaShowIndexes(tableName) {
|
|
69
|
+
const result = await (0, mariadb_js_1.showIndexes)(tableName);
|
|
70
|
+
return {
|
|
71
|
+
table: tableName,
|
|
72
|
+
indexes: result.rows,
|
|
73
|
+
columnCount: result.columns.length,
|
|
74
|
+
executionTime: result.executionTime,
|
|
75
|
+
error: result.error,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
async function mariaSearchTables(pattern) {
|
|
79
|
+
const tables = await (0, mariadb_js_1.listTables)();
|
|
80
|
+
const matching = tables.filter(t => t.toLowerCase().includes(pattern.toLowerCase()));
|
|
81
|
+
return {
|
|
82
|
+
pattern,
|
|
83
|
+
matched: matching,
|
|
84
|
+
count: matching.length,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
async function mariaGetTableData(tableName, options) {
|
|
88
|
+
const limit = options?.limit || 20;
|
|
89
|
+
const offset = options?.offset || 0;
|
|
90
|
+
const orderBy = options?.orderBy || 'id';
|
|
91
|
+
const orderDir = options?.orderDir || 'DESC';
|
|
92
|
+
let sql = `SELECT * FROM \`${tableName}\``;
|
|
93
|
+
const params = [];
|
|
94
|
+
if (options?.filter) {
|
|
95
|
+
const filterConditions = [];
|
|
96
|
+
for (const [key, value] of Object.entries(options.filter)) {
|
|
97
|
+
filterConditions.push(`\`${key}\` = ?`);
|
|
98
|
+
params.push(value);
|
|
99
|
+
}
|
|
100
|
+
if (filterConditions.length > 0) {
|
|
101
|
+
sql += ` WHERE ${filterConditions.join(' AND ')}`;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
sql += ` ORDER BY \`${orderBy}\` ${orderDir} LIMIT ? OFFSET ?`;
|
|
105
|
+
params.push(limit, offset);
|
|
106
|
+
const result = await (0, mariadb_js_1.executeQuery)(sql);
|
|
107
|
+
if (result.error) {
|
|
108
|
+
return {
|
|
109
|
+
error: result.error,
|
|
110
|
+
query: result.query,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
table: tableName,
|
|
115
|
+
columns: result.columns,
|
|
116
|
+
rows: result.rows,
|
|
117
|
+
rowCount: result.rowCount,
|
|
118
|
+
pagination: {
|
|
119
|
+
limit,
|
|
120
|
+
offset,
|
|
121
|
+
orderBy,
|
|
122
|
+
orderDir,
|
|
123
|
+
},
|
|
124
|
+
query: result.query,
|
|
125
|
+
executionTime: result.executionTime,
|
|
126
|
+
};
|
|
127
|
+
}
|