@emailmaker/filemanager 0.10.92 → 0.10.94

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/file-manager.js CHANGED
@@ -22726,8 +22726,8 @@ __webpack_require__.d(__webpack_exports__, {
22726
22726
 
22727
22727
  // EXTERNAL MODULE: ./src/hooks/core/context.tsx
22728
22728
  var context = __webpack_require__(8361);
22729
- // EXTERNAL MODULE: ./src/hooks/core/files/index.ts + 17 modules
22730
- var core_files = __webpack_require__(9557);
22729
+ // EXTERNAL MODULE: ./src/hooks/core/files/index.ts + 18 modules
22730
+ var core_files = __webpack_require__(8573);
22731
22731
  ;// ./src/hooks/core/useFiles.ts
22732
22732
 
22733
22733
 
@@ -27028,8 +27028,8 @@ __webpack_require__.d(__webpack_exports__, {
27028
27028
  var core = __webpack_require__(4002);
27029
27029
  // EXTERNAL MODULE: external {"root":"React","commonjs2":"react","commonjs":"react","amd":"react"}
27030
27030
  var external_root_React_commonjs2_react_commonjs_react_amd_react_ = __webpack_require__(5442);
27031
- // EXTERNAL MODULE: ./src/hooks/core/files/index.ts + 17 modules
27032
- var core_files = __webpack_require__(9557);
27031
+ // EXTERNAL MODULE: ./src/hooks/core/files/index.ts + 18 modules
27032
+ var core_files = __webpack_require__(8573);
27033
27033
  ;// ./src/hooks/useFileActions.ts
27034
27034
 
27035
27035
 
@@ -28282,314 +28282,7 @@ const FileManagerProvider = ({ children, options }) => {
28282
28282
 
28283
28283
  /***/ }),
28284
28284
 
28285
- /***/ 9142:
28286
- /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
28287
-
28288
- "use strict";
28289
- /* harmony export */ __webpack_require__.d(__webpack_exports__, {
28290
- /* harmony export */ $5: () => (/* binding */ getUniqueFileName),
28291
- /* harmony export */ mF: () => (/* binding */ encodeUrlForImageSrc),
28292
- /* harmony export */ nF: () => (/* binding */ formatFileSizeDisplay),
28293
- /* harmony export */ v7: () => (/* binding */ formatFileSize),
28294
- /* harmony export */ w3: () => (/* binding */ MAX_FILE_SIZE)
28295
- /* harmony export */ });
28296
- /* unused harmony exports MIN_FILE_SIZE, ALLOWED_FILE_TYPES, ALL_ALLOWED_TYPES, validateFile, validateFiles, validateFileUrl, getFileCategory, formatFileSizeShort, sanitizeFileName */
28297
- /* harmony import */ var antd__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(550);
28298
- /* harmony import */ var antd__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(antd__WEBPACK_IMPORTED_MODULE_0__);
28299
- /* harmony import */ var _i18n__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3829);
28300
-
28301
-
28302
- const MAX_FILE_SIZE = 50 * 1024 * 1024;
28303
- const MIN_FILE_SIZE = 1;
28304
- const ALLOWED_FILE_TYPES = {
28305
- images: ['image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/svg+xml', 'image/bmp', 'image/tiff'],
28306
- documents: [
28307
- 'application/pdf',
28308
- 'text/plain',
28309
- 'application/msword',
28310
- 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
28311
- ],
28312
- archives: ['application/zip', 'application/x-rar-compressed', 'application/x-7z-compressed'],
28313
- videos: ['video/mp4', 'video/avi', 'video/quicktime', 'video/x-msvideo'],
28314
- audio: ['audio/mpeg', 'audio/wav', 'audio/ogg'],
28315
- };
28316
- const ALL_ALLOWED_TYPES = Object.values(ALLOWED_FILE_TYPES).flat();
28317
- const validateFile = (file, options = {}) => {
28318
- const { maxSize = MAX_FILE_SIZE, minSize = MIN_FILE_SIZE, allowedTypes = ALL_ALLOWED_TYPES, allowAllTypes = false, maxFileNameLength = 255, } = options;
28319
- const errors = [];
28320
- const warnings = [];
28321
- if (file.size > maxSize) {
28322
- errors.push(i18n.t('File too large. Maximum size: {{size}}', { size: formatFileSize(maxSize) }));
28323
- }
28324
- if (file.size < minSize) {
28325
- errors.push(i18n.t('File too small. Minimum size: {{size}}', { size: formatFileSize(minSize) }));
28326
- }
28327
- if (!allowAllTypes && !allowedTypes.includes(file.type)) {
28328
- errors.push(i18n.t('Unsupported file type: {{type}}', { type: file.type || i18n.t('unknown') }));
28329
- }
28330
- if (file.name.length > maxFileNameLength) {
28331
- errors.push(i18n.t('File name is too long. Maximum {{max}} characters', { max: maxFileNameLength }));
28332
- }
28333
- const invalidChars = /[<>:"/\\|?*()#]/;
28334
- const hasControlChars = file.name.split('').some(char => {
28335
- const code = char.charCodeAt(0);
28336
- return code >= 0 && code <= 31;
28337
- });
28338
- if (invalidChars.test(file.name) || hasControlChars) {
28339
- errors.push(i18n.t('File name contains invalid characters'));
28340
- }
28341
- if (file.size > 10 * 1024 * 1024) {
28342
- warnings.push(i18n.t('Large file may take a long time to upload'));
28343
- }
28344
- return {
28345
- isValid: errors.length === 0,
28346
- errors,
28347
- warnings,
28348
- };
28349
- };
28350
- const validateFiles = (files, options = {}) => {
28351
- const valid = [];
28352
- const invalid = [];
28353
- files.forEach(file => {
28354
- const result = validateFile(file, options);
28355
- if (result.isValid) {
28356
- valid.push(file);
28357
- }
28358
- else {
28359
- invalid.push({ file, result });
28360
- }
28361
- });
28362
- return { valid, invalid };
28363
- };
28364
- const validateFileUrl = async (url) => {
28365
- const errors = [];
28366
- let notified = false;
28367
- let lastError = undefined;
28368
- const notifyError = (message) => {
28369
- notified = true;
28370
- notification.error({
28371
- key: 'FILE_URL_VALIDATION_FAILED',
28372
- title: message,
28373
- placement: 'bottomRight',
28374
- description: url,
28375
- });
28376
- };
28377
- try {
28378
- new URL(url);
28379
- }
28380
- catch (error) {
28381
- console.error('Invalid URL:', error);
28382
- lastError = error;
28383
- const message = i18n.t('Invalid file URL');
28384
- errors.push(message);
28385
- notifyError(message);
28386
- return { isValid: false, errors };
28387
- }
28388
- try {
28389
- const response = await fetch(url, { method: 'HEAD' });
28390
- if (!response.ok) {
28391
- errors.push(i18n.t('File unavailable: {{status}} {{statusText}}', {
28392
- status: response.status,
28393
- statusText: response.statusText,
28394
- }));
28395
- }
28396
- const contentLength = response.headers.get('content-length');
28397
- if (contentLength && parseInt(contentLength) > MAX_FILE_SIZE) {
28398
- errors.push(i18n.t('File too large: {{size}}', { size: formatFileSize(parseInt(contentLength)) }));
28399
- }
28400
- const contentType = response.headers.get('content-type');
28401
- if (contentType && !ALL_ALLOWED_TYPES.includes(contentType)) {
28402
- errors.push(i18n.t('Unsupported file type: {{contentType}}', { contentType }));
28403
- }
28404
- }
28405
- catch (error) {
28406
- console.error('Failed to validate file URL:', error);
28407
- lastError = error;
28408
- const message = i18n.t('Unable to validate file URL');
28409
- errors.push(message);
28410
- notifyError(message);
28411
- }
28412
- if (errors.length > 0 && !notified) {
28413
- notifyError(i18n.t('Unable to validate file URL'));
28414
- }
28415
- return {
28416
- isValid: errors.length === 0,
28417
- errors,
28418
- };
28419
- };
28420
- const getFileCategory = (file) => {
28421
- const type = file.type;
28422
- if (ALLOWED_FILE_TYPES.images.includes(type))
28423
- return 'image';
28424
- if (ALLOWED_FILE_TYPES.documents.includes(type))
28425
- return 'document';
28426
- if (ALLOWED_FILE_TYPES.archives.includes(type))
28427
- return 'archive';
28428
- if (ALLOWED_FILE_TYPES.videos.includes(type))
28429
- return 'video';
28430
- if (ALLOWED_FILE_TYPES.audio.includes(type))
28431
- return 'audio';
28432
- return 'other';
28433
- };
28434
- const formatFileSize = (bytes) => {
28435
- if (bytes === 0)
28436
- return '0 Bytes';
28437
- const k = 1024;
28438
- const sizes = ['Bytes', 'KB', 'MB', 'GB'];
28439
- const i = Math.floor(Math.log(bytes) / Math.log(k));
28440
- return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
28441
- };
28442
- const formatFileSizeShort = (bytes) => {
28443
- if (!bytes || bytes <= 0)
28444
- return '';
28445
- const KILOBYTE = 1024;
28446
- const MEGABYTE = KILOBYTE * 1024;
28447
- if (bytes < MEGABYTE) {
28448
- const kb = Math.round(bytes / KILOBYTE);
28449
- return `${kb} Kb`;
28450
- }
28451
- const mb = bytes / MEGABYTE;
28452
- return `${mb.toFixed(2)} Mb`;
28453
- };
28454
- const formatFileSizeDisplay = (value) => {
28455
- if (value === undefined || value === null)
28456
- return '';
28457
- if (typeof value === 'number') {
28458
- return formatFileSizeShort(value);
28459
- }
28460
- const normalized = String(value).trim();
28461
- if (!normalized)
28462
- return '';
28463
- const parsed = Number(normalized);
28464
- if (!Number.isNaN(parsed)) {
28465
- return formatFileSizeShort(parsed);
28466
- }
28467
- return normalized;
28468
- };
28469
- /**
28470
- * Генерирует уникальное имя файла: если name уже есть в existingNames, добавляет _1 (или _2, _3 и т.д.).
28471
- * @param name — исходное имя файла (с расширением)
28472
- * @param existingNames — массив имён файлов/папок в целевой директории
28473
- */
28474
- const getUniqueFileName = (name, existingNames) => {
28475
- const safeNames = existingNames.filter((n) => typeof n === 'string');
28476
- const set = new Set(safeNames.map(n => n.toLowerCase()));
28477
- const safeName = typeof name === 'string' ? name : String(name !== null && name !== void 0 ? name : '');
28478
- if (!set.has(safeName.toLowerCase()))
28479
- return safeName;
28480
- const lastDot = safeName.lastIndexOf('.');
28481
- const baseName = lastDot > 0 ? safeName.slice(0, lastDot) : safeName;
28482
- const ext = lastDot > 0 ? safeName.slice(lastDot) : '';
28483
- let suffix = 1;
28484
- let candidate;
28485
- do {
28486
- candidate = `${baseName}_${suffix}${ext}`;
28487
- suffix++;
28488
- } while (set.has(candidate.toLowerCase()));
28489
- return candidate;
28490
- };
28491
- /**
28492
- * Кодирует URL для безопасного использования в img src. Решает проблему с кириллицей и другими
28493
- * не-ASCII символами в пути (например, emcdn.ru/.../Снимок_экрана.png).
28494
- * data: и blob: URLs возвращаются без изменений.
28495
- */
28496
- const encodeUrlForImageSrc = (url) => {
28497
- if (!url || typeof url !== 'string')
28498
- return undefined;
28499
- if (url.startsWith('data:') || url.startsWith('blob:'))
28500
- return url;
28501
- try {
28502
- if (url.startsWith('http://') || url.startsWith('https://') || url.startsWith('/')) {
28503
- const parsed = new URL(url.startsWith('/') ? `https://x${url}` : url);
28504
- const origin = url.startsWith('/') ? '' : `${parsed.protocol}//${parsed.host}`;
28505
- const pathEncoded = parsed.pathname
28506
- .split('/')
28507
- .map(seg => {
28508
- if (!seg)
28509
- return '';
28510
- try {
28511
- return encodeURIComponent(decodeURIComponent(seg));
28512
- }
28513
- catch (_a) {
28514
- return encodeURIComponent(seg);
28515
- }
28516
- })
28517
- .join('/');
28518
- const result = url.startsWith('/') ? pathEncoded + (parsed.search || '') + (parsed.hash || '') : `${origin}${pathEncoded}${parsed.search}${parsed.hash}`;
28519
- return result;
28520
- }
28521
- }
28522
- catch (_a) {
28523
- // если парсинг не удался, возвращаем как есть
28524
- }
28525
- return url;
28526
- };
28527
- /**
28528
- * @deprecated Эта функция оставлена только для обратной совместимости.
28529
- * Используйте {@link normalizeFileName} из `nameNormalization.ts` для настраиваемой нормализации имен файлов.
28530
- *
28531
- * Упрощенная санитизация имени файла:
28532
- * - Заменяет запрещенные символы на `_`
28533
- * - Заменяет пробелы на `_`
28534
- * - Удаляет множественные подчеркивания
28535
- * - Ограничивает длину до 255 символов
28536
- */
28537
- const sanitizeFileName = (fileName) => {
28538
- return fileName
28539
- .replace(/[<>:"/\\|?*()#]/g, '_')
28540
- .split('')
28541
- .map(char => {
28542
- const code = char.charCodeAt(0);
28543
- return code >= 0 && code <= 31 ? '_' : char;
28544
- })
28545
- .join('')
28546
- .replace(/\s+/g, '_')
28547
- .replace(/_{2,}/g, '_')
28548
- .substring(0, 255);
28549
- };
28550
-
28551
-
28552
- /***/ }),
28553
-
28554
- /***/ 9287:
28555
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
28556
-
28557
- // Imports
28558
- var ___CSS_LOADER_API_SOURCEMAP_IMPORT___ = __webpack_require__(1354);
28559
- var ___CSS_LOADER_API_IMPORT___ = __webpack_require__(6314);
28560
- var ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);
28561
- // Module
28562
- ___CSS_LOADER_EXPORT___.push([module.id, `.FolderSidebar-module__button__Yf2rX.ant-btn.ant-btn-icon-only{padding:calc(var(--paddingXXS)*1px) calc(var(--paddingSM)*1px);cursor:pointer;color:var(--colorTextSecondary);display:flex;gap:calc(var(--marginXS)*1px);align-items:center;justify-content:center;border-radius:calc(var(--borderRadiusSM)*1px);transition:all var(--motionDurationFast);box-shadow:none;border:none;width:32px;height:32px}.FolderSidebar-module__button__Yf2rX.ant-btn.ant-btn-icon-only:hover{background-color:var(--colorBgLayout);color:inherit}.FolderSidebar-module__button__Yf2rX:hover{background-color:var(--colorBgContainer);color:var(--colorPrimary)}.FolderSidebar-module__foldersTitle__Uh6u7{display:flex;align-items:center;flex:1;cursor:pointer}.FolderSidebar-module__folderActions__qA2Bk{position:absolute;top:4px;right:4px;display:flex;align-items:center;gap:4px;z-index:10}.FolderSidebar-module__folderActions__qA2Bk .FolderSidebar-module__button__Yf2rX.FolderSidebar-module__ant-btn__LXAXm.FolderSidebar-module__ant-btn-icon-only__j_wVF{padding:calc(var(--paddingXXS)*1px) calc(var(--paddingSM)*1px);cursor:pointer;color:var(--colorTextSecondary);display:flex;gap:calc(var(--marginXS)*1px);align-items:center;justify-content:center;border-radius:calc(var(--borderRadiusSM)*1px);transition:all var(--motionDurationFast);box-shadow:none;border:none;width:32px;height:32px}.FolderSidebar-module__folderActions__qA2Bk .FolderSidebar-module__button__Yf2rX.FolderSidebar-module__ant-btn__LXAXm.FolderSidebar-module__ant-btn-icon-only__j_wVF:hover{background-color:var(--colorBgLayout);color:inherit}.FolderSidebar-module__customExpandIcon__IhZJl{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;margin-right:8px;cursor:pointer;color:#666;font-size:10px;transition:transform .2s ease}.FolderSidebar-module__customExpandIcon__IhZJl:hover{color:var(--colorPrimary)}.FolderSidebar-module__fileCount__bD9DD{display:inline-flex;align-items:center;justify-content:center;min-width:20px;height:100%;padding:0 6px;margin-left:8px;color:#8d8d8d;font-size:14px;font-weight:500;transition:all .2s ease;white-space:nowrap;cursor:default;flex-shrink:0;margin-right:10px}.ant-tree .ant-tree-node-content-wrapper.ant-tree-node-selected{background-color:rgba(0,0,0,0) !important}.FolderSidebar-module__folderMenu__JCzLF .ant-tree-treenode-selected .folder-label span,.FolderSidebar-module__folderMenu__JCzLF .ant-tree .ant-tree-node-content-wrapper.ant-tree-node-selected .folderLabelItem,.FolderSidebar-module__folderMenu__JCzLF .ant-tree-treenode-selected .folderLabelItem,.FolderSidebar-module__folderMenu__JCzLF .ant-tree-node-selected .folderLabelItem{font-weight:600 !important}.FolderSidebar-module__uploadButton__QQUid{width:100%;justify-content:flex-start}.FolderSidebar-module__uploadButton__QQUid button:hover{background-color:var(--colorPrimaryHover) !important}.FolderSidebar-module__folderMenu__JCzLF{padding-left:0;padding-right:0}.FolderSidebar-module__folderMenu__JCzLF .ant-tree-treenode{display:flex;align-items:center;justify-content:space-between;padding:4px 0;border-radius:4px;transition:background-color .2s ease;width:100%;margin-bottom:0}.FolderSidebar-module__folderMenu__JCzLF .ant-tree-node-content-wrapper{flex:1;align-items:center;padding:0;transition:background-color .2s ease}.FolderSidebar-module__folderMenu__JCzLF .ant-tree-node-content-wrapper:hover{background-color:rgba(0,0,0,0)}.FolderSidebar-module__folderMenu__JCzLF .ant-tree-switcher{height:24px;width:24px;margin-top:5px;display:flex !important;align-items:center;justify-content:center;transition:color .2s ease;flex-shrink:0}.FolderSidebar-module__folderMenu__JCzLF .ant-tree-switcher-noop{width:24px}.FolderSidebar-module__folderMenu__JCzLF .ant-tree-switcher-line-icon{color:#d9d9d9}.FolderSidebar-module__folderMenu__JCzLF .FolderSidebar-module__folderItemContainer__byl5b{width:100%;display:flex;align-items:center;justify-content:space-between;padding:2px 0;min-width:0}.FolderSidebar-module__folderMenu__JCzLF .folder-label{display:flex;align-items:center;flex:1;color:#595959;font-size:14px;min-width:0;overflow:hidden}.FolderSidebar-module__folderMenu__JCzLF .ant-tree-treenode[data-key="folders"]{border-bottom:1px solid var(--colorBorderSecondary);margin-bottom:8px;padding-bottom:8px}.FolderSidebar-module__folderMenu__JCzLF .ant-tree-treenode[data-key="folders"].ant-tree-treenode-selected{background-color:rgba(0,0,0,0) !important}.FolderSidebar-module__folderMenu__JCzLF .ant-tree-treenode[data-key="folders"] .ant-tree-node-content-wrapper{padding:0}.FolderSidebar-module__folderMenu__JCzLF .ant-tree-treenode[data-key="folders"] .ant-tree-node-content-wrapper:hover{background-color:rgba(0,0,0,0) !important}.FolderSidebar-module__folderMenu__JCzLF .ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0}.FolderSidebar-module__folderMenu__JCzLF .FolderSidebar-module__emptyFolderContainer__WK6tx{padding:20px;text-align:center}.FolderSidebar-module__folderMenu__JCzLF .ant-tree > .ant-tree-treenode{padding-left:0 !important}.FolderSidebar-module__folderIcon__UoZzH{margin-right:8px;font-size:18px;flex-shrink:0}.FolderSidebar-module__folderLabelItem__uJ062{font-size:14px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex:1;min-width:0;user-select:none}.FolderSidebar-module__foldersTitleItem__gapOI{display:flex;align-items:center;flex:1;cursor:pointer;min-width:0;overflow:hidden}.FolderSidebar-module__folderLabel__fHWMp{display:flex;align-items:center;flex:1;min-width:0;overflow:hidden}.FolderSidebar-module__foldersContainer__zdBVU{position:relative;width:100%}.FolderSidebar-module__uploadButton__QQUid .FolderSidebar-module__ant-btn__LXAXm,.FolderSidebar-module__uploadButton__QQUid .ant-btn{display:flex;align-items:center;justify-content:center;gap:3px}.FolderSidebar-module__buttonWrapper__a9Qi5{margin-bottom:24px;display:flex;gap:4px}.FolderSidebar-module__buttonWrapper__a9Qi5>:first-child{flex:1;height:40px;padding-left:10px}.FolderSidebar-module__buttonWrapper__a9Qi5>:last-child{width:40px;height:40px;flex-shrink:0}.FolderSidebar-module__uploadButtonIcon__mWQmq{font-size:20px}.FolderSidebar-module__uploadButtonTitle__wk_o6{line-height:1em}.FolderSidebar-module__emptyFolderContainer__WK6tx{user-select:none;cursor:default;color:var(--colorTextTertiary)}.FolderSidebar-module__folderItemContainer__byl5b{width:100%;display:flex;align-items:center;justify-content:space-between;padding:2px 0;min-width:0}`, "",{"version":3,"sources":["webpack://./src/components/FolderSidebar/FolderSidebar.module.scss"],"names":[],"mappings":"AAAA,+DACI,8DAAA,CACA,cAAA,CACA,+BAAA,CACA,YAAA,CACA,6BAAA,CACA,kBAAA,CACA,sBAAA,CACA,6CAAA,CACA,wCAAA,CACA,eAAA,CAEA,WAAA,CACA,UAAA,CACA,WAAA,CAEA,qEACI,qCAAA,CACA,aAAA,CAIR,2CACI,wCAAA,CACA,yBAAA,CAGJ,2CACE,YAAA,CACA,kBAAA,CACA,MAAA,CACA,cAAA,CAGF,4CACI,iBAAA,CACA,OAAA,CACA,SAAA,CACA,YAAA,CACA,kBAAA,CACA,OAAA,CACA,UAAA,CAEA,qKACE,8DAAA,CACA,cAAA,CACA,+BAAA,CACA,YAAA,CACA,6BAAA,CACA,kBAAA,CACA,sBAAA,CACA,6CAAA,CACA,wCAAA,CACA,eAAA,CAEA,WAAA,CACA,UAAA,CACA,WAAA,CAEA,2KACI,qCAAA,CACA,aAAA,CAKV,+CACE,mBAAA,CACA,kBAAA,CACA,sBAAA,CACA,UAAA,CACA,WAAA,CACA,gBAAA,CACA,cAAA,CACA,UAAA,CACA,cAAA,CACA,6BAAA,CAGF,qDACI,yBAAA,CAGJ,wCACE,mBAAA,CACA,kBAAA,CACA,sBAAA,CACA,cAAA,CACE,WAAA,CACF,aAAA,CACA,eAAA,CACE,aAAA,CACA,cAAA,CACF,eAAA,CACA,uBAAA,CACA,kBAAA,CACA,cAAA,CACA,aAAA,CACA,iBAAA,CAQF,gEACE,yCAAA,CAQF,0XAIE,0BAAA,CAWF,2CACI,UAAA,CACA,0BAAA,CAEA,wDACE,oDAAA,CAIN,yCACE,cAAA,CACA,eAAA,CAGF,4DACE,YAAA,CACA,kBAAA,CACA,6BAAA,CACA,aAAA,CACA,iBAAA,CACA,oCAAA,CACA,UAAA,CACA,eAAA,CAGF,wEACE,MAAA,CAEA,kBAAA,CACA,SAAA,CAEA,oCAAA,CAGF,8EACE,8BAAA,CAGF,4DACE,WAAA,CACA,UAAA,CACA,cAAA,CACA,uBAAA,CACA,kBAAA,CACA,sBAAA,CACA,yBAAA,CACA,aAAA,CAGF,iEACE,UAAA,CAIF,sEACE,aAAA,CAIF,2FACE,UAAA,CACA,YAAA,CACA,kBAAA,CACA,6BAAA,CACA,aAAA,CACA,WAAA,CAGF,uDACE,YAAA,CACA,kBAAA,CACA,MAAA,CACA,aAAA,CACA,cAAA,CACA,WAAA,CACA,eAAA,CAIF,gFACI,mDAAA,CACF,iBAAA,CACA,kBAAA,CAGF,2GACE,yCAAA,CAGF,+GACE,SAAA,CAGF,qHACE,yCAAA,CAIF,mDACE,eAAA,CACA,sBAAA,CACA,kBAAA,CACA,MAAA,CACA,WAAA,CAIF,4FACE,YAAA,CACA,iBAAA,CAIF,wEACE,yBAAA,CAEF,yCACE,gBAAA,CACE,cAAA,CACF,aAAA,CAGF,8CACE,cAAA,CACA,kBAAA,CACA,eAAA,CACA,sBAAA,CACA,MAAA,CACA,WAAA,CACA,gBAAA,CAGF,+CACE,YAAA,CACA,kBAAA,CACA,MAAA,CACA,cAAA,CACA,WAAA,CACA,eAAA,CASF,0CACE,YAAA,CACA,kBAAA,CACA,MAAA,CACA,WAAA,CACA,eAAA,CAGF,+CACE,iBAAA,CACA,UAAA,CAWF,qIAEE,YAAA,CACA,kBAAA,CACA,sBAAA,CACA,OAAA,CAaF,4CAEI,kBAAA,CACA,YAAA,CACA,OAAA,CAIA,yDACI,MAAA,CACA,WAAA,CACA,iBAAA,CAIJ,wDACI,UAAA,CACA,WAAA,CACA,aAAA,CAIR,+CACI,cAAA,CAGJ,gDACI,eAAA,CAGJ,mDACI,gBAAA,CACA,cAAA,CACA,8BAAA,CAGJ,kDACI,UAAA,CACA,YAAA,CACA,kBAAA,CACA,6BAAA,CACA,aAAA,CACA,WAAA","sourcesContent":[".button:global(.ant-btn.ant-btn-icon-only) {\r\n padding: calc(var(--paddingXXS) * 1px) calc(var(--paddingSM) * 1px);\r\n cursor: pointer;\r\n color: var(--colorTextSecondary);\r\n display: flex;\r\n gap: calc(var(--marginXS) * 1px);\r\n align-items: center;\r\n justify-content: center;\r\n border-radius: calc(var(--borderRadiusSM) * 1px);\r\n transition: all var(--motionDurationFast);\r\n box-shadow: none;\r\n\r\n border: none;\r\n width: 32px;\r\n height: 32px;\r\n\r\n &:hover {\r\n background-color: var(--colorBgLayout);\r\n color: inherit;\r\n }\r\n}\r\n\r\n.button:hover {\r\n background-color: var(--colorBgContainer);\r\n color: var(--colorPrimary);\r\n}\r\n\r\n.foldersTitle {\r\n display: flex;\r\n align-items: center;\r\n flex: 1;\r\n cursor: pointer;\r\n}\r\n\r\n.folderActions {\r\n position: absolute;\r\n top: 4px; /* Выравниваем по заголовку Folders */\r\n right: 4px;\r\n display: flex;\r\n align-items: center;\r\n gap: 4px;\r\n z-index: 10;\r\n\r\n .button.ant-btn.ant-btn-icon-only {\r\n padding: calc(var(--paddingXXS) * 1px) calc(var(--paddingSM) * 1px);\r\n cursor: pointer;\r\n color: var(--colorTextSecondary);\r\n display: flex;\r\n gap: calc(var(--marginXS) * 1px);\r\n align-items: center;\r\n justify-content: center;\r\n border-radius: calc(var(--borderRadiusSM) * 1px);\r\n transition: all var(--motionDurationFast);\r\n box-shadow: none;\r\n\r\n border: none;\r\n width: 32px;\r\n height: 32px;\r\n\r\n &:hover {\r\n background-color: var(--colorBgLayout);\r\n color: inherit;\r\n }\r\n }\r\n}\r\n\r\n.customExpandIcon {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 16px;\r\n height: 16px;\r\n margin-right: 8px;\r\n cursor: pointer;\r\n color: #666;\r\n font-size: 10px;\r\n transition: transform 0.2s ease;\r\n}\r\n\r\n.customExpandIcon:hover {\r\n color: var(--colorPrimary);\r\n}\r\n\r\n.fileCount {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n min-width: 20px;\r\n height: 100%;\r\n padding: 0 6px;\r\n margin-left: 8px;\r\n color: #8D8D8D;\r\n font-size: 14px;\r\n font-weight: 500;\r\n transition: all 0.2s ease;\r\n white-space: nowrap;\r\n cursor: default;\r\n flex-shrink: 0; /* Запрещаем сжатие счетчика */\r\n margin-right: 10px;\r\n}\r\n\r\n// .fileCount:hover {\r\n// border-color: var(--colorPrimary);\r\n// color: var(--colorPrimary);\r\n// }\r\n\r\n:global(.ant-tree .ant-tree-node-content-wrapper.ant-tree-node-selected) {\r\n background-color: transparent !important;\r\n}\r\n\r\n/* :global(.ant-tree .ant-tree-node-content-wrapper.ant-tree-node-selected):hover {\r\n color: red !important;\r\n} */\r\n\r\n/* Стили для выделения текста в выбранной папке */\r\n.folderMenu :global(.ant-tree-treenode-selected .folder-label span),\r\n.folderMenu :global(.ant-tree .ant-tree-node-content-wrapper.ant-tree-node-selected .folderLabelItem),\r\n.folderMenu :global(.ant-tree-treenode-selected .folderLabelItem),\r\n.folderMenu :global(.ant-tree-node-selected .folderLabelItem) {\r\n font-weight: 600 !important;\r\n}\r\n\r\n/* Стили для иконки в выбранной папке */\r\n/* .folderMenu :global(.ant-tree-treenode-selected .folderIcon),\r\n.folderMenu :global(.ant-tree-node-selected .folderIcon) {\r\n color: red !important;\r\n} */\r\n\r\n/* CSS переменные для упрощения расчетов */\r\n\r\n.uploadButton {\r\n width: 100%;\r\n justify-content: flex-start;\r\n\r\n & button:hover {\r\n background-color: var(--colorPrimaryHover) !important;\r\n }\r\n}\r\n\r\n.folderMenu {\r\n padding-left: 0;\r\n padding-right: 0; /* Место для кнопки справа */\r\n}\r\n\r\n.folderMenu :global(.ant-tree-treenode) {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 4px 0;\r\n border-radius: 4px;\r\n transition: background-color 0.2s ease;\r\n width: 100%;\r\n margin-bottom: 0;\r\n}\r\n\r\n.folderMenu :global(.ant-tree-node-content-wrapper) {\r\n flex: 1;\r\n /* display: flex; */\r\n align-items: center;\r\n padding: 0;\r\n /* border-radius: 4px; */\r\n transition: background-color 0.2s ease;\r\n}\r\n\r\n.folderMenu :global(.ant-tree-node-content-wrapper:hover) {\r\n background-color: transparent;\r\n}\r\n\r\n.folderMenu :global(.ant-tree-switcher) {\r\n height: 24px;\r\n width: 24px;\r\n margin-top: 5px;\r\n display: flex !important;\r\n align-items: center;\r\n justify-content: center;\r\n transition: color 0.2s ease;\r\n flex-shrink: 0; /* Запрещаем сжатие переключателя */\r\n}\r\n\r\n.folderMenu :global(.ant-tree-switcher-noop) {\r\n width: 24px;\r\n}\r\n\r\n/* Стили для линий дерева */\r\n.folderMenu :global(.ant-tree-switcher-line-icon) {\r\n color: #d9d9d9;\r\n}\r\n\r\n/* Улучшение отображения folder-item-container */\r\n.folderMenu .folderItemContainer {\r\n width: 100%;\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 2px 0;\r\n min-width: 0; /* Позволяет flex-элементам сжиматься */\r\n}\r\n\r\n.folderMenu :global(.folder-label) {\r\n display: flex;\r\n align-items: center;\r\n flex: 1;\r\n color: #595959;\r\n font-size: 14px;\r\n min-width: 0;\r\n overflow: hidden;\r\n}\r\n\r\n/* Стили для корневого элемента Folders */\r\n.folderMenu :global(.ant-tree-treenode[data-key='folders']) {\r\n border-bottom: 1px solid var(--colorBorderSecondary);\r\n margin-bottom: 8px;\r\n padding-bottom: 8px;\r\n}\r\n\r\n.folderMenu :global(.ant-tree-treenode[data-key='folders'].ant-tree-treenode-selected) {\r\n background-color: transparent !important;\r\n}\r\n\r\n.folderMenu :global(.ant-tree-treenode[data-key='folders'] .ant-tree-node-content-wrapper) {\r\n padding: 0;\r\n}\r\n\r\n.folderMenu :global(.ant-tree-treenode[data-key='folders'] .ant-tree-node-content-wrapper:hover) {\r\n background-color: transparent !important;\r\n}\r\n\r\n/* Стили для ellipsis - удаляем max-width для гибкости */\r\n.folderMenu :global(.ellipsis) {\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n flex: 1;\r\n min-width: 0;\r\n}\r\n\r\n/* Стили для пустого состояния */\r\n.folderMenu .emptyFolderContainer {\r\n padding: 20px;\r\n text-align: center;\r\n}\r\n\r\n/* Убираем отступы у корневого узла */\r\n.folderMenu :global(.ant-tree > .ant-tree-treenode) {\r\n padding-left: 0 !important;\r\n}\r\n.folderIcon {\r\n margin-right: 8px;\r\n font-size: 18px;\r\n flex-shrink: 0; /* Запрещаем сжатие иконки */\r\n}\r\n\r\n.folderLabelItem {\r\n font-size: 14px;\r\n white-space: nowrap; /* Запрещаем перенос строк */\r\n overflow: hidden; /* Скрываем переполнение */\r\n text-overflow: ellipsis; /* Показываем троеточие */\r\n flex: 1; /* Занимает доступное место */\r\n min-width: 0; /* Позволяет сжиматься */\r\n user-select: none;\r\n}\r\n\r\n.foldersTitleItem {\r\n display: flex;\r\n align-items: center;\r\n flex: 1;\r\n cursor: pointer;\r\n min-width: 0; /* Позволяет сжиматься */\r\n overflow: hidden; /* Скрываем переполнение */\r\n}\r\n\r\n/* .foldersTitleItem .folderLabelItem {\r\n font-weight: 500;\r\n color: #262626;\r\n} */\r\n\r\n/* Класс для заголовка папок */\r\n.folderLabel {\r\n display: flex;\r\n align-items: center;\r\n flex: 1;\r\n min-width: 0;\r\n overflow: hidden;\r\n}\r\n\r\n.foldersContainer {\r\n position: relative;\r\n width: 100%;\r\n}\r\n\r\n/* Дополнительные стили для улучшения визуала */\r\n/* .folderMenu :global(.ant-tree-treenode:hover .folder-label span) {\r\n color: #1890ff;\r\n} */\r\n\r\n/* Стили для дивайдера между папками */\r\n\r\n\r\n.uploadButton .ant-btn,\r\n.uploadButton :global(.ant-btn) {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n gap: 3px;\r\n}\r\n/* .folderMenu :global(.ant-tree-treenode-selected) .folderLabelItem {\r\n color: #1890ff !important;\r\n} */\r\n\r\n// .folderMenu :global(.ant-tree-treenode-selected) .folderLabel .folderLabelItem,\r\n// .folderMenu :global(.ant-tree-treenode-selected) .folderLabel .folderIcon,\r\n// .folderMenu :global(.ant-tree-treenode-selected) .folderLabelItem {\r\n// color: var(--colorLink);\r\n// }\r\n\r\n\r\n.buttonWrapper {\r\n // overflow: hidden;\r\n margin-bottom: 24px;\r\n display: flex;\r\n gap: 4px;\r\n // border-radius: calc(var(--borderRadius) * 1px);\r\n \r\n // Левая кнопка занимает всю доступную ширину\r\n > :first-child {\r\n flex: 1;\r\n height: 40px;\r\n padding-left: 10px;\r\n }\r\n \r\n // Правая кнопка строго 40px\r\n > :last-child {\r\n width: 40px;\r\n height: 40px;\r\n flex-shrink: 0;\r\n }\r\n}\r\n\r\n.uploadButtonIcon {\r\n font-size: 20px;\r\n}\r\n\r\n.uploadButtonTitle {\r\n line-height: 1em;\r\n}\r\n\r\n.emptyFolderContainer {\r\n user-select: none;\r\n cursor: default;\r\n color: var(--colorTextTertiary);\r\n}\r\n\r\n.folderItemContainer {\r\n width: 100%;\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 2px 0;\r\n min-width: 0; /* Позволяет flex-элементам сжиматься */\r\n}\r\n"],"sourceRoot":""}]);
28563
- // Exports
28564
- ___CSS_LOADER_EXPORT___.locals = {
28565
- "button": `FolderSidebar-module__button__Yf2rX`,
28566
- "foldersTitle": `FolderSidebar-module__foldersTitle__Uh6u7`,
28567
- "folderActions": `FolderSidebar-module__folderActions__qA2Bk`,
28568
- "ant-btn": `FolderSidebar-module__ant-btn__LXAXm`,
28569
- "antBtn": `FolderSidebar-module__ant-btn__LXAXm`,
28570
- "ant-btn-icon-only": `FolderSidebar-module__ant-btn-icon-only__j_wVF`,
28571
- "antBtnIconOnly": `FolderSidebar-module__ant-btn-icon-only__j_wVF`,
28572
- "customExpandIcon": `FolderSidebar-module__customExpandIcon__IhZJl`,
28573
- "fileCount": `FolderSidebar-module__fileCount__bD9DD`,
28574
- "folderMenu": `FolderSidebar-module__folderMenu__JCzLF`,
28575
- "uploadButton": `FolderSidebar-module__uploadButton__QQUid`,
28576
- "folderItemContainer": `FolderSidebar-module__folderItemContainer__byl5b`,
28577
- "emptyFolderContainer": `FolderSidebar-module__emptyFolderContainer__WK6tx`,
28578
- "folderIcon": `FolderSidebar-module__folderIcon__UoZzH`,
28579
- "folderLabelItem": `FolderSidebar-module__folderLabelItem__uJ062`,
28580
- "foldersTitleItem": `FolderSidebar-module__foldersTitleItem__gapOI`,
28581
- "folderLabel": `FolderSidebar-module__folderLabel__fHWMp`,
28582
- "foldersContainer": `FolderSidebar-module__foldersContainer__zdBVU`,
28583
- "buttonWrapper": `FolderSidebar-module__buttonWrapper__a9Qi5`,
28584
- "uploadButtonIcon": `FolderSidebar-module__uploadButtonIcon__mWQmq`,
28585
- "uploadButtonTitle": `FolderSidebar-module__uploadButtonTitle__wk_o6`
28586
- };
28587
- module.exports = ___CSS_LOADER_EXPORT___;
28588
-
28589
-
28590
- /***/ }),
28591
-
28592
- /***/ 9557:
28285
+ /***/ 8573:
28593
28286
  /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
