@haiiro/docuflow 0.0.15 → 0.0.16
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/bin/install.mjs +9 -4
- package/manifest.json +5 -5
- package/package.json +1 -1
- package/public/app/docflow-app.js +1 -1
- package/src/front-components/docflow-tasks.front-component.mjs +32 -32
- package/src/front-components/docflow-tasks.front-component.tsx +19 -2
- package/src/logic-functions/bitrix-app.logic-function.mjs +1 -1
- package/src/logic-functions/docflow-app.logic-function.mjs +1 -1
package/bin/install.mjs
CHANGED
|
@@ -104,12 +104,17 @@ class CrmApiError extends Error {
|
|
|
104
104
|
return /(not|must be) higher than the currently deployed/i.test(`${this.message} ${this.rawMessage}`);
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
-
// The app
|
|
108
|
-
//
|
|
107
|
+
// The app is tied to npm on this CRM: installed from the marketplace before,
|
|
108
|
+
// or (Twenty 2.50+) listed in the marketplace from npm by the server itself,
|
|
109
|
+
// which then claims its identifier. The server refuses an archive for it
|
|
110
|
+
// and installs the same version from npm.
|
|
109
111
|
get isSourceChannelMismatch() {
|
|
112
|
+
const codes = [this.extensions.code, this.extensions.subCode];
|
|
113
|
+
|
|
110
114
|
return (
|
|
111
|
-
|
|
112
|
-
|
|
115
|
+
codes.includes('SOURCE_CHANNEL_MISMATCH') ||
|
|
116
|
+
codes.includes('UNIVERSAL_IDENTIFIER_ALREADY_CLAIMED') ||
|
|
117
|
+
/source channel|Cannot upload tarball|already claimed/i.test(`${this.message} ${this.rawMessage}`)
|
|
113
118
|
);
|
|
114
119
|
}
|
|
115
120
|
|
package/manifest.json
CHANGED
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"defaultRoleUniversalIdentifier": "26b1dde8-4ed9-4f39-8516-e0dcb734ea5a",
|
|
50
50
|
"aboutDescription": "# Документооборот (`@crm-nordiv/docuflow`)\n\nЗадания, процессы и документы компании в одном разделе. Ставится в CRM как приложение, без правок\nсервера.\n\n- universalIdentifier: `0b7d5d2e-8c4f-4a59-9a43-2f6f1c3e9d21`\n\n## Что получается после установки\n\n| Где | Что |\n|---|---|\n| Сайдбар | папка «Документооборот» с пунктами «Задания», «Процессы», «Документы» — у каждого своя страница |\n| «Задания» | задачи раздела «Документооборот»; фильтры «Открытые / Мои / Просроченные / Выполненные / Архив» (архив — удалённые, со штатным «Восстановить»), поиск, создание задания с инструкцией и полями для заполнения |\n| Панель задания | вкладки «Задание» (поля и ход) и «Чат», если стоит `@haiiro/chats`: переписка задачи с меню сообщения, как в «Чатах» |\n| Карточка задачи | вкладка «Задание»: инструкция, поля задания (собрать конструктором, заполнить), «Выполнить» |\n| Карточка процесса | кнопка «Параметры запуска» вверху (боковая панель): параметры запуска (конструктор полей) и, для шагов «Человеческий ввод» черновика, кто выполняет, срок в днях, обязательные поля; у каждого поля видна переменная, которой его читают следующие шаги |\n| Редактор процесса | первый блок «Запуск с параметрами» (ставится сам): параметры, заполненные перед запуском, и запись, на которой запустили, — его переменные |\n| Командное меню | «Запустить процесс» (Cmd+K и меню выбранных записей любого объекта): выбор процесса, форма параметров в боковой панели, «Запустить»; запуск открывается в боковой панели, как штатный ручной |\n| «Процессы» | процессы с ручным запуском раздела «Документооборот»; форма параметров до запуска, «Запустить», «Создать», «Изменить процесс» |\n| «Документы» | папки, фильтры, поиск по названию и номеру, документ с реквизитами (тип, номер, дата, срок действия, контрагент, описание), файл в поле «Файл» карточки, карточка с источником |\n| Автоматически | шаг «Человеческий ввод» процесса становится задачей; её выполнение продолжает процесс; файл, приложенный к любой записи, копируется в документы с отметкой, кто, когда и куда его добавил |\n| Отдельная страница | `https://<адрес CRM>/s/docflow/app`: «Задания», «Процессы», «Документы» без остальной CRM, вход — тот же, что в CRM |\n| Битрикс24 | та же страница внутри приложения портала, вход через CRM в отдельном окне; уведомление исполнителю нового задания |\n\n## Данные\n\n| Объект | Поля |\n|---|---|\n| `smbDocument` (новый) | название, файл, тип, номер, дата, действует до, контрагент (компания), описание, статус, автор, ответственный, папка; источник: `origin`, `sourceObjectName`, `sourceRecordId`, `sourceRecordName`, `sourceFileId`, `workflowRunId` |\n| `smbDocumentFolder` (новый) | название, цвет, родительская папка |\n| `workflow` | `smbSection` «Раздел»: CRM / Документооборот; `smbLaunchFields` «Параметры запуска» — поля, которые заполняют перед запуском |\n| `task` | `smbSection`, `smbInstruction` «Инструкция»; `smbFormSchema`, `smbFormValues` — поля задания; `smbWorkflowRunId`, `smbWorkflowStepId`, `smbWorkflowThreadId` — связь с шагом процесса |\n| `company` | `smbDocuments` — документы контрагента |\n| роли | «Документооборот: функции приложения» (права функций), «Документооборот: участник процессов» (для людей, см. ниже) |\n\n## Установка\n\nС любого компьютера с Node.js 20+, нужен только адрес CRM и ключ API администратора\n(«Настройки → API и вебхуки → Создать ключ»). Повторный запуск ставит новую версию:\n\n```bash\nnpx -y @haiiro/docuflow install --url https://crm.example.ru --api-key <ключ>\n```\n\nУстановщик загружает в CRM опубликованный архив этой версии пакета и устанавливает приложение\n(как `twenty app:install`), доступ к серверу и его настройки не нужны. Конкретная версия:\n`--version 0.0.8`. Пакет собран под Twenty 2.45: на другой минорной версии установщик\nпредупреждает, на другой мажорной останавливается (`--force` — ставить всё равно). После установки\nон сверяет версию в CRM: CRM не ставит версию ниже уже загруженной и говорит об этом прямо.\n\nИз исходников (для разработки): `node scripts/reinstall.mjs docuflow --local` в корне репозитория\n(нужны `CRM_URL` и `CRM_API_KEY` в `.env`).\n\nЗатем в «Настройки → Приложения → Документооборот» заполнить переменные:\n\n| Переменная | Что указать |\n|---|---|\n| `DOCFLOW_ENGINE` | `APP` |\n| `CRM_PUBLIC_URL` | адрес CRM компании, например `https://acme.example.ru`; по нему строятся ссылки в CRM с отдельной страницы и из Битрикс24 |\n| `BITRIX_CLIENT_ID`, `BITRIX_CLIENT_SECRET` | из карточки локального приложения портала; без них Битрикс24 не подключается, остальное работает |\n\n**Права людей.** Отвечать на шаг запущенного процесса может только тот, у кого есть право\n«Рабочие процессы». Кто выполняет задания процессов или запускает процессы с параметрами,\nполучает роль «Документооборот: участник процессов» или это право в своей роли. Право также\nпозволяет менять процессы: давайте его тем, кому это допустимо. Обычные задания и документы\nправа «Рабочие процессы» не требуют.\n\n## Как пользоваться\n\n- **Процесс.** «Процессы → Создать» создаёт процесс с ручным запуском в разделе «Документооборот» и\n открывает редактор. Существующий процесс переносится в документооборот полем «Раздел».\n- **Параметры запуска.** Кнопка процесса «Параметры запуска» → «Добавить поле»: название, тип\n (текст, число, дата, сотрудник, компания, контакт, сделка), обязательность. «Сохранить\n параметры» делает первым блоком черновика «Запуск с параметрами»: в следующих шагах параметры\n выбираются как его переменные `{{trigger.<поле>}}` — например «Запуск с параметрами →\n Сотрудник → Id» в поле «Исполнитель» задачи. «Где запускать» — «Откуда угодно, без записи» или\n «На записи: <объект>»: тогда процесс запускают на выбранных записях этого объекта, по запуску\n на каждую, а запись — переменная `{{trigger.record}}` с полями объекта (как у штатного запуска\n вручную на записи). Без параметров и записи процесс начинается с обычного «Запуск вручную».\n Опубликуйте процесс. Запускают его командой «Запустить процесс»: из Cmd+K — процессы без\n записи, на выбранных записях — процессы их объекта и процессы без записи. Процессы без записи\n запускаются и со страницы «Процессы». Обязательные параметры проверяются и в форме, и на сервере.\n\n Устройство: своих типов триггеров у приложений Twenty нет, а у «Запуск вручную» редактор\n показывает только свои переменные. Штатный пункт меню ручного запуска запускает процесс сразу,\n без формы, и встроиться в него приложение не может. Поэтому «Запуск с параметрами» — штатный триггер Webhook\n (POST, только с ключом API), поля параметров — его тело. Документооборот запускает такую версию\n сам; внешняя система (например, мост в Битрикс24) может запустить процесс POST-запросом на адрес\n вебхука с ключом API и телом из этих полей — тогда проверку обязательных полей делает она.\n Шаг «Параметры запуска» процессов из 0.0.6 и раньше при первом сохранении параметров убирается,\n его переменные в следующих шагах переводятся на `trigger`.\n- **Задание шага.** Шаг «Человеческий ввод» становится задачей раздела процесса: у исполнителя\n из «Параметров запуска», без него — у запустившего. Поля задания — поля шага из редактора.\n «Выполнить» проверяет обязательные поля и продолжает процесс; значения дальше читаются\n переменными шага `{{<шаг>.<поле>}}`.\n- **Списки.** Фильтры — в окне под полем поиска (значок фильтра горит, когда фильтр включён),\n сортировка — кликом по заголовку колонки. Действия со строкой — в «⋯» в её конце: открыть,\n переименовать, переместить в папку, удалить и т. п. «Процессы» показывают все процессы раздела,\n опубликованные и черновики.\n- **Папки документов.** «+ Новая папка», у папки «⋯ → Переименовать и оформить»: название, цвет и\n значок; удаление папки оставляет документы в «Все документы».\n- **Удаление.** «⋯ → Удалить» спрашивает ещё раз и удаляет. Запись уходит в корзину Twenty и\n восстанавливается: задания — в фильтре «Архив», документы — в фильтре «Удалённые», процессы — в\n штатном списке «Рабочие процессы → Удалённые»; в карточке удалённой записи есть «Восстановить».\n Для этого роль приложения может мягко удалять только документы, задачи и процессы.\n- **Параметры в редакторе.** После «Сохранить параметры» редактор процесса открывается заново:\n он держит загруженную версию и иначе показал бы новые переменные только после перезагрузки.\n- **Своё задание.** «Задания → Создать»: название, исполнитель, срок, инструкция и поля для\n заполнения тем же конструктором. Поля меняются в панели задания («Изменить поля»).\n- **Документы.** «Документы → Создать» создаёт черновик в открытой папке и открывает его штатную\n карточку: там реквизиты и поле «Файл»; строка списка открывает ту же карточку. Так сделано потому, что\n страница приложения в песочнице видит только имя и размер выбранного файла, не его содержимое.\n Файл, приложенный к любой записи (компания, сделка, задача, свой объект), появляется в\n документах сам: «Где загружен», автор, дата, для задачи процесса — ссылка на запуск. Документ\n хранит копию файла.\n\n## Ограничения\n\n- Рамки вокруг страницы раздела рисует платформа: карточку виджета и рамку вокруг компонента\n приложения. Компоненты приложений работают в изолированном worker'е и убрать их не могут.\n- Блок «Запуск с параметрами» в редакторе открывает штатные настройки вебхука (адрес, тело,\n авторизация): поля там те же, что в «Параметрах запуска», менять их удобнее кнопкой. Если\n переименовать блок, Документооборот перестанет узнавать его как свой запуск.\n- Параметры запуска относятся к процессу, а не к версии: после правки полей опубликованная версия\n до публикации нового черновика получает новые поля, а переменные убранных полей в ней пусты.\n- Документ без файла создаётся раньше файла: если закрыть карточку, не прикрепив файл, документ\n останется с пустым полем «Файл».\n- На отдельной странице и в Битрикс24 карточка записи (задачи, документа, процесса) открывается в\n CRM в новой вкладке: боковой панели CRM там нет. Файл документа прикрепляется там же.\n- Отдельная страница выглядит как штатный Twenty (светлая или тёмная тема по настройке системы):\n скин `@haiiro/interface` на неё не действует.\n\n## Отдельная страница\n\n`https://<адрес CRM>/s/docflow/app` — документооборот без остальной CRM: шапка с разделами «Задания»,\n«Процессы», «Документы», кнопки «На весь экран» и «Открыть CRM». Раздел при открытии —\n`?section=processes` или `?section=documents`. Это те же страницы, что в папке «Документооборот»\nсайдбара, с теми же правами: страница работает от имени сотрудника, вошедшего в CRM в этом\nбраузере. Если вход не выполнен, она предлагает войти в CRM в соседней вкладке и открывается сама.\n\n## Битрикс24\n\nПодключается локальным приложением портала (одна компания — один портал).\n\n1. В портале: «Разработчикам → Другое → Локальное приложение», тип «Серверное».\n2. Адреса — HTTP-маршруты приложения на адресе компании (точный адрес виден в «Настройки →\n Приложения → Документооборот → функции»):\n - путь обработчика: `https://<адрес компании>/s/bitrix/app`\n - путь первоначальной установки: `https://<адрес компании>/s/bitrix/install`\n3. Права приложения: `user`, `im`.\n4. Сохранить, скопировать «Код приложения» и «Ключ приложения» в `BITRIX_CLIENT_ID` и\n `BITRIX_CLIENT_SECRET`, затем открыть приложение в портале — установка завершится сама.\n\nКаждый запрос портала проверяется обменом refresh-токена на `oauth.bitrix.info` с ключом\nприложения; адрес портала берётся из ответа Битрикс24. Привязывается первый подтверждённый портал,\nдругой портал к той же компании не подключится. Токены портала хранятся в хранилище приложения, не\nв записях. Сотрудник находится по почте профиля Битрикс24: если такого ещё нет в CRM, он\nсоздаётся сам (нужна включённая публичная ссылка-приглашение в «Настройки → Участники») с той же\nпочтой и ФИО из Битрикс24.\n\n**Вход.** В портале открывается отдельная страница документооборота. Сессия CRM во фрейме портала\nне работает (браузер не отдаёт cookie CRM чужому сайту), поэтому при первом открытии страница\nпросит «Войти через CRM»: открывается окно на адресе CRM, оно берёт вход сотрудника в CRM (если его\nнет — ждёт, пока сотрудник войдёт в CRM в соседней вкладке), передаёт его во фрейм и закрывается.\nДальше страница работает с токеном этого сотрудника (его права в CRM, 30 минут) и сама продлевает\nего, пока открыта; токен хранится в хранилище браузера только для этого портала. Если приложение не\nоткрывали дольше получаса, «Войти через CRM» нажимают снова — при живом входе в CRM окно закроется\nсамо. Если в CRM в этом браузере вошёл не тот сотрудник, что в Битрикс24, страница предупреждает.\nСтраница работает только во фрейме привязанного портала.\n\n## Разработка\n\n```bash\nyarn app dev # следит за src/ и синхронизирует с сервером\nyarn app dev:function:logs\nyarn build:app # отдельная страница: public/app (yarn build делает это сам)\nyarn test && yarn typecheck && yarn lint\n```\n\nУстройство `src/`: `shared/` — общий код (формы, процессы, фильтры REST, Битрикс24); `server/` —\nобращения к записям и движку процессов из функций; `logic-functions/`; `front/` и\n`front-components/` — интерфейс; `standalone/` — отдельная страница (те же страницы вне CRM); `objects/`, `fields/`, `views/`, `roles/`, `page-layouts/`,\n`navigation-menu-items/` — данные и раскладка. Записи читаются и пишутся только через REST API\n(`server/records.ts`, `front/api.ts`), движок процессов — через две мутации GraphQL\n(`server/workflow-engine.ts`, `server/launch-step.ts`): при смене версии платформы сверять эти\nфайлы. Стили интерфейса только inline: теги `<style>` в странице приложения платформа отбрасывает.\n\nПравила правки пакета (песочница страниц, процессы, единый вид вкладок, проверка на чистой CRM) —\nв [EDITING.md](EDITING.md).\n",
|
|
51
51
|
"yarnLockChecksum": "d4d3dd414c49b677cf14b279b38ecd54",
|
|
52
|
-
"packageJsonChecksum": "
|
|
52
|
+
"packageJsonChecksum": "ff9706c913c867b36c402b2187ab51a5",
|
|
53
53
|
"requiredServerVersionRange": null,
|
|
54
54
|
"healthCheckLogicFunction": {
|
|
55
55
|
"universalIdentifier": "84360081-db5a-4f1c-9644-d975ccad9b2c"
|
|
@@ -815,7 +815,7 @@
|
|
|
815
815
|
"handlerName": "default.config.handler",
|
|
816
816
|
"sourceHandlerPath": "src/logic-functions/bitrix-app.logic-function.ts",
|
|
817
817
|
"builtHandlerPath": "src/logic-functions/bitrix-app.logic-function.mjs",
|
|
818
|
-
"builtHandlerChecksum": "
|
|
818
|
+
"builtHandlerChecksum": "5c6bbb235eccc1b00675ea5e312ef1a4"
|
|
819
819
|
},
|
|
820
820
|
{
|
|
821
821
|
"universalIdentifier": "13952f55-e84f-4d3a-a5a2-f3d68d78ba5e",
|
|
@@ -926,7 +926,7 @@
|
|
|
926
926
|
"handlerName": "default.config.handler",
|
|
927
927
|
"sourceHandlerPath": "src/logic-functions/docflow-app.logic-function.ts",
|
|
928
928
|
"builtHandlerPath": "src/logic-functions/docflow-app.logic-function.mjs",
|
|
929
|
-
"builtHandlerChecksum": "
|
|
929
|
+
"builtHandlerChecksum": "c7dac9924891566e3c7ebfb077266e1b"
|
|
930
930
|
},
|
|
931
931
|
{
|
|
932
932
|
"universalIdentifier": "c164c184-3b24-4d26-832b-219f3f02102a",
|
|
@@ -1114,7 +1114,7 @@
|
|
|
1114
1114
|
"componentName": "DocflowTasks",
|
|
1115
1115
|
"sourceComponentPath": "src/front-components/docflow-tasks.front-component.tsx",
|
|
1116
1116
|
"builtComponentPath": "src/front-components/docflow-tasks.front-component.mjs",
|
|
1117
|
-
"builtComponentChecksum": "
|
|
1117
|
+
"builtComponentChecksum": "b3de6c3a0e0283af2d6d447e86f0891021b4acce2f8f8ef4bc46de5604f09d61",
|
|
1118
1118
|
"isHeadless": false,
|
|
1119
1119
|
"usesSdkClient": true
|
|
1120
1120
|
},
|
|
@@ -1152,7 +1152,7 @@
|
|
|
1152
1152
|
"filePath": "public/app/docflow-app.js",
|
|
1153
1153
|
"fileName": "docflow-app.js",
|
|
1154
1154
|
"fileType": "js",
|
|
1155
|
-
"checksum": "
|
|
1155
|
+
"checksum": "19c9e650bd1a770ff4961944d8f7d8a8"
|
|
1156
1156
|
},
|
|
1157
1157
|
{
|
|
1158
1158
|
"filePath": "public/cover.svg",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@haiiro/docuflow",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.16",
|
|
4
4
|
"description": "NorDiv Документооборот: задания с полями, процессы с запуском по параметрам, документы со всех записей, приложение Битрикс24",
|
|
5
5
|
"license": "AGPL-3.0-only",
|
|
6
6
|
"publishConfig": {
|
|
@@ -92,4 +92,4 @@ Please change the parent <Route path="${e}"> to <Route path="${e===`/`?`*`:`${e}
|
|
|
92
92
|
`)),await Tl({message:e.length===1?`Текст скопирован`:`Сообщения скопированы`,variant:`success`})},le=e=>j(async()=>{for(let t of e)A((await cX({action:`removeMessage`,messageId:t.id})).message)},`Сообщение не удалено`),ue=(e,t)=>j(async()=>{A((await cX(e)).message)},t),de=(e,t)=>{switch(t){case`reply`:b(void 0),v(e);return;case`copy`:ce([e]);return;case`edit`:v(void 0),b(e),m(e.text);return;case`forward`:ee([e.id]);return;case`createTask`:j(async()=>{let t=await TG(`tasks`,{title:(e.text.split(`
|
|
93
93
|
`).find(e=>e.trim().length>0)??`Задача из чата`).trim().slice(0,120),bodyV2:{markdown:e.text}});await Tl({message:`Задача создана`,variant:`success`}),t!==void 0&&await Dl({to:bl.RecordShowPage,params:{objectNameSingular:`task`,objectRecordId:t.id},pageTitle:`Задача`})},`Задача не создана`);return;case`toggleResult`:ue({action:`setResult`,messageId:e.id,isResult:!e.isResult},`Не удалось изменить результат`);return;case`togglePin`:ue({action:`setPinned`,messageId:e.id,isPinned:!e.isPinned},`Не удалось закрепить`);return;case`markUnread`:j(async()=>{O!==void 0&&(await cX({action:`markUnread`,conversationId:O,seq:e.seq}),D(re))},`Не удалось отметить непрочитанным`);return;case`remove`:le([e]);return;case`select`:w([e.id]);return}};if(a===void 0)return d===void 0?(0,$.jsx)(lq,{rows:6}):(0,$.jsx)(RK,{tone:`danger`,children:d});let fe=s.filter(e=>C?.includes(e.id)),pe=ne?.pinned[0],me=y===void 0?_===void 0?void 0:{icon:ve,title:`Ответ: ${k(_.authorId)}`,text:_.text}:{icon:Jt,title:`Редактирование`,text:y.text},he=p.trim().length>0&&!h,N={overflow:`hidden`,textOverflow:`ellipsis`,whiteSpace:`nowrap`};return(0,$.jsxs)(`div`,{style:{display:`flex`,flex:1,flexDirection:`column`,gap:r.spacing[2],minHeight:0,position:`relative`},children:[pe!==void 0&&(0,$.jsxs)(`div`,{style:{alignItems:`center`,borderLeft:`2px solid ${r.color.blue}`,display:`flex`,gap:r.spacing[2],paddingLeft:r.spacing[2]},children:[(0,$.jsx)(Zt,{size:r.icon.size.sm,color:r.color.blue}),(0,$.jsxs)(`span`,{style:{display:`flex`,flex:1,flexDirection:`column`,minWidth:0},children:[(0,$.jsxs)(`strong`,{style:{color:r.color.blue,fontSize:r.font.size.xs},children:[`Закреплено`,ne!==void 0&&ne.pinned.length>1?` · ${ne.pinned.length}`:``]}),(0,$.jsx)(`span`,{style:{...N,fontSize:r.font.size.sm},children:pe.text})]}),(0,$.jsx)(iK,{icon:Qn,label:`Открепить`,onClick:()=>de(pe,`togglePin`)})]}),(0,$.jsx)(`div`,{role:`log`,"aria-live":`polite`,style:{display:`flex`,flex:`1 1 360px`,flexDirection:`column-reverse`,minHeight:0,overflowY:`auto`},children:(0,$.jsxs)(`div`,{style:{display:`flex`,flexDirection:`column`,gap:2,padding:`${r.spacing[2]} 0`},children:[l&&(0,$.jsx)(`div`,{style:{alignSelf:`center`},children:(0,$.jsx)(rK,{variant:`ghost`,size:`sm`,onClick:()=>void ae(),children:`Показать раньше`})}),s.length===0&&(0,$.jsx)(RK,{children:`Сообщений пока нет: обсудите задание здесь.`}),s.map((e,t)=>{let a=s[t-1],o=a===void 0||!uX(a.createdAt,e.createdAt);return(0,$.jsxs)(L.Fragment,{children:[o&&(0,$.jsx)(`div`,{style:{alignSelf:`center`,background:r.background.transparent.light,borderRadius:r.border.radius.md,color:r.font.color.secondary,fontSize:r.font.size.xs,margin:`${r.spacing[2]} 0`,padding:`2px ${r.spacing[2]}`},children:dX(e.createdAt,i)}),(0,$.jsx)(rX,{message:e,conversationId:O??``,viewerId:n,isGroupStart:o||a?.authorId!==e.authorId,readerIds:ie(e),memberName:k,isMenuOpen:x===e.id,menuPlacement:t>=s.length-4?`above`:`below`,isSelecting:C!==void 0,isSelected:C?.includes(e.id)??!1,onOpenMenu:()=>S(e.id),onCloseMenu:()=>S(void 0),onToggleSelected:()=>w(t=>t?.includes(e.id)?t.filter(t=>t!==e.id):[...t??[],e.id]),onAction:t=>de(e,t),onReact:t=>void ue({action:`toggleReaction`,messageId:e.id,emoji:t},`Реакция не поставлена`)})]},e.id)})]})}),d!==void 0&&(0,$.jsx)(RK,{tone:`danger`,children:d}),C===void 0?(0,$.jsxs)(`div`,{style:{display:`flex`,flexDirection:`column`,gap:r.spacing[1]},children:[me!==void 0&&(0,$.jsxs)(`div`,{style:{alignItems:`center`,borderLeft:`2px solid ${r.color.blue}`,display:`flex`,gap:r.spacing[2],paddingLeft:r.spacing[2]},children:[(0,$.jsx)(me.icon,{size:r.icon.size.sm,color:r.color.blue}),(0,$.jsxs)(`span`,{style:{display:`flex`,flex:1,flexDirection:`column`,minWidth:0},children:[(0,$.jsx)(`strong`,{style:{color:r.color.blue,fontSize:r.font.size.xs},children:me.title}),(0,$.jsx)(`span`,{style:{...N,color:r.font.color.secondary,fontSize:r.font.size.sm},children:me.text})]}),(0,$.jsx)(iK,{icon:Qn,label:`Отмена`,onClick:()=>{y!==void 0&&m(``),b(void 0),v(void 0)}})]}),(0,$.jsxs)(`div`,{style:{alignItems:`flex-end`,display:`flex`,gap:r.spacing[2]},children:[(0,$.jsx)(`textarea`,{"aria-label":`Сообщение`,placeholder:`Сообщение`,value:p,rows:Math.min(Math.max(p.split(`
|
|
94
94
|
`).length,1),sX),onChange:e=>{let t=oe.current;oe.current=void 0,t!==void 0&&e.target.value.replace(`
|
|
95
|
-
`,``)===t?m(``):m(e.target.value)},onKeyDown:e=>{e.key===`Enter`&&!e.shiftKey&&(e.preventDefault(),oe.current=he?p:void 0,se()),e.key===`Escape`&&me!==void 0&&(b(void 0),v(void 0))},style:{background:r.background.transparent.lighter,border:`1px solid ${r.border.color.light}`,borderRadius:r.border.radius.md,boxSizing:`border-box`,color:r.font.color.primary,flex:1,font:`inherit`,lineHeight:`20px`,minHeight:36,minWidth:0,padding:`7px 10px`,resize:`none`}}),(0,$.jsx)(`button`,{type:`button`,"aria-label":y===void 0?`Отправить`:`Сохранить`,title:y===void 0?`Отправить · Enter`:`Сохранить · Enter`,disabled:!he,onClick:()=>void se(),style:{alignItems:`center`,background:he?r.color.blue:r.background.transparent.light,border:`none`,borderRadius:r.border.radius.md,color:he?r.font.color.inverted:r.font.color.light,cursor:he?`pointer`:`default`,display:`inline-flex`,flexShrink:0,height:36,justifyContent:`center`,padding:0,width:36},children:(0,$.jsx)(Tn,{size:r.icon.size.md,stroke:r.icon.stroke.md})})]})]}):(0,$.jsxs)(`div`,{style:{alignItems:`center`,display:`flex`,flexWrap:`wrap`,gap:r.spacing[1]},children:[(0,$.jsxs)(`strong`,{style:{flex:1},children:[`Выбрано: `,fe.length]}),(0,$.jsx)(rK,{variant:`ghost`,size:`sm`,disabled:fe.length===0,onClick:()=>void ce(fe),children:`Копировать`}),(0,$.jsx)(rK,{variant:`ghost`,size:`sm`,disabled:fe.length===0,onClick:()=>ee(fe.map(e=>e.id)),children:`Переслать`}),fe.length>0&&fe.every(e=>e.authorId===n)&&(0,$.jsx)(rK,{variant:`ghost`,size:`sm`,onClick:()=>void le(fe).then(()=>w(void 0)),children:`Удалить`}),(0,$.jsx)(rK,{variant:`outline`,size:`sm`,onClick:()=>w(void 0),children:`Отмена`})]}),T!==void 0&&(0,$.jsx)(pX,{messageIds:T,viewerId:n,memberName:k,onClose:()=>ee(void 0),onForwarded:e=>{ee(void 0),w(void 0),Tl({message:`Переслано в «${e}»`,variant:`success`})}})]})},hX=e=>typeof e==`string`&&e.length>0&&!Number.isNaN(Date.parse(e)),gX=e=>Array.isArray(e)?e.flatMap(e=>{if(typeof e!=`object`||!e)return[];let t=e;return t.kind===`run`&&hX(t.start)?[{kind:`run`,start:t.start,end:hX(t.end)?t.end:null}]:t.kind===`add`&&typeof t.minutes==`number`&&Number.isFinite(t.minutes)&&t.minutes>0?[{kind:`add`,minutes:Math.round(t.minutes),at:hX(t.at)?t.at:new Date(0).toISOString()}]:[]}):[],_X=e=>e.some(e=>e.kind===`run`&&e.end===null),vX=(e,t)=>e.reduce((e,n)=>{if(n.kind===`add`)return e+n.minutes*6e4;let r=Date.parse(n.start),i=n.end===null?t.getTime():Date.parse(n.end);return Number.isNaN(r)||Number.isNaN(i)||i<r?e:e+(i-r)},0),yX=e=>{let t=Math.max(0,Math.floor(e/1e3)),n=Math.floor(t/3600),r=Math.floor(t%3600/60),i=t%60;return n>0?`${n}ч ${String(r).padStart(2,`0`)}м`:r>0?i>0?`${r}м ${String(i).padStart(2,`0`)}с`:`${r}м`:`${i}с`},bX=(e,t)=>_X(e)?e:[...e,{kind:`run`,start:t.toISOString(),end:null}],xX=(e,t)=>e.map(e=>e.kind===`run`&&e.end===null?{...e,end:t.toISOString()}:e),SX=(e,t,n)=>{let r=Math.round(t);return!Number.isFinite(r)||r<=0?e:[...e,{kind:`add`,minutes:r,at:n.toISOString()}]};an(),cn(),mn(),fe();var CX=`IN_PROGRESS`,wX=({answers:e})=>e.length===0?null:(0,$.jsx)(QK,{rows:e.map(({label:e,value:t})=>({label:e,value:KG(t)}))}),TX=({task:e,disabled:t,onChanged:n})=>{let r=M(),[i,a]=(0,L.useState)(!1),[o,s]=(0,L.useState)(!1),[c,l]=(0,L.useState)(``),[u,d]=(0,L.useState)(()=>new Date),f=gX(e.smbTimeLog),p=_X(f);(0,L.useEffect)(()=>{if(!p)return;let e=window.setInterval(()=>d(new Date),1e3);return()=>window.clearInterval(e)},[p]);let m=async(t,r)=>{s(!0);try{await EG(`tasks`,e.id,{smbTimeLog:t}),await Tl({message:r,variant:`success`}),await n()}catch(e){await Tl({message:PG(e,`Не удалось сохранить время`),variant:`error`})}finally{s(!1)}};return(0,$.jsxs)(`div`,{style:{alignItems:`center`,display:`flex`,gap:r.spacing[1]},children:[(0,$.jsx)(`span`,{style:{color:p?r.color.blue:r.font.color.secondary,fontSize:r.font.size.sm,fontVariantNumeric:`tabular-nums`,minWidth:`3.5em`},children:yX(vX(f,u))}),(0,$.jsx)(iK,{icon:p?rn:sn,label:p?`Пауза`:`Пуск`,disabled:t||o,isActive:p,onClick:()=>{m(p?xX(f,new Date):bX(f,new Date),p?`Таймер остановлен`:`Таймер запущен`)}}),(0,$.jsx)(cK,{isOpen:i,onClose:()=>a(!1),align:`left`,width:`200px`,anchor:(0,$.jsx)(iK,{icon:pn,label:`Добавить время`,disabled:t||o,isActive:i,onClick:()=>a(!i)}),children:(0,$.jsxs)(`div`,{style:{display:`flex`,flexDirection:`column`,gap:r.spacing[2],padding:r.spacing[2]},children:[(0,$.jsxs)(`label`,{style:{color:r.font.color.tertiary,fontSize:r.font.size.xs},children:[`Минуты`,(0,$.jsx)(`input`,{type:`number`,min:1,step:1,value:c,onChange:e=>l(e.target.value),style:{background:r.background.transparent.lighter,border:`1px solid ${r.border.color.medium}`,borderRadius:r.border.radius.sm,boxSizing:`border-box`,color:r.font.color.primary,display:`block`,fontFamily:`inherit`,fontSize:r.font.size.md,marginTop:r.spacing[1],outline:`none`,padding:r.spacing[2],width:`100%`}})]}),(0,$.jsx)(rK,{variant:`outline`,size:`sm`,disabled:o||Number(c)<=0,onClick:()=>{let e=Number(c);m(SX(f,e,new Date),`Добавлено ${Math.round(e)} мин`),l(``),a(!1)},children:`Добавить`})]})})]})},EX=({task:e,onChanged:t,rail:n,meta:r})=>{let i=M(),[a,o]=(0,L.useState)(),[s,c]=(0,L.useState)(!1),[l,u]=(0,L.useState)(),d=xJ(e.smbFormSchema),f=a??SJ(e.smbFormValues),p=e.status===dq,m=async(e,n,r)=>{c(!0),u(void 0);try{await e(),await Tl({message:n,variant:`success`}),o(void 0),await t()}catch(e){u(PG(e,r))}finally{c(!1)}};return(0,$.jsxs)(`div`,{style:{display:`flex`,flex:1,flexDirection:`column`,minHeight:0},children:[(0,$.jsxs)(`div`,{style:{display:`flex`,flex:1,gap:i.spacing[3],minHeight:0},children:[n,(0,$.jsxs)(`div`,{style:{display:`flex`,flex:1,flexDirection:`column`,gap:i.spacing[3],minHeight:0,minWidth:0},children:[r,typeof e.smbInstruction==`string`&&e.smbInstruction.trim().length>0&&(0,$.jsxs)(`section`,{"aria-label":`Инструкция`,style:{background:i.background.transparent.lighter,borderLeft:`2px solid ${i.border.color.medium}`,padding:i.spacing[3],whiteSpace:`pre-wrap`},children:[(0,$.jsx)(`div`,{style:{color:i.font.color.tertiary,fontSize:i.font.size.sm,marginBottom:i.spacing[1]},children:`Инструкция`}),e.smbInstruction]}),d.length>0?(0,$.jsx)(kJ,{fields:d,values:f,disabled:s||p,onChange:o}):(0,$.jsx)(RK,{tone:`hint`,children:`Полей нет: задание выполняется без ответа.`}),l!==void 0&&(0,$.jsx)(RK,{tone:`danger`,children:l})]})]}),(0,$.jsx)(sK,{value:`above`,children:(0,$.jsxs)(`div`,{style:{alignItems:`center`,borderTop:`1px solid ${i.border.color.light}`,display:`flex`,flexWrap:`wrap`,gap:i.spacing[2],justifyContent:`space-between`,marginTop:i.spacing[3],paddingTop:i.spacing[3]},children:[(0,$.jsx)(TX,{task:e,disabled:s,onChanged:t}),(0,$.jsxs)(`div`,{style:{display:`flex`,flexWrap:`wrap`,gap:i.spacing[2]},children:[!p&&a!==void 0&&(0,$.jsx)(rK,{variant:`outline`,size:`sm`,disabled:s,onClick:()=>m(()=>NG(`/docflow/tasks/form`,{taskId:e.id,values:f}),`Сохранено`,`Не удалось сохранить`),children:`Сохранить`}),!p&&(0,$.jsx)(rK,{variant:`solid`,tone:`accent`,size:`sm`,loading:s,onClick:()=>m(()=>NG(`/docflow/tasks/complete`,{taskId:e.id,values:f}),`Задание выполнено`,`Не удалось выполнить задание`),children:`Выполнить`})]})]})})]})},DX=(e,t)=>FG(e.find(e=>e.id===t)),OX=({task:e,run:t,members:n,now:r})=>{let i=aY(t.state,r),a=t.status===`COMPLETED`,o=t.status===`FAILED`||t.status===`STOPPED`;return[{key:`start`,title:`Запуск процесса`,meta:[t.createdBy?.name,VG(t.startedAt??t.createdAt)].filter(Boolean).join(` · `),state:`done`},...i.map(t=>{let r=t.stepId===e.smbWorkflowStepId,i=r?DX(n,e.assigneeId):DX(n,t.assigneeWorkspaceMemberId);return{key:t.stepId,title:t.name,meta:[YG[t.type]??t.type,i].filter(Boolean).join(` · `),state:t.state,isFocus:r,details:t.answers.length>0?(0,$.jsx)(wX,{answers:t.answers}):void 0}}),{key:`end`,title:o?`Процесс остановлен`:`Процесс завершён`,meta:t.endedAt?VG(t.endedAt):void 0,state:a?`done`:o?`failed`:`upcoming`}]},kX=({task:e,members:t,now:n})=>{let r=e.status===dq,i=GG(e.dueAt,n);return[{key:`created`,title:`Задание создано`,meta:[e.createdBy?.name,VG(e.createdAt)].filter(Boolean).join(` · `),state:`done`},{key:`work`,title:e.status===CX?`В работе`:`Исполнение`,meta:[DX(t,e.assigneeId)||`Исполнитель не назначен`,e.dueAt?`срок ${IG(e.dueAt)}`:void 0].filter(Boolean).join(` · `),state:r?`done`:`current`,isFocus:!0},{key:`done`,title:`Выполнено`,meta:r?VG(e.updatedAt):e.dueAt?i.label:void 0,state:r?`done`:`upcoming`}]},AX=({taskId:e,withChat:t=!1,showTitle:n=!0,onChanged:r})=>{let i=M(),{members:a,currentMember:o}=Bq(),[s]=(0,L.useState)(()=>new Date),[c,l]=(0,L.useState)(`work`),[u,d]=(0,L.useState)(!1),{data:f,loading:p,error:m,reload:h}=QG(async()=>{let t=await wG(`tasks`,e);return{task:t,run:typeof t?.smbWorkflowRunId==`string`&&t.smbWorkflowRunId.length>0?await wG(`workflowRuns`,t.smbWorkflowRunId).catch(()=>void 0):void 0}},[e]),g=f?.task;if(g===void 0)return p?(0,$.jsx)(lq,{rows:4}):(0,$.jsx)(RK,{tone:`danger`,children:PG(m,`Задание не найдено или нет доступа.`)});let _=f?.run,v=async()=>{await h(),r?.()},y=_===void 0?kX({task:g,members:a,now:s}):OX({task:g,run:_,members:a,now:s}),b=t&&g.smbIsChatEnabled===!0,x=b&&(c===`chat`||u),S={display:`flex`,flex:1,flexDirection:`column`,gap:i.spacing[3],minHeight:0};return(0,$.jsxs)(`div`,{style:S,children:[n&&(0,$.jsx)(`div`,{style:{alignItems:`flex-start`,display:`flex`,gap:i.spacing[2],justifyContent:`space-between`},children:(0,$.jsx)(`strong`,{style:{fontSize:i.font.size.lg,overflowWrap:`anywhere`},children:g.title?.trim()||`Без названия`})}),b&&(0,$.jsx)(CK,{options:[{value:`work`,label:`Задание`},{value:`chat`,label:`Чат`}],value:c,onChange:e=>{e===`chat`&&d(!0),l(e)}}),(0,$.jsx)(`div`,{style:{...S,display:!b||c===`work`?`flex`:`none`},children:(0,$.jsx)(EX,{task:g,onChanged:v,rail:(0,$.jsx)(LJ,{items:y}),meta:(0,$.jsxs)($.Fragment,{children:[(0,$.jsx)(QK,{labelAlign:`right`,fontSize:`calc(${i.font.size.sm} + 1px)`,rows:[{label:`Исполнитель`,value:DX(a,g.assigneeId)||`Не назначен`},{label:`Срок`,value:g.dueAt?IG(g.dueAt):`Без срока`},{label:`Автор`,value:g.createdBy?.name},{label:`Создано`,value:VG(g.createdAt)}]}),(0,$.jsx)(`div`,{style:{borderTop:`1px solid ${i.border.color.light}`}})]})},`${g.id}-${g.updatedAt??``}`)}),x&&(0,$.jsx)(`div`,{style:{...S,display:c===`chat`?`flex`:`none`},children:(0,$.jsx)(mX,{taskId:g.id,members:a,viewerId:o?.id})})]})};Be(),ut(),pt(),Yt(),cn(),_n(),Wn(),fe();var jX=300,MX=``,NX=`any`,PX=`nobody`,FX=864e5,IX=3,LX=30,RX=`IN_PROGRESS`,zX=[`задание`,`задания`,`заданий`],BX=[{value:`open`,label:`Открытые`},{value:`mine`,label:`Мои`},{value:`done`,label:`Выполненные`}],VX={source:`any`,due:`any`,assignee:NX,scope:`active`},HX={key:`dueAt`,direction:`asc`},UX=[{key:`title`,label:`Задание`,width:`30%`,sortKey:`title`},{key:`assignee`,label:`Исполнитель`,width:`15%`,sortKey:`assigneeId`},{key:`dueAt`,label:`Срок`,width:`15%`,sortKey:`dueAt`},{key:`fields`,label:`Поля`,width:`11%`},{key:`status`,label:`Статус`,width:`13%`,sortKey:`status`},{key:`source`,label:`Откуда`,width:`10%`},{key:`createdAt`,label:`Создано`,sortKey:`createdAt`}],WX=mG(oG(`status`,dq),sG(`status`)),GX=e=>Dl({to:bl.RecordShowPage,params:{objectNameSingular:`task`,objectRecordId:e},pageTitle:`Задание`}),KX=(e,t,n=!1)=>pG(n?cG(`deletedAt`):e===`done`?aG(`status`,dq):WX,e===`mine`?t===void 0?sG(`assigneeId`):aG(`assigneeId`,t):void 0),qX=({view:e,filters:t,searchQuery:n,currentMemberId:r,now:i,weekAhead:a})=>pG(aG(`smbSection`,uq),KX(e,r,t.scope===`deleted`),t.source===`process`?cG(`smbWorkflowThreadId`):void 0,t.source===`own`?sG(`smbWorkflowThreadId`):void 0,t.due===`overdue`?lG(`dueAt`,i):void 0,t.due===`week`?pG(cG(`dueAt`),lG(`dueAt`,a)):void 0,t.due===`none`?sG(`dueAt`):void 0,t.assignee===PX?sG(`assigneeId`):t.assignee===NX?void 0:aG(`assigneeId`,t.assignee),n.trim().length>0?fG(`title`,n):void 0),JX=(e,t)=>pG(aG(`assigneeId`,e),cG(`dueAt`),lG(`dueAt`,t)),YX=(e,t)=>mG(oG(`assigneeId`,e),sG(`assigneeId`),sG(`dueAt`),uG(`dueAt`,t)),XX=e=>e.map(e=>({value:e.id,label:FG(e)||e.id})),ZX=({currentMemberId:e,onCreated:t,onCancel:n})=>{let r=M(),{members:i}=Bq(),[a,o]=(0,L.useState)(``),[s,c]=(0,L.useState)(e??MX),[l,u]=(0,L.useState)(``),[d,f]=(0,L.useState)(``),[p,m]=(0,L.useState)([]),[h,g]=(0,L.useState)(!1),[_,v]=(0,L.useState)(),y=async()=>{let e=bJ(p);if(e!==void 0)v(e);else{g(!0),v(void 0);try{let e=await TG(`tasks`,{title:a.trim(),assigneeId:s===MX?null:s,dueAt:/^\d{4}-\d{2}-\d{2}$/.test(l)?l:null,status:fq,smbSection:uq,smbInstruction:d.trim().length>0?d.trim():null,smbFormSchema:p.length>0?p:null,smbFormValues:p.length>0?{}:null});if(e===void 0)throw Error(`The created task was not returned`);await Tl({message:`Задание создано`,variant:`success`}),t(e.id)}catch(e){v(PG(e,`Не удалось создать задание`))}finally{g(!1)}}};return(0,$.jsxs)(`div`,{style:{display:`flex`,flexDirection:`column`,gap:r.spacing[3]},children:[(0,$.jsx)(PK,{label:`Название`,value:a,onChange:o}),(0,$.jsx)(IK,{label:`Исполнитель`,value:s,options:[{value:MX,label:`Не назначен`},...XX(i)],onChange:c}),(0,$.jsx)(PK,{label:`Срок`,type:`date`,value:l,onChange:u}),(0,$.jsx)(FK,{label:`Инструкция`,value:d,onChange:f,rows:4}),(0,$.jsx)(zK,{children:`Поля для заполнения`}),(0,$.jsx)(BY,{fields:p,onChange:m,disabled:h}),_!==void 0&&(0,$.jsx)(RK,{tone:`danger`,children:_}),(0,$.jsxs)(`div`,{style:{display:`flex`,gap:r.spacing[2]},children:[(0,$.jsx)(rK,{variant:`solid`,tone:`accent`,size:`sm`,loading:h,disabled:a.trim().length===0,onClick:()=>void y(),children:`Создать`}),(0,$.jsx)(rK,{variant:`ghost`,size:`sm`,onClick:n,children:`Отмена`})]})]})},QX=er({universalIdentifier:_q,name:`docflow-tasks`,description:`Задания документооборота: штатные задачи с разделом «Документооборот»`,component:()=>{let e=M(),{members:t,currentMember:n}=Bq(),[r,i]=(0,L.useState)(``),a=$G(r,jX),[o,s]=(0,L.useState)(`open`),[c,l]=(0,L.useState)(VX),[u,d]=(0,L.useState)(HX),[f,p]=(0,L.useState)({kind:`closed`}),[m,h]=(0,L.useState)(1),[g,_]=WK([`createdAt`]),[v,y]=(0,L.useState)(),[b]=(0,L.useState)(()=>new Date),x=b.toISOString(),S=new Date(b.getTime()+7*FX).toISOString(),C=new Date(b.getFullYear(),b.getMonth(),b.getDate()+IX+1).toISOString(),w=n?.id,T=c.scope===`deleted`,ee=o!==`done`&&!T&&w!==void 0,E=f.kind===`task`?f.taskId:void 0,D=(0,L.useMemo)(()=>qX({view:o,filters:c,searchQuery:a,currentMemberId:w,now:x,weekAhead:S}),[o,c,a,w,x,S]),{data:O,loading:k,error:te,reload:ne}=QG(()=>CG(`tasks`,{filter:ee?pG(D,YX(w,C)):D,order_by:HK(u),limit:50*m}),[D,ee,w,C,u,m]),{data:re,reload:A}=QG(async()=>ee?(await CG(`tasks`,{filter:pG(D,JX(w,C)),order_by:`dueAt[AscNullsLast]`,limit:LX})).records:[],[D,ee,w,C]),{data:j,reload:ie}=QG(async()=>Object.fromEntries(await Promise.all(BX.map(async({value:e})=>[e,await OG(`tasks`,pG(aG(`smbSection`,uq),KX(e,w),a.trim().length>0?fG(`title`,a):void 0))]))),[a,w]),ae=O?.records??[],oe=re??[],se=UK(ae.map(({id:e})=>e)),ce=ae.filter(({id:e})=>se.selectedIds.includes(e)),le=(c.source===NX?0:1)+(c.due===NX?0:1)+(c.assignee===NX?0:1)+ +!!T,ue=async()=>{await Promise.all([ne(),A(),ie()])},de=eK({onDone:async()=>{se.clear(),y(void 0),await ue()}}),fe=e=>{s(e),h(1),se.clear()},pe=e=>{l(t=>({...t,...e})),h(1)},me=e=>de.runEach(e,e=>NG(`/docflow/tasks/complete`,{taskId:e}),{done:e=>`Выполнено: ${e}`,failed:`Не выполнены`}),he=(e,t)=>de.run(()=>AG(`tasks`,e,{status:t}),`Статус изменён: ${BG[t]}`,`Не удалось изменить статус`),N=e=>de.run(async()=>{await jG(`tasks`,e),p(t=>t.kind===`task`&&e.includes(t.taskId)?{kind:`closed`}:t)},e.length===1?`Задание удалено: оно в фильтре «Удалённые»`:`Удалено заданий: ${e.length}, они в фильтре «Удалённые»`,`Не удалось удалить`),P=e=>de.run(()=>MG(`tasks`,e),`Восстановлено: ${e.length}`,`Не удалось восстановить`),F=e=>{let t=ae.find(({id:t})=>t===e);if(T)return[{key:`restore`,label:`Восстановить`,icon:gn,onSelect:()=>void P([e])},{key:`card`,label:`Открыть карточку`,icon:lt,onSelect:()=>void GX(e)}];let n=t?.status===dq;return[{key:`open`,label:`Открыть`,icon:ft,onSelect:()=>p({kind:`task`,taskId:e})},{key:`card`,label:`Карточка задачи`,icon:lt,onSelect:()=>void GX(e)},...t?.status===`TODO`?[{key:`start`,label:`Взять в работу`,icon:sn,onSelect:()=>void he([e],RX)}]:[],...n?[]:[{key:`complete`,label:`Выполнить`,icon:ze,onSelect:()=>void me([e])}],{key:`delete`,label:`Удалить`,confirmLabel:`Точно удалить?`,icon:Un,tone:`danger`,onSelect:()=>void N([e])}]},I=se.selectedIds,ge=ce.filter(e=>e.status!==dq).length,_e=f.kind===`task`?ae.find(({id:e})=>e===f.taskId)??oe.find(({id:e})=>e===f.taskId):void 0,ve=f.kind===`create`?`Новое задание`:_e?.title?.trim()||(f.kind===`task`?`Без названия`:void 0);return(0,$.jsxs)(jK,{children:[(0,$.jsxs)(ZK,{panelTitle:ve,onClosePanel:()=>p({kind:`closed`}),panel:f.kind===`create`?(0,$.jsx)(ZX,{currentMemberId:w,onCancel:()=>p({kind:`closed`}),onCreated:e=>{p({kind:`task`,taskId:e}),ue()}}):f.kind===`task`?(0,$.jsx)(AX,{taskId:f.taskId,withChat:!0,showTitle:!1,onChanged:()=>void ue()},f.taskId):void 0,children:[(0,$.jsx)(KK,{search:{value:r,onChange:i,placeholder:`Поиск заданий`,activeFilterCount:le,onResetFilters:()=>pe(VX),filters:[{key:`source`,title:`Откуда`,value:c.source,options:[{value:NX,label:`Все`},{value:`process`,label:`Шаги процессов`},{value:`own`,label:`Свои задания`}],onChange:e=>pe({source:e})},{key:`due`,title:`Срок`,value:c.due,options:[{value:NX,label:`Любой`},{value:`overdue`,label:`Просроченные`},{value:`week`,label:`В ближайшие 7 дней`},{value:`none`,label:`Без срока`}],onChange:e=>pe({due:e})},{key:`assignee`,title:`Исполнитель`,value:c.assignee,options:[{value:NX,label:`Любой`},{value:PX,label:`Не назначен`},...XX(t)],onChange:e=>pe({assignee:e})},{key:`scope`,title:`Корзина`,value:c.scope,options:[{value:`active`,label:`Действующие`},{value:`deleted`,label:`Удалённые`}],onChange:e=>{pe({scope:e}),se.clear()}}]},views:(0,$.jsx)(TK,{value:o,onChange:fe,options:BX.map(e=>({...e,count:j?.[e.value]}))}),onCreate:()=>p({kind:`create`})}),ee&&(0,$.jsx)(WY,{tasks:oe,members:t,now:b,selectedTaskId:E,onOpen:e=>p({kind:`task`,taskId:e})}),te!==void 0&&(0,$.jsx)(`div`,{style:{padding:e.spacing[4]},children:(0,$.jsx)(RK,{tone:`danger`,children:PG(te,`Не удалось загрузить задания`)})}),k&&O===void 0&&(0,$.jsx)(cq,{}),!k&&te===void 0&&ae.length===0&&(0,$.jsx)(RK,{children:oe.length>0?`Остальных заданий нет: все срочные — в карточках выше.`:`Заданий нет.`}),ae.length>0&&(0,$.jsxs)($.Fragment,{children:[ee&&oe.length>0&&(0,$.jsx)(`div`,{style:{padding:`${e.spacing[1]} ${e.spacing[5]} 0`},children:(0,$.jsx)(zK,{children:`Остальные задания`})}),(0,$.jsx)(GK,{columns:UX,hiddenColumnKeys:g,onHiddenColumnsChange:_,sort:u,onSortChange:e=>{d(e),h(1)},selectedRowId:E,selectedIds:I,onSelectionChange:se.setSelectedIds,rowActions:F,onRowClick:e=>T?void GX(e):p({kind:`task`,taskId:e}),rows:ae.map(n=>{let r=GG(n.dueAt,b),i=n.status===`DONE`,a=DY(n);return{id:n.id,isMuted:i&&o!==`done`,cells:{title:n.title?.trim()||`Без названия`,assignee:FG(t.find(e=>e.id===n.assigneeId))||`—`,dueAt:n.dueAt?(0,$.jsx)(`span`,{title:IG(n.dueAt),style:{color:i?void 0:r.tone===`overdue`?e.font.color.danger:r.tone===`today`?e.color.orange:void 0},children:i?IG(n.dueAt):`${IG(n.dueAt)} · ${r.label.toLowerCase()}`}):`—`,fields:a.total>0?(0,$.jsxs)(`span`,{style:{alignItems:`center`,display:`flex`,gap:e.spacing[2]},children:[(0,$.jsx)(`span`,{style:{flex:1,maxWidth:`48px`},children:(0,$.jsx)(XK,{value:a.filled,total:a.total,tone:i?`green`:`blue`})}),a.filled,`/`,a.total]}):`—`,status:(0,$.jsx)(aK,{color:qG[n.status??``]??`gray`,children:BG[n.status??``]??n.status??`Без статуса`}),source:EY(n)?`Процесс`:`Своё`,createdAt:IG(n.createdAt)}}})})]}),(0,$.jsx)(YK,{isVisible:O?.pageInfo.hasNextPage===!0,loading:k,onClick:()=>h(e=>e+1)}),(0,$.jsx)(qK,{count:I.length,noun:zX,onClear:se.clear,children:T?(0,$.jsx)(rK,{icon:gn,loading:de.isBusy,onClick:()=>void P(I),children:`Восстановить`}):(0,$.jsxs)($.Fragment,{children:[ge>0&&(0,$.jsx)(rK,{icon:ze,loading:de.isBusy,onClick:()=>void me(I),children:`Выполнить`}),(0,$.jsx)(rK,{icon:Jt,disabled:de.isBusy,onClick:()=>y(`change`),children:`Изменить`}),(0,$.jsx)(pK,{label:`Удалить`,icon:Un,disabled:de.isBusy,actions:[{key:`delete`,label:`Удалить выбранные (${I.length})`,confirmLabel:`Точно удалить?`,icon:Un,tone:`danger`,onSelect:()=>void N(I)}]})]})})]}),v===`change`&&(0,$.jsx)(AK,{title:`Изменить поле`,hint:`Для ${I.length} ${JK(I.length,zX)}`,fields:[{key:`status`,label:`Статус`,options:[`TODO`,RX].map(e=>({value:e,label:BG[e]}))},{key:`assignee`,label:`Исполнитель`,options:[{value:MX,label:`Не назначен`},...XX(t)]},{key:`dueAt`,label:`Срок`,inputType:`date`}],onClose:()=>y(void 0),onSubmit:(e,t)=>e===`status`?he(I,t):e===`assignee`?de.run(()=>AG(`tasks`,I,{assigneeId:t===MX?null:t}),`Исполнитель назначен`,`Не удалось назначить исполнителя`):de.run(()=>AG(`tasks`,I,{dueAt:/^\d{4}-\d{2}-\d{2}$/.test(t)?t:null}),`Срок изменён`,`Не удалось изменить срок`)})]})}}),$X=5e3,eZ=[],tZ=1,nZ=new Set,rZ=e=>{eZ=e,nZ.forEach(e=>e(eZ))},iZ=(e,t=`info`)=>{let n=tZ++;rZ([...eZ,{id:n,message:e,variant:t}]),setTimeout(()=>rZ(eZ.filter(e=>e.id!==n)),$X)},aZ=e=>(nZ.add(e),e(eZ),()=>{nZ.delete(e)}),oZ=e=>{d.TWENTY_APP_ACCESS_TOKEN=e},sZ=(e,t,n,r)=>{window.open(re(e,t,n,r),`_blank`,`noopener`)},cZ=({crmUrl:e,userId:t,colorScheme:n,refreshAccessToken:r})=>{globalThis.__twentySdkExecutionContext__={frontComponentId:`docflow-app`,userId:t,recordId:null,selectedRecordIds:[],timelineActivityId:null,colorScheme:n,locale:`ru-RU`},globalThis.frontComponentHostCommunicationApi??={},Object.assign(globalThis.frontComponentHostCommunicationApi,{enqueueSnackbar:async({message:e,variant:t})=>iZ(e,t),openSidePanelPage:async t=>{typeof t.to==`string`&&sZ(e,t.to,t.params)},navigate:async(t,n,r)=>sZ(e,t,n,r),closeSidePanel:async()=>void 0,copyToClipboard:e=>navigator.clipboard.writeText(e),requestAccessTokenRefresh:async()=>await r()??``})};ut(),gt(),Ut(),Kt(),fe();var lZ={tasks:QX.config.component,processes:TY.config.component,documents:Rq.config.component},uZ=e=>e.crmUrl.length>0?e.crmUrl:window.location.origin,dZ=({config:e,section:t,onSectionChange:n})=>{let r=M(),[i,a]=(0,L.useState)(document.fullscreenElement!==null);return(0,L.useEffect)(()=>{let e=()=>a(document.fullscreenElement!==null);return document.addEventListener(`fullscreenchange`,e),()=>document.removeEventListener(`fullscreenchange`,e)},[]),(0,$.jsxs)(`header`,{style:{alignItems:`center`,borderBottom:`1px solid ${r.border.color.medium}`,display:`grid`,gap:r.spacing[3],gridTemplateColumns:`1fr auto 1fr`,padding:`0 ${r.spacing[4]}`},children:[(0,$.jsxs)(`div`,{style:{alignItems:`center`,display:`flex`,gap:r.spacing[2],fontWeight:r.font.weight.medium},children:[(0,$.jsx)(ht,{size:18}),`Документооборот`]}),(0,$.jsx)(`nav`,{role:`tablist`,style:{display:`flex`,gap:r.spacing[4]},children:T.map(e=>{let i=e===t;return(0,$.jsx)(`button`,{type:`button`,role:`tab`,"aria-selected":i,onClick:()=>n(e),style:{background:`none`,border:`none`,borderBottom:`2px solid ${i?r.font.color.primary:`transparent`}`,color:i?r.font.color.primary:r.font.color.tertiary,cursor:`pointer`,fontFamily:`inherit`,fontSize:r.font.size.md,fontWeight:i?r.font.weight.medium:r.font.weight.regular,padding:`${r.spacing[3]} ${r.spacing[1]}`},children:ee[e]},e)})}),(0,$.jsxs)(`div`,{style:{alignItems:`center`,display:`flex`,gap:r.spacing[2],justifyContent:`flex-end`},children:[document.fullscreenEnabled&&(0,$.jsx)(iK,{icon:i?Gt:Ht,label:i?`Свернуть`:`На весь экран`,onClick:()=>void(i?document.exitFullscreen():document.documentElement.requestFullscreen())}),(0,$.jsx)(rK,{icon:lt,onClick:()=>window.open(uZ(e),`_blank`,`noopener`),children:`Открыть CRM`})]})]})},fZ=()=>{let e=M(),[t,n]=(0,L.useState)([]);return(0,L.useEffect)(()=>aZ(n),[]),(0,$.jsx)(`div`,{"aria-live":`polite`,style:{bottom:e.spacing[4],display:`flex`,flexDirection:`column`,gap:e.spacing[2],position:`fixed`,right:e.spacing[4],zIndex:1e3},children:t.map(t=>(0,$.jsx)(`div`,{role:t.variant===`error`?`alert`:`status`,style:{background:e.background.primary,border:`1px solid ${t.variant===`error`?e.color.red:e.border.color.medium}`,borderRadius:e.border.radius.md,boxShadow:e.boxShadow.strong,color:t.variant===`error`?e.font.color.danger:e.font.color.primary,fontSize:e.font.size.sm,maxWidth:360,padding:`${e.spacing[2]} ${e.spacing[3]}`},children:t.message},t.id))})},pZ=({config:e,session:t})=>{let n=M(),[r,i]=(0,L.useState)(e.section),[a,o]=(0,L.useState)([e.section]),s=e.expectedWorkspaceMemberId!==void 0&&t.workspaceMemberId!==e.expectedWorkspaceMemberId;return(0,$.jsxs)(`div`,{style:{background:n.background.primary,color:n.font.color.primary,display:`flex`,flexDirection:`column`,height:`100%`},children:[(0,$.jsx)(dZ,{config:e,section:r,onSectionChange:e=>{i(e),o(t=>t.includes(e)?t:[...t,e])}}),s&&(0,$.jsx)(`div`,{role:`status`,style:{background:n.background.transparent.light,color:n.font.color.secondary,fontSize:n.font.size.sm,padding:`${n.spacing[2]} ${n.spacing[4]}`},children:`В CRM в этом браузере вы вошли не под тем сотрудником, что в Битрикс24. Чтобы сменить, выйдите из CRM, войдите нужным сотрудником и откройте приложение заново.`}),(0,$.jsx)(`main`,{style:{flex:1,minHeight:0,position:`relative`},children:a.map(e=>{let t=lZ[e];return(0,$.jsx)(`div`,{style:{display:e===r?`block`:`none`,height:`100%`,overflow:`auto`},children:(0,$.jsx)(t,{})},e)})}),(0,$.jsx)(fZ,{})]})},mZ=({title:e,text:t,action:n})=>{let r=M();return(0,$.jsxs)(`div`,{style:{alignItems:`center`,background:r.background.primary,color:r.font.color.primary,display:`flex`,flexDirection:`column`,gap:r.spacing[3],height:`100%`,justifyContent:`center`,padding:r.spacing[6],textAlign:`center`},children:[(0,$.jsx)(ht,{size:32}),(0,$.jsx)(`div`,{style:{fontSize:r.font.size.lg,fontWeight:r.font.weight.medium},children:e}),(0,$.jsx)(`div`,{style:{color:r.font.color.tertiary,fontSize:r.font.size.md,maxWidth:420},children:t}),n!==void 0&&(0,$.jsx)(rK,{variant:`solid`,tone:`accent`,loading:n.loading,onClick:n.onClick,children:n.label})]})},hZ=`docflow.app.session`,gZ=6e4,_Z=3e3,vZ=async e=>{try{let t=await fetch(C,{method:`POST`,credentials:e===void 0?`same-origin`:`omit`,headers:{"content-type":`application/json`,...e===void 0?{}:{authorization:`Bearer ${e}`}},body:`{}`});return t.ok?D(await t.json()):void 0}catch{return}},yZ=()=>{try{let e=window.localStorage.getItem(hZ);return e===null?void 0:D(JSON.parse(e))}catch{return}},bZ=e=>{try{e===void 0?window.localStorage.removeItem(hZ):window.localStorage.setItem(hZ,JSON.stringify(e))}catch{}},xZ=({mode:e,session:t,onRenewed:n,onLost:r})=>{let i=t,a=null,o=()=>(a??=(async()=>{let t=await vZ(e===`crm`?void 0:te(i,Date.now())?i.token:void 0);return t===void 0?(te(i,Date.now())||(bZ(void 0),r()),te(i,Date.now())?i.token:null):(i=t,bZ(e===`bitrix`?i:void 0),n(i),i.token)})().finally(()=>{a=null}),a),s=window.setInterval(()=>{ne(i,Date.now())&&o()},gZ);return{current:()=>i,refresh:o,stop:()=>window.clearInterval(s)}},SZ=async e=>{if(e===`bitrix`){let e=yZ();if(te(e,Date.now()))return e}let t=await vZ();return t!==void 0&&e===`bitrix`&&bZ(t),t},CZ=()=>new Promise(e=>{let t=window.open(`${S}?connect=1`,`docflow-sign-in`,`width=520,height=560`);if(t===null){e(void 0);return}let n=t=>{window.removeEventListener(`message`,r),window.clearInterval(i),t!==void 0&&bZ(t),e(t)},r=e=>{e.origin===window.location.origin&&e.source===t&&e.data?.type===`docflow-app-session`&&n(D(e.data.session))},i=window.setInterval(()=>{t.closed&&n(void 0)},500);window.addEventListener(`message`,r)}),wZ=(e,t)=>{let n=window.opener;if(n===null){t();return}let r=async()=>{let e=await vZ();return e!==void 0&&(n.postMessage({type:w,session:e},window.location.origin),window.close(),!0)};r().then(t=>{if(t)return;e();let n=window.setInterval(()=>{r().then(e=>{e&&window.clearInterval(n)})},_Z)})},TZ=3e3,EZ=800,DZ=()=>{let e=document.getElementById(`docflow-app-config`),t=JSON.parse(e?.textContent??`{}`);return{mode:t.mode===`bitrix`||t.mode===`connect`?t.mode:`crm`,crmUrl:typeof t.crmUrl==`string`?t.crmUrl:``,section:E(t.section),expectedWorkspaceMemberId:t.expectedWorkspaceMemberId,portalDomain:t.portalDomain}},OZ=e=>A({portalDomain:e.portalDomain,ancestorOrigins:window.location.ancestorOrigins===void 0?void 0:Array.from(window.location.ancestorOrigins),referrer:document.referrer}),kZ=window.matchMedia(`(prefers-color-scheme: light)`).matches?`light`:`dark`,AZ=e=>e.crmUrl.length>0?e.crmUrl:window.location.origin,jZ=({config:e})=>{let[t,n]=(0,L.useState)(`working`),r=(0,L.useRef)(!1);return(0,L.useEffect)(()=>{r.current||(r.current=!0,wZ(()=>n(`waiting`),()=>n(`no-opener`)))},[]),t===`no-opener`?(0,$.jsx)(mZ,{title:`Вход в документооборот`,text:`Это окно открывается из приложения «Документооборот» в Битрикс24. Откройте приложение там и нажмите «Войти через CRM».`}):t===`working`?(0,$.jsx)(mZ,{title:`Вход в документооборот`,text:`Проверяю вход в CRM…`}):(0,$.jsx)(mZ,{title:`Войдите в CRM`,text:`Войдите в CRM в открывшейся вкладке. Это окно само заметит вход, передаст его в Битрикс24 и закроется.`,action:{label:`Открыть CRM`,onClick:()=>window.open(AZ(e),`_blank`,`noopener`)}})},MZ=({config:e})=>{let[t,n]=(0,L.useState)({kind:`loading`}),r=(0,L.useRef)(null),i=(0,L.useRef)(!1),a=t=>{r.current?.stop(),r.current=xZ({mode:e.mode,session:t,onRenewed:e=>oZ(e.token),onLost:()=>n({kind:`sign-in`,isWaiting:!1})}),oZ(t.token),cZ({crmUrl:AZ(e),userId:t.userId,colorScheme:kZ,refreshAccessToken:()=>r.current?.refresh()??Promise.resolve(null)}),n({kind:`signed-in`,session:t})};switch((0,L.useEffect)(()=>{if(!i.current&&(i.current=!0,SZ(e.mode).then(e=>e===void 0?n({kind:`sign-in`,isWaiting:!1}):a(e)),e.mode===`bitrix`)){let e=window.BX24;e?.init(()=>e.resizeWindow?.(document.documentElement.scrollWidth,Math.max(EZ,window.innerHeight)))}},[]),(0,L.useEffect)(()=>{if(t.kind!==`sign-in`||!t.isWaiting||e.mode!==`crm`)return;let n=window.setInterval(()=>{vZ().then(e=>{e!==void 0&&(window.clearInterval(n),a(e))})},TZ);return()=>window.clearInterval(n)},[t]),t.kind){case`loading`:return(0,$.jsx)(mZ,{title:`Документооборот`,text:`Загрузка…`});case`signed-in`:return(0,$.jsx)(pZ,{config:e,session:t.session});case`sign-in`:return e.mode===`bitrix`?(0,$.jsx)(mZ,{title:`Войдите через CRM`,text:`Документооборот работает с вашей учётной записью CRM. Вход откроется в отдельном окне; в этом браузере его хватит надолго.`,action:{label:`Войти через CRM`,loading:t.isWaiting,onClick:()=>{n({kind:`sign-in`,isWaiting:!0}),CZ().then(e=>e===void 0?n({kind:`sign-in`,isWaiting:!1}):a(e))}}}):(0,$.jsx)(mZ,{title:`Войдите в CRM`,text:t.isWaiting?`Войдите в CRM в открывшейся вкладке, эта страница откроется сама.`:`Документооборот открывается для сотрудника, вошедшего в CRM.`,action:{label:`Войти в CRM`,loading:t.isWaiting,onClick:()=>{window.open(AZ(e),`_blank`,`noopener`),n({kind:`sign-in`,isWaiting:!0})}}})}},NZ=DZ();document.documentElement.className=kZ;var PZ=document.getElementById(`root`);PZ!==null&&(0,x.createRoot)(PZ).render(NZ.mode===`connect`?(0,$.jsx)(jZ,{config:NZ}):NZ.mode===`bitrix`&&!OZ(NZ)?(0,$.jsx)(mZ,{title:`Документооборот`,text:`Эта страница открывается только в приложении портала Битрикс24, связанного с CRM.`}):(0,$.jsx)(MZ,{config:NZ}))})();
|
|
95
|
+
`,``)===t?m(``):m(e.target.value)},onKeyDown:e=>{e.key===`Enter`&&!e.shiftKey&&(e.preventDefault(),oe.current=he?p:void 0,se()),e.key===`Escape`&&me!==void 0&&(b(void 0),v(void 0))},style:{background:r.background.transparent.lighter,border:`1px solid ${r.border.color.light}`,borderRadius:r.border.radius.md,boxSizing:`border-box`,color:r.font.color.primary,flex:1,font:`inherit`,lineHeight:`20px`,minHeight:36,minWidth:0,padding:`7px 10px`,resize:`none`}}),(0,$.jsx)(`button`,{type:`button`,"aria-label":y===void 0?`Отправить`:`Сохранить`,title:y===void 0?`Отправить · Enter`:`Сохранить · Enter`,disabled:!he,onClick:()=>void se(),style:{alignItems:`center`,background:he?r.color.blue:r.background.transparent.light,border:`none`,borderRadius:r.border.radius.md,color:he?r.font.color.inverted:r.font.color.light,cursor:he?`pointer`:`default`,display:`inline-flex`,flexShrink:0,height:36,justifyContent:`center`,padding:0,width:36},children:(0,$.jsx)(Tn,{size:r.icon.size.md,stroke:r.icon.stroke.md})})]})]}):(0,$.jsxs)(`div`,{style:{alignItems:`center`,display:`flex`,flexWrap:`wrap`,gap:r.spacing[1]},children:[(0,$.jsxs)(`strong`,{style:{flex:1},children:[`Выбрано: `,fe.length]}),(0,$.jsx)(rK,{variant:`ghost`,size:`sm`,disabled:fe.length===0,onClick:()=>void ce(fe),children:`Копировать`}),(0,$.jsx)(rK,{variant:`ghost`,size:`sm`,disabled:fe.length===0,onClick:()=>ee(fe.map(e=>e.id)),children:`Переслать`}),fe.length>0&&fe.every(e=>e.authorId===n)&&(0,$.jsx)(rK,{variant:`ghost`,size:`sm`,onClick:()=>void le(fe).then(()=>w(void 0)),children:`Удалить`}),(0,$.jsx)(rK,{variant:`outline`,size:`sm`,onClick:()=>w(void 0),children:`Отмена`})]}),T!==void 0&&(0,$.jsx)(pX,{messageIds:T,viewerId:n,memberName:k,onClose:()=>ee(void 0),onForwarded:e=>{ee(void 0),w(void 0),Tl({message:`Переслано в «${e}»`,variant:`success`})}})]})},hX=e=>typeof e==`string`&&e.length>0&&!Number.isNaN(Date.parse(e)),gX=e=>Array.isArray(e)?e.flatMap(e=>{if(typeof e!=`object`||!e)return[];let t=e;return t.kind===`run`&&hX(t.start)?[{kind:`run`,start:t.start,end:hX(t.end)?t.end:null}]:t.kind===`add`&&typeof t.minutes==`number`&&Number.isFinite(t.minutes)&&t.minutes>0?[{kind:`add`,minutes:Math.round(t.minutes),at:hX(t.at)?t.at:new Date(0).toISOString()}]:[]}):[],_X=e=>e.some(e=>e.kind===`run`&&e.end===null),vX=(e,t)=>e.reduce((e,n)=>{if(n.kind===`add`)return e+n.minutes*6e4;let r=Date.parse(n.start),i=n.end===null?t.getTime():Date.parse(n.end);return Number.isNaN(r)||Number.isNaN(i)||i<r?e:e+(i-r)},0),yX=e=>{let t=Math.max(0,Math.floor(e/1e3)),n=Math.floor(t/3600),r=Math.floor(t%3600/60),i=t%60;return n>0?`${n}ч ${String(r).padStart(2,`0`)}м`:r>0?i>0?`${r}м ${String(i).padStart(2,`0`)}с`:`${r}м`:`${i}с`},bX=(e,t)=>_X(e)?e:[...e,{kind:`run`,start:t.toISOString(),end:null}],xX=(e,t)=>e.map(e=>e.kind===`run`&&e.end===null?{...e,end:t.toISOString()}:e),SX=(e,t,n)=>{let r=Math.round(t);return!Number.isFinite(r)||r<=0?e:[...e,{kind:`add`,minutes:r,at:n.toISOString()}]};an(),cn(),mn(),fe();var CX=`IN_PROGRESS`,wX=({answers:e})=>e.length===0?null:(0,$.jsx)(QK,{rows:e.map(({label:e,value:t})=>({label:e,value:KG(t)}))}),TX=({task:e,disabled:t,onChanged:n})=>{let r=M(),[i,a]=(0,L.useState)(!1),[o,s]=(0,L.useState)(!1),[c,l]=(0,L.useState)(``),[u,d]=(0,L.useState)(()=>new Date),f=gX(e.smbTimeLog),p=_X(f);(0,L.useEffect)(()=>{if(!p)return;let e=window.setInterval(()=>d(new Date),1e3);return()=>window.clearInterval(e)},[p]);let m=async(t,r)=>{s(!0);try{await EG(`tasks`,e.id,{smbTimeLog:t}),await Tl({message:r,variant:`success`}),await n()}catch(e){await Tl({message:PG(e,`Не удалось сохранить время`),variant:`error`})}finally{s(!1)}};return(0,$.jsxs)(`div`,{style:{alignItems:`center`,display:`flex`,gap:r.spacing[1]},children:[(0,$.jsx)(`span`,{style:{color:p?r.color.blue:r.font.color.secondary,fontSize:r.font.size.sm,fontVariantNumeric:`tabular-nums`,minWidth:`3.5em`},children:yX(vX(f,u))}),(0,$.jsx)(iK,{icon:p?rn:sn,label:p?`Пауза`:`Пуск`,disabled:t||o,isActive:p,onClick:()=>{m(p?xX(f,new Date):bX(f,new Date),p?`Таймер остановлен`:`Таймер запущен`)}}),(0,$.jsx)(cK,{isOpen:i,onClose:()=>a(!1),align:`left`,width:`200px`,anchor:(0,$.jsx)(iK,{icon:pn,label:`Добавить время`,disabled:t||o,isActive:i,onClick:()=>a(!i)}),children:(0,$.jsxs)(`div`,{style:{display:`flex`,flexDirection:`column`,gap:r.spacing[2],padding:r.spacing[2]},children:[(0,$.jsxs)(`label`,{style:{color:r.font.color.tertiary,fontSize:r.font.size.xs},children:[`Минуты`,(0,$.jsx)(`input`,{type:`number`,min:1,step:1,value:c,onChange:e=>l(e.target.value),style:{background:r.background.transparent.lighter,border:`1px solid ${r.border.color.medium}`,borderRadius:r.border.radius.sm,boxSizing:`border-box`,color:r.font.color.primary,display:`block`,fontFamily:`inherit`,fontSize:r.font.size.md,marginTop:r.spacing[1],outline:`none`,padding:r.spacing[2],width:`100%`}})]}),(0,$.jsx)(rK,{variant:`outline`,size:`sm`,disabled:o||Number(c)<=0,onClick:()=>{let e=Number(c);m(SX(f,e,new Date),`Добавлено ${Math.round(e)} мин`),l(``),a(!1)},children:`Добавить`})]})})]})},EX=({task:e,onChanged:t,rail:n,meta:r})=>{let i=M(),[a,o]=(0,L.useState)(),[s,c]=(0,L.useState)(!1),[l,u]=(0,L.useState)(),d=xJ(e.smbFormSchema),f=a??SJ(e.smbFormValues),p=e.status===dq,m=async(e,n,r)=>{c(!0),u(void 0);try{await e(),await Tl({message:n,variant:`success`}),o(void 0),await t()}catch(e){u(PG(e,r))}finally{c(!1)}};return(0,$.jsxs)(`div`,{style:{display:`flex`,flex:1,flexDirection:`column`,minHeight:0},children:[(0,$.jsxs)(`div`,{style:{display:`flex`,flex:1,gap:i.spacing[3],minHeight:0},children:[n,(0,$.jsxs)(`div`,{style:{display:`flex`,flex:1,flexDirection:`column`,gap:i.spacing[3],minHeight:0,minWidth:0},children:[r,typeof e.smbInstruction==`string`&&e.smbInstruction.trim().length>0&&(0,$.jsxs)(`section`,{"aria-label":`Инструкция`,style:{background:i.background.transparent.lighter,borderLeft:`2px solid ${i.border.color.medium}`,padding:i.spacing[3],whiteSpace:`pre-wrap`},children:[(0,$.jsx)(`div`,{style:{color:i.font.color.tertiary,fontSize:i.font.size.sm,marginBottom:i.spacing[1]},children:`Инструкция`}),e.smbInstruction]}),d.length>0?(0,$.jsx)(kJ,{fields:d,values:f,disabled:s||p,onChange:o}):(0,$.jsx)(RK,{tone:`hint`,children:`Полей нет: задание выполняется без ответа.`}),l!==void 0&&(0,$.jsx)(RK,{tone:`danger`,children:l})]})]}),(0,$.jsx)(sK,{value:`above`,children:(0,$.jsxs)(`div`,{style:{alignItems:`center`,borderTop:`1px solid ${i.border.color.light}`,display:`flex`,flexWrap:`wrap`,gap:i.spacing[2],justifyContent:`space-between`,marginTop:i.spacing[3],paddingTop:i.spacing[3]},children:[(0,$.jsx)(TX,{task:e,disabled:s,onChanged:t}),(0,$.jsxs)(`div`,{style:{display:`flex`,flexWrap:`wrap`,gap:i.spacing[2]},children:[!p&&a!==void 0&&(0,$.jsx)(rK,{variant:`outline`,size:`sm`,disabled:s,onClick:()=>m(()=>NG(`/docflow/tasks/form`,{taskId:e.id,values:f}),`Сохранено`,`Не удалось сохранить`),children:`Сохранить`}),!p&&(0,$.jsx)(rK,{variant:`solid`,tone:`accent`,size:`sm`,loading:s,onClick:()=>m(()=>NG(`/docflow/tasks/complete`,{taskId:e.id,values:f}),`Задание выполнено`,`Не удалось выполнить задание`),children:`Выполнить`})]})]})})]})},DX=(e,t)=>FG(e.find(e=>e.id===t)),OX=({task:e,run:t,members:n,now:r})=>{let i=aY(t.state,r),a=t.status===`COMPLETED`,o=t.status===`FAILED`||t.status===`STOPPED`;return[{key:`start`,title:`Запуск процесса`,meta:[t.createdBy?.name,VG(t.startedAt??t.createdAt)].filter(Boolean).join(` · `),state:`done`},...i.map(t=>{let r=t.stepId===e.smbWorkflowStepId,i=r?DX(n,e.assigneeId):DX(n,t.assigneeWorkspaceMemberId);return{key:t.stepId,title:t.name,meta:[YG[t.type]??t.type,i].filter(Boolean).join(` · `),state:t.state,isFocus:r,details:t.answers.length>0?(0,$.jsx)(wX,{answers:t.answers}):void 0}}),{key:`end`,title:o?`Процесс остановлен`:`Процесс завершён`,meta:t.endedAt?VG(t.endedAt):void 0,state:a?`done`:o?`failed`:`upcoming`}]},kX=({task:e,members:t,now:n})=>{let r=e.status===dq,i=GG(e.dueAt,n);return[{key:`created`,title:`Задание создано`,meta:[e.createdBy?.name,VG(e.createdAt)].filter(Boolean).join(` · `),state:`done`},{key:`work`,title:e.status===CX?`В работе`:`Исполнение`,meta:[DX(t,e.assigneeId)||`Исполнитель не назначен`,e.dueAt?`срок ${IG(e.dueAt)}`:void 0].filter(Boolean).join(` · `),state:r?`done`:`current`,isFocus:!0},{key:`done`,title:`Выполнено`,meta:r?VG(e.updatedAt):e.dueAt?i.label:void 0,state:r?`done`:`upcoming`}]},AX=({taskId:e,withChat:t=!1,showTitle:n=!0,onChanged:r})=>{let i=M(),{members:a,currentMember:o}=Bq(),[s]=(0,L.useState)(()=>new Date),[c,l]=(0,L.useState)(`work`),[u,d]=(0,L.useState)(!1),{data:f,loading:p,error:m,reload:h}=QG(async()=>{let t=await wG(`tasks`,e);return{task:t,run:typeof t?.smbWorkflowRunId==`string`&&t.smbWorkflowRunId.length>0?await wG(`workflowRuns`,t.smbWorkflowRunId).catch(()=>void 0):void 0}},[e]),g=f?.task;if(g===void 0)return p?(0,$.jsx)(lq,{rows:4}):(0,$.jsx)(RK,{tone:`danger`,children:PG(m,`Задание не найдено или нет доступа.`)});let _=f?.run,v=async()=>{await h(),r?.()},y=_===void 0?kX({task:g,members:a,now:s}):OX({task:g,run:_,members:a,now:s}),b=t&&g.smbIsChatEnabled===!0,x=b&&(c===`chat`||u),S={display:`flex`,flex:1,flexDirection:`column`,gap:i.spacing[3],minHeight:0};return(0,$.jsxs)(`div`,{style:S,children:[n&&(0,$.jsx)(`div`,{style:{alignItems:`flex-start`,display:`flex`,gap:i.spacing[2],justifyContent:`space-between`},children:(0,$.jsx)(`strong`,{style:{fontSize:i.font.size.lg,overflowWrap:`anywhere`},children:g.title?.trim()||`Без названия`})}),b&&(0,$.jsx)(CK,{options:[{value:`work`,label:`Задание`},{value:`chat`,label:`Чат`}],value:c,onChange:e=>{e===`chat`&&d(!0),l(e)}}),(0,$.jsx)(`div`,{style:{...S,display:!b||c===`work`?`flex`:`none`},children:(0,$.jsx)(EX,{task:g,onChanged:v,rail:(0,$.jsx)(LJ,{items:y}),meta:(0,$.jsxs)($.Fragment,{children:[(0,$.jsx)(QK,{labelAlign:`right`,fontSize:`calc(${i.font.size.sm} + 1px)`,rows:[{label:`Исполнитель`,value:DX(a,g.assigneeId)||`Не назначен`},{label:`Срок`,value:g.dueAt?IG(g.dueAt):`Без срока`},{label:`Автор`,value:g.createdBy?.name},{label:`Создано`,value:VG(g.createdAt)}]}),(0,$.jsx)(`div`,{style:{borderTop:`1px solid ${i.border.color.light}`}})]})},`${g.id}-${g.updatedAt??``}`)}),x&&(0,$.jsx)(`div`,{style:{...S,display:c===`chat`?`flex`:`none`},children:(0,$.jsx)(mX,{taskId:g.id,members:a,viewerId:o?.id})})]})};Be(),ut(),pt(),Yt(),cn(),_n(),Wn(),fe();var jX=300,MX=``,NX=`any`,PX=`nobody`,FX=864e5,IX=3,LX=30,RX=`IN_PROGRESS`,zX=[`задание`,`задания`,`заданий`],BX=[{value:`open`,label:`Открытые`},{value:`mine`,label:`Мои`},{value:`done`,label:`Выполненные`}],VX={source:`any`,due:`any`,assignee:NX,scope:`active`},HX={key:`dueAt`,direction:`asc`},UX=[{key:`title`,label:`Задание`,width:`30%`,sortKey:`title`},{key:`assignee`,label:`Исполнитель`,width:`15%`,sortKey:`assigneeId`},{key:`dueAt`,label:`Срок`,width:`15%`,sortKey:`dueAt`},{key:`fields`,label:`Поля`,width:`11%`},{key:`status`,label:`Статус`,width:`13%`,sortKey:`status`},{key:`source`,label:`Откуда`,width:`10%`},{key:`createdAt`,label:`Создано`,sortKey:`createdAt`}],WX=mG(oG(`status`,dq),sG(`status`)),GX=e=>Dl({to:bl.RecordShowPage,params:{objectNameSingular:`task`,objectRecordId:e},pageTitle:`Задание`}),KX=(e,t,n=!1)=>pG(n?cG(`deletedAt`):e===`done`?aG(`status`,dq):WX,e===`mine`?t===void 0?sG(`assigneeId`):aG(`assigneeId`,t):void 0),qX=({view:e,filters:t,searchQuery:n,currentMemberId:r,now:i,weekAhead:a})=>pG(aG(`smbSection`,uq),KX(e,r,t.scope===`deleted`),t.source===`process`?cG(`smbWorkflowThreadId`):void 0,t.source===`own`?sG(`smbWorkflowThreadId`):void 0,t.due===`overdue`?lG(`dueAt`,i):void 0,t.due===`week`?pG(cG(`dueAt`),lG(`dueAt`,a)):void 0,t.due===`none`?sG(`dueAt`):void 0,t.assignee===PX?sG(`assigneeId`):t.assignee===NX?void 0:aG(`assigneeId`,t.assignee),n.trim().length>0?fG(`title`,n):void 0),JX=(e,t)=>pG(aG(`assigneeId`,e),cG(`dueAt`),lG(`dueAt`,t)),YX=(e,t)=>mG(oG(`assigneeId`,e),sG(`assigneeId`),sG(`dueAt`),uG(`dueAt`,t)),XX=e=>e.map(e=>({value:e.id,label:FG(e)||e.id})),ZX=({currentMemberId:e,onCreated:t,onCancel:n})=>{let r=M(),{members:i}=Bq(),[a,o]=(0,L.useState)(``),[s,c]=(0,L.useState)(e??MX),[l,u]=(0,L.useState)(``),[d,f]=(0,L.useState)(``),[p,m]=(0,L.useState)([]),[h,g]=(0,L.useState)(!1),[_,v]=(0,L.useState)(),y=async()=>{let e=bJ(p);if(e!==void 0)v(e);else{g(!0),v(void 0);try{let e=await TG(`tasks`,{title:a.trim(),assigneeId:s===MX?null:s,dueAt:/^\d{4}-\d{2}-\d{2}$/.test(l)?l:null,status:fq,smbSection:uq,smbInstruction:d.trim().length>0?d.trim():null,smbFormSchema:p.length>0?p:null,smbFormValues:p.length>0?{}:null});if(e===void 0)throw Error(`The created task was not returned`);await Tl({message:`Задание создано`,variant:`success`}),t(e.id)}catch(e){v(PG(e,`Не удалось создать задание`))}finally{g(!1)}}};return(0,$.jsxs)(`div`,{style:{display:`flex`,flexDirection:`column`,gap:r.spacing[3]},children:[(0,$.jsx)(PK,{label:`Название`,value:a,onChange:o}),(0,$.jsx)(IK,{label:`Исполнитель`,value:s,options:[{value:MX,label:`Не назначен`},...XX(i)],onChange:c}),(0,$.jsx)(PK,{label:`Срок`,type:`date`,value:l,onChange:u}),(0,$.jsx)(FK,{label:`Инструкция`,value:d,onChange:f,rows:4}),(0,$.jsx)(zK,{children:`Поля для заполнения`}),(0,$.jsx)(BY,{fields:p,onChange:m,disabled:h}),_!==void 0&&(0,$.jsx)(RK,{tone:`danger`,children:_}),(0,$.jsxs)(`div`,{style:{display:`flex`,gap:r.spacing[2]},children:[(0,$.jsx)(rK,{variant:`solid`,tone:`accent`,size:`sm`,loading:h,disabled:a.trim().length===0,onClick:()=>void y(),children:`Создать`}),(0,$.jsx)(rK,{variant:`ghost`,size:`sm`,onClick:n,children:`Отмена`})]})]})},QX=er({universalIdentifier:_q,name:`docflow-tasks`,description:`Задания документооборота: штатные задачи с разделом «Документооборот»`,component:()=>{let e=M(),{members:t,currentMember:n}=Bq(),[r,i]=(0,L.useState)(``),a=$G(r,jX),[o,s]=(0,L.useState)(`open`),[c,l]=(0,L.useState)(VX),[u,d]=(0,L.useState)(HX),[f,p]=(0,L.useState)({kind:`closed`}),[m,h]=(0,L.useState)({}),[g,_]=(0,L.useState)(1),[v,y]=WK([`createdAt`]),[b,x]=(0,L.useState)(),[S]=(0,L.useState)(()=>new Date),C=S.toISOString(),w=new Date(S.getTime()+7*FX).toISOString(),T=new Date(S.getFullYear(),S.getMonth(),S.getDate()+IX+1).toISOString(),ee=n?.id,E=c.scope===`deleted`,D=o!==`done`&&!E&&ee!==void 0,O=f.kind===`task`?f.taskId:void 0,k=(0,L.useMemo)(()=>qX({view:o,filters:c,searchQuery:a,currentMemberId:ee,now:C,weekAhead:w}),[o,c,a,ee,C,w]),{data:te,loading:ne,error:re,reload:A}=QG(()=>CG(`tasks`,{filter:D?pG(k,YX(ee,T)):k,order_by:HK(u),limit:50*g}),[k,D,ee,T,u,g]),{data:j,reload:ie}=QG(async()=>D?(await CG(`tasks`,{filter:pG(k,JX(ee,T)),order_by:`dueAt[AscNullsLast]`,limit:LX})).records:[],[k,D,ee,T]),{data:ae,reload:oe}=QG(async()=>Object.fromEntries(await Promise.all(BX.map(async({value:e})=>[e,await OG(`tasks`,pG(aG(`smbSection`,uq),KX(e,ee),a.trim().length>0?fG(`title`,a):void 0))]))),[a,ee]),se=te?.records??[],ce=j??[],le=UK(se.map(({id:e})=>e)),ue=se.filter(({id:e})=>le.selectedIds.includes(e)),de=(c.source===NX?0:1)+(c.due===NX?0:1)+(c.assignee===NX?0:1)+ +!!E,fe=async()=>{await Promise.all([A(),ie(),oe()])},pe=eK({onDone:async()=>{le.clear(),x(void 0),await fe()}}),me=e=>{s(e),_(1),le.clear()},he=e=>{l(t=>({...t,...e})),_(1)},N=e=>pe.runEach(e,e=>NG(`/docflow/tasks/complete`,{taskId:e}),{done:e=>`Выполнено: ${e}`,failed:`Не выполнены`}),P=(e,t)=>pe.run(()=>AG(`tasks`,e,{status:t}),`Статус изменён: ${BG[t]}`,`Не удалось изменить статус`),F=e=>pe.run(async()=>{await jG(`tasks`,e),p(t=>t.kind===`task`&&e.includes(t.taskId)?{kind:`closed`}:t)},e.length===1?`Задание удалено: оно в фильтре «Удалённые»`:`Удалено заданий: ${e.length}, они в фильтре «Удалённые»`,`Не удалось удалить`),I=e=>pe.run(()=>MG(`tasks`,e),`Восстановлено: ${e.length}`,`Не удалось восстановить`),ge=e=>{let t=se.find(({id:t})=>t===e);if(E)return[{key:`restore`,label:`Восстановить`,icon:gn,onSelect:()=>void I([e])},{key:`card`,label:`Открыть карточку`,icon:lt,onSelect:()=>void GX(e)}];let n=t?.status===dq;return[{key:`open`,label:`Открыть`,icon:ft,onSelect:()=>p({kind:`task`,taskId:e})},{key:`card`,label:`Карточка задачи`,icon:lt,onSelect:()=>void GX(e)},...t?.status===`TODO`?[{key:`start`,label:`Взять в работу`,icon:sn,onSelect:()=>void P([e],RX)}]:[],...n?[]:[{key:`complete`,label:`Выполнить`,icon:ze,onSelect:()=>void N([e])}],{key:`delete`,label:`Удалить`,confirmLabel:`Точно удалить?`,icon:Un,tone:`danger`,onSelect:()=>void F([e])}]},_e=le.selectedIds,ve=ue.filter(e=>e.status!==dq).length,ye=f.kind===`task`?se.find(({id:e})=>e===f.taskId)??ce.find(({id:e})=>e===f.taskId):void 0,be=ye?.title?.trim()??``;(0,L.useEffect)(()=>{ye!==void 0&&be.length>0&&h(e=>e[ye.id]===be?e:{...e,[ye.id]:be})},[ye?.id,be]);let xe=f.kind===`create`?`Новое задание`:f.kind===`task`?be||m[f.taskId]||`Без названия`:void 0;return(0,$.jsxs)(jK,{children:[(0,$.jsxs)(ZK,{panelTitle:xe,onClosePanel:()=>p({kind:`closed`}),panel:f.kind===`create`?(0,$.jsx)(ZX,{currentMemberId:ee,onCancel:()=>p({kind:`closed`}),onCreated:e=>{p({kind:`task`,taskId:e}),fe()}}):f.kind===`task`?(0,$.jsx)(AX,{taskId:f.taskId,withChat:!0,showTitle:!1,onChanged:()=>void fe()},f.taskId):void 0,children:[(0,$.jsx)(KK,{search:{value:r,onChange:i,placeholder:`Поиск заданий`,activeFilterCount:de,onResetFilters:()=>he(VX),filters:[{key:`source`,title:`Откуда`,value:c.source,options:[{value:NX,label:`Все`},{value:`process`,label:`Шаги процессов`},{value:`own`,label:`Свои задания`}],onChange:e=>he({source:e})},{key:`due`,title:`Срок`,value:c.due,options:[{value:NX,label:`Любой`},{value:`overdue`,label:`Просроченные`},{value:`week`,label:`В ближайшие 7 дней`},{value:`none`,label:`Без срока`}],onChange:e=>he({due:e})},{key:`assignee`,title:`Исполнитель`,value:c.assignee,options:[{value:NX,label:`Любой`},{value:PX,label:`Не назначен`},...XX(t)],onChange:e=>he({assignee:e})},{key:`scope`,title:`Корзина`,value:c.scope,options:[{value:`active`,label:`Действующие`},{value:`deleted`,label:`Удалённые`}],onChange:e=>{he({scope:e}),le.clear()}}]},views:(0,$.jsx)(TK,{value:o,onChange:me,options:BX.map(e=>({...e,count:ae?.[e.value]}))}),onCreate:()=>p({kind:`create`})}),D&&(0,$.jsx)(WY,{tasks:ce,members:t,now:S,selectedTaskId:O,onOpen:e=>p({kind:`task`,taskId:e})}),re!==void 0&&(0,$.jsx)(`div`,{style:{padding:e.spacing[4]},children:(0,$.jsx)(RK,{tone:`danger`,children:PG(re,`Не удалось загрузить задания`)})}),ne&&te===void 0&&(0,$.jsx)(cq,{}),!ne&&re===void 0&&se.length===0&&(0,$.jsx)(RK,{children:ce.length>0?`Остальных заданий нет: все срочные — в карточках выше.`:`Заданий нет.`}),se.length>0&&(0,$.jsxs)($.Fragment,{children:[D&&ce.length>0&&(0,$.jsx)(`div`,{style:{padding:`${e.spacing[1]} ${e.spacing[5]} 0`},children:(0,$.jsx)(zK,{children:`Остальные задания`})}),(0,$.jsx)(GK,{columns:UX,hiddenColumnKeys:v,onHiddenColumnsChange:y,sort:u,onSortChange:e=>{d(e),_(1)},selectedRowId:O,selectedIds:_e,onSelectionChange:le.setSelectedIds,rowActions:ge,onRowClick:e=>E?void GX(e):p({kind:`task`,taskId:e}),rows:se.map(n=>{let r=GG(n.dueAt,S),i=n.status===`DONE`,a=DY(n);return{id:n.id,isMuted:i&&o!==`done`,cells:{title:n.title?.trim()||`Без названия`,assignee:FG(t.find(e=>e.id===n.assigneeId))||`—`,dueAt:n.dueAt?(0,$.jsx)(`span`,{title:IG(n.dueAt),style:{color:i?void 0:r.tone===`overdue`?e.font.color.danger:r.tone===`today`?e.color.orange:void 0},children:i?IG(n.dueAt):`${IG(n.dueAt)} · ${r.label.toLowerCase()}`}):`—`,fields:a.total>0?(0,$.jsxs)(`span`,{style:{alignItems:`center`,display:`flex`,gap:e.spacing[2]},children:[(0,$.jsx)(`span`,{style:{flex:1,maxWidth:`48px`},children:(0,$.jsx)(XK,{value:a.filled,total:a.total,tone:i?`green`:`blue`})}),a.filled,`/`,a.total]}):`—`,status:(0,$.jsx)(aK,{color:qG[n.status??``]??`gray`,children:BG[n.status??``]??n.status??`Без статуса`}),source:EY(n)?`Процесс`:`Своё`,createdAt:IG(n.createdAt)}}})})]}),(0,$.jsx)(YK,{isVisible:te?.pageInfo.hasNextPage===!0,loading:ne,onClick:()=>_(e=>e+1)}),(0,$.jsx)(qK,{count:_e.length,noun:zX,onClear:le.clear,children:E?(0,$.jsx)(rK,{icon:gn,loading:pe.isBusy,onClick:()=>void I(_e),children:`Восстановить`}):(0,$.jsxs)($.Fragment,{children:[ve>0&&(0,$.jsx)(rK,{icon:ze,loading:pe.isBusy,onClick:()=>void N(_e),children:`Выполнить`}),(0,$.jsx)(rK,{icon:Jt,disabled:pe.isBusy,onClick:()=>x(`change`),children:`Изменить`}),(0,$.jsx)(pK,{label:`Удалить`,icon:Un,disabled:pe.isBusy,actions:[{key:`delete`,label:`Удалить выбранные (${_e.length})`,confirmLabel:`Точно удалить?`,icon:Un,tone:`danger`,onSelect:()=>void F(_e)}]})]})})]}),b===`change`&&(0,$.jsx)(AK,{title:`Изменить поле`,hint:`Для ${_e.length} ${JK(_e.length,zX)}`,fields:[{key:`status`,label:`Статус`,options:[`TODO`,RX].map(e=>({value:e,label:BG[e]}))},{key:`assignee`,label:`Исполнитель`,options:[{value:MX,label:`Не назначен`},...XX(t)]},{key:`dueAt`,label:`Срок`,inputType:`date`}],onClose:()=>x(void 0),onSubmit:(e,t)=>e===`status`?P(_e,t):e===`assignee`?pe.run(()=>AG(`tasks`,_e,{assigneeId:t===MX?null:t}),`Исполнитель назначен`,`Не удалось назначить исполнителя`):pe.run(()=>AG(`tasks`,_e,{dueAt:/^\d{4}-\d{2}-\d{2}$/.test(t)?t:null}),`Срок изменён`,`Не удалось изменить срок`)})]})}}),$X=5e3,eZ=[],tZ=1,nZ=new Set,rZ=e=>{eZ=e,nZ.forEach(e=>e(eZ))},iZ=(e,t=`info`)=>{let n=tZ++;rZ([...eZ,{id:n,message:e,variant:t}]),setTimeout(()=>rZ(eZ.filter(e=>e.id!==n)),$X)},aZ=e=>(nZ.add(e),e(eZ),()=>{nZ.delete(e)}),oZ=e=>{d.TWENTY_APP_ACCESS_TOKEN=e},sZ=(e,t,n,r)=>{window.open(re(e,t,n,r),`_blank`,`noopener`)},cZ=({crmUrl:e,userId:t,colorScheme:n,refreshAccessToken:r})=>{globalThis.__twentySdkExecutionContext__={frontComponentId:`docflow-app`,userId:t,recordId:null,selectedRecordIds:[],timelineActivityId:null,colorScheme:n,locale:`ru-RU`},globalThis.frontComponentHostCommunicationApi??={},Object.assign(globalThis.frontComponentHostCommunicationApi,{enqueueSnackbar:async({message:e,variant:t})=>iZ(e,t),openSidePanelPage:async t=>{typeof t.to==`string`&&sZ(e,t.to,t.params)},navigate:async(t,n,r)=>sZ(e,t,n,r),closeSidePanel:async()=>void 0,copyToClipboard:e=>navigator.clipboard.writeText(e),requestAccessTokenRefresh:async()=>await r()??``})};ut(),gt(),Ut(),Kt(),fe();var lZ={tasks:QX.config.component,processes:TY.config.component,documents:Rq.config.component},uZ=e=>e.crmUrl.length>0?e.crmUrl:window.location.origin,dZ=({config:e,section:t,onSectionChange:n})=>{let r=M(),[i,a]=(0,L.useState)(document.fullscreenElement!==null);return(0,L.useEffect)(()=>{let e=()=>a(document.fullscreenElement!==null);return document.addEventListener(`fullscreenchange`,e),()=>document.removeEventListener(`fullscreenchange`,e)},[]),(0,$.jsxs)(`header`,{style:{alignItems:`center`,borderBottom:`1px solid ${r.border.color.medium}`,display:`grid`,gap:r.spacing[3],gridTemplateColumns:`1fr auto 1fr`,padding:`0 ${r.spacing[4]}`},children:[(0,$.jsxs)(`div`,{style:{alignItems:`center`,display:`flex`,gap:r.spacing[2],fontWeight:r.font.weight.medium},children:[(0,$.jsx)(ht,{size:18}),`Документооборот`]}),(0,$.jsx)(`nav`,{role:`tablist`,style:{display:`flex`,gap:r.spacing[4]},children:T.map(e=>{let i=e===t;return(0,$.jsx)(`button`,{type:`button`,role:`tab`,"aria-selected":i,onClick:()=>n(e),style:{background:`none`,border:`none`,borderBottom:`2px solid ${i?r.font.color.primary:`transparent`}`,color:i?r.font.color.primary:r.font.color.tertiary,cursor:`pointer`,fontFamily:`inherit`,fontSize:r.font.size.md,fontWeight:i?r.font.weight.medium:r.font.weight.regular,padding:`${r.spacing[3]} ${r.spacing[1]}`},children:ee[e]},e)})}),(0,$.jsxs)(`div`,{style:{alignItems:`center`,display:`flex`,gap:r.spacing[2],justifyContent:`flex-end`},children:[document.fullscreenEnabled&&(0,$.jsx)(iK,{icon:i?Gt:Ht,label:i?`Свернуть`:`На весь экран`,onClick:()=>void(i?document.exitFullscreen():document.documentElement.requestFullscreen())}),(0,$.jsx)(rK,{icon:lt,onClick:()=>window.open(uZ(e),`_blank`,`noopener`),children:`Открыть CRM`})]})]})},fZ=()=>{let e=M(),[t,n]=(0,L.useState)([]);return(0,L.useEffect)(()=>aZ(n),[]),(0,$.jsx)(`div`,{"aria-live":`polite`,style:{bottom:e.spacing[4],display:`flex`,flexDirection:`column`,gap:e.spacing[2],position:`fixed`,right:e.spacing[4],zIndex:1e3},children:t.map(t=>(0,$.jsx)(`div`,{role:t.variant===`error`?`alert`:`status`,style:{background:e.background.primary,border:`1px solid ${t.variant===`error`?e.color.red:e.border.color.medium}`,borderRadius:e.border.radius.md,boxShadow:e.boxShadow.strong,color:t.variant===`error`?e.font.color.danger:e.font.color.primary,fontSize:e.font.size.sm,maxWidth:360,padding:`${e.spacing[2]} ${e.spacing[3]}`},children:t.message},t.id))})},pZ=({config:e,session:t})=>{let n=M(),[r,i]=(0,L.useState)(e.section),[a,o]=(0,L.useState)([e.section]),s=e.expectedWorkspaceMemberId!==void 0&&t.workspaceMemberId!==e.expectedWorkspaceMemberId;return(0,$.jsxs)(`div`,{style:{background:n.background.primary,color:n.font.color.primary,display:`flex`,flexDirection:`column`,height:`100%`},children:[(0,$.jsx)(dZ,{config:e,section:r,onSectionChange:e=>{i(e),o(t=>t.includes(e)?t:[...t,e])}}),s&&(0,$.jsx)(`div`,{role:`status`,style:{background:n.background.transparent.light,color:n.font.color.secondary,fontSize:n.font.size.sm,padding:`${n.spacing[2]} ${n.spacing[4]}`},children:`В CRM в этом браузере вы вошли не под тем сотрудником, что в Битрикс24. Чтобы сменить, выйдите из CRM, войдите нужным сотрудником и откройте приложение заново.`}),(0,$.jsx)(`main`,{style:{flex:1,minHeight:0,position:`relative`},children:a.map(e=>{let t=lZ[e];return(0,$.jsx)(`div`,{style:{display:e===r?`block`:`none`,height:`100%`,overflow:`auto`},children:(0,$.jsx)(t,{})},e)})}),(0,$.jsx)(fZ,{})]})},mZ=({title:e,text:t,action:n})=>{let r=M();return(0,$.jsxs)(`div`,{style:{alignItems:`center`,background:r.background.primary,color:r.font.color.primary,display:`flex`,flexDirection:`column`,gap:r.spacing[3],height:`100%`,justifyContent:`center`,padding:r.spacing[6],textAlign:`center`},children:[(0,$.jsx)(ht,{size:32}),(0,$.jsx)(`div`,{style:{fontSize:r.font.size.lg,fontWeight:r.font.weight.medium},children:e}),(0,$.jsx)(`div`,{style:{color:r.font.color.tertiary,fontSize:r.font.size.md,maxWidth:420},children:t}),n!==void 0&&(0,$.jsx)(rK,{variant:`solid`,tone:`accent`,loading:n.loading,onClick:n.onClick,children:n.label})]})},hZ=`docflow.app.session`,gZ=6e4,_Z=3e3,vZ=async e=>{try{let t=await fetch(C,{method:`POST`,credentials:e===void 0?`same-origin`:`omit`,headers:{"content-type":`application/json`,...e===void 0?{}:{authorization:`Bearer ${e}`}},body:`{}`});return t.ok?D(await t.json()):void 0}catch{return}},yZ=()=>{try{let e=window.localStorage.getItem(hZ);return e===null?void 0:D(JSON.parse(e))}catch{return}},bZ=e=>{try{e===void 0?window.localStorage.removeItem(hZ):window.localStorage.setItem(hZ,JSON.stringify(e))}catch{}},xZ=({mode:e,session:t,onRenewed:n,onLost:r})=>{let i=t,a=null,o=()=>(a??=(async()=>{let t=await vZ(e===`crm`?void 0:te(i,Date.now())?i.token:void 0);return t===void 0?(te(i,Date.now())||(bZ(void 0),r()),te(i,Date.now())?i.token:null):(i=t,bZ(e===`bitrix`?i:void 0),n(i),i.token)})().finally(()=>{a=null}),a),s=window.setInterval(()=>{ne(i,Date.now())&&o()},gZ);return{current:()=>i,refresh:o,stop:()=>window.clearInterval(s)}},SZ=async e=>{if(e===`bitrix`){let e=yZ();if(te(e,Date.now()))return e}let t=await vZ();return t!==void 0&&e===`bitrix`&&bZ(t),t},CZ=()=>new Promise(e=>{let t=window.open(`${S}?connect=1`,`docflow-sign-in`,`width=520,height=560`);if(t===null){e(void 0);return}let n=t=>{window.removeEventListener(`message`,r),window.clearInterval(i),t!==void 0&&bZ(t),e(t)},r=e=>{e.origin===window.location.origin&&e.source===t&&e.data?.type===`docflow-app-session`&&n(D(e.data.session))},i=window.setInterval(()=>{t.closed&&n(void 0)},500);window.addEventListener(`message`,r)}),wZ=(e,t)=>{let n=window.opener;if(n===null){t();return}let r=async()=>{let e=await vZ();return e!==void 0&&(n.postMessage({type:w,session:e},window.location.origin),window.close(),!0)};r().then(t=>{if(t)return;e();let n=window.setInterval(()=>{r().then(e=>{e&&window.clearInterval(n)})},_Z)})},TZ=3e3,EZ=800,DZ=()=>{let e=document.getElementById(`docflow-app-config`),t=JSON.parse(e?.textContent??`{}`);return{mode:t.mode===`bitrix`||t.mode===`connect`?t.mode:`crm`,crmUrl:typeof t.crmUrl==`string`?t.crmUrl:``,section:E(t.section),expectedWorkspaceMemberId:t.expectedWorkspaceMemberId,portalDomain:t.portalDomain}},OZ=e=>A({portalDomain:e.portalDomain,ancestorOrigins:window.location.ancestorOrigins===void 0?void 0:Array.from(window.location.ancestorOrigins),referrer:document.referrer}),kZ=window.matchMedia(`(prefers-color-scheme: light)`).matches?`light`:`dark`,AZ=e=>e.crmUrl.length>0?e.crmUrl:window.location.origin,jZ=({config:e})=>{let[t,n]=(0,L.useState)(`working`),r=(0,L.useRef)(!1);return(0,L.useEffect)(()=>{r.current||(r.current=!0,wZ(()=>n(`waiting`),()=>n(`no-opener`)))},[]),t===`no-opener`?(0,$.jsx)(mZ,{title:`Вход в документооборот`,text:`Это окно открывается из приложения «Документооборот» в Битрикс24. Откройте приложение там и нажмите «Войти через CRM».`}):t===`working`?(0,$.jsx)(mZ,{title:`Вход в документооборот`,text:`Проверяю вход в CRM…`}):(0,$.jsx)(mZ,{title:`Войдите в CRM`,text:`Войдите в CRM в открывшейся вкладке. Это окно само заметит вход, передаст его в Битрикс24 и закроется.`,action:{label:`Открыть CRM`,onClick:()=>window.open(AZ(e),`_blank`,`noopener`)}})},MZ=({config:e})=>{let[t,n]=(0,L.useState)({kind:`loading`}),r=(0,L.useRef)(null),i=(0,L.useRef)(!1),a=t=>{r.current?.stop(),r.current=xZ({mode:e.mode,session:t,onRenewed:e=>oZ(e.token),onLost:()=>n({kind:`sign-in`,isWaiting:!1})}),oZ(t.token),cZ({crmUrl:AZ(e),userId:t.userId,colorScheme:kZ,refreshAccessToken:()=>r.current?.refresh()??Promise.resolve(null)}),n({kind:`signed-in`,session:t})};switch((0,L.useEffect)(()=>{if(!i.current&&(i.current=!0,SZ(e.mode).then(e=>e===void 0?n({kind:`sign-in`,isWaiting:!1}):a(e)),e.mode===`bitrix`)){let e=window.BX24;e?.init(()=>e.resizeWindow?.(document.documentElement.scrollWidth,Math.max(EZ,window.innerHeight)))}},[]),(0,L.useEffect)(()=>{if(t.kind!==`sign-in`||!t.isWaiting||e.mode!==`crm`)return;let n=window.setInterval(()=>{vZ().then(e=>{e!==void 0&&(window.clearInterval(n),a(e))})},TZ);return()=>window.clearInterval(n)},[t]),t.kind){case`loading`:return(0,$.jsx)(mZ,{title:`Документооборот`,text:`Загрузка…`});case`signed-in`:return(0,$.jsx)(pZ,{config:e,session:t.session});case`sign-in`:return e.mode===`bitrix`?(0,$.jsx)(mZ,{title:`Войдите через CRM`,text:`Документооборот работает с вашей учётной записью CRM. Вход откроется в отдельном окне; в этом браузере его хватит надолго.`,action:{label:`Войти через CRM`,loading:t.isWaiting,onClick:()=>{n({kind:`sign-in`,isWaiting:!0}),CZ().then(e=>e===void 0?n({kind:`sign-in`,isWaiting:!1}):a(e))}}}):(0,$.jsx)(mZ,{title:`Войдите в CRM`,text:t.isWaiting?`Войдите в CRM в открывшейся вкладке, эта страница откроется сама.`:`Документооборот открывается для сотрудника, вошедшего в CRM.`,action:{label:`Войти в CRM`,loading:t.isWaiting,onClick:()=>{window.open(AZ(e),`_blank`,`noopener`),n({kind:`sign-in`,isWaiting:!0})}}})}},NZ=DZ();document.documentElement.className=kZ;var PZ=document.getElementById(`root`);PZ!==null&&(0,x.createRoot)(PZ).render(NZ.mode===`connect`?(0,$.jsx)(jZ,{config:NZ}):NZ.mode===`bitrix`&&!OZ(NZ)?(0,$.jsx)(mZ,{title:`Документооборот`,text:`Эта страница открывается только в приложении портала Битрикс24, связанного с CRM.`}):(0,$.jsx)(MZ,{config:NZ}))})();
|