createProgressNotification function exported ✓ 100.0%

Last updated: 2026-03-04T23:21:38.399Z

Metrics

LOC: 159 Complexity: 13 Params: 0 Coverage: 100.0% (64/64 lines, 0x executed)

Signature

createProgressNotification(): : ProgressNotification

Architecture violations

View all

  • [warning] max-cyclomatic-complexity: 'createProgressNotification' has cyclomatic complexity 13 (max 10)
  • [warning] max-lines: 'createProgressNotification' has 159 lines (max 80)

Source Code

export function createProgressNotification(): ProgressNotification {
  ensureStyles();

  // Remove existing
  document.getElementById(CONTAINER_ID)?.remove();

  const container = document.createElement("div");
  container.id = CONTAINER_ID;

  const header = document.createElement("div");
  header.className = "fa-progress-header";
  header.textContent = t("progressHeaderProcessing");
  container.appendChild(header);

  const list = document.createElement("div");
  list.className = "fa-progress-list";
  container.appendChild(list);

  document.body.appendChild(container);

  const fieldItems = new Map<string, HTMLElement>();
  let hideTimer: ReturnType<typeof setTimeout> | undefined;
  let aiGeneratingItem: HTMLElement | undefined;

  function getOrCreateItem(field: FormField): HTMLElement {
    const key = field.selector;
    let item = fieldItems.get(key);
    if (!item) {
      item = document.createElement("div");
      item.className = "fa-progress-item";
      list.appendChild(item);
      fieldItems.set(key, item);
      // Auto-scroll to bottom
      container.scrollTop = container.scrollHeight;
    }
    return item;
  }

  return {
    show() {
      requestAnimationFrame(() => {
        container.classList.add("fa-progress-visible");
      });
    },

    showAiGenerating() {
      if (aiGeneratingItem) return;
      aiGeneratingItem = document.createElement("div");
      aiGeneratingItem.className = "fa-progress-item filling";
      aiGeneratingItem.innerHTML = `
        <span class="fa-progress-icon"><span class="fa-spinner ai"></span></span>
        <span class="fa-progress-label">${escapeTextContent(t("progressAiGenerating"))}</span>
        <span class="fa-progress-badge">AI</span>
      `;
      list.appendChild(aiGeneratingItem);
      container.scrollTop = container.scrollHeight;
    },

    hideAiGenerating() {
      aiGeneratingItem?.remove();
      aiGeneratingItem = undefined;
    },

    addDetecting(field: FormField) {
      const item = getOrCreateItem(field);
      const label = escapeTextContent(getFieldLabel(field));
      const isAi =
        field.detectionMethod === "chrome-ai" ||
        field.detectionMethod === "tensorflow";
      item.className = "fa-progress-item detecting";
      item.innerHTML = `
        <span class="fa-progress-icon"><span class="fa-spinner${isAi ? " ai" : ""}"></span></span>
        <span class="fa-progress-label">${label}</span>
        <span class="fa-progress-badge">${escapeTextContent(t("progressDetecting"))}</span>
      `;
    },

    updateDetected(field: FormField) {
      const item = getOrCreateItem(field);
      const label = escapeTextContent(getFieldLabel(field));
      const method = field.detectionMethod ?? "html-fallback";
      const icon = METHOD_ICON[method] ?? "🔍";
      item.className = "fa-progress-item detected";
      item.innerHTML = `
        <span class="fa-progress-icon">${icon}</span>
        <span class="fa-progress-label">${label}</span>
        <span class="fa-progress-badge">${escapeTextContent(field.fieldType)} ${escapeTextContent(method)}</span>
      `;
    },

    addFilling(field: FormField) {
      const item = getOrCreateItem(field);
      const label = escapeTextContent(getFieldLabel(field));
      const method = field.detectionMethod ?? "html-fallback";
      const methodIcon = METHOD_ICON[method] ?? "🔍";
      item.className = "fa-progress-item filling";
      item.innerHTML = `
        <span class="fa-progress-icon"><span class="fa-spinner ai"></span></span>
        <span class="fa-progress-label">${methodIcon} ${label}</span>
        <span class="fa-progress-badge">${escapeTextContent(t("progressFilling"))}</span>
      `;
    },

    updateFilled(field: FormField, result: GenerationResult) {
      const item = getOrCreateItem(field);
      const label = escapeTextContent(getFieldLabel(field));
      const sourceIcon = SOURCE_ICON[result.source] ?? "✅";
      const valuePrev = escapeTextContent(
        result.value.length > 20
          ? result.value.slice(0, 20) + "…"
          : result.value,
      );
      item.className = "fa-progress-item filled";
      item.innerHTML = `
        <span class="fa-progress-icon">${sourceIcon}</span>
        <span class="fa-progress-label">${label}</span>
        <span class="fa-progress-badge">✓ ${valuePrev}</span>
      `;
    },

    updateError(field: FormField, error?: string) {
      const item = getOrCreateItem(field);
      const label = escapeTextContent(getFieldLabel(field));
      const errorMsg = error
        ? escapeTextContent(error.slice(0, 30))
        : t("progressFailed");
      item.className = "fa-progress-item error";
      item.innerHTML = `
        <span class="fa-progress-icon">❌</span>
        <span class="fa-progress-label">${label}</span>
        <span class="fa-progress-badge">${errorMsg}</span>
      `;
    },

    done(totalFilled: number, totalFields: number) {
      header.textContent = t("progressHeaderDone");

      const summary = document.createElement("div");
      summary.className = "fa-progress-summary";
      summary.textContent = t("progressSummary", [
        String(totalFilled),
        String(totalFields),
      ]);
      container.appendChild(summary);

      hideTimer = setTimeout(() => {
        container.style.transition = "opacity 0.5s ease, transform 0.5s ease";
        container.style.opacity = "0";
        container.style.transform = "translateY(12px)";
        setTimeout(() => container.remove(), 500);
      }, AUTO_HIDE_MS);
    },

    destroy() {
      if (hideTimer) clearTimeout(hideTimer);
      container.remove();
    },
  };
}