28594
28287
 
28595
28288
  "use strict";
@@ -28735,6 +28428,27 @@ var dedupeUploadNamesOnClient = __webpack_require__(3795);
28735
28428
  var utils_resolveUniqueUploadName = __webpack_require__(7742);
28736
28429
  // EXTERNAL MODULE: ./src/utils/fileFormatUtils.ts
28737
28430
  var fileFormatUtils = __webpack_require__(6825);
28431
+ ;// ./src/utils/mapWithConcurrency.ts
28432
+ async function mapWithConcurrency(items, limit, fn) {
28433
+ if (items.length === 0) {
28434
+ return [];
28435
+ }
28436
+ const results = new Array(items.length);
28437
+ let nextIndex = 0;
28438
+ const poolSize = Math.max(1, Math.min(limit, items.length));
28439
+ const worker = async () => {
28440
+ while (true) {
28441
+ const currentIndex = nextIndex++;
28442
+ if (currentIndex >= items.length) {
28443
+ return;
28444
+ }
28445
+ results[currentIndex] = await fn(items[currentIndex], currentIndex);
28446
+ }
28447
+ };
28448
+ await Promise.all(Array.from({ length: poolSize }, () => worker()));
28449
+ return results;
28450
+ }
28451
+
28738
28452
  // EXTERNAL MODULE: ./src/hooks/core/context.tsx
