refactor: centralize shared utilities across backend and frontend

Backend:
- Move SHA256 normalization logic from path_utils._normalize_header_sha256
  into core/type_utils.normalize_sha256, adding support for 0x-prefixed
  hashes and unifying the normalization path used by
  extract_safetensors_header_sha256.
- Add tests for the 0x prefix normalization cases.

Frontend:
- Introduce copyTextWithFeedback in web/resolver/utils/html_utils.js
  as a shared clipboard helper with configurable feedback text, CSS class,
  and duration, replacing repeated inline clipboard copy logic in
  globals.js, model_info_methods.js, and the notification utility.
- Centralize showNotification on ResolverManagerDialog and remove the
  duplicate implementation from missingBrowserMethods.
- Replace local const localStorage = safeStorage aliases in
  model_info_methods.js, missing_browser_methods.js, and
  options_methods.js with direct safeStorage usage.
This commit is contained in:
Dariusz L
2026-07-17 18:06:22 +02:00
parent 28d24214aa
commit be12494953
9 changed files with 109 additions and 103 deletions
+6 -18
View File
@@ -3,11 +3,9 @@ import { api } from "../../../../../scripts/api.js";
import { $el } from "../../../../../scripts/ui.js";
import { getSvgIcon } from "../../utils/icon_utils.js";
import { createFloatingTreePicker } from "../utils/tree_picker.js";
import { showNotification as showNotificationUtils } from "../../utils/notification_utils.js";
import { startSplitterDrag } from "../utils/splitter_drag.js";
import { getCivitaiModelUrl } from "../globals.js";
import { safeStorage, normalizePathIdentity } from "../utils/html_utils.js";
const localStorage = safeStorage;
export const missingBrowserMethods = {
getMissingFilename(missing = {}) {
@@ -678,7 +676,7 @@ export const missingBrowserMethods = {
showResolvedToggle.addEventListener('change', () => {
this.showResolvedModels = Boolean(showResolvedToggle.checked);
try {
localStorage.setItem(this.showResolvedModelsStorageKey, this.showResolvedModels ? '1' : '0');
safeStorage.setItem(this.showResolvedModelsStorageKey, this.showResolvedModels ? '1' : '0');
} catch (e) {}
this.displayMissingModels(container, data);
});
@@ -690,7 +688,7 @@ export const missingBrowserMethods = {
showAutoDownloadToggle.addEventListener('change', () => {
this.showAutoDownloadModels = Boolean(showAutoDownloadToggle.checked);
try {
localStorage.setItem(this.showAutoDownloadModelsStorageKey, this.showAutoDownloadModels ? '1' : '0');
safeStorage.setItem(this.showAutoDownloadModelsStorageKey, this.showAutoDownloadModels ? '1' : '0');
} catch (e) {}
this.displayMissingModels(container, data);
});
@@ -811,7 +809,7 @@ export const missingBrowserMethods = {
this._missingBrowserLastDetailWidth = null;
this.cancelMissingBrowserSplitWidthPersist();
try {
localStorage.removeItem(this.missingBrowserSplitStorageKey);
safeStorage.removeItem(this.missingBrowserSplitStorageKey);
} catch (e) {}
});
@@ -863,7 +861,7 @@ export const missingBrowserMethods = {
let savedWidth = null;
try {
const storedWidth = parseInt(localStorage.getItem(this.missingBrowserSplitStorageKey) || '', 10);
const storedWidth = parseInt(safeStorage.getItem(this.missingBrowserSplitStorageKey) || '', 10);
savedWidth = Number.isFinite(storedWidth) && storedWidth > 0 ? storedWidth : null;
} catch (e) {}
@@ -1228,7 +1226,7 @@ export const missingBrowserMethods = {
this._missingBrowserSplitPersistIdle = null;
this._missingBrowserSplitPersistTimer = null;
try {
localStorage.setItem(this.missingBrowserSplitStorageKey, String(nextWidth));
safeStorage.setItem(this.missingBrowserSplitStorageKey, String(nextWidth));
} catch (e) {}
};
@@ -2174,17 +2172,7 @@ export const missingBrowserMethods = {
return html;
},
/**
* Show a notification banner (similar to ComfyUI's "Reconnecting" banner)
*/
showNotification(message, type = 'success', options = {}) {
const duration = options?.duration || (type === 'success' ? 4000 : (type === 'error' ? 6000 : 3000));
return showNotificationUtils(message, type, {
...options,
duration,
deduplicate: options?.deduplicate || false
});
},
refreshMissingListRow(missing, options = {}) {
if (!missing || !this.contentElement) return;