Members

Name Kind Visibility Status Signature
getOrCreateItem function - getOrCreateItem(field: FormField): : HTMLElement
show method - show()
showAiGenerating method - showAiGenerating()
hideAiGenerating method - hideAiGenerating()
addDetecting method - addDetecting(field: FormField)
updateDetected method - updateDetected(field: FormField)
addFilling method - addFilling(field: FormField)
updateFilled method - updateFilled(field: FormField, result: GenerationResult)
updateError method - updateError(field: FormField, error?: string)
done method - done(totalFilled: number, totalFields: number)
destroy method - destroy()

Dependencies (Outgoing)

graph LR createProgressNotification["createProgressNotification"] ensureStyles["ensureStyles"] createProgressNotification -->|calls| ensureStyles style createProgressNotification fill:#dbeafe,stroke:#2563eb,stroke-width:2px click createProgressNotification "2f3f7f6d24a2f425.html" click ensureStyles "9133434bbe64c3e3.html"
TargetType
ensureStyles calls
key dynamic_call

Impact (Incoming)

graph LR createProgressNotification["createProgressNotification"] setNativeValue["setNativeValue"] doFillAllFields["doFillAllFields"] fillContextualAI["fillContextualAI"] makeField["makeField"] setNativeValue -->|uses| createProgressNotification doFillAllFields -->|calls| createProgressNotification fillContextualAI -->|calls| createProgressNotification makeField -->|uses| createProgressNotification style createProgressNotification fill:#dbeafe,stroke:#2563eb,stroke-width:2px click createProgressNotification "2f3f7f6d24a2f425.html" click setNativeValue "334bd99609d7c37c.html" click doFillAllFields "23fe5c1a0125e335.html" click fillContextualAI "854e1a4562eb49e4.html" click makeField "6ec42aac80783d3b.html"
SourceType
setNativeValue uses
doFillAllFields calls
fillContextualAI calls
makeField uses