28739
28453
  var context = __webpack_require__(8361);
28740
28454
  // EXTERNAL MODULE: ./src/constants/index.tsx
@@ -28766,6 +28480,8 @@ var fileManagerApiError = __webpack_require__(7036);
28766
28480
 
28767
28481
 
28768
28482
 
28483
+
28484
+ const UPLOAD_IMAGE_PREPARE_CONCURRENCY = 4;
28769
28485
  /**
28770
28486
  * Проверяет, нужно ли сжимать изображение
28771
28487
  */
@@ -29674,7 +29390,7 @@ const useFilesAPI = () => {
29674
29390
  }
29675
29391
  }, [resolveTargetFolderId]);
29676
29392
  const uploadFilesBatch = (0,external_root_React_commonjs2_react_commonjs_react_amd_react_.useCallback)(async (filesToUpload, progressCallbacks) => {
29677
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10;
29393
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0;
29678
29394
  if (filesToUpload.length === 0) {
29679
29395
  return { successCount: 0, failCount: 0, successes: [], errors: [], totalCount: 0 };
29680
29396
  }
@@ -29684,9 +29400,8 @@ const useFilesAPI = () => {
29684
29400
  const filtered = names.filter(Boolean);
29685
29401
  return filtered.length > 0 && filtered.length <= MAX_NAMES_PREVIEW ? filtered.join(', ') : null;
29686
29402
  };
29687
- const preparedItems = [];
29688
- for (let index = 0; index < filesToUpload.length; index++) {
29689
- const file = filesToUpload[index];
29403
+ const preparedResults = await mapWithConcurrency(filesToUpload, UPLOAD_IMAGE_PREPARE_CONCURRENCY, async (file, index) => {
29404
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
29690
29405
  if (!(0,mimeUtils/* isAllowedImageUploadFile */.rc)(file)) {
29691
29406
  const payload = await notification.warning({
29692
29407
  id: 'FILES_UPLOAD_UNSUPPORTED_TYPE',
@@ -29698,8 +29413,8 @@ const useFilesAPI = () => {
29698
29413
  folderId: selectedFolder || null,
29699
29414
  },
29700
29415
  });
29701
- (_b = progressCallbacks === null || progressCallbacks === void 0 ? void 0 : progressCallbacks.onError) === null || _b === void 0 ? void 0 : _b.call(progressCallbacks, file.name, payload.message);
29702
- continue;
29416
+ (_a = progressCallbacks === null || progressCallbacks === void 0 ? void 0 : progressCallbacks.onError) === null || _a === void 0 ? void 0 : _a.call(progressCallbacks, file.name, payload.message);
29417
+ return null;
29703
29418
  }
29704
29419
  // Нормализуем имя файла заранее для подготовки изображения и fallback
29705
29420
  const normalizedFileName = (0,nameNormalization/* normalizeFileName */.Px)(file.name, options === null || options === void 0 ? void 0 : options.config);
@@ -29707,24 +29422,19 @@ const useFilesAPI = () => {
29707
29422
  // eslint-disable-next-line sonarjs/no-dead-store
29708
29423
  let fileToUpload = file;
29709
29424
  try {
29710
- if ((0,mimeUtils/* isAllowedImageUploadFile */.rc)(file)) {
29711
- const maxSizeMB = (_d = (_c = options === null || options === void 0 ? void 0 : options.config) === null || _c === void 0 ? void 0 : _c.compressMaxSize) !== null && _d !== void 0 ? _d : fileFormatUtils/* IMAGE_COMPRESSION_DEFAULTS */.a9.MAX_SIZE_MB;
29712
- const maxWidthOrHeight = (_f = (_e = options === null || options === void 0 ? void 0 : options.config) === null || _e === void 0 ? void 0 : _e.compressMaxWidthOrHeight) !== null && _f !== void 0 ? _f : 2000;
29713
- const compressorUrl = (_h = (_g = options === null || options === void 0 ? void 0 : options.config) === null || _g === void 0 ? void 0 : _g.compessorUrl) !== null && _h !== void 0 ? _h : (_j = options === null || options === void 0 ? void 0 : options.config) === null || _j === void 0 ? void 0 : _j.compressorUrl;
29714
- const effectiveMime = ((_k = file.type) === null || _k === void 0 ? void 0 : _k.trim()) || (0,mimeUtils/* inferImageMimeFromFileName */.xU)(file.name) || file.type;
29715
- fileToUpload = await (0,imageCompression/* prepareImageForUpload */.j)(file, {
29716
- maxSizeMB,
29717
- maxWidthOrHeight,
29718
- mimeType: effectiveMime,
29719
- fileName: normalizedFileName,
29720
- libURL: compressorUrl,
29721
- enableCompression: shouldCompressImage(effectiveMime),
29722
- convertSvgToPng: true,
29723
- });
29724
- }
29725
- else {
29726
- fileToUpload = createNormalizedFile(file, normalizedFileName);
29727
- }
29425
+ const maxSizeMB = (_c = (_b = options === null || options === void 0 ? void 0 : options.config) === null || _b === void 0 ? void 0 : _b.compressMaxSize) !== null && _c !== void 0 ? _c : fileFormatUtils/* IMAGE_COMPRESSION_DEFAULTS */.a9.MAX_SIZE_MB;
29426
+ const maxWidthOrHeight = (_e = (_d = options === null || options === void 0 ? void 0 : options.config) === null || _d === void 0 ? void 0 : _d.compressMaxWidthOrHeight) !== null && _e !== void 0 ? _e : 2000;
29427
+ const compressorUrl = (_g = (_f = options === null || options === void 0 ? void 0 : options.config) === null || _f === void 0 ? void 0 : _f.compessorUrl) !== null && _g !== void 0 ? _g : (_h = options === null || options === void 0 ? void 0 : options.config) === null || _h === void 0 ? void 0 : _h.compressorUrl;
29428
+ const effectiveMime = ((_j = file.type) === null || _j === void 0 ? void 0 : _j.trim()) || (0,mimeUtils/* inferImageMimeFromFileName */.xU)(file.name) || file.type;
29429
+ fileToUpload = await (0,imageCompression/* prepareImageForUpload */.j)(file, {
29430
+ maxSizeMB,
29431
+ maxWidthOrHeight,
29432
+ mimeType: effectiveMime,
29433
+ fileName: normalizedFileName,
29434
+ libURL: compressorUrl,
29435
+ enableCompression: shouldCompressImage(effectiveMime),
29436
+ convertSvgToPng: true,
29437
+ });
29728
29438
  }
29729
29439
  catch (e) {
29730
29440
  console.warn('Image preparation failed, uploading original file', e);
@@ -29735,15 +29445,16 @@ const useFilesAPI = () => {
29735
29445
  // тогда результат будет сопоставлен по индексу массива.
29736
29446
  const requestId = `${Date.now()}-${index}-${Math.random().toString(36).slice(2, 8)}`;
29737
29447
  const targetFolderId = await resolveTargetFolderId(fileToUpload, selectedFolder);
29738
- (_l = progressCallbacks === null || progressCallbacks === void 0 ? void 0 : progressCallbacks.onStart) === null || _l === void 0 ? void 0 : _l.call(progressCallbacks, fileToUpload);
29739
- preparedItems.push({
29448
+ (_k = progressCallbacks === null || progressCallbacks === void 0 ? void 0 : progressCallbacks.onStart) === null || _k === void 0 ? void 0 : _k.call(progressCallbacks, fileToUpload);
29449
+ return {
29740
29450
  file: fileToUpload,
29741
29451
  targetFolderId,
29742
29452
  requestId,
29743
29453
  originalFileName: file.name,
29744
29454
  originalIndex: index,
29745
- });
29746
- }
29455
+ };
29456
+ });
29457
+ const preparedItems = preparedResults.filter((item) => item !== null);
29747
29458
  const totalCount = preparedItems.length;
29748
29459
  if (totalCount === 0) {
29749
29460
  return { successCount: 0, failCount: 0, successes: [], errors: [], totalCount: 0 };
@@ -29825,7 +29536,7 @@ const useFilesAPI = () => {
29825
29536
  },
29826
29537
  }, silent || !shouldEmitAnyNotifications);
29827
29538
  };
29828
- const maxFileSize = (_o = (_m = options === null || options === void 0 ? void 0 : options.config) === null || _m === void 0 ? void 0 : _m.maxFileSize) !== null && _o !== void 0 ? _o : fileValidation/* MAX_FILE_SIZE */.w3;
29539
+ const maxFileSize = (_c = (_b = options === null || options === void 0 ? void 0 : options.config) === null || _b === void 0 ? void 0 : _b.maxFileSize) !== null && _c !== void 0 ? _c : fileValidation/* MAX_FILE_SIZE */.w3;
29829
29540
  const emitErrorNotification = (fileName, folderId, innerException, silent, context) => {
29830
29541
  var _a, _b, _c, _d, _e, _f, _g;
29831
29542
  const apiError = (0,errorMessages/* asFileManagerApiError */.sj)(innerException);
@@ -29929,17 +29640,17 @@ const useFilesAPI = () => {
29929
29640
  });
29930
29641
  progressIntervals.forEach(id => window.clearInterval(id));
29931
29642
  progressIntervals.length = 0;
29932
- const detailedList = (_p = batchResult.detailed) !== null && _p !== void 0 ? _p : [];
29643
+ const detailedList = (_d = batchResult.detailed) !== null && _d !== void 0 ? _d : [];
29933
29644
  const detailedMap = new Map(detailedList.filter(detail => detail.requestId).map(detail => [detail.requestId, detail]));
29934
29645
  if (detailedList.length > 0) {
29935
29646
  for (let index = 0; index < uploadItems.length; index++) {
29936
29647
  const item = uploadItems[index];
29937
29648
  // Пытаемся сопоставить по requestId, а при его отсутствии — по порядку.
29938
- const detail = (_q = (item.requestId ? detailedMap.get(item.requestId) : undefined)) !== null && _q !== void 0 ? _q : detailedList[index];
29649
+ const detail = (_e = (item.requestId ? detailedMap.get(item.requestId) : undefined)) !== null && _e !== void 0 ? _e : detailedList[index];
29939
29650
  if (detail && detail.success) {
29940
29651
  const data = detail.data;
29941
- const normalizedFileName = (_r = data === null || data === void 0 ? void 0 : data.name) !== null && _r !== void 0 ? _r : item.resolvedUploadName;
29942
- const folderId = (_u = (_t = (_s = data === null || data === void 0 ? void 0 : data.folderId) !== null && _s !== void 0 ? _s : item.targetFolderId) !== null && _t !== void 0 ? _t : selectedFolder) !== null && _u !== void 0 ? _u : null;
29652
+ const normalizedFileName = (_f = data === null || data === void 0 ? void 0 : data.name) !== null && _f !== void 0 ? _f : item.resolvedUploadName;
29653
+ const folderId = (_j = (_h = (_g = data === null || data === void 0 ? void 0 : data.folderId) !== null && _g !== void 0 ? _g : item.targetFolderId) !== null && _h !== void 0 ? _h : selectedFolder) !== null && _j !== void 0 ? _j : null;
29943
29654
  const fileId = data === null || data === void 0 ? void 0 : data.id;
29944
29655
  // Сохраняем информацию о загруженном файле (включая size для корректного отображения в попапе)
29945
29656
  uploadedFilesMap.set(normalizedFileName, {
@@ -29956,9 +29667,9 @@ const useFilesAPI = () => {
29956
29667
  }
29957
29668
  else {
29958
29669
  const data = detail === null || detail === void 0 ? void 0 : detail.data;
29959
- const normalizedFileName = (_v = data === null || data === void 0 ? void 0 : data.name) !== null && _v !== void 0 ? _v : item.resolvedUploadName;
29960
- const folderId = (_y = (_x = (_w = data === null || data === void 0 ? void 0 : data.folderId) !== null && _w !== void 0 ? _w : item.targetFolderId) !== null && _x !== void 0 ? _x : selectedFolder) !== null && _y !== void 0 ? _y : null;
29961
- await handleFailure(normalizedFileName, folderId, (_z = detail === null || detail === void 0 ? void 0 : detail.error) !== null && _z !== void 0 ? _z : new Error(t('Error uploading file')), {
29670
+ const normalizedFileName = (_k = data === null || data === void 0 ? void 0 : data.name) !== null && _k !== void 0 ? _k : item.resolvedUploadName;
29671
+ const folderId = (_o = (_m = (_l = data === null || data === void 0 ? void 0 : data.folderId) !== null && _l !== void 0 ? _l : item.targetFolderId) !== null && _m !== void 0 ? _m : selectedFolder) !== null && _o !== void 0 ? _o : null;
29672
+ await handleFailure(normalizedFileName, folderId, (_p = detail === null || detail === void 0 ? void 0 : detail.error) !== null && _p !== void 0 ? _p : new Error(t('Error uploading file')), {
29962
29673
  emitNotification: shouldEmitPerItemNotifications,
29963
29674
  fileSize: item.file.size,
29964
29675
  progressCallbackName: item.originalFileName,
@@ -29970,17 +29681,17 @@ const useFilesAPI = () => {
29970
29681
  else if (batchResult.success) {
29971
29682
  for (const item of uploadItems) {
29972
29683
  const normalizedFileName = item.resolvedUploadName;
29973
- const folderId = (_1 = (_0 = item.targetFolderId) !== null && _0 !== void 0 ? _0 : selectedFolder) !== null && _1 !== void 0 ? _1 : null;
29684
+ const folderId = (_r = (_q = item.targetFolderId) !== null && _q !== void 0 ? _q : selectedFolder) !== null && _r !== void 0 ? _r : null;
29974
29685
  await handleSuccess(normalizedFileName, folderId, undefined, {
29975
29686
  emitNotification: shouldEmitPerItemNotifications,
29976
29687
  });
29977
29688
  }
29978
29689
  }
29979
29690
  else {
29980
- const batchError = (_2 = batchResult.error) !== null && _2 !== void 0 ? _2 : new Error(t('Error uploading file'));
29691
+ const batchError = (_s = batchResult.error) !== null && _s !== void 0 ? _s : new Error(t('Error uploading file'));
29981
29692
  for (const item of uploadItems) {
29982
29693
  const normalizedFileName = item.resolvedUploadName;
29983
- const folderId = (_4 = (_3 = item.targetFolderId) !== null && _3 !== void 0 ? _3 : selectedFolder) !== null && _4 !== void 0 ? _4 : null;
29694
+ const folderId = (_u = (_t = item.targetFolderId) !== null && _t !== void 0 ? _t : selectedFolder) !== null && _u !== void 0 ? _u : null;
29984
29695
  await handleFailure(normalizedFileName, folderId, batchError, {
29985
29696
  emitNotification: shouldEmitPerItemNotifications,
29986
29697
  fileSize: item.file.size,
@@ -29993,7 +29704,7 @@ const useFilesAPI = () => {
29993
29704
  catch (error) {
29994
29705
  for (const item of uploadItems) {
29995
29706
  const normalizedFileName = item.resolvedUploadName;
29996
- const folderId = (_6 = (_5 = item.targetFolderId) !== null && _5 !== void 0 ? _5 : selectedFolder) !== null && _6 !== void 0 ? _6 : null;
29707
+ const folderId = (_w = (_v = item.targetFolderId) !== null && _v !== void 0 ? _v : selectedFolder) !== null && _w !== void 0 ? _w : null;
29997
29708
  await handleFailure(normalizedFileName, folderId, error !== null && error !== void 0 ? error : new Error(t('Error uploading file')), {
29998
29709
  emitNotification: shouldEmitPerItemNotifications,
29999
29710
  fileSize: item.file.size,
@@ -30061,10 +29772,10 @@ const useFilesAPI = () => {
30061
29772
  },
30062
29773
  });
30063
29774
  }
30064
- else if (totalCount === 1 && errorDetails.length > 0 && ((_7 = errorDetails[0].error) === null || _7 === void 0 ? void 0 : _7.code)) {
29775
+ else if (totalCount === 1 && errorDetails.length > 0 && ((_x = errorDetails[0].error) === null || _x === void 0 ? void 0 : _x.code)) {
30065
29776
  // Для одного файла используем конкретное сообщение об ошибке
30066
- const codeMessage = (0,errorMessages/* getErrorMessageFromCode */.j2)((_8 = errorDetails[0].error) === null || _8 === void 0 ? void 0 : _8.code, t);
30067
- const failedFileName = (_10 = (_9 = errors[0]) === null || _9 === void 0 ? void 0 : _9.fileName) !== null && _10 !== void 0 ? _10 : '';
29777
+ const codeMessage = (0,errorMessages/* getErrorMessageFromCode */.j2)((_y = errorDetails[0].error) === null || _y === void 0 ? void 0 : _y.code, t);
29778
+ const failedFileName = (_0 = (_z = errors[0]) === null || _z === void 0 ? void 0 : _z.fileName) !== null && _0 !== void 0 ? _0 : '';
30068
29779
  const failureMessage = codeMessage !== null && codeMessage !== void 0 ? codeMessage : (failedFileName ? `${t('Failed to upload files')}: ${failedFileName}` : t('Failed to upload files'));
30069
29780
  notification.error({
30070
29781
  id: 'FILES_UPLOAD_BATCH_FAILED',
@@ -31995,29 +31706,336 @@ const useFilesDeleteModal = (fetchFiles) => {
31995
31706
  },
31996
31707
  };
31997
31708
  };
31998
-
31999
- ;// ./src/hooks/core/files/useFilesModals.ts
32000
-
32001
-
32002
-
32003
-
32004
- const useFilesModals = (fetchFiles) => {
32005
- const renameModal = useFilesRenameModal(fetchFiles);
32006
- const moveModal = useFilesMoveModal(fetchFiles);
32007
- const copyModal = useFilesCopyModal(fetchFiles);
32008
- const deleteModal = useFilesDeleteModal(fetchFiles);
32009
- return {
32010
- state: renameModal.state,
32011
- actions: Object.assign(Object.assign(Object.assign(Object.assign({}, renameModal.actions), moveModal.actions), copyModal.actions), deleteModal.actions),
32012
- };
31709
+
31710
+ ;// ./src/hooks/core/files/useFilesModals.ts
31711
+
31712
+
31713
+
31714
+
31715
+ const useFilesModals = (fetchFiles) => {
31716
+ const renameModal = useFilesRenameModal(fetchFiles);
31717
+ const moveModal = useFilesMoveModal(fetchFiles);
31718
+ const copyModal = useFilesCopyModal(fetchFiles);
31719
+ const deleteModal = useFilesDeleteModal(fetchFiles);
31720
+ return {
31721
+ state: renameModal.state,
31722
+ actions: Object.assign(Object.assign(Object.assign(Object.assign({}, renameModal.actions), moveModal.actions), copyModal.actions), deleteModal.actions),
31723
+ };
31724
+ };
31725
+
31726
+ ;// ./src/hooks/core/files/index.ts
31727
+
31728
+
31729
+
31730
+
31731
+
31732
+
31733
+
31734
+ /***/ }),
31735
+
31736
+ /***/ 9142:
31737
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
31738
+
31739
+ "use strict";
31740
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
31741
+ /* harmony export */ $5: () => (/* binding */ getUniqueFileName),
31742
+ /* harmony export */ mF: () => (/* binding */ encodeUrlForImageSrc),
31743
+ /* harmony export */ nF: () => (/* binding */ formatFileSizeDisplay),
31744
+ /* harmony export */ v7: () => (/* binding */ formatFileSize),
31745
+ /* harmony export */ w3: () => (/* binding */ MAX_FILE_SIZE)
31746
+ /* harmony export */ });
31747
+ /* unused harmony exports MIN_FILE_SIZE, ALLOWED_FILE_TYPES, ALL_ALLOWED_TYPES, validateFile, validateFiles, validateFileUrl, getFileCategory, formatFileSizeShort, sanitizeFileName */
31748
+ /* harmony import */ var antd__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(550);
31749
+ /* harmony import */ var antd__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(antd__WEBPACK_IMPORTED_MODULE_0__);
31750
+ /* harmony import */ var _i18n__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3829);
31751
+
31752
+
31753
+ const MAX_FILE_SIZE = 50 * 1024 * 1024;
31754
+ const MIN_FILE_SIZE = 1;
31755
+ const ALLOWED_FILE_TYPES = {
31756
+ images: ['image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/svg+xml', 'image/bmp', 'image/tiff'],
31757
+ documents: [
31758
+ 'application/pdf',
31759
+ 'text/plain',
31760
+ 'application/msword',
31761
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
31762
+ ],
31763
+ archives: ['application/zip', 'application/x-rar-compressed', 'application/x-7z-compressed'],
31764
+ videos: ['video/mp4', 'video/avi', 'video/quicktime', 'video/x-msvideo'],
31765
+ audio: ['audio/mpeg', 'audio/wav', 'audio/ogg'],
31766
+ };
31767
+ const ALL_ALLOWED_TYPES = Object.values(ALLOWED_FILE_TYPES).flat();
31768
+ const validateFile = (file, options = {}) => {
31769
+ const { maxSize = MAX_FILE_SIZE, minSize = MIN_FILE_SIZE, allowedTypes = ALL_ALLOWED_TYPES, allowAllTypes = false, maxFileNameLength = 255, } = options;
31770
+ const errors = [];
31771
+ const warnings = [];
31772
+ if (file.size > maxSize) {
31773
+ errors.push(i18n.t('File too large. Maximum size: {{size}}', { size: formatFileSize(maxSize) }));
31774
+ }
31775
+ if (file.size < minSize) {
31776
+ errors.push(i18n.t('File too small. Minimum size: {{size}}', { size: formatFileSize(minSize) }));
31777
+ }
31778
+ if (!allowAllTypes && !allowedTypes.includes(file.type)) {
31779
+ errors.push(i18n.t('Unsupported file type: {{type}}', { type: file.type || i18n.t('unknown') }));
31780
+ }
31781
+ if (file.name.length > maxFileNameLength) {
31782
+ errors.push(i18n.t('File name is too long. Maximum {{max}} characters', { max: maxFileNameLength }));
31783
+ }
31784
+ const invalidChars = /[<>:"/\\|?*()#]/;
31785
+ const hasControlChars = file.name.split('').some(char => {
31786
+ const code = char.charCodeAt(0);
31787
+ return code >= 0 && code <= 31;
31788
+ });
31789
+ if (invalidChars.test(file.name) || hasControlChars) {
31790
+ errors.push(i18n.t('File name contains invalid characters'));
31791
+ }
31792
+ if (file.size > 10 * 1024 * 1024) {
31793
+ warnings.push(i18n.t('Large file may take a long time to upload'));
31794
+ }
31795
+ return {
31796
+ isValid: errors.length === 0,
31797
+ errors,
31798
+ warnings,
31799
+ };
31800
+ };
31801
+ const validateFiles = (files, options = {}) => {
31802
+ const valid = [];
31803
+ const invalid = [];
31804
+ files.forEach(file => {
31805
+ const result = validateFile(file, options);
31806
+ if (result.isValid) {
31807
+ valid.push(file);
31808
+ }
31809
+ else {
31810
+ invalid.push({ file, result });
31811
+ }
31812
+ });
31813
+ return { valid, invalid };
31814
+ };
31815
+ const validateFileUrl = async (url) => {
31816
+ const errors = [];
31817
+ let notified = false;
31818
+ let lastError = undefined;
31819
+ const notifyError = (message) => {
31820
+ notified = true;
31821
+ notification.error({
31822
+ key: 'FILE_URL_VALIDATION_FAILED',
31823
+ title: message,
31824
+ placement: 'bottomRight',
31825
+ description: url,
31826
+ });
31827
+ };
31828
+ try {
31829
+ new URL(url);
31830
+ }
31831
+ catch (error) {
31832
+ console.error('Invalid URL:', error);
31833
+ lastError = error;
31834
+ const message = i18n.t('Invalid file URL');
31835
+ errors.push(message);
31836
+ notifyError(message);
31837
+ return { isValid: false, errors };
31838
+ }
31839
+ try {
31840
+ const response = await fetch(url, { method: 'HEAD' });
31841
+ if (!response.ok) {
31842
+ errors.push(i18n.t('File unavailable: {{status}} {{statusText}}', {
31843
+ status: response.status,
31844
+ statusText: response.statusText,
31845
+ }));
31846
+ }
31847
+ const contentLength = response.headers.get('content-length');
31848
+ if (contentLength && parseInt(contentLength) > MAX_FILE_SIZE) {
31849
+ errors.push(i18n.t('File too large: {{size}}', { size: formatFileSize(parseInt(contentLength)) }));
31850
+ }
31851
+ const contentType = response.headers.get('content-type');
31852
+ if (contentType && !ALL_ALLOWED_TYPES.includes(contentType)) {
31853
+ errors.push(i18n.t('Unsupported file type: {{contentType}}', { contentType }));
31854
+ }
31855
+ }
31856
+ catch (error) {
31857
+ console.error('Failed to validate file URL:', error);
31858
+ lastError = error;
31859
+ const message = i18n.t('Unable to validate file URL');
31860
+ errors.push(message);
31861
+ notifyError(message);
31862
+ }
31863
+ if (errors.length > 0 && !notified) {
31864
+ notifyError(i18n.t('Unable to validate file URL'));
31865
+ }
31866
+ return {
31867
+ isValid: errors.length === 0,
31868
+ errors,
31869
+ };
31870
+ };
31871
+ const getFileCategory = (file) => {
31872
+ const type = file.type;
31873
+ if (ALLOWED_FILE_TYPES.images.includes(type))
31874
+ return 'image';
31875
+ if (ALLOWED_FILE_TYPES.documents.includes(type))
31876
+ return 'document';
31877
+ if (ALLOWED_FILE_TYPES.archives.includes(type))
31878
+ return 'archive';
31879
+ if (ALLOWED_FILE_TYPES.videos.includes(type))
31880
+ return 'video';
31881
+ if (ALLOWED_FILE_TYPES.audio.includes(type))
31882
+ return 'audio';
31883
+ return 'other';
31884
+ };
31885
+ const formatFileSize = (bytes) => {
31886
+ if (bytes === 0)
31887
+ return '0 Bytes';
31888
+ const k = 1024;
31889
+ const sizes = ['Bytes', 'KB', 'MB', 'GB'];
31890
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
31891
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
31892
+ };
31893
+ const formatFileSizeShort = (bytes) => {
31894
+ if (!bytes || bytes <= 0)
31895
+ return '';
31896
+ const KILOBYTE = 1024;
31897
+ const MEGABYTE = KILOBYTE * 1024;
31898
+ if (bytes < MEGABYTE) {
31899
+ const kb = Math.round(bytes / KILOBYTE);
31900
+ return `${kb} Kb`;
31901
+ }
31902
+ const mb = bytes / MEGABYTE;
31903
+ return `${mb.toFixed(2)} Mb`;
31904
+ };
31905
+ const formatFileSizeDisplay = (value) => {
31906
+ if (value === undefined || value === null)
31907
+ return '';
31908
+ if (typeof value === 'number') {
31909
+ return formatFileSizeShort(value);
31910
+ }
31911
+ const normalized = String(value).trim();
31912
+ if (!normalized)
31913
+ return '';
31914
+ const parsed = Number(normalized);
31915
+ if (!Number.isNaN(parsed)) {
31916
+ return formatFileSizeShort(parsed);
31917
+ }
31918
+ return normalized;
31919
+ };
31920
+ /**
31921
+ * Генерирует уникальное имя файла: если name уже есть в existingNames, добавляет _1 (или _2, _3 и т.д.).
31922
+ * @param name — исходное имя файла (с расширением)
31923
+ * @param existingNames — массив имён файлов/папок в целевой директории
31924
+ */
31925
+ const getUniqueFileName = (name, existingNames) => {
31926
+ const safeNames = existingNames.filter((n) => typeof n === 'string');
31927
+ const set = new Set(safeNames.map(n => n.toLowerCase()));
31928
+ const safeName = typeof name === 'string' ? name : String(name !== null && name !== void 0 ? name : '');
31929
+ if (!set.has(safeName.toLowerCase()))
31930
+ return safeName;
31931
+ const lastDot = safeName.lastIndexOf('.');
31932
+ const baseName = lastDot > 0 ? safeName.slice(0, lastDot) : safeName;
31933
+ const ext = lastDot > 0 ? safeName.slice(lastDot) : '';
31934
+ let suffix = 1;
31935
+ let candidate;
31936
+ do {
31937
+ candidate = `${baseName}_${suffix}${ext}`;
31938
+ suffix++;
31939
+ } while (set.has(candidate.toLowerCase()));
31940
+ return candidate;
31941
+ };
31942
+ /**
31943
+ * Кодирует URL для безопасного использования в img src. Решает проблему с кириллицей и другими
31944
+ * не-ASCII символами в пути (например, emcdn.ru/.../Снимок_экрана.png).
31945
+ * data: и blob: URLs возвращаются без изменений.
31946
+ */
31947
+ const encodeUrlForImageSrc = (url) => {
31948
+ if (!url || typeof url !== 'string')
31949
+ return undefined;
31950
+ if (url.startsWith('data:') || url.startsWith('blob:'))
31951
+ return url;
31952
+ try {
31953
+ if (url.startsWith('http://') || url.startsWith('https://') || url.startsWith('/')) {
31954
+ const parsed = new URL(url.startsWith('/') ? `https://x${url}` : url);
31955
+ const origin = url.startsWith('/') ? '' : `${parsed.protocol}//${parsed.host}`;
31956
+ const pathEncoded = parsed.pathname
31957
+ .split('/')
31958
+ .map(seg => {
31959
+ if (!seg)
31960
+ return '';
31961
+ try {
31962
+ return encodeURIComponent(decodeURIComponent(seg));
31963
+ }
31964
+ catch (_a) {
31965
+ return encodeURIComponent(seg);
31966
+ }
31967
+ })
31968
+ .join('/');
31969
+ const result = url.startsWith('/') ? pathEncoded + (parsed.search || '') + (parsed.hash || '') : `${origin}${pathEncoded}${parsed.search}${parsed.hash}`;
31970
+ return result;
31971
+ }
31972
+ }
31973
+ catch (_a) {
31974
+ // если парсинг не удался, возвращаем как есть
31975
+ }
31976
+ return url;
31977
+ };
31978
+ /**
31979
+ * @deprecated Эта функция оставлена только для обратной совместимости.
31980
+ * Используйте {@link normalizeFileName} из `nameNormalization.ts` для настраиваемой нормализации имен файлов.
31981
+ *
31982
+ * Упрощенная санитизация имени файла:
31983
+ * - Заменяет запрещенные символы на `_`
31984
+ * - Заменяет пробелы на `_`
31985
+ * - Удаляет множественные подчеркивания
31986
+ * - Ограничивает длину до 255 символов
31987
+ */
31988
+ const sanitizeFileName = (fileName) => {
31989
+ return fileName
31990
+ .replace(/[<>:"/\\|?*()#]/g, '_')
31991
+ .split('')
31992
+ .map(char => {
31993
+ const code = char.charCodeAt(0);
31994
+ return code >= 0 && code <= 31 ? '_' : char;
31995
+ })
31996
+ .join('')
31997
+ .replace(/\s+/g, '_')
31998
+ .replace(/_{2,}/g, '_')
31999
+ .substring(0, 255);
32013
32000
  };
32014
32001
 
32015
- ;// ./src/hooks/core/files/index.ts
32016
-
32017
-
32018
32002
 
32003
+ /***/ }),
32019
32004
 
32005
+ /***/ 9287:
32006
+ /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
32020
32007
 
32008
+ // Imports
32009
+ var ___CSS_LOADER_API_SOURCEMAP_IMPORT___ = __webpack_require__(1354);
32010
+ var ___CSS_LOADER_API_IMPORT___ = __webpack_require__(6314);
32011
+ var ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);
32012
+ // Module
32013
+ ___CSS_LOADER_EXPORT___.push([module.id, `.FolderSidebar-module__button__Yf2rX.ant-btn.ant-btn-icon-only{padding:calc(var(--paddingXXS)*1px) calc(var(--paddingSM)*1px);cursor:pointer;color:var(--colorTextSecondary);display:flex;gap:calc(var(--marginXS)*1px);align-items:center;justify-content:center;border-radius:calc(var(--borderRadiusSM)*1px);transition:all var(--motionDurationFast);box-shadow:none;border:none;width:32px;height:32px}.FolderSidebar-module__button__Yf2rX.ant-btn.ant-btn-icon-only:hover{background-color:var(--colorBgLayout);color:inherit}.FolderSidebar-module__button__Yf2rX:hover{background-color:var(--colorBgContainer);color:var(--colorPrimary)}.FolderSidebar-module__foldersTitle__Uh6u7{display:flex;align-items:center;flex:1;cursor:pointer}.FolderSidebar-module__folderActions__qA2Bk{position:absolute;top:4px;right:4px;display:flex;align-items:center;gap:4px;z-index:10}.FolderSidebar-module__folderActions__qA2Bk .FolderSidebar-module__button__Yf2rX.FolderSidebar-module__ant-btn__LXAXm.FolderSidebar-module__ant-btn-icon-only__j_wVF{padding:calc(var(--paddingXXS)*1px) calc(var(--paddingSM)*1px);cursor:pointer;color:var(--colorTextSecondary);display:flex;gap:calc(var(--marginXS)*1px);align-items:center;justify-content:center;border-radius:calc(var(--borderRadiusSM)*1px);transition:all var(--motionDurationFast);box-shadow:none;border:none;width:32px;height:32px}.FolderSidebar-module__folderActions__qA2Bk .FolderSidebar-module__button__Yf2rX.FolderSidebar-module__ant-btn__LXAXm.FolderSidebar-module__ant-btn-icon-only__j_wVF:hover{background-color:var(--colorBgLayout);color:inherit}.FolderSidebar-module__customExpandIcon__IhZJl{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;margin-right:8px;cursor:pointer;color:#666;font-size:10px;transition:transform .2s ease}.FolderSidebar-module__customExpandIcon__IhZJl:hover{color:var(--colorPrimary)}.FolderSidebar-module__fileCount__bD9DD{display:inline-flex;align-items:center;justify-content:center;min-width:20px;height:100%;padding:0 6px;margin-left:8px;color:#8d8d8d;font-size:14px;font-weight:500;transition:all .2s ease;white-space:nowrap;cursor:default;flex-shrink:0;margin-right:10px}.ant-tree .ant-tree-node-content-wrapper.ant-tree-node-selected{background-color:rgba(0,0,0,0) !important}.FolderSidebar-module__folderMenu__JCzLF .ant-tree-treenode-selected .folder-label span,.FolderSidebar-module__folderMenu__JCzLF .ant-tree .ant-tree-node-content-wrapper.ant-tree-node-selected .folderLabelItem,.FolderSidebar-module__folderMenu__JCzLF .ant-tree-treenode-selected .folderLabelItem,.FolderSidebar-module__folderMenu__JCzLF .ant-tree-node-selected .folderLabelItem{font-weight:600 !important}.FolderSidebar-module__uploadButton__QQUid{width:100%;justify-content:flex-start}.FolderSidebar-module__uploadButton__QQUid button:hover{background-color:var(--colorPrimaryHover) !important}.FolderSidebar-module__folderMenu__JCzLF{padding-left:0;padding-right:0}.FolderSidebar-module__folderMenu__JCzLF .ant-tree-treenode{display:flex;align-items:center;justify-content:space-between;padding:4px 0;border-radius:4px;transition:background-color .2s ease;width:100%;margin-bottom:0}.FolderSidebar-module__folderMenu__JCzLF .ant-tree-node-content-wrapper{flex:1;align-items:center;padding:0;transition:background-color .2s ease}.FolderSidebar-module__folderMenu__JCzLF .ant-tree-node-content-wrapper:hover{background-color:rgba(0,0,0,0)}.FolderSidebar-module__folderMenu__JCzLF .ant-tree-switcher{height:24px;width:24px;margin-top:5px;display:flex !important;align-items:center;justify-content:center;transition:color .2s ease;flex-shrink:0}.FolderSidebar-module__folderMenu__JCzLF .ant-tree-switcher-noop{width:24px}.FolderSidebar-module__folderMenu__JCzLF .ant-tree-switcher-line-icon{color:#d9d9d9}.FolderSidebar-module__folderMenu__JCzLF .FolderSidebar-module__folderItemContainer__byl5b{width:100%;display:flex;align-items:center;justify-content:space-between;padding:2px 0;min-width:0}.FolderSidebar-module__folderMenu__JCzLF .folder-label{display:flex;align-items:center;flex:1;color:#595959;font-size:14px;min-width:0;overflow:hidden}.FolderSidebar-module__folderMenu__JCzLF .ant-tree-treenode[data-key="folders"]{border-bottom:1px solid var(--colorBorderSecondary);margin-bottom:8px;padding-bottom:8px}.FolderSidebar-module__folderMenu__JCzLF .ant-tree-treenode[data-key="folders"].ant-tree-treenode-selected{background-color:rgba(0,0,0,0) !important}.FolderSidebar-module__folderMenu__JCzLF .ant-tree-treenode[data-key="folders"] .ant-tree-node-content-wrapper{padding:0}.FolderSidebar-module__folderMenu__JCzLF .ant-tree-treenode[data-key="folders"] .ant-tree-node-content-wrapper:hover{background-color:rgba(0,0,0,0) !important}.FolderSidebar-module__folderMenu__JCzLF .ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0}.FolderSidebar-module__folderMenu__JCzLF .FolderSidebar-module__emptyFolderContainer__WK6tx{padding:20px;text-align:center}.FolderSidebar-module__folderMenu__JCzLF .ant-tree > .ant-tree-treenode{padding-left:0 !important}.FolderSidebar-module__folderIcon__UoZzH{margin-right:8px;font-size:18px;flex-shrink:0}.FolderSidebar-module__folderLabelItem__uJ062{font-size:14px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex:1;min-width:0;user-select:none}.FolderSidebar-module__foldersTitleItem__gapOI{display:flex;align-items:center;flex:1;cursor:pointer;min-width:0;overflow:hidden}.FolderSidebar-module__folderLabel__fHWMp{display:flex;align-items:center;flex:1;min-width:0;overflow:hidden}.FolderSidebar-module__foldersContainer__zdBVU{position:relative;width:100%}.FolderSidebar-module__uploadButton__QQUid .FolderSidebar-module__ant-btn__LXAXm,.FolderSidebar-module__uploadButton__QQUid .ant-btn{display:flex;align-items:center;justify-content:center;gap:3px}.FolderSidebar-module__buttonWrapper__a9Qi5{margin-bottom:24px;display:flex;gap:4px}.FolderSidebar-module__buttonWrapper__a9Qi5>:first-child{flex:1;height:40px;padding-left:10px}.FolderSidebar-module__buttonWrapper__a9Qi5>:last-child{width:40px;height:40px;flex-shrink:0}.FolderSidebar-module__uploadButtonIcon__mWQmq{font-size:20px}.FolderSidebar-module__uploadButtonTitle__wk_o6{line-height:1em}.FolderSidebar-module__emptyFolderContainer__WK6tx{user-select:none;cursor:default;color:var(--colorTextTertiary)}.FolderSidebar-module__folderItemContainer__byl5b{width:100%;display:flex;align-items:center;justify-content:space-between;padding:2px 0;min-width:0}`, "",{"version":3,"sources":["webpack://./src/components/FolderSidebar/FolderSidebar.module.scss"],"names":[],"mappings":"AAAA,+DACI,8DAAA,CACA,cAAA,CACA,+BAAA,CACA,YAAA,CACA,6BAAA,CACA,kBAAA,CACA,sBAAA,CACA,6CAAA,CACA,wCAAA,CACA,eAAA,CAEA,WAAA,CACA,UAAA,CACA,WAAA,CAEA,qEACI,qCAAA,CACA,aAAA,CAIR,2CACI,wCAAA,CACA,yBAAA,CAGJ,2CACE,YAAA,CACA,kBAAA,CACA,MAAA,CACA,cAAA,CAGF,4CACI,iBAAA,CACA,OAAA,CACA,SAAA,CACA,YAAA,CACA,kBAAA,CACA,OAAA,CACA,UAAA,CAEA,qKACE,8DAAA,CACA,cAAA,CACA,+BAAA,CACA,YAAA,CACA,6BAAA,CACA,kBAAA,CACA,sBAAA,CACA,6CAAA,CACA,wCAAA,CACA,eAAA,CAEA,WAAA,CACA,UAAA,CACA,WAAA,CAEA,2KACI,qCAAA,CACA,aAAA,CAKV,+CACE,mBAAA,CACA,kBAAA,CACA,sBAAA,CACA,UAAA,CACA,WAAA,CACA,gBAAA,CACA,cAAA,CACA,UAAA,CACA,cAAA,CACA,6BAAA,CAGF,qDACI,yBAAA,CAGJ,wCACE,mBAAA,CACA,kBAAA,CACA,sBAAA,CACA,cAAA,CACE,WAAA,CACF,aAAA,CACA,eAAA,CACE,aAAA,CACA,cAAA,CACF,eAAA,CACA,uBAAA,CACA,kBAAA,CACA,cAAA,CACA,aAAA,CACA,iBAAA,CAQF,gEACE,yCAAA,CAQF,0XAIE,0BAAA,CAWF,2CACI,UAAA,CACA,0BAAA,CAEA,wDACE,oDAAA,CAIN,yCACE,cAAA,CACA,eAAA,CAGF,4DACE,YAAA,CACA,kBAAA,CACA,6BAAA,CACA,aAAA,CACA,iBAAA,CACA,oCAAA,CACA,UAAA,CACA,eAAA,CAGF,wEACE,MAAA,CAEA,kBAAA,CACA,SAAA,CAEA,oCAAA,CAGF,8EACE,8BAAA,CAGF,4DACE,WAAA,CACA,UAAA,CACA,cAAA,CACA,uBAAA,CACA,kBAAA,CACA,sBAAA,CACA,yBAAA,CACA,aAAA,CAGF,iEACE,UAAA,CAIF,sEACE,aAAA,CAIF,2FACE,UAAA,CACA,YAAA,CACA,kBAAA,CACA,6BAAA,CACA,aAAA,CACA,WAAA,CAGF,uDACE,YAAA,CACA,kBAAA,CACA,MAAA,CACA,aAAA,CACA,cAAA,CACA,WAAA,CACA,eAAA,CAIF,gFACI,mDAAA,CACF,iBAAA,CACA,kBAAA,CAGF,2GACE,yCAAA,CAGF,+GACE,SAAA,CAGF,qHACE,yCAAA,CAIF,mDACE,eAAA,CACA,sBAAA,CACA,kBAAA,CACA,MAAA,CACA,WAAA,CAIF,4FACE,YAAA,CACA,iBAAA,CAIF,wEACE,yBAAA,CAEF,yCACE,gBAAA,CACE,cAAA,CACF,aAAA,CAGF,8CACE,cAAA,CACA,kBAAA,CACA,eAAA,CACA,sBAAA,CACA,MAAA,CACA,WAAA,CACA,gBAAA,CAGF,+CACE,YAAA,CACA,kBAAA,CACA,MAAA,CACA,cAAA,CACA,WAAA,CACA,eAAA,CASF,0CACE,YAAA,CACA,kBAAA,CACA,MAAA,CACA,WAAA,CACA,eAAA,CAGF,+CACE,iBAAA,CACA,UAAA,CAWF,qIAEE,YAAA,CACA,kBAAA,CACA,sBAAA,CACA,OAAA,CAaF,4CAEI,kBAAA,CACA,YAAA,CACA,OAAA,CAIA,yDACI,MAAA,CACA,WAAA,CACA,iBAAA,CAIJ,wDACI,UAAA,CACA,WAAA,CACA,aAAA,CAIR,+CACI,cAAA,CAGJ,gDACI,eAAA,CAGJ,mDACI,gBAAA,CACA,cAAA,CACA,8BAAA,CAGJ,kDACI,UAAA,CACA,YAAA,CACA,kBAAA,CACA,6BAAA,CACA,aAAA,CACA,WAAA","sourcesContent":[".button:global(.ant-btn.ant-btn-icon-only) {\r\n padding: calc(var(--paddingXXS) * 1px) calc(var(--paddingSM) * 1px);\r\n cursor: pointer;\r\n color: var(--colorTextSecondary);\r\n display: flex;\r\n gap: calc(var(--marginXS) * 1px);\r\n align-items: center;\r\n justify-content: center;\r\n border-radius: calc(var(--borderRadiusSM) * 1px);\r\n transition: all var(--motionDurationFast);\r\n box-shadow: none;\r\n\r\n border: none;\r\n width: 32px;\r\n height: 32px;\r\n\r\n &:hover {\r\n background-color: var(--colorBgLayout);\r\n color: inherit;\r\n }\r\n}\r\n\r\n.button:hover {\r\n background-color: var(--colorBgContainer);\r\n color: var(--colorPrimary);\r\n}\r\n\r\n.foldersTitle {\r\n display: flex;\r\n align-items: center;\r\n flex: 1;\r\n cursor: pointer;\r\n}\r\n\r\n.folderActions {\r\n position: absolute;\r\n top: 4px; /* Выравниваем по заголовку Folders */\r\n right: 4px;\r\n display: flex;\r\n align-items: center;\r\n gap: 4px;\r\n z-index: 10;\r\n\r\n .button.ant-btn.ant-btn-icon-only {\r\n padding: calc(var(--paddingXXS) * 1px) calc(var(--paddingSM) * 1px);\r\n cursor: pointer;\r\n color: var(--colorTextSecondary);\r\n display: flex;\r\n gap: calc(var(--marginXS) * 1px);\r\n align-items: center;\r\n justify-content: center;\r\n border-radius: calc(var(--borderRadiusSM) * 1px);\r\n transition: all var(--motionDurationFast);\r\n box-shadow: none;\r\n\r\n border: none;\r\n width: 32px;\r\n height: 32px;\r\n\r\n &:hover {\r\n background-color: var(--colorBgLayout);\r\n color: inherit;\r\n }\r\n }\r\n}\r\n\r\n.customExpandIcon {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 16px;\r\n height: 16px;\r\n margin-right: 8px;\r\n cursor: pointer;\r\n color: #666;\r\n font-size: 10px;\r\n transition: transform 0.2s ease;\r\n}\r\n\r\n.customExpandIcon:hover {\r\n color: var(--colorPrimary);\r\n}\r\n\r\n.fileCount {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n min-width: 20px;\r\n height: 100%;\r\n padding: 0 6px;\r\n margin-left: 8px;\r\n color: #8D8D8D;\r\n font-size: 14px;\r\n font-weight: 500;\r\n transition: all 0.2s ease;\r\n white-space: nowrap;\r\n cursor: default;\r\n flex-shrink: 0; /* Запрещаем сжатие счетчика */\r\n margin-right: 10px;\r\n}\r\n\r\n// .fileCount:hover {\r\n// border-color: var(--colorPrimary);\r\n// color: var(--colorPrimary);\r\n// }\r\n\r\n:global(.ant-tree .ant-tree-node-content-wrapper.ant-tree-node-selected) {\r\n background-color: transparent !important;\r\n}\r\n\r\n/* :global(.ant-tree .ant-tree-node-content-wrapper.ant-tree-node-selected):hover {\r\n color: red !important;\r\n} */\r\n\r\n/* Стили для выделения текста в выбранной папке */\r\n.folderMenu :global(.ant-tree-treenode-selected .folder-label span),\r\n.folderMenu :global(.ant-tree .ant-tree-node-content-wrapper.ant-tree-node-selected .folderLabelItem),\r\n.folderMenu :global(.ant-tree-treenode-selected .folderLabelItem),\r\n.folderMenu :global(.ant-tree-node-selected .folderLabelItem) {\r\n font-weight: 600 !important;\r\n}\r\n\r\n/* Стили для иконки в выбранной папке */\r\n/* .folderMenu :global(.ant-tree-treenode-selected .folderIcon),\r\n.folderMenu :global(.ant-tree-node-selected .folderIcon) {\r\n color: red !important;\r\n} */\r\n\r\n/* CSS переменные для упрощения расчетов */\r\n\r\n.uploadButton {\r\n width: 100%;\r\n justify-content: flex-start;\r\n\r\n & button:hover {\r\n background-color: var(--colorPrimaryHover) !important;\r\n }\r\n}\r\n\r\n.folderMenu {\r\n padding-left: 0;\r\n padding-right: 0; /* Место для кнопки справа */\r\n}\r\n\r\n.folderMenu :global(.ant-tree-treenode) {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 4px 0;\r\n border-radius: 4px;\r\n transition: background-color 0.2s ease;\r\n width: 100%;\r\n margin-bottom: 0;\r\n}\r\n\r\n.folderMenu :global(.ant-tree-node-content-wrapper) {\r\n flex: 1;\r\n /* display: flex; */\r\n align-items: center;\r\n padding: 0;\r\n /* border-radius: 4px; */\r\n transition: background-color 0.2s ease;\r\n}\r\n\r\n.folderMenu :global(.ant-tree-node-content-wrapper:hover) {\r\n background-color: transparent;\r\n}\r\n\r\n.folderMenu :global(.ant-tree-switcher) {\r\n height: 24px;\r\n width: 24px;\r\n margin-top: 5px;\r\n display: flex !important;\r\n align-items: center;\r\n justify-content: center;\r\n transition: color 0.2s ease;\r\n flex-shrink: 0; /* Запрещаем сжатие переключателя */\r\n}\r\n\r\n.folderMenu :global(.ant-tree-switcher-noop) {\r\n width: 24px;\r\n}\r\n\r\n/* Стили для линий дерева */\r\n.folderMenu :global(.ant-tree-switcher-line-icon) {\r\n color: #d9d9d9;\r\n}\r\n\r\n/* Улучшение отображения folder-item-container */\r\n.folderMenu .folderItemContainer {\r\n width: 100%;\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 2px 0;\r\n min-width: 0; /* Позволяет flex-элементам сжиматься */\r\n}\r\n\r\n.folderMenu :global(.folder-label) {\r\n display: flex;\r\n align-items: center;\r\n flex: 1;\r\n color: #595959;\r\n font-size: 14px;\r\n min-width: 0;\r\n overflow: hidden;\r\n}\r\n\r\n/* Стили для корневого элемента Folders */\r\n.folderMenu :global(.ant-tree-treenode[data-key='folders']) {\r\n border-bottom: 1px solid var(--colorBorderSecondary);\r\n margin-bottom: 8px;\r\n padding-bottom: 8px;\r\n}\r\n\r\n.folderMenu :global(.ant-tree-treenode[data-key='folders'].ant-tree-treenode-selected) {\r\n background-color: transparent !important;\r\n}\r\n\r\n.folderMenu :global(.ant-tree-treenode[data-key='folders'] .ant-tree-node-content-wrapper) {\r\n padding: 0;\r\n}\r\n\r\n.folderMenu :global(.ant-tree-treenode[data-key='folders'] .ant-tree-node-content-wrapper:hover) {\r\n background-color: transparent !important;\r\n}\r\n\r\n/* Стили для ellipsis - удаляем max-width для гибкости */\r\n.folderMenu :global(.ellipsis) {\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n flex: 1;\r\n min-width: 0;\r\n}\r\n\r\n/* Стили для пустого состояния */\r\n.folderMenu .emptyFolderContainer {\r\n padding: 20px;\r\n text-align: center;\r\n}\r\n\r\n/* Убираем отступы у корневого узла */\r\n.folderMenu :global(.ant-tree > .ant-tree-treenode) {\r\n padding-left: 0 !important;\r\n}\r\n.folderIcon {\r\n margin-right: 8px;\r\n font-size: 18px;\r\n flex-shrink: 0; /* Запрещаем сжатие иконки */\r\n}\r\n\r\n.folderLabelItem {\r\n font-size: 14px;\r\n white-space: nowrap; /* Запрещаем перенос строк */\r\n overflow: hidden; /* Скрываем переполнение */\r\n text-overflow: ellipsis; /* Показываем троеточие */\r\n flex: 1; /* Занимает доступное место */\r\n min-width: 0; /* Позволяет сжиматься */\r\n user-select: none;\r\n}\r\n\r\n.foldersTitleItem {\r\n display: flex;\r\n align-items: center;\r\n flex: 1;\r\n cursor: pointer;\r\n min-width: 0; /* Позволяет сжиматься */\r\n overflow: hidden; /* Скрываем переполнение */\r\n}\r\n\r\n/* .foldersTitleItem .folderLabelItem {\r\n font-weight: 500;\r\n color: #262626;\r\n} */\r\n\r\n/* Класс для заголовка папок */\r\n.folderLabel {\r\n display: flex;\r\n align-items: center;\r\n flex: 1;\r\n min-width: 0;\r\n overflow: hidden;\r\n}\r\n\r\n.foldersContainer {\r\n position: relative;\r\n width: 100%;\r\n}\r\n\r\n/* Дополнительные стили для улучшения визуала */\r\n/* .folderMenu :global(.ant-tree-treenode:hover .folder-label span) {\r\n color: #1890ff;\r\n} */\r\n\r\n/* Стили для дивайдера между папками */\r\n\r\n\r\n.uploadButton .ant-btn,\r\n.uploadButton :global(.ant-btn) {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n gap: 3px;\r\n}\r\n/* .folderMenu :global(.ant-tree-treenode-selected) .folderLabelItem {\r\n color: #1890ff !important;\r\n} */\r\n\r\n// .folderMenu :global(.ant-tree-treenode-selected) .folderLabel .folderLabelItem,\r\n// .folderMenu :global(.ant-tree-treenode-selected) .folderLabel .folderIcon,\r\n// .folderMenu :global(.ant-tree-treenode-selected) .folderLabelItem {\r\n// color: var(--colorLink);\r\n// }\r\n\r\n\r\n.buttonWrapper {\r\n // overflow: hidden;\r\n margin-bottom: 24px;\r\n display: flex;\r\n gap: 4px;\r\n // border-radius: calc(var(--borderRadius) * 1px);\r\n \r\n // Левая кнопка занимает всю доступную ширину\r\n > :first-child {\r\n flex: 1;\r\n height: 40px;\r\n padding-left: 10px;\r\n }\r\n \r\n // Правая кнопка строго 40px\r\n > :last-child {\r\n width: 40px;\r\n height: 40px;\r\n flex-shrink: 0;\r\n }\r\n}\r\n\r\n.uploadButtonIcon {\r\n font-size: 20px;\r\n}\r\n\r\n.uploadButtonTitle {\r\n line-height: 1em;\r\n}\r\n\r\n.emptyFolderContainer {\r\n user-select: none;\r\n cursor: default;\r\n color: var(--colorTextTertiary);\r\n}\r\n\r\n.folderItemContainer {\r\n width: 100%;\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 2px 0;\r\n min-width: 0; /* Позволяет flex-элементам сжиматься */\r\n}\r\n"],"sourceRoot":""}]);
32014
+ // Exports
32015
+ ___CSS_LOADER_EXPORT___.locals = {
32016
+ "button": `FolderSidebar-module__button__Yf2rX`,
32017
+ "foldersTitle": `FolderSidebar-module__foldersTitle__Uh6u7`,
32018
+ "folderActions": `FolderSidebar-module__folderActions__qA2Bk`,
32019
+ "ant-btn": `FolderSidebar-module__ant-btn__LXAXm`,
32020
+ "antBtn": `FolderSidebar-module__ant-btn__LXAXm`,
32021
+ "ant-btn-icon-only": `FolderSidebar-module__ant-btn-icon-only__j_wVF`,
32022
+ "antBtnIconOnly": `FolderSidebar-module__ant-btn-icon-only__j_wVF`,
32023
+ "customExpandIcon": `FolderSidebar-module__customExpandIcon__IhZJl`,
32024
+ "fileCount": `FolderSidebar-module__fileCount__bD9DD`,
32025
+ "folderMenu": `FolderSidebar-module__folderMenu__JCzLF`,
32026
+ "uploadButton": `FolderSidebar-module__uploadButton__QQUid`,
32027
+ "folderItemContainer": `FolderSidebar-module__folderItemContainer__byl5b`,
32028
+ "emptyFolderContainer": `FolderSidebar-module__emptyFolderContainer__WK6tx`,
32029
+ "folderIcon": `FolderSidebar-module__folderIcon__UoZzH`,
32030
+ "folderLabelItem": `FolderSidebar-module__folderLabelItem__uJ062`,
32031
+ "foldersTitleItem": `FolderSidebar-module__foldersTitleItem__gapOI`,
32032
+ "folderLabel": `FolderSidebar-module__folderLabel__fHWMp`,
32033
+ "foldersContainer": `FolderSidebar-module__foldersContainer__zdBVU`,
32034
+ "buttonWrapper": `FolderSidebar-module__buttonWrapper__a9Qi5`,
32035
+ "uploadButtonIcon": `FolderSidebar-module__uploadButtonIcon__mWQmq`,
32036
+ "uploadButtonTitle": `FolderSidebar-module__uploadButtonTitle__wk_o6`
32037
+ };
32038
+ module.exports = ___CSS_LOADER_EXPORT___;
32021
32039
 
32022
32040
 
32023
32041
  /***/ }),
@@ -32433,7 +32451,7 @@ __webpack_require__.d(__webpack_exports__, {
32433
32451
  "default": () => (/* binding */ src)
32434
32452
  });
32435
32453
 
32436
- // UNUSED EXPORTS: DEFAULT_FILE_MANAGER_CACHE_TTL_MS, DataSourceProxyBase, FailedRequestCache, FileContent, FileManagerApiError, FileManagerApp, FileManagerAppWithContext, FileModals, FolderSidebar, MutationRegistry, PathAwareStorageAdapter, PixieOnlyApp, TreeCache, ViewCacheManager, buildAssetsPath, defaultIsFolderNotFoundError, fetchRemoteImageBlobByUrl, getAssetsBase, init, initFileManager, initPixieEditor, installResizeObserverErrorHandler, joinUrls, mapHttpStatusToErrorCode, uninstallResizeObserverErrorHandler, unmount, unmountPixieEditor
32454
+ // UNUSED EXPORTS: DEFAULT_FILE_MANAGER_CACHE_TTL_MS, DataSourceProxyBase, FailedRequestCache, FileContent, FileManagerApiError, FileManagerApp, FileManagerAppWithContext, FileModals, FolderSidebar, MutationRegistry, PathAwareStorageAdapter, PixieOnlyApp, TRASH_FOLDER_ID, TreeCache, ViewCacheManager, buildAssetsPath, compareFileSystemItems, createSystemFolderByPathResolver, defaultChildrenViewFilterMatch, defaultFileSystemItemComparator, defaultIsFolderNotFoundError, fetchRemoteImageBlobByUrl, getAssetsBase, getTrashFolderLookupCandidates, init, initFileManager, initPixieEditor, installResizeObserverErrorHandler, joinUrls, mapHttpStatusToErrorCode, matchesChildrenViewFilter, normalizeSystemFolderPath, resolveSortParams, resolveViewStrategyOptions, uninstallResizeObserverErrorHandler, unmount, unmountPixieEditor
32437
32455
 
32438
32456
  // EXTERNAL MODULE: ./node_modules/react/jsx-runtime.js
32439
32457
  var jsx_runtime = __webpack_require__(4848);
@@ -33361,8 +33379,8 @@ const SearchInput = ({ onSearch, placeholder, className }) => {
33361
33379
  ;// ./src/components/SearchInput/index.ts
33362
33380
 
33363
33381
 
33364
- // EXTERNAL MODULE: ./src/hooks/core/files/index.ts + 17 modules
33365
- var core_files = __webpack_require__(9557);
33382
+ // EXTERNAL MODULE: ./src/hooks/core/files/index.ts + 18 modules
33383
+ var core_files = __webpack_require__(8573);
33366
33384
  ;// ./src/hooks/core/types.ts
33367
33385
  /** Полный список опций сортировки в дропдауне (порядок отображения). */
33368
33386
  const ALL_SORT_OPTIONS = [
@@ -39870,6 +39888,7 @@ var TreeCache_rest = (undefined && undefined.__rest) || function (s, e) {
39870
39888
  return t;
39871
39889
  };
39872
39890
 
39891
+
39873
39892
  const ROOT_KEY = '';
39874
39893
  /** When `fileManager.cacheStrategy.ttl` is unset: success/error cache and notification dedupe fallback (30 min). */
39875
39894
  const DEFAULT_FILE_MANAGER_CACHE_TTL_MS = (/* unused pure expression or super */ null && (30 * 60 * 1000));
@@ -40326,14 +40345,15 @@ class ViewCacheManager {
40326
40345
  this.views = new Map();
40327
40346
  // Защита от переполнения
40328
40347
  this.maxViewsPerParent = 50;
40348
+ const resolved = resolveViewStrategyOptions(options);
40329
40349
  this.strategy = {
40330
- allowSortedInsert: (_a = options.allowSortedInsert) !== null && _a !== void 0 ? _a : true,
40331
- allowSearchInsert: (_b = options.allowSearchInsert) !== null && _b !== void 0 ? _b : true,
40332
- invalidateOnPaginationFull: (_c = options.invalidateOnPaginationFull) !== null && _c !== void 0 ? _c : true,
40333
- preloadPagesBefore: (_d = options.preloadPagesBefore) !== null && _d !== void 0 ? _d : 0,
40334
- preloadPagesAfter: (_e = options.preloadPagesAfter) !== null && _e !== void 0 ? _e : 1,
40335
- comparator: options.comparator,
40336
- filterMatch: options.filterMatch,
40350
+ allowSortedInsert: (_a = resolved.allowSortedInsert) !== null && _a !== void 0 ? _a : true,
40351
+ allowSearchInsert: (_b = resolved.allowSearchInsert) !== null && _b !== void 0 ? _b : true,
40352
+ invalidateOnPaginationFull: (_c = resolved.invalidateOnPaginationFull) !== null && _c !== void 0 ? _c : true,
40353
+ preloadPagesBefore: (_d = resolved.preloadPagesBefore) !== null && _d !== void 0 ? _d : 0,
40354
+ preloadPagesAfter: (_e = resolved.preloadPagesAfter) !== null && _e !== void 0 ? _e : 1,
40355
+ comparator: resolved.comparator,
40356
+ filterMatch: resolved.filterMatch,
40337
40357
  };
40338
40358
  this.ttl = ttl;
40339
40359
  this.errorTtl = errorTtl !== null && errorTtl !== void 0 ? errorTtl : ttl;
@@ -40375,6 +40395,17 @@ class ViewCacheManager {
40375
40395
  return true;
40376
40396
  return false;
40377
40397
  }
40398
+ /** Mark cached view as stale and cancel any in-flight load for this record. */
40399
+ markViewStaleForReload(rec) {
40400
+ var _a;
40401
+ rec.view.meta = Object.assign(Object.assign({}, ((_a = rec.view.meta) !== null && _a !== void 0 ? _a : {})), { stale: true });
40402
+ rec.view.updatedAt = this.now();
40403
+ rec.view.loadId = generateId();
40404
+ if (rec.view.abortController) {
40405
+ rec.view.abortController.abort();
40406
+ rec.view.abortController = undefined;
40407
+ }
40408
+ }
40378
40409
  cleanupOldViews(bucket) {
40379
40410
  if (bucket.size <= this.maxViewsPerParent)
40380
40411
  return;
@@ -40651,14 +40682,6 @@ class ViewCacheManager {
40651
40682
  }
40652
40683
  }
40653
40684
  }
40654
- // Если задан comparator — считаем клиентскую сортировку авторитетной
40655
- canSafelyModifySortedView(baseParams) {
40656
- if (!baseParams.sortBy && !baseParams.sortOrder)
40657
- return true;
40658
- if (this.strategy.comparator)
40659
- return true;
40660
- return false;
40661
- }
40662
40685
  cascadeShiftPages(bucket, startPageRec, startPageNum, pageSize, totalPages, entitiesManager, baseParams) {
40663
40686
  var _a, _b, _c;
40664
40687
  let currentPageRec = startPageRec;
@@ -40775,7 +40798,7 @@ class ViewCacheManager {
40775
40798
  return wasNewPageCreated;
40776
40799
  }
40777
40800
  tryInsertSorted(rec, entity, entitiesManager) {
40778
- var _a;
40801
+ var _a, _b;
40779
40802
  const comparator = this.strategy.comparator;
40780
40803
  if (!comparator)
40781
40804
  return false;
@@ -40787,6 +40810,21 @@ class ViewCacheManager {
40787
40810
  const currentEntities = rec.view.value.map((id) => entitiesManager.getEntity(id));
40788
40811
  if (currentEntities.some((e) => !e))
40789
40812
  return false;
40813
+ if (currentEntities.length === 0) {
40814
+ const params = (_b = rec.params) !== null && _b !== void 0 ? _b : {};
40815
+ if (params.sortBy || params.sortOrder) {
40816
+ const probe = comparator(entity, entity, rec.params);
40817
+ if (typeof probe !== 'number' || Number.isNaN(probe))
40818
+ return false;
40819
+ }
40820
+ if (rec.view.value.includes(entity.id)) {
40821
+ rec.view.updatedAt = this.now();
40822
+ return true;
40823
+ }
40824
+ rec.view.value = [entity.id];
40825
+ rec.view.updatedAt = this.now();
40826
+ return true;
40827
+ }
40790
40828
  let lo = 0;
40791
40829
  let hi = currentEntities.length;
40792
40830
  while (lo < hi) {
@@ -40805,9 +40843,6 @@ class ViewCacheManager {
40805
40843
  }
40806
40844
  rec.view.value = [...rec.view.value.slice(0, lo), entity.id, ...rec.view.value.slice(lo)];
40807
40845
  rec.view.updatedAt = this.now();
40808
- if (rec.view.meta && typeof rec.view.meta.total === 'number') {
40809
- rec.view.meta.total = Number(rec.view.meta.total) + 1;
40810
- }
40811
40846
  return true;
40812
40847
  }
40813
40848
  updateChildrenCountForOperation(operation, entity, prevParentId, entitiesManager) {
@@ -40842,7 +40877,7 @@ class ViewCacheManager {
40842
40877
  }
40843
40878
  // Разделили smartInvalidate на хелперы
40844
40879
  smartInvalidateChildrenViews(parentId, entity, operation, entitiesManager, prevParentId, prevEntity) {
40845
- var _a, _b, _c, _d;
40880
+ var _a, _b, _c;
40846
40881
  if (!entity)
40847
40882
  return;
40848
40883
  // Всегда обновляем childrenCount (entitiesManager обязателен)
@@ -40867,7 +40902,7 @@ class ViewCacheManager {
40867
40902
  if (rec.view.meta && typeof rec.view.meta.total === 'number') {
40868
40903
  rec.view.meta.total = Math.max(0, rec.view.meta.total - 1);
40869
40904
  }
40870
- rec.view.updatedAt = Date.now();
40905
+ this.markViewStaleForReload(rec);
40871
40906
  }
40872
40907
  continue;
40873
40908
  }
@@ -40885,13 +40920,7 @@ class ViewCacheManager {
40885
40920
  const entityInView = rec.view.value.includes(entity.id);
40886
40921
  const shouldInvalidateCompletely = this.shouldInvalidateCompletely(rec, operation, entity, hasSort, isPaginated, page);
40887
40922
  if (shouldInvalidateCompletely) {
40888
- rec.view.meta = Object.assign(Object.assign({}, ((_d = rec.view.meta) !== null && _d !== void 0 ? _d : {})), { stale: true });
40889
- rec.view.loadId = generateId();
40890
- // Отменяем старый AbortController если был
40891
- if (rec.view.abortController) {
40892
- rec.view.abortController.abort();
40893
- rec.view.abortController = undefined;
40894
- }
40923
+ this.markViewStaleForReload(rec);
40895
40924
  continue;
40896
40925
  }
40897
40926
  switch (operation) {
@@ -40911,13 +40940,10 @@ class ViewCacheManager {
40911
40940
  }
40912
40941
  }
40913
40942
  }
40914
- shouldInvalidateCompletely(rec, operation, entity, hasSort, isPaginated, page) {
40943
+ shouldInvalidateCompletely(rec, operation, _entity, _hasSort, isPaginated, page) {
40915
40944
  if (isPaginated && page > 1 && (operation === 'insert' || operation === 'delete' || operation === 'move')) {
40916
40945
  return true;
40917
40946
  }
40918
- if (hasSort && !this.strategy.comparator && (operation === 'insert' || operation === 'move')) {
40919
- return true;
40920
- }
40921
40947
  if (this.isExpired(rec.view.updatedAt)) {
40922
40948
  return true;
40923
40949
  }
@@ -40928,16 +40954,13 @@ class ViewCacheManager {
40928
40954
  const itemType = ((_a = rec.params) === null || _a === void 0 ? void 0 : _a.itemType) || 'all';
40929
40955
  if (!this.isEntityTypeCompatible(entity, itemType))
40930
40956
  return false;
40931
- if (this.strategy.comparator && this.strategy.filterMatch) {
40932
- if (!this.strategy.filterMatch(entity, rec.params))
40933
- return false;
40934
- const inserted = this.tryInsertSorted(rec, entity, entitiesManager);
40935
- if (inserted)
40936
- return true;
40937
- }
40938
40957
  const params = (_b = rec.params) !== null && _b !== void 0 ? _b : {};
40939
- const hasSort = !!(params.sortBy || params.sortOrder);
40940
- if (hasSort && !this.canSafelyModifySortedView(params))
40958
+ if (!this.strategy.filterMatch(entity, params))
40959
+ return false;
40960
+ const inserted = this.tryInsertSorted(rec, entity, entitiesManager);
40961
+ if (inserted)
40962
+ return true;
40963
+ if (params.sortBy || params.sortOrder)
40941
40964
  return false;
40942
40965
  if (!isPaginated || rec.view.value.length < pageSize) {
40943
40966
  rec.view.value.push(entity.id);
@@ -40982,31 +41005,37 @@ class ViewCacheManager {
40982
41005
  }
40983
41006
  // helper: вставка
40984
41007
  handleInsert(bucket, rec, page, pageSize, isPaginated, hasSort, entity, entitiesManager) {
40985
- var _a, _b, _c, _d;
41008
+ var _a, _b, _c;
40986
41009
  if (rec.view.value.includes(entity.id))
40987
41010
  return;
40988
41011
  if (hasSort && this.strategy.allowSortedInsert && this.strategy.comparator && entitiesManager) {
40989
41012
  const inserted = this.tryInsertSorted(rec, entity, entitiesManager);
40990
- if (inserted && rec.view.meta && typeof rec.view.meta.total === 'number') {
40991
- rec.view.meta.total += 1;
40992
- if (isPaginated && Number.isFinite(pageSize)) {
40993
- const finitePageSize = pageSize;
40994
- if (finitePageSize > 0) {
40995
- rec.view.meta.totalPages = Math.max(1, Math.ceil(rec.view.meta.total / finitePageSize));
41013
+ if (inserted) {
41014
+ if (rec.view.meta && typeof rec.view.meta.total === 'number') {
41015
+ rec.view.meta.total += 1;
41016
+ if (isPaginated && Number.isFinite(pageSize)) {
41017
+ const finitePageSize = pageSize;
41018
+ if (finitePageSize > 0) {
41019
+ rec.view.meta.totalPages = Math.max(1, Math.ceil(rec.view.meta.total / finitePageSize));
41020
+ }
40996
41021
  }
41022
+ this.syncTotalsInSameViews(bucket, rec);
40997
41023
  }
40998
- this.syncTotalsInSameViews(bucket, rec);
40999
- }
41000
- if (isPaginated && ((_b = (_a = rec.view.value) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) > pageSize && entitiesManager) {
41001
- const meta = rec.view.meta;
41002
- const totalPages = meta && typeof meta.totalPages === 'number' ? meta.totalPages : 1;
41003
- const wasNewPageCreated = this.cascadeShiftToNextPage(bucket, rec, page, pageSize, totalPages, entitiesManager, (_c = rec.params) !== null && _c !== void 0 ? _c : {});
41004
- if (wasNewPageCreated && rec.view.meta && typeof rec.view.meta.totalPages === 'number') {
41005
- const newTotalPages = rec.view.meta.totalPages + 1;
41006
- rec.view.meta.totalPages = newTotalPages;
41007
- this.updateTotalPagesForAllViews(bucket, newTotalPages);
41024
+ rec.view.updatedAt = Date.now();
41025
+ if (isPaginated && ((_b = (_a = rec.view.value) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) > pageSize && entitiesManager) {
41026
+ const meta = rec.view.meta;
41027
+ const totalPages = meta && typeof meta.totalPages === 'number' ? meta.totalPages : 1;
41028
+ const wasNewPageCreated = this.cascadeShiftToNextPage(bucket, rec, page, pageSize, totalPages, entitiesManager, (_c = rec.params) !== null && _c !== void 0 ? _c : {});
41029
+ if (wasNewPageCreated && rec.view.meta && typeof rec.view.meta.totalPages === 'number') {
41030
+ const newTotalPages = rec.view.meta.totalPages + 1;
41031
+ rec.view.meta.totalPages = newTotalPages;
41032
+ this.updateTotalPagesForAllViews(bucket, newTotalPages);
41033
+ }
41008
41034
  }
41009
41035
  }
41036
+ else {
41037
+ this.markViewStaleForReload(rec);
41038
+ }
41010
41039
  }
41011
41040
  else {
41012
41041
  if (!isPaginated || rec.view.value.length < pageSize) {
@@ -41024,7 +41053,7 @@ class ViewCacheManager {
41024
41053
  rec.view.updatedAt = Date.now();
41025
41054
  }
41026
41055
  else {
41027
- rec.view.meta = Object.assign(Object.assign({}, ((_d = rec.view.meta) !== null && _d !== void 0 ? _d : {})), { stale: true });
41056
+ this.markViewStaleForReload(rec);
41028
41057
  }
41029
41058
  }
41030
41059
  rec.view.loadId = generateId();
@@ -41036,7 +41065,7 @@ class ViewCacheManager {
41036
41065
  }
41037
41066
  // helper: update
41038
41067
  handleUpdate(bucket, rec, page, pageSize, isPaginated, hasSort, hasSearch, entity, entitiesManager) {
41039
- var _a, _b, _c, _d;
41068
+ var _a, _b;
41040
41069
  const entityInView = rec.view.value.includes(entity.id);
41041
41070
  const stillCompatible = this.isEntityTypeCompatible(entity, ((_a = rec.params) === null || _a === void 0 ? void 0 : _a.itemType) || 'all');
41042
41071
  if (entityInView && !stillCompatible) {
@@ -41073,46 +41102,16 @@ class ViewCacheManager {
41073
41102
  rec.view.value = rec.view.value.filter((id) => id !== entity.id);
41074
41103
  const reinserted = this.tryReinsertEntity(rec, entity, entitiesManager, isPaginated, pageSize);
41075
41104
  if (!reinserted) {
41076
- if (rec.view.meta && typeof rec.view.meta.total === 'number') {
41077
- rec.view.meta.total = Math.max(0, rec.view.meta.total - 1);
41078
- if (isPaginated && Number.isFinite(pageSize) && typeof rec.view.meta.total === 'number') {
41079
- const finitePageSize = pageSize;
41080
- if (finitePageSize > 0) {
41081
- rec.view.meta.totalPages = Math.max(1, Math.ceil(rec.view.meta.total / finitePageSize));
41082
- }
41083
- }
41084
- this.syncTotalsInSameViews(bucket, rec);
41085
- }
41086
- if (isPaginated && rec.view.value.length < pageSize && entitiesManager) {
41087
- const meta = rec.view.meta;
41088
- const totalPages = meta && typeof meta.totalPages === 'number' ? meta.totalPages : 1;
41089
- const wasEmptyPageRemoved = this.cascadeShiftPages(bucket, rec, page, pageSize, totalPages, entitiesManager, (_c = rec.params) !== null && _c !== void 0 ? _c : {});
41090
- if (wasEmptyPageRemoved && rec.view.meta && typeof rec.view.meta.totalPages === 'number') {
41091
- const newTotalPages = Math.max(1, rec.view.meta.totalPages - 1);
41092
- rec.view.meta.totalPages = newTotalPages;
41093
- this.updateTotalPagesForAllViews(bucket, newTotalPages);
41094
- }
41095
- }
41105
+ this.markViewStaleForReload(rec);
41096
41106
  }
41097
41107
  else {
41098
- if (rec.view.meta && typeof rec.view.meta.total === 'number') {
41099
- rec.view.meta.total += 1;
41100
- if (isPaginated && Number.isFinite(pageSize)) {
41101
- const finitePageSize = pageSize;
41102
- if (finitePageSize > 0) {
41103
- rec.view.meta.totalPages = Math.max(1, Math.ceil(rec.view.meta.total / finitePageSize));
41104
- }
41105
- }
41106
- this.syncTotalsInSameViews(bucket, rec);
41108
+ rec.view.updatedAt = Date.now();
41109
+ rec.view.loadId = generateId();
41110
+ if (rec.view.abortController) {
41111
+ rec.view.abortController.abort();
41112
+ rec.view.abortController = undefined;
41107
41113
  }
41108
41114
  }
41109
- rec.view.updatedAt = Date.now();
41110
- rec.view.loadId = generateId();
41111
- // Отменяем старый AbortController если был
41112
- if (rec.view.abortController) {
41113
- rec.view.abortController.abort();
41114
- rec.view.abortController = undefined;
41115
- }
41116
41115
  return;
41117
41116
  }
41118
41117
  if (entityInView) {
@@ -41128,15 +41127,21 @@ class ViewCacheManager {
41128
41127
  if (stillCompatible && !hasSearch) {
41129
41128
  if (hasSort && this.strategy.allowSortedInsert && this.strategy.comparator && entitiesManager) {
41130
41129
  const inserted = this.tryInsertSorted(rec, entity, entitiesManager);
41131
- if (inserted && rec.view.meta && typeof rec.view.meta.total === 'number') {
41132
- rec.view.meta.total += 1;
41133
- if (isPaginated && Number.isFinite(pageSize)) {
41134
- const finitePageSize = pageSize;
41135
- if (finitePageSize > 0) {
41136
- rec.view.meta.totalPages = Math.max(1, Math.ceil(rec.view.meta.total / finitePageSize));
41130
+ if (inserted) {
41131
+ if (rec.view.meta && typeof rec.view.meta.total === 'number') {
41132
+ rec.view.meta.total += 1;
41133
+ if (isPaginated && Number.isFinite(pageSize)) {
41134
+ const finitePageSize = pageSize;
41135
+ if (finitePageSize > 0) {
41136
+ rec.view.meta.totalPages = Math.max(1, Math.ceil(rec.view.meta.total / finitePageSize));
41137
+ }
41137
41138
  }
41139
+ this.syncTotalsInSameViews(bucket, rec);
41138
41140
  }
41139
- this.syncTotalsInSameViews(bucket, rec);
41141
+ rec.view.updatedAt = Date.now();
41142
+ }
41143
+ else {
41144
+ this.markViewStaleForReload(rec);
41140
41145
  }
41141
41146
  }
41142
41147
  else if (!isPaginated || rec.view.value.length < pageSize) {
@@ -41154,7 +41159,7 @@ class ViewCacheManager {
41154
41159
  rec.view.updatedAt = Date.now();
41155
41160
  }
41156
41161
  else {
41157
- rec.view.meta = Object.assign(Object.assign({}, ((_d = rec.view.meta) !== null && _d !== void 0 ? _d : {})), { stale: true });
41162
+ this.markViewStaleForReload(rec);
41158
41163
  }
41159
41164
  rec.view.loadId = generateId();
41160
41165
  // Отменяем старый AbortController если был
@@ -41560,14 +41565,15 @@ class TreeCache_TreeCache {
41560
41565
  });
41561
41566
  // Применяем viewOptions к ViewCacheManager после создания
41562
41567
  if (viewOptions) {
41568
+ const resolved = resolveViewStrategyOptions(viewOptions);
41563
41569
  v.strategy = {
41564
- allowSortedInsert: (_g = viewOptions.allowSortedInsert) !== null && _g !== void 0 ? _g : true,
41565
- allowSearchInsert: (_h = viewOptions.allowSearchInsert) !== null && _h !== void 0 ? _h : true,
41566
- invalidateOnPaginationFull: (_j = viewOptions.invalidateOnPaginationFull) !== null && _j !== void 0 ? _j : true,
41567
- preloadPagesBefore: (_k = viewOptions.preloadPagesBefore) !== null && _k !== void 0 ? _k : 0,
41568
- preloadPagesAfter: (_l = viewOptions.preloadPagesAfter) !== null && _l !== void 0 ? _l : 1,
41569
- comparator: viewOptions.comparator,
41570
- filterMatch: viewOptions.filterMatch,
41570
+ allowSortedInsert: (_g = resolved.allowSortedInsert) !== null && _g !== void 0 ? _g : true,
41571
+ allowSearchInsert: (_h = resolved.allowSearchInsert) !== null && _h !== void 0 ? _h : true,
41572
+ invalidateOnPaginationFull: (_j = resolved.invalidateOnPaginationFull) !== null && _j !== void 0 ? _j : true,
41573
+ preloadPagesBefore: (_k = resolved.preloadPagesBefore) !== null && _k !== void 0 ? _k : 0,
41574
+ preloadPagesAfter: (_l = resolved.preloadPagesAfter) !== null && _l !== void 0 ? _l : 1,
41575
+ comparator: resolved.comparator,
41576
+ filterMatch: resolved.filterMatch,
41571
41577
  };
41572
41578
  }
41573
41579
  tc.entities = ent;
@@ -41617,6 +41623,8 @@ var DataSourceProxyBase_rest = (undefined && undefined.__rest) || function (s, e
41617
41623
 
41618
41624
 
41619
41625
 
41626
+
41627
+
41620
41628
  // Константы для стандартных идентификаторов
41621
41629
  const DEFAULT_ROOT_ID = '';
41622
41630
  const DEFAULT_TRASH_PATH = 'Trash';
@@ -41672,12 +41680,62 @@ function parseFilePath(filePath) {
41672
41680
  * Extend this class in a consumer app to add backend-specific logic.
41673
41681
  */
41674
41682
  class DataSourceProxyBase {
41683
+ _getTrashPath() {
41684
+ return this._pathOptions.trashPath || DEFAULT_TRASH_PATH;
41685
+ }
41686
+ _getPathLookupCandidates(path) {
41687
+ return getTrashFolderLookupCandidates(path, this._getTrashPath(), TRASH_FOLDER_ID);
41688
+ }
41689
+ _folderFromResolvedPath(resolved, lookupPath) {
41690
+ var _a;
41691
+ if (resolved.isFolder !== true) {
41692
+ const message = resolved.isFolder === false ?
41693
+ "Path '%s' resolves to a file, not a folder".replace('%s', lookupPath)
41694
+ : "Path '%s' resolved to an item that is not marked as a folder".replace('%s', lookupPath);
41695
+ throw new FileManagerApiError(message, 'ValidationError');
41696
+ }
41697
+ if (!resolved.id) {
41698
+ const message = "Path '%s' resolved to a folder without id".replace('%s', lookupPath);
41699
+ throw new FileManagerApiError(message, 'ValidationError');
41700
+ }
41701
+ const folder = {
41702
+ id: resolved.id,
41703
+ name: resolved.name || resolved.id,
41704
+ parentId: resolved.folderId,
41705
+ };
41706
+ // Synthetic system folders (e.g. backend-managed trash) must exist in the entity
41707
+ // graph so forceInvalidate(trash.id) can invalidate children views.
41708
+ this._cache.upsertEntity(normalizeFileSystemItem({
41709
+ id: folder.id,
41710
+ name: folder.name,
41711
+ folderId: (_a = folder.parentId) !== null && _a !== void 0 ? _a : null,
41712
+ isFolder: true,
41713
+ }));
41714
+ return folder;
41715
+ }
41716
+ async _resolveFolderByPath(path) {
41717
+ if (typeof this._dataProvider.findItemByPath !== 'function') {
41718
+ return undefined;
41719
+ }
41720
+ for (const lookupPath of this._getPathLookupCandidates(path)) {
41721
+ const resolved = await this._dataProvider.findItemByPath(lookupPath);
41722
+ if (!resolved) {
41723
+ continue;
41724
+ }
41725
+ return this._folderFromResolvedPath(resolved, lookupPath);
41726
+ }
41727
+ return undefined;
41728
+ }
41675
41729
  async _findOrCreateFolderByPath(path) {
41676
41730
  const parts = parseFilePath(path);
41677
41731
  if (parts.length > MAX_PATH_DEPTH) {
41678
41732
  const message = 'Path depth exceeds maximum limit of %s'.replace('%s', String(MAX_PATH_DEPTH));
41679
41733
  throw new FileManagerApiError(message, 'ValidationError');
41680
41734
  }
41735
+ const resolvedFolder = await this._resolveFolderByPath(path);
41736
+ if (resolvedFolder) {
41737
+ return resolvedFolder;
41738
+ }
41681
41739
  let current = undefined;
41682
41740
  for (const part of parts) {
41683
41741
  const { files } = await this.getFiles({ folderId: (current === null || current === void 0 ? void 0 : current.id) || '', itemType: 'folder' });
@@ -41698,8 +41756,13 @@ class DataSourceProxyBase {
41698
41756
  }
41699
41757
  return current;
41700
41758
  }
41701
- getTrashFolder() {
41702
- return this._findOrCreateFolderByPath(this._pathOptions.trashPath || DEFAULT_TRASH_PATH);
41759
+ async getTrashFolder() {
41760
+ const folder = await this._findOrCreateFolderByPath(this._getTrashPath());
41761
+ if (!folder) {
41762
+ const message = "Trash folder path '%s' could not be resolved".replace('%s', this._getTrashPath());
41763
+ throw new FileManagerApiError(message, 'FolderNotFound');
41764
+ }
41765
+ return folder;
41703
41766
  }
41704
41767
  async getTempFolder() {
41705
41768
  var _a;
@@ -41747,7 +41810,7 @@ class DataSourceProxyBase {
41747
41810
  this._rootId = this._pathOptions.rootId || DEFAULT_ROOT_ID;
41748
41811
  this._enableTrash = this._options.enableTrash === undefined ? true : this._options.enableTrash;
41749
41812
  this._validateDuplicates = this._dataProvider.validateDuplicates;
41750
- // Инициализация кэша с переданными настройками
41813
+ // ViewCacheManager applies resolveViewStrategyOptions in its constructor.
41751
41814
  this._cache = new TreeCache(_options.cacheStrategy || {}, (_a = _options.cacheStrategy) === null || _a === void 0 ? void 0 : _a.ttl, (_b = _options.cacheStrategy) === null || _b === void 0 ? void 0 : _b.errorTtl);
41752
41815
  // if (!this._dataProvider.deleteItems) {
41753
41816
  // this.deleteItems = undefined;
@@ -42163,23 +42226,7 @@ class DataSourceProxyBase {
42163
42226
  * Стандартная клиентская сортировка файлов
42164
42227
  */
42165
42228
  _defaultClientSideSort(files, sortBy, sortOrder) {
42166
- return files.sort((a, b) => {
42167
- let compareResult = 0;
42168
- switch (sortBy) {
42169
- case 'name':
42170
- compareResult = (a.name || '').localeCompare(b.name || '');
42171
- break;
42172
- case 'date':
42173
- compareResult = new Date(a.date || 0).getTime() - new Date(b.date || 0).getTime();
42174
- break;
42175
- case 'size':
42176
- compareResult = (Number(a.size) || 0) - (Number(b.size) || 0);
42177
- break;
42178
- default:
42179
- compareResult = (a.name || '').localeCompare(b.name || '');
42180
- }
42181
- return sortOrder === 'desc' ? -compareResult : compareResult;
42182
- });
42229
+ return files.sort((a, b) => compareFileSystemItems(a, b, { sortBy, sortOrder }));
42183
42230
  }
42184
42231
  async getFileData(fileOrId, options) {
42185
42232
  var _a;
@@ -43004,11 +43051,11 @@ var PathAwareStorageAdapter_rest = (undefined && undefined.__rest) || function (
43004
43051
  // @ts-nocheck
43005
43052
 
43006
43053
 
43054
+
43007
43055
  const PathAwareStorageAdapter_DEFAULT_ROOT_ID = '';
43008
43056
  const PathAwareStorageAdapter_DEFAULT_TRASH_PATH = 'Trash';
43009
- const DEFAULT_TRASH_ID = 'Trash';
43010
43057
  class PathAwareStorageAdapter {
43011
- constructor(_inner, rootPath = PathAwareStorageAdapter_DEFAULT_ROOT_ID, trashId = DEFAULT_TRASH_ID, trashPath = PathAwareStorageAdapter_DEFAULT_TRASH_PATH, ensureFolderTrailingSlash = true) {
43058
+ constructor(_inner, rootPath = PathAwareStorageAdapter_DEFAULT_ROOT_ID, trashId = TRASH_FOLDER_ID, trashPath = PathAwareStorageAdapter_DEFAULT_TRASH_PATH, ensureFolderTrailingSlash = true) {
43012
43059
  var _a;
43013
43060
  this._inner = _inner;
43014
43061
  this.rootPath = rootPath;
@@ -43082,11 +43129,46 @@ class PathAwareStorageAdapter {
43082
43129
  return;
43083
43130
  return this._inner.clearCache(pathFolder);
43084
43131
  }
43132
+ findItemByPath(path) {
43133
+ if (typeof this._inner.findItemByPath !== 'function') {
43134
+ return undefined;
43135
+ }
43136
+ const mapResolved = (resolved, lookupPath, requestPath) => {
43137
+ if (!resolved) {
43138
+ return undefined;
43139
+ }
43140
+ if (resolved.isFolder !== true) {
43141
+ return resolved;
43142
+ }
43143
+ const requestPathClean = normalizeSystemFolderPath(requestPath);
43144
+ const trashPathClean = normalizeSystemFolderPath(this.trashPath);
43145
+ const idPath = requestPathClean === trashPathClean ? this.trashPath : lookupPath;
43146
+ const cleanedIdPath = normalizeSystemFolderPath(idPath);
43147
+ const parentPath = resolved.folderId != null && resolved.folderId !== '' ?
43148
+ normalizeSystemFolderPath(resolved.folderId)
43149
+ : this.rootPath;
43150
+ return Object.assign(Object.assign({}, resolved), { id: this._getOrGenerateId(cleanedIdPath), name: resolved.name, folderId: parentPath === normalizeSystemFolderPath(this.rootPath) ?
43151
+ this.rootPath || ''
43152
+ : this._getOrGenerateId(parentPath), isFolder: true });
43153
+ };
43154
+ const lookupPaths = getTrashFolderLookupCandidates(path, this.trashPath, this.trashId);
43155
+ const resolveCandidates = async () => {
43156
+ for (const lookupPath of lookupPaths) {
43157
+ const resolved = await Promise.resolve(this._inner.findItemByPath(lookupPath));
43158
+ const mapped = mapResolved(resolved, lookupPath, path);
43159
+ if (mapped) {
43160
+ return mapped;
43161
+ }
43162
+ }
43163
+ return undefined;
43164
+ };
43165
+ return resolveCandidates();
43166
+ }
43085
43167
  _getOrGenerateId(path) {
43086
43168
  if (path === this.rootPath)
43087
43169
  return '';
43088
- const cleanedPath = path.replaceAll(/^\/+|\/+$/g, '');
43089
- if (cleanedPath === this.trashPath.replaceAll(/^\/+|\/+$/g, ''))
43170
+ const cleanedPath = normalizeSystemFolderPath(path);
43171
+ if (cleanedPath === normalizeSystemFolderPath(this.trashPath))
43090
43172
  return this.trashId;
43091
43173
  if (this._pathToId.has(cleanedPath))
43092
43174
  return this._pathToId.get(cleanedPath);
@@ -43566,6 +43648,8 @@ var remoteFileFetchPipeline = __webpack_require__(5597);
43566
43648
 
43567
43649
 
43568
43650
 
43651
+
43652
+
43569
43653
  })();
43570
43654
 
43571
43655
  __webpack_exports__ = __webpack_exports__["default"];