Merge pull request #3412 from yurikuzn/i/category

Category drag and drop
This commit is contained in:
Yurii Kuznietsov
2025-06-18 13:24:40 +03:00
committed by GitHub
19 changed files with 1327 additions and 33 deletions
@@ -29,15 +29,20 @@
namespace Espo\Core\Controllers;
use Espo\Core\Acl\Table;
use Espo\Core\Exceptions\Forbidden;
use Espo\Core\Exceptions\BadRequest;
use Espo\Core\Exceptions\Error;
use Espo\Core\Exceptions\NotFound;
use Espo\Core\ORM\Entity;
use Espo\Core\Templates\Entities\CategoryTree;
use Espo\Services\RecordTree as Service;
use Espo\Core\Api\Request;
use Espo\Tools\CategoryTree\Move\MoveParams;
use Espo\Tools\CategoryTree\MoveService;
use RuntimeException;
use stdClass;
class RecordTree extends Record
@@ -58,11 +63,6 @@ class RecordTree extends Record
*/
public function getActionListTree(Request $request): stdClass
{
if (method_exists($this, 'actionListTree')) {
// For backward compatibility.
return (object) $this->actionListTree($request->getRouteParams(), $request->getParsedBody(), $request);
}
$selectParams = $this->fetchSearchParamsFromRequest($request);
$parentId = $request->getQueryParam('parentId');
@@ -101,7 +101,7 @@ class RecordTree extends Record
*/
public function getActionLastChildrenIdList(Request $request): array
{
if (!$this->acl->check($this->name, 'read')) {
if (!$this->acl->check($this->name, Table::ACTION_READ)) {
throw new Forbidden();
}
@@ -110,6 +110,68 @@ class RecordTree extends Record
return $this->getRecordTreeService()->getLastChildrenIdList($parentId);
}
/**
* @throws Forbidden
* @throws BadRequest
* @throws NotFound
* @throws Error
* @noinspection PhpUnused
*/
public function postActionMove(Request $request): bool
{
if (!$this->acl->check($this->name, Table::ACTION_EDIT)) {
throw new Forbidden();
}
$id = $request->getParsedBody()->id ?? null;
$referenceId = $request->getParsedBody()->referenceId ?? null;
$type = $request->getParsedBody()->type ?? null;
if (!is_string($id)) {
throw new BadRequest("Bad id.");
}
if (!is_string($referenceId)) {
throw new BadRequest("Bad referenceId.");
}
$typeInternal = match ($type) {
'into' => MoveParams::TYPE_INTO,
'before' => MoveParams::TYPE_BEFORE,
'after' => MoveParams::TYPE_AFTER,
default => null,
};
if ($typeInternal === null) {
throw new BadRequest("Bad type.");
}
$entity = $this->getRecordService()->getEntity($id);
if (!$entity) {
throw new NotFound("Record not found.");
}
if (!$entity instanceof CategoryTree) {
throw new RuntimeException("Non-tree entity.");
}
if (!$this->acl->checkEntityEdit($entity)) {
throw new Forbidden("No edit access.");
}
$params = new MoveParams(
type: $typeInternal,
referenceId: $referenceId,
);
$service = $this->injectableFactory->create(MoveService::class);
$service->move($entity, $params);
return true;
}
/**
* @return Service<Entity>
*/
@@ -117,7 +179,9 @@ class RecordTree extends Record
{
$service = $this->getRecordService();
assert($service instanceof Service);
if (!$service instanceof Service) {
throw new RuntimeException();
}
return $service;
}
@@ -86,7 +86,14 @@ class DevModeJsFileListProvider
$amdId = $item->amdId ?? null;
if ($amdId) {
return 'client/lib/original/' . $amdId . '.js';
$file = $amdId;
if (str_starts_with($amdId, '@')) {
$file = substr($amdId, 1);
$file = str_replace('/', '-', $file);
}
return 'client/lib/original/' . $file . '.js';
}
$src = $item->src ?? null;
@@ -78,7 +78,7 @@
}
},
"collection": {
"orderBy": "parent",
"orderBy": "name",
"order": "asc"
},
"additionalTables": {
@@ -35,6 +35,7 @@
"order": {
"type": "int",
"minValue": 1,
"readOnly": true,
"disableFormatting": true,
"textFilterDisabled": true
},
@@ -7,6 +7,7 @@
"order": {
"type": "int",
"minValue": 1,
"readOnly": true,
"textFilterDisabled": true
},
"description": {
@@ -77,6 +77,9 @@
"exportsTo": "window",
"exportsAs": "Selectize"
},
"@shopify/draggable": {
"devPath": "client/lib/original/shopify-draggable.js"
},
"autonumeric": {},
"intl-tel-input": {
"exportsTo": "window",
@@ -7,6 +7,7 @@
"order": {
"type": "int",
"minValue": 1,
"readOnly": true,
"textFilterDisabled": true
},
"description": {
@@ -0,0 +1,42 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM Open Source CRM application.
* Copyright (C) 2014-2025 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Tools\CategoryTree\Move;
readonly class MoveParams
{
public const TYPE_INTO = 0;
public const TYPE_BEFORE = 1;
public const TYPE_AFTER = 2;
public function __construct(
public int $type,
public ?string $referenceId = null,
) {}
}
@@ -0,0 +1,234 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM Open Source CRM application.
* Copyright (C) 2014-2025 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Tools\CategoryTree;
use Espo\Core\Acl;
use Espo\Core\Exceptions\Error;
use Espo\Core\Exceptions\Forbidden;
use Espo\Core\Exceptions\NotFound;
use Espo\Core\Templates\Entities\CategoryTree;
use Espo\ORM\Entity;
use Espo\ORM\EntityManager;
use Espo\ORM\Query\Part\Expression as Expr;
use Espo\ORM\Query\UpdateBuilder;
use Espo\ORM\Repository\Option\SaveOption;
use Espo\Tools\CategoryTree\Move\MoveParams;
class MoveService
{
private const ATTR_PARENT_ID = 'parentId';
private const ATTR_ORDER = 'order';
public function __construct(
private EntityManager $entityManager,
private Acl $acl,
) {}
/**
* @throws NotFound
* @throws Forbidden
* @throws Error
*/
public function move(CategoryTree $entity, MoveParams $params): void
{
$hasOrder = $entity->hasAttribute(self::ATTR_ORDER);
if (!$hasOrder && $params->type !== MoveParams::TYPE_INTO) {
throw new Error("Order not supported.");
}
$entityType = $entity->getEntityType();
$reference = null;
if ($params->referenceId) {
$reference = $this->entityManager->getEntityById($entityType, $params->referenceId);
if (!$reference) {
throw new NotFound("No reference record found.");
}
}
if ($params->type === MoveParams::TYPE_INTO) {
$this->processInto($reference, $entity, $params);
return;
}
if (!$reference) {
throw new Error("No reference.");
}
$parentId = $reference->get(self::ATTR_PARENT_ID);
if ($parentId !== $entity->get(self::ATTR_PARENT_ID) && $parentId) {
$parent = $this->entityManager->getEntityById($entityType, $parentId);
if ($parent && !$this->acl->checkEntityEdit($parent)) {
throw new Forbidden("No edit access to target category.");
}
if ($parent) {
$this->checkReferenceNoLoop($parent, $entity);
}
}
if ($params->type === MoveParams::TYPE_AFTER) {
$this->processAfter($reference, $entity);
return;
}
$this->processBefore($reference, $entity);
}
private function incrementAfter(Entity $reference): void
{
$update = UpdateBuilder::create()
->in($reference->getEntityType())
->where([
self::ATTR_PARENT_ID => $reference->get(self::ATTR_PARENT_ID),
self::ATTR_ORDER . '>' => $reference->get(self::ATTR_ORDER),
])
->set([
self::ATTR_ORDER => Expr::add(Expr::column(self::ATTR_ORDER), 2)
])
->build();
$this->entityManager->getQueryExecutor()->execute($update);
}
private function decrementBefore(Entity $reference): void
{
$update = UpdateBuilder::create()
->in($reference->getEntityType())
->where([
self::ATTR_PARENT_ID => $reference->get(self::ATTR_PARENT_ID),
self::ATTR_ORDER . '<' => $reference->get(self::ATTR_ORDER),
])
->set([
self::ATTR_ORDER => Expr::subtract(Expr::column(self::ATTR_ORDER), 2)
])
->build();
$this->entityManager->getQueryExecutor()->execute($update);
}
private function rearrange(Entity $reference): void
{
$entities = $this->entityManager
->getRDBRepository($reference->getEntityType())
->where([
self::ATTR_PARENT_ID => $reference->get(self::ATTR_PARENT_ID),
])
->order(self::ATTR_ORDER)
->find();
foreach ($entities as $i => $entity) {
$entity->set(self::ATTR_ORDER, $i + 1);
$this->entityManager->saveEntity($entity, [SaveOption::SKIP_ALL => true]);
}
}
private function processAfter(Entity $reference, CategoryTree $entity): void
{
$this->incrementAfter($reference);
$this->rearrange($reference);
$order = ($reference->get(self::ATTR_ORDER) ?? 0) + 1;
$entity->set(self::ATTR_ORDER, $order);
$entity->set(self::ATTR_PARENT_ID, $reference->get(self::ATTR_PARENT_ID));
$this->entityManager->saveEntity($entity);
$this->rearrange($reference);
}
private function processBefore(Entity $reference, CategoryTree $entity): void
{
$this->decrementBefore($reference);
$order = ($reference->get(self::ATTR_ORDER) ?? 0) - 1;
$entity->set(self::ATTR_ORDER, $order);
$entity->set(self::ATTR_PARENT_ID, $reference->get(self::ATTR_PARENT_ID));
$this->entityManager->saveEntity($entity);
$this->rearrange($reference);
}
/**
* @throws Forbidden
*/
private function processInto(?Entity $reference, CategoryTree $entity, MoveParams $params): void
{
if ($reference && !$this->acl->checkEntityEdit($reference)) {
throw new Forbidden("No edit access to target category.");
}
if ($reference) {
$this->checkReferenceNoLoop($reference, $entity);
}
$entity->setMultiple([
self::ATTR_PARENT_ID => $params->referenceId,
self::ATTR_ORDER => null,
]);
$this->entityManager->saveEntity($entity);
}
/**
* @throws Forbidden
*/
private function checkReferenceNoLoop(Entity $reference, CategoryTree $entity): void
{
$parentId = $reference->get(self::ATTR_PARENT_ID);
if (!$parentId) {
return;
}
if ($parentId === $entity->getId()) {
throw new Forbidden("Cannot move. Circle reference.");
}
$parent = $this->entityManager->getEntityById($entity->getEntityType(), $parentId);
if (!$parent) {
return;
}
$this->checkReferenceNoLoop($parent, $entity);
}
}
+4 -1
View File
@@ -11,7 +11,10 @@
<div class="no-data">{{translate 'No Data'}}</div>
{{/if}}
<div class="list list-expanded list-tree{{#if noData}} hidden{{/if}}">
<div
class="list list-expanded list-tree {{#if noData}} hidden {{/if}}"
{{#if isEditable}} data-editable="true" {{/if}}
>
{{#if showRoot}}
<div class="root-item">
<a
+11 -2
View File
@@ -38,6 +38,12 @@ class ListTreeRecordItemView extends View {
level = 0
listViewName = 'views/record/list-tree'
/**
* @private
* @type {import('views/record/list-tree').default}
*/
rootView
data() {
return {
name: this.model.get('name'),
@@ -282,11 +288,14 @@ class ListTreeRecordItemView extends View {
if (!this.readOnly) {
const $remove = this.$el.find('> .cell [data-action="remove"]');
this.$el.find('> .cell').on('mouseenter', function () {
this.$el.find('> .cell').on('mouseenter', () => {
if (this.rootView.movedId) {
return;
}
$remove.removeClass('hidden');
});
this.$el.find('> .cell').on('mouseleave', function () {
this.$el.find('> .cell').on('mouseleave', () => {
$remove.addClass('hidden');
});
}
+312 -5
View File
@@ -30,6 +30,7 @@
import ListRecordView from 'views/record/list';
import RecordModal from 'helpers/record-modal';
import {Draggable} from '@shopify/draggable';
class ListTreeRecordView extends ListRecordView {
@@ -51,8 +52,43 @@ class ListTreeRecordView extends ListRecordView {
level = 0
itemViewName = 'views/record/list-tree-item'
/**
* @protected
* @type {boolean}
*/
readOnly
expandToggleInactive = false;
/**
* @private
* @type {ListTreeRecordView}
*/
rootView
/**
* @type {string|null}
*/
movedId = null
/**
* @private
* @type {boolean}
*/
blockDraggable = false
/**
* @private
* @type {boolean}
*/
moveSupported
/**
* @private
* {Draggable}
*/
draggable
// noinspection JSCheckFunctionSignatures
data() {
const data = super.data();
@@ -77,6 +113,8 @@ class ListTreeRecordView extends ListRecordView {
data.expandToggleInactive = this.expandToggleInactive;
data.hasExpandToggle = !this.getUser().isPortal();
data.isEditable = this.level === 0 && !this.readOnly;
return data;
}
@@ -137,6 +175,16 @@ class ListTreeRecordView extends ListRecordView {
}
});
}
this.moveSupported = !!this.getMetadata().get(`entityDefs.${this.entityType}.fields.order`);
}
afterRender() {
super.afterRender();
if (this.level === 0 && !this.readOnly && this.moveSupported) {
this.initDraggableRoot();
}
}
/**
@@ -145,8 +193,7 @@ class ListTreeRecordView extends ListRecordView {
setSelected(id) {
if (id === null) {
this.selectedData.id = null;
}
else {
} else {
this.selectedData.id = id;
}
@@ -166,6 +213,13 @@ class ListTreeRecordView extends ListRecordView {
});
}
/**
* @return {import('views/record/list-tree-item').default[]}
*/
getItemViews() {
return this.rowList.map(key => this.getView(key));
}
buildRows(callback) {
this.checkedList = [];
this.rowList = [];
@@ -251,12 +305,10 @@ class ListTreeRecordView extends ListRecordView {
attributes.parentName = this.model.attributes.name;
}
const scope = this.collection.entityType;
const helper = new RecordModal();
helper.showCreate(this, {
entityType: scope,
entityType: this.entityType,
attributes: attributes,
afterSave: model => {
const collection = /** @type {import('collections/tree').default} collection */
@@ -296,6 +348,261 @@ class ListTreeRecordView extends ListRecordView {
this.setSelected(null);
}
}
/**
* @private
*/
initDraggableRoot() {
if (this.draggable) {
this.draggable.destroy();
}
const draggable = this.draggable = new Draggable(this.element, {
distance: 8,
draggable: '.list-group-item > .cell > .link',
mirror: {
cursorOffsetX: 5,
cursorOffsetY: 5,
appendTo: 'body',
},
});
/** @type {HTMLElement[]} */
let rows;
/** @type {Map<HTMLElement, number>} */
let levelMap;
/** @type {HTMLElement|null} */
let movedLink = null;
/** @type {HTMLElement|null} */
let movedFromLi = null;
draggable.on('mirror:created', event => {
const mirror = event.mirror;
const source = event.source;
const originalSource = event.originalSource;
originalSource.style.display = '';
source.style.display = 'none';
mirror.style.display = 'block';
mirror.style.cursor = 'grabbing';
mirror.classList.add('draggable-helper', 'draggable-helper-transparent', 'text-info');
mirror.classList.remove('link');
mirror.style.pointerEvents = 'auto';
mirror.removeAttribute('href');
mirror.style.textDecoration = 'none';
});
draggable.on('mirror:move', event => {
event.mirror.style.pointerEvents = 'auto';
});
draggable.on('drag:start', event => {
if (this.blockDraggable) {
event.cancel();
return;
}
rows = Array.from(this.element.querySelectorAll('.list-group-tree > .list-group-item'));
levelMap = new Map();
rows.forEach(row => {
let depth = 0;
let current = row;
while (current && current !== this.element) {
current = current.parentElement;
depth ++;
}
levelMap.set(row, depth);
});
rows.sort((a, b) => levelMap.get(b) - levelMap.get(a));
this.movedId = event.source.dataset.id;
movedLink = event.originalSource;
movedFromLi = movedLink.parentElement.parentElement;
movedLink.classList.add('text-info');
});
let overId = null;
let overParentId = null;
let isAfter = false;
let wasOutOfSelf = false;
draggable.on('drag:move', event => {
isAfter = false;
overId = null;
let rowFound = null;
for (const row of rows) {
const rect = row.getBoundingClientRect();
const isIn =
rect.left < event.sensorEvent.clientX &&
rect.right > event.sensorEvent.clientX &&
rect.top < event.sensorEvent.clientY &&
rect.bottom >= event.sensorEvent.clientY;
if (!isIn) {
continue;
}
const itemId = row.dataset.id ?? null;
let itemParentId = null;
if (!itemId) {
const parent = row.closest(`.list-group-item[data-id]`);
if (parent instanceof HTMLElement) {
// Over a plus row.
itemParentId = parent.dataset.id;
}
}
const itemIsAfter = event.sensorEvent.clientY - rect.top >= rect.bottom - event.sensorEvent.clientY;
if (itemParentId && itemIsAfter) {
continue;
}
if (itemId === this.movedId) {
break;
}
if (movedFromLi.contains(row)) {
break;
}
if (!itemId && !itemParentId) {
continue;
}
isAfter = itemIsAfter;
overParentId = itemParentId;
overId = itemId;
rowFound = row;
break;
}
for (const row of rows) {
row.classList.remove('border-top-highlighted');
row.classList.remove('border-bottom-highlighted');
}
if (!rowFound) {
return;
}
if (isAfter) {
rowFound.classList.add('border-bottom-highlighted');
rowFound.classList.remove('border-top-highlighted');
} else {
rowFound.classList.add('border-top-highlighted');
rowFound.classList.remove('border-bottom-highlighted');
}
});
draggable.on('drag:stop', async () => {
if (movedLink) {
movedLink.classList.remove('text-info');
}
rows.forEach(row => {
row.classList.remove('border-bottom-highlighted');
row.classList.remove('border-top-highlighted');
});
rows = undefined;
let moveType;
let referenceId = overId;
if (overParentId || overId) {
if (overParentId) {
moveType = 'into';
referenceId = overParentId;
} else if (isAfter) {
moveType = 'after';
} else {
moveType = 'before';
}
}
if (moveType) {
this.blockDraggable = true;
const movedId = this.movedId;
const affectedId = referenceId;
Espo.Ui.notifyWait();
Espo.Ajax
.postRequest(`${this.entityType}/action/move`, {
id: this.movedId,
referenceId: referenceId,
type: moveType,
})
.then(async () => {
/**
*
* @param {ListTreeRecordView} view
* @param {string} movedId
* @return {Promise}
*/
const update = async (view, movedId) => {
if (view.collection.has(movedId)) {
await view.collection.fetch();
return;
}
for (const subView of view.getItemViews()) {
if (!subView.getChildrenView()) {
continue;
}
await update(subView.getChildrenView(), movedId);
}
};
const promises = [];
if (movedId) {
promises.push(update(this, movedId));
}
if (affectedId) {
promises.push(update(this, affectedId));
}
await Promise.all(promises);
Espo.Ui.success(this.translate('Done'));
})
.finally(() => {
this.blockDraggable = false;
});
}
this.movedId = null;
movedLink = null;
movedFromLi = null;
levelMap = undefined;
overParentId = null;
overId = null;
isAfter = false;
wasOutOfSelf = false;
});
}
}
export default ListTreeRecordView;
+64 -9
View File
@@ -2928,18 +2928,69 @@ table.table td.cell .html-container {
.list-group-tree {
border: 0;
}
.list-group-tree > li {
border: 0;
padding: 0 0 0 var(--panel-padding);
> li {
border: 0;
padding: 0 0 0 var(--panel-padding);
.cell {
padding: var(--3px) 0;
.remove-link {
margin-left: var(--4px);
margin-right: var(--4px);
}
}
}
}
.list-group-tree > li .cell {
padding: var(--3px) 0;
.list-tree {
&[data-editable="true"] {
.list-group-tree {
> li {
position: relative;
.remove-link {
margin-left: var(--4px);
margin-right: var(--4px);
&.border-bottom-highlighted,
&.border-top-highlighted {
&::after {
display: block;
content: " ";
height: var(--2px);
width: var(--20px);
background-color: var(--gray-soft);
left: var(--30px);
position: absolute;
border-radius: var(--1px);
}
}
&.border-bottom-highlighted {
&::after {
bottom: var(--minus-1px);
}
}
&.border-top-highlighted {
&::after {
top: var(--minus-1px);
}
}
> .cell {
user-select: none;
}
a[data-action="fold"],
a[data-action="unfold"],
a[data-action="remove"],
a[data-action="create"] {
&,
&:hover {
color: var(--btn-text-color);
}
}
}
}
}
}
@@ -3978,6 +4029,10 @@ body:has(.modal-backdrop) {
opacity: 1;
position: absolute;
z-index: 10002;
&.draggable-helper-transparent {
opacity: 0.5;
}
}
.reminders-container {
+6
View File
@@ -129,6 +129,12 @@
"bundle": true,
"amdId": "intl-tel-input-globals"
},
{
"src": "client/lib/original/shopify-draggable.js",
"bundle": true,
"amdId": "@shopify/draggable",
"prepareCommand": "npx rollup node_modules/@shopify/draggable/build/esm/index.mjs --format amd --file client/lib/original/shopify-draggable.js --amd.id @shopify/draggable"
},
{
"src": "node_modules/summernote/dist/summernote.js",
"amdId": "summernote",
+32 -4
View File
@@ -28,14 +28,37 @@
const BuildUtils = {
/**
* @param {Array} libs
* @param {{
* src?: string,
* dest?: string,
* bundle?: boolean,
* amdId?: string,
* suppressAmd?: boolean,
* minify?: boolean,
* prepareCommand?: string,
* name?: string,
* files?: {
* src: string,
* dest: string,
* }[],
* }[]} libs
* @param {boolean} [skipPreparable]
* @return {{src: string, file: string}[]}
*/
getBundleLibList: function(libs) {
getBundleLibList: function(libs, skipPreparable = false) {
const list = [];
/**
*
* @param {{amdId?: string, src: string}} item
* @return {*|string}
*/
const getFile = item => {
if (item.amdId) {
if (item.amdId.startsWith('@')) {
return item.amdId.slice(1).replace('/', '-') + '.js';
}
return item.amdId + '.js';
}
@@ -44,6 +67,10 @@ const BuildUtils = {
libs.filter(item => item.bundle)
.forEach(item => {
if (item.prepareCommand && skipPreparable) {
return;
}
if (item.files) {
item.files.forEach(item => list.push({
src: item.src,
@@ -67,8 +94,9 @@ const BuildUtils = {
},
getPreparedBundleLibList: function (libs) {
return BuildUtils.getBundleLibList(libs)
.map(item => 'client/lib/original/' + item.file);
const items = BuildUtils.getBundleLibList(libs);
return items.map(item => 'client/lib/original/' + item.file);
},
destToOriginalDest: function (dest) {
+25 -3
View File
@@ -27,9 +27,28 @@
************************************************************************/
const fs = require('fs');
const cp = require('child_process');
const buildUtils = require('../build-utils');
// @todo Introduce libs-provider.
/**
* @type {{
* src?: string,
* dest?: string,
* bundle?: boolean,
* amdId?: string,
* suppressAmd?: boolean,
* minify?: boolean,
* prepareCommand?: string,
* name?: string,
* files?: {
* src: string,
* dest: string,
* }[],
* }[]}
*/
const libs = require('./../../frontend/libs.json');
const bundleConfig = require('../../frontend/bundle-config.json');
const libDir = './client/lib';
@@ -55,6 +74,11 @@ fs.readdirSync(originalLibDir)
fs.readdirSync(originalLibCrmDir)
.forEach(file => fs.unlinkSync(originalLibCrmDir + '/' + file));
libs.filter(it => it.prepareCommand)
.forEach(it => {
cp.execSync(it.prepareCommand, {stdio: ['ignore', 'ignore', 'pipe']});
});
const stripSourceMappingUrl = path => {
/** @var {string} */
const originalContents = fs.readFileSync(path, {encoding: 'utf-8'});
@@ -94,8 +118,6 @@ const addSuppressAmd = path => {
fs.writeFileSync(path, contents, {encoding: 'utf-8'});
}
const bundleLibDataList = buildUtils.getBundleLibList(libs);
const amdIdMap = {};
const suppressAmdMap = {};
@@ -113,7 +135,7 @@ libs.forEach(item => {
amdIdMap[item.src] = 'lib!' + item.amdId;
});
bundleLibDataList.forEach(item => {
buildUtils.getBundleLibList(libs, true).forEach(item => {
const src = item.src;
const dest = originalLibDir + '/' + item.file;
+16
View File
@@ -29,6 +29,22 @@
const fs = require('fs');
const buildUtils = require('../build-utils');
/**
* @type {{
* src?: string,
* dest?: string,
* bundle?: boolean,
* amdId?: string,
* suppressAmd?: boolean,
* minify?: boolean,
* prepareCommand?: string,
* name?: string,
* files?: {
* src: string,
* dest: string,
* }[],
* }[]}
*/
const libs = require('./../../frontend/libs.json');
const stripSourceMappingUrl = path => {
+493
View File
@@ -12,6 +12,7 @@
"dependencies": {
"@fullcalendar/moment": "^6.1.8",
"@fullcalendar/moment-timezone": "^6.1.8",
"@shopify/draggable": "^1.1.4",
"ace-builds": "^1.4.12",
"autobahn-espo": "github:yurikuzn/autobahn-espo#0.1.0",
"autonumeric": "^4.6.0",
@@ -71,6 +72,7 @@
"jasmine-core": "^5.2.0",
"js-yaml": "^3.13.1",
"pofile": "^1.1.3",
"rollup": "^4.43.0",
"tar": "^6.1.11"
},
"engines": {
@@ -1914,6 +1916,266 @@
"node": ">=14"
}
},
"node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.43.0.tgz",
"integrity": "sha512-Krjy9awJl6rKbruhQDgivNbD1WuLb8xAclM4IR4cN5pHGAs2oIMMQJEiC3IC/9TZJ+QZkmZhlMO/6MBGxPidpw==",
"cpu": [
"arm"
],
"dev": true,
"optional": true,
"os": [
"android"
]
},
"node_modules/@rollup/rollup-android-arm64": {
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.43.0.tgz",
"integrity": "sha512-ss4YJwRt5I63454Rpj+mXCXicakdFmKnUNxr1dLK+5rv5FJgAxnN7s31a5VchRYxCFWdmnDWKd0wbAdTr0J5EA==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"android"
]
},
"node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.43.0.tgz",
"integrity": "sha512-eKoL8ykZ7zz8MjgBenEF2OoTNFAPFz1/lyJ5UmmFSz5jW+7XbH1+MAgCVHy72aG59rbuQLcJeiMrP8qP5d/N0A==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
]
},
"node_modules/@rollup/rollup-darwin-x64": {
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.43.0.tgz",
"integrity": "sha512-SYwXJgaBYW33Wi/q4ubN+ldWC4DzQY62S4Ll2dgfr/dbPoF50dlQwEaEHSKrQdSjC6oIe1WgzosoaNoHCdNuMg==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
]
},
"node_modules/@rollup/rollup-freebsd-arm64": {
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.43.0.tgz",
"integrity": "sha512-SV+U5sSo0yujrjzBF7/YidieK2iF6E7MdF6EbYxNz94lA+R0wKl3SiixGyG/9Klab6uNBIqsN7j4Y/Fya7wAjQ==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"freebsd"
]
},
"node_modules/@rollup/rollup-freebsd-x64": {
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.43.0.tgz",
"integrity": "sha512-J7uCsiV13L/VOeHJBo5SjasKiGxJ0g+nQTrBkAsmQBIdil3KhPnSE9GnRon4ejX1XDdsmK/l30IYLiAaQEO0Cg==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"freebsd"
]
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.43.0.tgz",
"integrity": "sha512-gTJ/JnnjCMc15uwB10TTATBEhK9meBIY+gXP4s0sHD1zHOaIh4Dmy1X9wup18IiY9tTNk5gJc4yx9ctj/fjrIw==",
"cpu": [
"arm"
],
"dev": true,
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.43.0.tgz",
"integrity": "sha512-ZJ3gZynL1LDSIvRfz0qXtTNs56n5DI2Mq+WACWZ7yGHFUEirHBRt7fyIk0NsCKhmRhn7WAcjgSkSVVxKlPNFFw==",
"cpu": [
"arm"
],
"dev": true,
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.43.0.tgz",
"integrity": "sha512-8FnkipasmOOSSlfucGYEu58U8cxEdhziKjPD2FIa0ONVMxvl/hmONtX/7y4vGjdUhjcTHlKlDhw3H9t98fPvyA==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.43.0.tgz",
"integrity": "sha512-KPPyAdlcIZ6S9C3S2cndXDkV0Bb1OSMsX0Eelr2Bay4EsF9yi9u9uzc9RniK3mcUGCLhWY9oLr6er80P5DE6XA==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.43.0.tgz",
"integrity": "sha512-HPGDIH0/ZzAZjvtlXj6g+KDQ9ZMHfSP553za7o2Odegb/BEfwJcR0Sw0RLNpQ9nC6Gy8s+3mSS9xjZ0n3rhcYg==",
"cpu": [
"loong64"
],
"dev": true,
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.43.0.tgz",
"integrity": "sha512-gEmwbOws4U4GLAJDhhtSPWPXUzDfMRedT3hFMyRAvM9Mrnj+dJIFIeL7otsv2WF3D7GrV0GIewW0y28dOYWkmw==",
"cpu": [
"ppc64"
],
"dev": true,
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.43.0.tgz",
"integrity": "sha512-XXKvo2e+wFtXZF/9xoWohHg+MuRnvO29TI5Hqe9xwN5uN8NKUYy7tXUG3EZAlfchufNCTHNGjEx7uN78KsBo0g==",
"cpu": [
"riscv64"
],
"dev": true,
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-riscv64-musl": {
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.43.0.tgz",
"integrity": "sha512-ruf3hPWhjw6uDFsOAzmbNIvlXFXlBQ4nk57Sec8E8rUxs/AI4HD6xmiiasOOx/3QxS2f5eQMKTAwk7KHwpzr/Q==",
"cpu": [
"riscv64"
],
"dev": true,
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-s390x-gnu": {
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.43.0.tgz",
"integrity": "sha512-QmNIAqDiEMEvFV15rsSnjoSmO0+eJLoKRD9EAa9rrYNwO/XRCtOGM3A5A0X+wmG+XRrw9Fxdsw+LnyYiZWWcVw==",
"cpu": [
"s390x"
],
"dev": true,
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.43.0.tgz",
"integrity": "sha512-jAHr/S0iiBtFyzjhOkAics/2SrXE092qyqEg96e90L3t9Op8OTzS6+IX0Fy5wCt2+KqeHAkti+eitV0wvblEoQ==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.43.0.tgz",
"integrity": "sha512-3yATWgdeXyuHtBhrLt98w+5fKurdqvs8B53LaoKD7P7H7FKOONLsBVMNl9ghPQZQuYcceV5CDyPfyfGpMWD9mQ==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.43.0.tgz",
"integrity": "sha512-wVzXp2qDSCOpcBCT5WRWLmpJRIzv23valvcTwMHEobkjippNf+C3ys/+wf07poPkeNix0paTNemB2XrHr2TnGw==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"win32"
]
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.43.0.tgz",
"integrity": "sha512-fYCTEyzf8d+7diCw8b+asvWDCLMjsCEA8alvtAutqJOJp/wL5hs1rWSqJ1vkjgW0L2NB4bsYJrpKkiIPRR9dvw==",
"cpu": [
"ia32"
],
"dev": true,
"optional": true,
"os": [
"win32"
]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.43.0.tgz",
"integrity": "sha512-SnGhLiE5rlK0ofq8kzuDkM0g7FN1s5VYY+YSMTibP7CqShxCQvqtNxTARS4xX4PFJfHjG0ZQYX9iGzI3FQh5Aw==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"win32"
]
},
"node_modules/@selectize/sifter": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/@selectize/sifter/-/sifter-0.6.2.tgz",
@@ -1929,6 +2191,11 @@
"sifter": "bin/sifter.js"
}
},
"node_modules/@shopify/draggable": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/@shopify/draggable/-/draggable-1.1.4.tgz",
"integrity": "sha512-EkXxBtQH119pGpLWhhhIPEdaeirGcVwkh6Nft1nqbMdM4N6b4r4v9wCmR1/r2gjTwu888I6qGI0VSlhoYivbYw=="
},
"node_modules/@testim/chrome-version": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/@testim/chrome-version/-/chrome-version-1.1.4.tgz",
@@ -1941,6 +2208,12 @@
"integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==",
"dev": true
},
"node_modules/@types/estree": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz",
"integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==",
"dev": true
},
"node_modules/@types/hammerjs": {
"version": "2.0.41",
"resolved": "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.41.tgz",
@@ -6393,6 +6666,45 @@
"node": "*"
}
},
"node_modules/rollup": {
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.43.0.tgz",
"integrity": "sha512-wdN2Kd3Twh8MAEOEJZsuxuLKCsBEo4PVNLK6tQWAn10VhsVewQLzcucMgLolRlhFybGxfclbPeEYBaP6RvUFGg==",
"dev": true,
"dependencies": {
"@types/estree": "1.0.7"
},
"bin": {
"rollup": "dist/bin/rollup"
},
"engines": {
"node": ">=18.0.0",
"npm": ">=8.0.0"
},
"optionalDependencies": {
"@rollup/rollup-android-arm-eabi": "4.43.0",
"@rollup/rollup-android-arm64": "4.43.0",
"@rollup/rollup-darwin-arm64": "4.43.0",
"@rollup/rollup-darwin-x64": "4.43.0",
"@rollup/rollup-freebsd-arm64": "4.43.0",
"@rollup/rollup-freebsd-x64": "4.43.0",
"@rollup/rollup-linux-arm-gnueabihf": "4.43.0",
"@rollup/rollup-linux-arm-musleabihf": "4.43.0",
"@rollup/rollup-linux-arm64-gnu": "4.43.0",
"@rollup/rollup-linux-arm64-musl": "4.43.0",
"@rollup/rollup-linux-loongarch64-gnu": "4.43.0",
"@rollup/rollup-linux-powerpc64le-gnu": "4.43.0",
"@rollup/rollup-linux-riscv64-gnu": "4.43.0",
"@rollup/rollup-linux-riscv64-musl": "4.43.0",
"@rollup/rollup-linux-s390x-gnu": "4.43.0",
"@rollup/rollup-linux-x64-gnu": "4.43.0",
"@rollup/rollup-linux-x64-musl": "4.43.0",
"@rollup/rollup-win32-arm64-msvc": "4.43.0",
"@rollup/rollup-win32-ia32-msvc": "4.43.0",
"@rollup/rollup-win32-x64-msvc": "4.43.0",
"fsevents": "~2.3.2"
}
},
"node_modules/safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
@@ -8750,6 +9062,146 @@
"dev": true,
"optional": true
},
"@rollup/rollup-android-arm-eabi": {
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.43.0.tgz",
"integrity": "sha512-Krjy9awJl6rKbruhQDgivNbD1WuLb8xAclM4IR4cN5pHGAs2oIMMQJEiC3IC/9TZJ+QZkmZhlMO/6MBGxPidpw==",
"dev": true,
"optional": true
},
"@rollup/rollup-android-arm64": {
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.43.0.tgz",
"integrity": "sha512-ss4YJwRt5I63454Rpj+mXCXicakdFmKnUNxr1dLK+5rv5FJgAxnN7s31a5VchRYxCFWdmnDWKd0wbAdTr0J5EA==",
"dev": true,
"optional": true
},
"@rollup/rollup-darwin-arm64": {
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.43.0.tgz",
"integrity": "sha512-eKoL8ykZ7zz8MjgBenEF2OoTNFAPFz1/lyJ5UmmFSz5jW+7XbH1+MAgCVHy72aG59rbuQLcJeiMrP8qP5d/N0A==",
"dev": true,
"optional": true
},
"@rollup/rollup-darwin-x64": {
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.43.0.tgz",
"integrity": "sha512-SYwXJgaBYW33Wi/q4ubN+ldWC4DzQY62S4Ll2dgfr/dbPoF50dlQwEaEHSKrQdSjC6oIe1WgzosoaNoHCdNuMg==",
"dev": true,
"optional": true
},
"@rollup/rollup-freebsd-arm64": {
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.43.0.tgz",
"integrity": "sha512-SV+U5sSo0yujrjzBF7/YidieK2iF6E7MdF6EbYxNz94lA+R0wKl3SiixGyG/9Klab6uNBIqsN7j4Y/Fya7wAjQ==",
"dev": true,
"optional": true
},
"@rollup/rollup-freebsd-x64": {
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.43.0.tgz",
"integrity": "sha512-J7uCsiV13L/VOeHJBo5SjasKiGxJ0g+nQTrBkAsmQBIdil3KhPnSE9GnRon4ejX1XDdsmK/l30IYLiAaQEO0Cg==",
"dev": true,
"optional": true
},
"@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.43.0.tgz",
"integrity": "sha512-gTJ/JnnjCMc15uwB10TTATBEhK9meBIY+gXP4s0sHD1zHOaIh4Dmy1X9wup18IiY9tTNk5gJc4yx9ctj/fjrIw==",
"dev": true,
"optional": true
},
"@rollup/rollup-linux-arm-musleabihf": {
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.43.0.tgz",
"integrity": "sha512-ZJ3gZynL1LDSIvRfz0qXtTNs56n5DI2Mq+WACWZ7yGHFUEirHBRt7fyIk0NsCKhmRhn7WAcjgSkSVVxKlPNFFw==",
"dev": true,
"optional": true
},
"@rollup/rollup-linux-arm64-gnu": {
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.43.0.tgz",
"integrity": "sha512-8FnkipasmOOSSlfucGYEu58U8cxEdhziKjPD2FIa0ONVMxvl/hmONtX/7y4vGjdUhjcTHlKlDhw3H9t98fPvyA==",
"dev": true,
"optional": true
},
"@rollup/rollup-linux-arm64-musl": {
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.43.0.tgz",
"integrity": "sha512-KPPyAdlcIZ6S9C3S2cndXDkV0Bb1OSMsX0Eelr2Bay4EsF9yi9u9uzc9RniK3mcUGCLhWY9oLr6er80P5DE6XA==",
"dev": true,
"optional": true
},
"@rollup/rollup-linux-loongarch64-gnu": {
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.43.0.tgz",
"integrity": "sha512-HPGDIH0/ZzAZjvtlXj6g+KDQ9ZMHfSP553za7o2Odegb/BEfwJcR0Sw0RLNpQ9nC6Gy8s+3mSS9xjZ0n3rhcYg==",
"dev": true,
"optional": true
},
"@rollup/rollup-linux-powerpc64le-gnu": {
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.43.0.tgz",
"integrity": "sha512-gEmwbOws4U4GLAJDhhtSPWPXUzDfMRedT3hFMyRAvM9Mrnj+dJIFIeL7otsv2WF3D7GrV0GIewW0y28dOYWkmw==",
"dev": true,
"optional": true
},
"@rollup/rollup-linux-riscv64-gnu": {
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.43.0.tgz",
"integrity": "sha512-XXKvo2e+wFtXZF/9xoWohHg+MuRnvO29TI5Hqe9xwN5uN8NKUYy7tXUG3EZAlfchufNCTHNGjEx7uN78KsBo0g==",
"dev": true,
"optional": true
},
"@rollup/rollup-linux-riscv64-musl": {
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.43.0.tgz",
"integrity": "sha512-ruf3hPWhjw6uDFsOAzmbNIvlXFXlBQ4nk57Sec8E8rUxs/AI4HD6xmiiasOOx/3QxS2f5eQMKTAwk7KHwpzr/Q==",
"dev": true,
"optional": true
},
"@rollup/rollup-linux-s390x-gnu": {
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.43.0.tgz",
"integrity": "sha512-QmNIAqDiEMEvFV15rsSnjoSmO0+eJLoKRD9EAa9rrYNwO/XRCtOGM3A5A0X+wmG+XRrw9Fxdsw+LnyYiZWWcVw==",
"dev": true,
"optional": true
},
"@rollup/rollup-linux-x64-gnu": {
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.43.0.tgz",
"integrity": "sha512-jAHr/S0iiBtFyzjhOkAics/2SrXE092qyqEg96e90L3t9Op8OTzS6+IX0Fy5wCt2+KqeHAkti+eitV0wvblEoQ==",
"dev": true,
"optional": true
},
"@rollup/rollup-linux-x64-musl": {
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.43.0.tgz",
"integrity": "sha512-3yATWgdeXyuHtBhrLt98w+5fKurdqvs8B53LaoKD7P7H7FKOONLsBVMNl9ghPQZQuYcceV5CDyPfyfGpMWD9mQ==",
"dev": true,
"optional": true
},
"@rollup/rollup-win32-arm64-msvc": {
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.43.0.tgz",
"integrity": "sha512-wVzXp2qDSCOpcBCT5WRWLmpJRIzv23valvcTwMHEobkjippNf+C3ys/+wf07poPkeNix0paTNemB2XrHr2TnGw==",
"dev": true,
"optional": true
},
"@rollup/rollup-win32-ia32-msvc": {
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.43.0.tgz",
"integrity": "sha512-fYCTEyzf8d+7diCw8b+asvWDCLMjsCEA8alvtAutqJOJp/wL5hs1rWSqJ1vkjgW0L2NB4bsYJrpKkiIPRR9dvw==",
"dev": true,
"optional": true
},
"@rollup/rollup-win32-x64-msvc": {
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.43.0.tgz",
"integrity": "sha512-SnGhLiE5rlK0ofq8kzuDkM0g7FN1s5VYY+YSMTibP7CqShxCQvqtNxTARS4xX4PFJfHjG0ZQYX9iGzI3FQh5Aw==",
"dev": true,
"optional": true
},
"@selectize/sifter": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/@selectize/sifter/-/sifter-0.6.2.tgz",
@@ -8762,6 +9214,11 @@
"optimist": "^0.5.2"
}
},
"@shopify/draggable": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/@shopify/draggable/-/draggable-1.1.4.tgz",
"integrity": "sha512-EkXxBtQH119pGpLWhhhIPEdaeirGcVwkh6Nft1nqbMdM4N6b4r4v9wCmR1/r2gjTwu888I6qGI0VSlhoYivbYw=="
},
"@testim/chrome-version": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/@testim/chrome-version/-/chrome-version-1.1.4.tgz",
@@ -8774,6 +9231,12 @@
"integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==",
"dev": true
},
"@types/estree": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz",
"integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==",
"dev": true
},
"@types/hammerjs": {
"version": "2.0.41",
"resolved": "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.41.tgz",
@@ -12092,6 +12555,36 @@
}
}
},
"rollup": {
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.43.0.tgz",
"integrity": "sha512-wdN2Kd3Twh8MAEOEJZsuxuLKCsBEo4PVNLK6tQWAn10VhsVewQLzcucMgLolRlhFybGxfclbPeEYBaP6RvUFGg==",
"dev": true,
"requires": {
"@rollup/rollup-android-arm-eabi": "4.43.0",
"@rollup/rollup-android-arm64": "4.43.0",
"@rollup/rollup-darwin-arm64": "4.43.0",
"@rollup/rollup-darwin-x64": "4.43.0",
"@rollup/rollup-freebsd-arm64": "4.43.0",
"@rollup/rollup-freebsd-x64": "4.43.0",
"@rollup/rollup-linux-arm-gnueabihf": "4.43.0",
"@rollup/rollup-linux-arm-musleabihf": "4.43.0",
"@rollup/rollup-linux-arm64-gnu": "4.43.0",
"@rollup/rollup-linux-arm64-musl": "4.43.0",
"@rollup/rollup-linux-loongarch64-gnu": "4.43.0",
"@rollup/rollup-linux-powerpc64le-gnu": "4.43.0",
"@rollup/rollup-linux-riscv64-gnu": "4.43.0",
"@rollup/rollup-linux-riscv64-musl": "4.43.0",
"@rollup/rollup-linux-s390x-gnu": "4.43.0",
"@rollup/rollup-linux-x64-gnu": "4.43.0",
"@rollup/rollup-linux-x64-musl": "4.43.0",
"@rollup/rollup-win32-arm64-msvc": "4.43.0",
"@rollup/rollup-win32-ia32-msvc": "4.43.0",
"@rollup/rollup-win32-x64-msvc": "4.43.0",
"@types/estree": "1.0.7",
"fsevents": "~2.3.2"
}
},
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+2
View File
@@ -37,11 +37,13 @@
"jasmine-core": "^5.2.0",
"js-yaml": "^3.13.1",
"pofile": "^1.1.3",
"rollup": "^4.43.0",
"tar": "^6.1.11"
},
"dependencies": {
"@fullcalendar/moment": "^6.1.8",
"@fullcalendar/moment-timezone": "^6.1.8",
"@shopify/draggable": "^1.1.4",
"ace-builds": "^1.4.12",
"autobahn-espo": "github:yurikuzn/autobahn-espo#0.1.0",
"autonumeric": "^4.6.0",