Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/devtools/client/shared/components/   (Firefox Browser Version 153.0.1©)  Datei vom 27.6.2026 mit Größe 11 kB image not shown  

Quelle  AppErrorBoundary.js

  Sprache: JAVA
 

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


"use strict";

// React deps
const {
  Component,
} = require("resource://devtools/client/shared/vendor/react.mjs");
const PropTypes = require("resource://devtools/client/shared/vendor/react-prop-types.mjs");
const dom = require("resource://devtools/client/shared/vendor/react-dom-factories.js");
const { div, h1, h2, h3, p, a, button } = dom;

loader.lazyRequireGetter(
  this,
  "Telemetry",
  "resource://devtools/client/shared/telemetry.js"
);

// Localized strings for (devtools/client/locales/en-US/components.properties)
loader.lazyGetter(this"L10N"function () {
  const { LocalizationHelper } = require("resource://devtools/shared/l10n.js");
  return new LocalizationHelper(
    "devtools/client/locales/components.properties"
  );
});

loader.lazyGetter(this"FILE_BUG_BUTTON"function () {
  return L10N.getStr("appErrorBoundary.fileBugButton");
});

loader.lazyGetter(this"RELOAD_PAGE_INFO"function () {
  return L10N.getStr("appErrorBoundary.reloadPanelInfo");
});

// File a bug for the selected component specifically
// Add format=__default__ to make sure users without EDITBUGS permission still
// use the regular UI to create bugs, including the prefilled description.
const bugLink =
  "https://bugzilla.mozilla.org/enter_bug.cgi?format=__default__&blocked=devtools-toolbox-crash&product=DevTools&component=";

/**
 * Error boundary that wraps around the a given component.
 */

class AppErrorBoundary extends Component {
  static get propTypes() {
    return {
      children: PropTypes.any.isRequired,
      panel: PropTypes.any.isRequired,
      componentName: PropTypes.string.isRequired,
      openLink: PropTypes.func,
    };
  }

  // Keep a flag to avoid submitting extra pings in case several components
  // fail in cascade.
  #pingSubmitted = false;

  constructor(props) {
    super(props);

    this.state = {
      errorMsg: "No error",
      errorStack: null,
      errorInfo: null,
      // Will be used to provide a button to close the toolbox.
      toolbox: null,
    };
  }

  /**
   *  Map the `info` object to a render.
   *  Currently, `info` usually just contains something similar to the
   *  following object (which is provided to componentDidCatch):
   *  componentStack: {"\n in (component) \n in (other component)..."}
   */

  renderErrorInfo(info = {}) {
    if (Object.keys(info).length) {
      return Object.keys(info)
        .filter(key => info[key])
        .map((obj, outerIdx) => {
          switch (obj) {
            case "componentStack": {
              const traceParts = info[obj]
                .split("\n")
                .map((part, idx) => p({ key: `strace${idx}` }, part));
              return div(
                { key: `st-div-${outerIdx}`, className: "stack-trace-section" },
                h3({}, "React Component Stack"),
                traceParts
              );
            }
            case "clientPacket":
            case "serverPacket": {
              // Only serverPacket has a stack.
              const stack = info[obj].stack;
              const traceParts = stack
                ? stack
                    .split("\n")
                    .map((part, idx) => p({ key: `strace${idx}` }, part))
                : null;

              // DevToolsProcessParent may receive stacktraces from the content process
              // and put them onto the exception's contentProcessStack attribute
              // which protocol.js Actor and Front layer will preserve so that we ultimately
              // can read it from here.
              // This is for server codebases using DevToolsProcess JS Actor to communicate
              // with the content processes from the parent process. Typically most methods
              // of the Watcher Actor.
              const contentProcessStack = info[obj].contentProcessStack;
              const contentProcessTraceParts = contentProcessStack
                ? contentProcessStack
                    .split("\n")
                    .map((part, idx) =>
                      p({ key: `contentProcessStrace${idx}` }, part)
                    )
                : null;

              return div(
                { className: "stack-trace-section" },
                h3(
                  {},
                  obj == "clientPacket" ? "Client packet" : "Server packet"
                ),
                // Display the packet as JSON, while removing the artificial `stack` attribute from it
                p(
                  {},
                  JSON.stringify({ ...info[obj], stack: undefined }, null2)
                ),
                stack ? h3({}, "Server stack") : null,
                traceParts,
                contentProcessStack
                  ? h3({}, "Server content process stack")
                  : null,
                contentProcessTraceParts
              );
            }
          }
          return null;
        });
    }

    return p({}, "undefined errorInfo");
  }

  renderStackTrace(stacktrace = "") {
    const re = /:\d+:\d+/g;
    const traces = stacktrace
      .replace(re, "$&,")
      .split(",")
      .map((trace, index) => {
        return p({ key: `rst-${index}` }, trace);
      });

    return div(
      { className: "stack-trace-section" },
      h3({}, "Stacktrace"),
      traces
    );
  }

  renderServerPacket(packet) {
    const traceParts = packet.stack
      .split("\n")
      .map((part, idx) => p({ key: `strace${idx}` }, part));
    return [
      div(
        { className: "stack-trace-section" },
        h3({}, "Server packet"),
        p({}, JSON.stringify(packet, null2))
      ),
      div(
        { className: "stack-trace-section" },
        h3({}, "Server Stack"),
        traceParts
      ),
    ];
  }

  // Return a valid object, even if we don't receive one
  getValidInfo(infoObj) {
    if (!infoObj.componentStack) {
      try {
        return { componentStack: JSON.stringify(infoObj) };
      } catch (err) {
        return { componentStack: `Unknown Error: ${err}` };
      }
    }
    return infoObj;
  }

