feat(ui): add hash search option and de-emphasized hash display in model modal

This commit is contained in:
Will Miao
2026-08-23 10:09:55 +08:00
parent 25e72b43ce
commit 030a32f8fa
26 changed files with 638 additions and 12 deletions
+3
View File
@@ -316,6 +316,7 @@ async function showModelModalFromCard(card, modelType) {
// Create model metadata object
const modelMeta = {
sha256: card.dataset.sha256,
autov3: card.dataset.autov3 || '',
preview_url: getCardPreviewUrl(card),
file_path: card.dataset.filepath,
model_name: card.dataset.name,
@@ -406,6 +407,7 @@ function showExampleAccessModal(card, modelType) {
// Get the model data from card dataset (works for both lora and checkpoint)
const modelMeta = {
sha256: card.dataset.sha256,
autov3: card.dataset.autov3 || '',
preview_url: getCardPreviewUrl(card),
file_path: card.dataset.filepath,
model_name: card.dataset.name,
@@ -460,6 +462,7 @@ export function createModelCard(model, modelType) {
// below, which ignore internal card drags via MODEL_CARD_DRAG_MIME_TYPE.
card.draggable = true;
card.dataset.sha256 = model.sha256;
card.dataset.autov3 = model.autov3 || '';
card.dataset.filepath = model.file_path;
card.dataset.name = model.model_name;
card.dataset.file_name = model.file_name;
+40 -1
View File
@@ -1,4 +1,4 @@
import { showToast, openCivitai, sendLoraToWorkflow, sendEmbeddingToWorkflow, sendModelPathToWorkflow, buildLoraSyntax } from '../../utils/uiHelpers.js';
import { showToast, openCivitai, sendLoraToWorkflow, sendEmbeddingToWorkflow, sendModelPathToWorkflow, buildLoraSyntax, copyToClipboard } from '../../utils/uiHelpers.js';
import { modalManager } from '../../managers/ModalManager.js';
import { MODEL_TYPES } from '../../api/apiConfig.js';
import {
@@ -351,6 +351,39 @@ export async function showModelModal(model, modelType) {
};
const escapedFilePathAttr = escapeAttribute(modelWithFullData.file_path || '');
const escapedFolderPath = escapeHtml((modelWithFullData.file_path || '').replace(/[^/]+$/, '') || 'N/A');
// De-emphasized hash display: a borderless full-width footnote line below
// the info grid — sha256 middle-truncated (first 10 + last 6), autov3 in
// full (12 chars); the full value is copied via data-hash.
const modelSha256 = modelWithFullData.sha256 || '';
const modelAutov3 = modelWithFullData.autov3 || '';
const truncatedSha256 = modelSha256.length > 16
? `${modelSha256.slice(0, 10)}\u2026${modelSha256.slice(-6)}`
: modelSha256;
const copyHashTitle = translate('modals.model.actions.copyHash', {}, 'Copy hash');
const hashEntries = [];
if (modelSha256) {
hashEntries.push(`
<span class="hash-entry">
<span class="hash-kind">SHA256</span>
<span class="model-hash-value" title="${escapeAttribute(modelSha256)}">${escapeHtml(truncatedSha256)}</span>
<button class="hash-copy-btn" data-action="copy-hash" data-hash="${escapeAttribute(modelSha256)}" title="${copyHashTitle}">
<i class="fas fa-copy"></i>
</button>
</span>`);
}
if (modelAutov3) {
hashEntries.push(`
<span class="hash-entry">
<span class="hash-kind">AutoV3</span>
<span class="model-hash-value" title="${escapeAttribute(modelAutov3)}">${escapeHtml(modelAutov3)}</span>
<button class="hash-copy-btn" data-action="copy-hash" data-hash="${escapeAttribute(modelAutov3)}" title="${copyHashTitle}">
<i class="fas fa-copy"></i>
</button>
</span>`);
}
const hashesMarkup = modelSha256 && hashEntries.length ? `
<div class="hash-footnote" aria-label="${translate('modals.model.metadata.hashes', {}, 'Hashes')}">${hashEntries.join('<span class="hash-sep">·</span>')}
</div>` : '';
const useNewIcons = state.global.settings.use_new_license_icons !== false;
const licenseIcons = useNewIcons
? renderNewLicenseIcons(modelWithFullData)
@@ -613,6 +646,7 @@ export async function showModelModal(model, modelType) {
<span>${formatFileSize(modelWithFullData.file_size)}</span>
</div>
</div>
${hashesMarkup}
${typeSpecificContent}
<div class="info-item notes">
<div class="notes-header">
@@ -910,6 +944,11 @@ function setupEventHandlers(filePath, modelType) {
case 'send-to-workflow':
handleSendToWorkflow(target, modelType);
break;
case 'copy-hash':
if (target.dataset.hash) {
copyToClipboard(target.dataset.hash, 'Hash copied to clipboard');
}
break;
}
}