From cd67176b41b688b5645d00344e96c0756eae4226baca5ac244bc8028017f42c3 Mon Sep 17 00:00:00 2001 From: AidarKC Date: Fri, 31 Jul 2026 13:50:17 +0400 Subject: [PATCH] =?UTF-8?q?UI:=20=D1=83=D0=BF=D0=BB=D0=BE=D1=82=D0=BD?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D0=B6=D1=83=D1=80=D0=BD=D0=B0=D0=BB=20?= =?UTF-8?q?=D0=B7=D0=B0=D0=B3=D1=80=D1=83=D0=B7=D0=BE=D0=BA=20Arweave?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- VERSION.properties | 2 +- docs/Blockchain/15_TEXT_Attachments.md | 3 +- docs/Blockchain/CHANGELOG.md | 5 + .../components/arweave-attachment-manager.js | 98 ++++++++++++++---- shine-UI/js/pages/arweave-uploads-view.js | 70 +++++++------ shine-UI/js/pages/channel-thread-view.js | 3 +- shine-UI/js/pages/channel-view.js | 4 +- shine-UI/js/pages/settings-view.js | 2 +- shine-UI/styles/components.css | 99 ++++++++++++++++--- 9 files changed, 219 insertions(+), 67 deletions(-) diff --git a/VERSION.properties b/VERSION.properties index 19420751..d3d382ac 100644 --- a/VERSION.properties +++ b/VERSION.properties @@ -1,2 +1,2 @@ -client.version=1.4.3 +client.version=1.4.4 server.version=1.4.0 diff --git a/docs/Blockchain/15_TEXT_Attachments.md b/docs/Blockchain/15_TEXT_Attachments.md index c043ed41..e472d2e7 100644 --- a/docs/Blockchain/15_TEXT_Attachments.md +++ b/docs/Blockchain/15_TEXT_Attachments.md @@ -61,7 +61,8 @@ UI поддерживает три сценария: - выбрать файл из журнала файлов, загруженных в текущей браузерной сессии. Журнал хранится только в `sessionStorage` текущего браузера и не является частью блокчейна. -В настройках клиента есть отдельный экран журнала загрузок Arweave: пользователь может заранее загрузить файл в Arweave без создания сообщения, увидеть плитку с именем, размером, датой, `txId` и статусом доступности через gateway, а затем выбрать этот файл из истории при создании сообщения. +В настройках клиента есть отдельный экран `Загрузить файлы в блокчейн`: пользователь может заранее загрузить файл в Arweave без создания сообщения, увидеть плитку с именем, размером, временем загрузки, `txId` и статусом доступности через gateway, а затем выбрать этот файл из истории при создании сообщения. +Если файл загружен заранее, но ещё не был отправлен ни в одном сообщении SHiNE, клиент показывает локальный флаг `Не добавлен в SHiNE`. Флаг снимается после успешной отправки сообщения с этим вложением. Если история очищена, уже созданные сообщения не меняются: в блокчейне остаются attach-блоки с `txId`. ## Отображение diff --git a/docs/Blockchain/CHANGELOG.md b/docs/Blockchain/CHANGELOG.md index 4a68b503..01c218ef 100644 --- a/docs/Blockchain/CHANGELOG.md +++ b/docs/Blockchain/CHANGELOG.md @@ -1,5 +1,10 @@ # История изменений документации блокчейна +## 2026-07-31 13:48:57 +0400 +- Базовый коммит-ориентир: `98eba54`. +- Уточнено UI-поведение журнала загрузок Arweave: экран называется `Загрузить файлы в блокчейн`, использует компактные плитки и локальный флаг `Не добавлен в SHiNE` для файлов, которые загружены заранее, но ещё не отправлены во вложении сообщения. +- Зафиксировано, что флаг хранится только в клиентском sessionStorage и снимается после успешной отправки сообщения с выбранным вложением; формат attach-блока не изменён. + ## 2026-07-31 13:12:24 +0400 - Базовый коммит-ориентир: `c530627`. - Для UI-вложений добавлен отдельный экран журнала загрузок Arweave в настройках: загрузка файла без создания сообщения, плитки истории с `txId`, размером, датой и статусом доступности через gateway. diff --git a/shine-UI/js/components/arweave-attachment-manager.js b/shine-UI/js/components/arweave-attachment-manager.js index c062abc6..e9d44581 100644 --- a/shine-UI/js/components/arweave-attachment-manager.js +++ b/shine-UI/js/components/arweave-attachment-manager.js @@ -13,13 +13,23 @@ const HISTORY_KEY = 'shine-ui-arweave-attachment-history-v1'; const MAX_HISTORY_ITEMS = 100; const RECENT_UPLOAD_MS = 20 * 60 * 1000; +function normalizeHistoryItem(input = {}) { + const item = normalizeAttachment(input); + const placedInShineAtMs = Number(input.placedInShineAtMs || 0) || 0; + return { + ...item, + pendingPlacement: input.pendingPlacement === true && !placedInShineAtMs, + placedInShineAtMs, + }; +} + export function readArweaveAttachmentHistory(login) { try { const raw = sessionStorage.getItem(HISTORY_KEY); const parsed = raw ? JSON.parse(raw) : {}; const key = String(login || '').trim().toLowerCase(); const rows = Array.isArray(parsed?.[key]) ? parsed[key] : []; - return rows.map((item) => normalizeAttachment(item)).filter(Boolean); + return rows.map((item) => normalizeHistoryItem(item)).filter(Boolean); } catch { return []; } @@ -30,7 +40,9 @@ export function saveArweaveAttachmentHistory(login, rows) { const key = String(login || '').trim().toLowerCase(); const raw = sessionStorage.getItem(HISTORY_KEY); const parsed = raw ? JSON.parse(raw) : {}; - parsed[key] = (Array.isArray(rows) ? rows : []).slice(0, MAX_HISTORY_ITEMS); + parsed[key] = (Array.isArray(rows) ? rows : []) + .map((item) => normalizeHistoryItem(item)) + .slice(0, MAX_HISTORY_ITEMS); sessionStorage.setItem(HISTORY_KEY, JSON.stringify(parsed)); } catch { // ignore sessionStorage errors @@ -41,12 +53,52 @@ export function clearArweaveAttachmentHistory(login) { saveArweaveAttachmentHistory(login, []); } -export function addArweaveAttachmentToHistory(login, attachment) { - const item = normalizeAttachment(attachment); - const rows = readArweaveAttachmentHistory(login).filter((row) => row.ar !== item.ar); - rows.unshift(item); - saveArweaveAttachmentHistory(login, rows); - return item; +export function addArweaveAttachmentToHistory(login, attachment, { pendingPlacement = undefined, markPlaced = false } = {}) { + const item = normalizeHistoryItem(attachment); + const rows = readArweaveAttachmentHistory(login); + const existing = rows.find((row) => row.ar === item.ar) || {}; + const placedInShineAtMs = markPlaced + ? Date.now() + : Number(existing.placedInShineAtMs || item.placedInShineAtMs || 0) || 0; + const nextPendingPlacement = pendingPlacement === undefined + ? (existing.pendingPlacement === true && !placedInShineAtMs) + : (!!pendingPlacement && !placedInShineAtMs); + const nextItem = { + ...item, + pendingPlacement: nextPendingPlacement, + placedInShineAtMs, + }; + const nextRows = rows.filter((row) => row.ar !== item.ar); + nextRows.unshift(nextItem); + saveArweaveAttachmentHistory(login, nextRows); + return nextItem; +} + +export function markArweaveAttachmentPlaced(login, attachment) { + const item = normalizeHistoryItem(attachment); + const rows = readArweaveAttachmentHistory(login); + const existing = rows.find((row) => row.ar === item.ar) || {}; + const nextItem = { + ...item, + uploadedAtMs: item.uploadedAtMs || existing.uploadedAtMs || Date.now(), + pendingPlacement: false, + placedInShineAtMs: Number(existing.placedInShineAtMs || 0) || Date.now(), + }; + const nextRows = rows.filter((row) => row.ar !== item.ar); + nextRows.unshift(nextItem); + saveArweaveAttachmentHistory(login, nextRows); + return nextItem; +} + +export function formatArweaveHistoryTime(ms) { + const value = Number(ms || 0); + if (!Number.isFinite(value) || value <= 0) return '—'; + const diffMs = Date.now() - value; + if (diffMs >= 0 && diffMs < RECENT_UPLOAD_MS) { + const minutes = Math.max(1, Math.floor(diffMs / 60000)); + return `${minutes} мин назад`; + } + return new Date(value).toLocaleString('ru-RU'); } export function formatArweaveHistoryDateTime(ms) { @@ -87,6 +139,7 @@ export function openArweaveAttachmentManager({ gateway, onSelect, selectedTxIds = [], + historyOnly = false, } = {}) { const cleanLogin = String(login || '').trim(); const cleanStoragePwd = String(storagePwd || '').trim(); @@ -118,9 +171,12 @@ export function openArweaveAttachmentManager({ resolve(result); } - function finish(resolve, attachment) { - const item = addArweaveAttachmentToHistory(cleanLogin, attachment); - if (typeof onSelect === 'function') onSelect(item); + function finish(resolve, attachment, { pendingPlacement = undefined } = {}) { + const item = addArweaveAttachmentToHistory(cleanLogin, attachment, { + pendingPlacement, + markPlaced: false, + }); + if (!pendingPlacement && typeof onSelect === 'function') onSelect(item); close(resolve, item); } @@ -151,19 +207,19 @@ export function openArweaveAttachmentManager({ root.innerHTML = `