  // Called automatically by React when a child component throws an error.
  componentDidCatch(error, info) {
    const validInfo = this.getValidInfo(info);
    const errorMessage = error.toString();

    this.setState({
      errorMsg: errorMessage,
      errorStack: error.stack,
      errorInfo: validInfo,
    });

    if (this.#pingSubmitted) {
      // If the component already sent the telemetry ping for this session, skip
      // recording a new event.
      return;
    }

    const extras = Telemetry.sanitizeEventExtras(
      {
        component_stack: validInfo.componentStack || "",
        error_name: error.name,
        stack: error.stack || "",
      },
      "devtoolsMain.toolboxComponentError",
      // Allow up to 500 characters for each extra value (maximum value
      // supported by Glean events).
      { limit: 500 }
    );
    Glean.devtoolsMain.toolboxComponentError.record(extras);
    this.#pingSubmitted = true;
  }

  // Manually called by devtools code when an exception is triggered before
  // or outside of React render codepath.
  handleException(exception, toolbox, showToolboxCloseButton = false) {
    const errorMessage = exception.toString();
    const clientPacket = exception.clientPacket || {};
    const serverPacket = exception.serverPacket || {};

    this.setState({
      errorMsg: errorMessage,
      errorStack: exception.stack,
      errorInfo: {
        clientPacket,
        serverPacket,
      },
      showToolboxCloseButton,
      toolbox,
    });

    if (this.#pingSubmitted) {
      // If the component already sent the telemetry ping for this session, skip
      // recording a new event.
      return;
    }

    const descriptorFront = toolbox.commands?.descriptorFront;
    const extras = Telemetry.sanitizeEventExtras(
      {
        descriptor_type: descriptorFront?.descriptorType,
        error_name: exception.name,
        host_type: toolbox.hostType,
        is_destroying: toolbox.isDestroying(),
        is_local_tab: descriptorFront?.isLocalTab,
        is_window_closed: !!toolbox.win?.closed,
        packet_error: serverPacket.error,
        packet_target: serverPacket.from,
        packet_type: clientPacket.type,
        server_stack: serverPacket.stack || "",
        server_content_process_stack: serverPacket.contentProcessStack || "",
        session_id: toolbox.sessionId,
        stack: exception.stack || "",
      },
      "devtoolsMain.toolboxServerError",
      // Allow up to 500 characters for each extra value (maximum value
      // supported by Glean events).
      { limit: 500 }
    );
    Glean.devtoolsMain.toolboxServerError.record(extras);
    this.#pingSubmitted = true;
  }

  getBugLink() {
    const { componentStack, clientPacket, serverPacket } = this.state.errorInfo;

    let msg =
      "## Steps to reproduce:\n\n" +
      "If possible, please share specific steps to reproduce the error.\n" +
      "Otherwise add any additional information useful to investigate the issue.\n\n";

    msg += `## Error in ${this.props.panel}: \n${this.state.errorMsg}\n\n`;

    if (componentStack) {
      msg += `## React Component Stack:${componentStack}\n\n`;
    }

    if (clientPacket) {
      msg += `## Client Packet:\n\`\`\`\n${JSON.stringify(clientPacket, null2)}\n\`\`\`\n\n`;
    }

    if (serverPacket) {
      // Display the packet as JSON, while removing the artificial `stack`/`contentProcessStack` attributes from it
      msg += `## Server Packet:\n\`\`\`\n${JSON.stringify({ ...serverPacket, stack: undefined, contentProcessStack: undefined }, null2)}\n\`\`\`\n\n`;
      msg += `## Server Stack:\n\`\`\`\n${serverPacket.stack}\n\`\`\`\n\n`;
      if (serverPacket.contentProcessStack) {
        msg += `## Server Content Process Stack:\n\`\`\`\n${serverPacket.contentProcessStack}\n\`\`\`\n\n`;
      }
    }

    msg += `## Stacktrace: \n\`\`\`\n${this.state.errorStack}\n\`\`\``;

    return `${bugLink}${this.props.componentName}&comment=${encodeURIComponent(
      msg
    )}`;
  }

  render() {
    if (this.state.errorInfo !== null) {
      // "The (componentDesc) has crashed"
      const errorDescription = L10N.getFormatStr(
        "appErrorBoundary.description",
        this.props.panel
      );

      const href = this.getBugLink();

      return div(
        {
          className: `app-error-panel`,
        },
        h1({ className: "error-panel-header" }, errorDescription),
        a(
          {
            className: "error-panel-file-button",
            href,
            target: "_blank",
            onClick: this.props.openLink
              ? e => this.props.openLink(href, e)
              : null,
          },
          FILE_BUG_BUTTON
        ),
        this.state.showToolboxCloseButton
          ? button({
              className: "devtools-tabbar-button error-panel-close",
              onClick: () => {
                this.state.toolbox.closeToolbox();
              },
            })
          : null,
        h2({ className: "error-panel-error" }, this.state.errorMsg),
        div({}, this.renderErrorInfo(this.state.errorInfo)),
        div({}, this.renderStackTrace(this.state.errorStack)),
        p({ className: "error-panel-reload-info" }, RELOAD_PAGE_INFO)
      );
    }
    return this.props.children;
  }
}

module.exports = AppErrorBoundary;

Messung V0.5 in Prozent
C=90 H=98 G=94

¤ Dauer der Verarbeitung: 0.5 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.