mirror of https://github.com/zulip/zulip.git
blueslip: Make stack trace more readable.
The stack trace popup is now sourcemapped and each stackframe have a expandable code context window. [anders@zulipchat.com: Rebased and simplified.]
This commit is contained in:
parent
94c8fffdf3
commit
c93522d847
|
@ -427,6 +427,7 @@
|
||||||
"no-magic-numbers": "off",
|
"no-magic-numbers": "off",
|
||||||
"semi": "off",
|
"semi": "off",
|
||||||
"no-unused-vars": "off",
|
"no-unused-vars": "off",
|
||||||
|
"no-useless-constructor": "off",
|
||||||
|
|
||||||
"@typescript-eslint/adjacent-overload-signatures": "error",
|
"@typescript-eslint/adjacent-overload-signatures": "error",
|
||||||
"@typescript-eslint/array-type": "error",
|
"@typescript-eslint/array-type": "error",
|
||||||
|
@ -451,7 +452,7 @@
|
||||||
"@typescript-eslint/no-extraneous-class": "error",
|
"@typescript-eslint/no-extraneous-class": "error",
|
||||||
"@typescript-eslint/no-for-in-array": "off",
|
"@typescript-eslint/no-for-in-array": "off",
|
||||||
"@typescript-eslint/no-inferrable-types": "error",
|
"@typescript-eslint/no-inferrable-types": "error",
|
||||||
"@typescript-eslint/no-magic-numbers": "error",
|
"@typescript-eslint/no-magic-numbers": "off",
|
||||||
"@typescript-eslint/no-misused-new": "error",
|
"@typescript-eslint/no-misused-new": "error",
|
||||||
"@typescript-eslint/no-namespace": "error",
|
"@typescript-eslint/no-namespace": "error",
|
||||||
"@typescript-eslint/no-non-null-assertion": "off",
|
"@typescript-eslint/no-non-null-assertion": "off",
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
const blueslip_stacktrace = zrequire("blueslip_stacktrace");
|
||||||
|
|
||||||
|
run_test("clean_path", () => {
|
||||||
|
// Local file
|
||||||
|
assert.strictEqual(
|
||||||
|
blueslip_stacktrace.clean_path("webpack:///static/js/upload.js"),
|
||||||
|
"/static/js/upload.js"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Third party library (jQuery)
|
||||||
|
assert.strictEqual(
|
||||||
|
blueslip_stacktrace.clean_path(
|
||||||
|
"webpack:///.-npm-cache/de76fb6f582a29b053274f9048b6158091351048/node_modules/jquery/dist/jquery.js"
|
||||||
|
),
|
||||||
|
"jquery/dist/jquery.js"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Third party library (underscore)
|
||||||
|
assert.strictEqual(
|
||||||
|
blueslip_stacktrace.clean_path(
|
||||||
|
"webpack:///.-npm-cache/de76fb6f582a29b053274f9048b…58091351048/node_modules/underscore/underscore.js"
|
||||||
|
),
|
||||||
|
"underscore/underscore.js"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
run_test("clean_function_name", () => {
|
||||||
|
assert.deepEqual(blueslip_stacktrace.clean_function_name(undefined), undefined);
|
||||||
|
|
||||||
|
// Local file
|
||||||
|
assert.deepEqual(
|
||||||
|
blueslip_stacktrace.clean_function_name("Object../static/js/upload.js.exports.options"),
|
||||||
|
{
|
||||||
|
scope: "Object../static/js/upload.js.exports.",
|
||||||
|
name: "options",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Third party library (jQuery)
|
||||||
|
assert.deepEqual(blueslip_stacktrace.clean_function_name("mightThrow"), {
|
||||||
|
scope: "",
|
||||||
|
name: "mightThrow",
|
||||||
|
});
|
||||||
|
|
||||||
|
// Third party library (underscore)
|
||||||
|
assert.deepEqual(
|
||||||
|
blueslip_stacktrace.clean_function_name(
|
||||||
|
"Function.../zulip-npm-cache/de76fb6f582a29b053274f…es/underscore/underscore.js?3817._.each._.forEach"
|
||||||
|
),
|
||||||
|
{
|
||||||
|
scope:
|
||||||
|
"Function.../zulip-npm-cache/de76fb6f582a29b053274f…es/underscore/underscore.js?3817._.each._.",
|
||||||
|
name: "forEach",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
|
@ -48,6 +48,7 @@
|
||||||
"postcss-nested": "^4.1.2",
|
"postcss-nested": "^4.1.2",
|
||||||
"postcss-scss": "^2.0.0",
|
"postcss-scss": "^2.0.0",
|
||||||
"postcss-simple-vars": "^5.0.2",
|
"postcss-simple-vars": "^5.0.2",
|
||||||
|
"regenerator-runtime": "^0.13.3",
|
||||||
"script-loader": "^0.7.2",
|
"script-loader": "^0.7.2",
|
||||||
"shebang-loader": "^0.0.1",
|
"shebang-loader": "^0.0.1",
|
||||||
"simplebar": "^4.1.0",
|
"simplebar": "^4.1.0",
|
||||||
|
@ -55,6 +56,7 @@
|
||||||
"sorttable": "^1.0.2",
|
"sorttable": "^1.0.2",
|
||||||
"source-sans-pro": "^3.6.0",
|
"source-sans-pro": "^3.6.0",
|
||||||
"spectrum-colorpicker": "^1.8.0",
|
"spectrum-colorpicker": "^1.8.0",
|
||||||
|
"stacktrace-gps": "^3.0.3",
|
||||||
"style-loader": "^1.0.0",
|
"style-loader": "^1.0.0",
|
||||||
"terser-webpack-plugin": "^2.1.0",
|
"terser-webpack-plugin": "^2.1.0",
|
||||||
"to-markdown": "^3.1.0",
|
"to-markdown": "^3.1.0",
|
||||||
|
@ -69,6 +71,7 @@
|
||||||
"zxcvbn": "^4.4.2"
|
"zxcvbn": "^4.4.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/jquery": "^3.3.31",
|
||||||
"@types/node": "^12.0.7",
|
"@types/node": "^12.0.7",
|
||||||
"@types/underscore": "^1.8.18",
|
"@types/underscore": "^1.8.18",
|
||||||
"@types/webpack": "^4.4.32",
|
"@types/webpack": "^4.4.32",
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
// in order to be able to report exceptions that occur during their
|
// in order to be able to report exceptions that occur during their
|
||||||
// execution.
|
// execution.
|
||||||
|
|
||||||
|
var blueslip_stacktrace = require("./blueslip_stacktrace");
|
||||||
|
|
||||||
if (Error.stackTraceLimit !== undefined) {
|
if (Error.stackTraceLimit !== undefined) {
|
||||||
Error.stackTraceLimit = 100000;
|
Error.stackTraceLimit = 100000;
|
||||||
}
|
}
|
||||||
|
@ -78,20 +80,6 @@ exports.get_log = function blueslip_get_log() {
|
||||||
return logger.get_log();
|
return logger.get_log();
|
||||||
};
|
};
|
||||||
|
|
||||||
// Format error stacks using the ErrorStackParser
|
|
||||||
// external library
|
|
||||||
function getErrorStack(stack) {
|
|
||||||
var ex = new Error();
|
|
||||||
ex.stack = stack;
|
|
||||||
return ErrorStackParser
|
|
||||||
.parse(ex)
|
|
||||||
.map(function (stackFrame) {
|
|
||||||
return stackFrame.lineNumber
|
|
||||||
+ ': ' + stackFrame.fileName
|
|
||||||
+ ' | ' + stackFrame.functionName;
|
|
||||||
}).join('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
var reported_errors = {};
|
var reported_errors = {};
|
||||||
var last_report_attempt = {};
|
var last_report_attempt = {};
|
||||||
|
|
||||||
|
@ -105,8 +93,7 @@ function report_error(msg, stack, opts) {
|
||||||
if (page_params.debug_mode) {
|
if (page_params.debug_mode) {
|
||||||
// In development, we display blueslip errors in the web UI,
|
// In development, we display blueslip errors in the web UI,
|
||||||
// to make them hard to miss.
|
// to make them hard to miss.
|
||||||
stack = getErrorStack(stack);
|
blueslip_stacktrace.display_stacktrace(msg, stack);
|
||||||
exports.display_errors_on_screen(msg, stack);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var key = ':' + msg + stack;
|
var key = ':' + msg + stack;
|
||||||
|
@ -253,15 +240,6 @@ exports.warn = function blueslip_warn (msg, more_info) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.display_errors_on_screen = function (error, stack) {
|
|
||||||
var $exit = "<div class='exit'></div>";
|
|
||||||
var $error = "<div class='error'>" + error + "</div>";
|
|
||||||
var $pre = "<pre>" + stack + "</pre>";
|
|
||||||
var $alert = $("<div class='alert browser-alert home-error-bar'></div>").html($error + $exit + $pre);
|
|
||||||
|
|
||||||
$(".app .alert-box").append($alert.addClass("show"));
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.error = function blueslip_error (msg, more_info, stack) {
|
exports.error = function blueslip_error (msg, more_info, stack) {
|
||||||
if (stack === undefined) {
|
if (stack === undefined) {
|
||||||
stack = Error().stack;
|
stack = Error().stack;
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
import $ from "jquery";
|
||||||
|
import ErrorStackParser from "error-stack-parser";
|
||||||
|
import StackTraceGPS from "stacktrace-gps";
|
||||||
|
import render_blueslip_stacktrace from "../templates/blueslip_stacktrace.hbs";
|
||||||
|
|
||||||
|
type FunctionName = {
|
||||||
|
scope: string;
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type NumberedLine = {
|
||||||
|
line_number: number;
|
||||||
|
line: string;
|
||||||
|
focus: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
type CleanStackFrame = {
|
||||||
|
full_path: string;
|
||||||
|
show_path: string;
|
||||||
|
function_name: FunctionName;
|
||||||
|
line_number: number;
|
||||||
|
context: NumberedLine[] | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function clean_path(full_path: string): string {
|
||||||
|
// If the file is local, just show the filename.
|
||||||
|
// Otherwise, show the full path starting from node_modules.
|
||||||
|
const idx = full_path.indexOf("/node_modules/");
|
||||||
|
if (idx !== -1) {
|
||||||
|
return full_path.slice(idx + "/node_modules/".length);
|
||||||
|
}
|
||||||
|
if (full_path.startsWith("webpack://")) {
|
||||||
|
return full_path.slice("webpack://".length);
|
||||||
|
}
|
||||||
|
return full_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function clean_function_name(
|
||||||
|
function_name: string | undefined
|
||||||
|
): { scope: string; name: string } | undefined {
|
||||||
|
if (function_name === undefined) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
const idx = function_name.lastIndexOf(".");
|
||||||
|
return {
|
||||||
|
scope: function_name.slice(0, idx + 1),
|
||||||
|
name: function_name.slice(idx + 1),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const sourceCache: { [source: string]: string } = {};
|
||||||
|
|
||||||
|
const stack_trace_gps = new StackTraceGPS({ sourceCache });
|
||||||
|
|
||||||
|
function get_context(location: StackFrame.StackFrame): NumberedLine[] | undefined {
|
||||||
|
const sourceContent = sourceCache[location.getFileName()];
|
||||||
|
if (sourceContent === undefined) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
const lines = sourceContent.split("\n");
|
||||||
|
const line_number = location.getLineNumber();
|
||||||
|
const lo_line_num = Math.max(line_number - 5, 0);
|
||||||
|
const hi_line_num = Math.min(line_number + 4, lines.length);
|
||||||
|
return lines.slice(lo_line_num, hi_line_num).map((line: string, i: number) => ({
|
||||||
|
line_number: lo_line_num + i + 1,
|
||||||
|
line,
|
||||||
|
focus: lo_line_num + i + 1 === line_number,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function display_stacktrace(error: string, stack: string): Promise<void> {
|
||||||
|
const ex = new Error();
|
||||||
|
ex.stack = stack;
|
||||||
|
|
||||||
|
const stackframes: CleanStackFrame[] = await Promise.all(
|
||||||
|
ErrorStackParser.parse(ex).map(async (stack_frame: ErrorStackParser.StackFrame) => {
|
||||||
|
const location = await stack_trace_gps.getMappedLocation(
|
||||||
|
// Work around mistake in ErrorStackParser.StackFrame definition
|
||||||
|
// https://github.com/stacktracejs/error-stack-parser/pull/49
|
||||||
|
(stack_frame as unknown) as StackFrame.StackFrame
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
full_path: location.getFileName(),
|
||||||
|
show_path: clean_path(location.getFileName()),
|
||||||
|
line_number: location.getLineNumber(),
|
||||||
|
function_name: clean_function_name(location.getFunctionName()),
|
||||||
|
context: get_context(location),
|
||||||
|
};
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const $alert = $("<div class='stacktrace'>").html(
|
||||||
|
render_blueslip_stacktrace({ error, stackframes })
|
||||||
|
);
|
||||||
|
$(".alert-box").append($alert);
|
||||||
|
$alert.addClass("show");
|
||||||
|
}
|
|
@ -18,7 +18,6 @@ import "handlebars/dist/cjs/handlebars.runtime.js";
|
||||||
import "to-markdown/dist/to-markdown.js";
|
import "to-markdown/dist/to-markdown.js";
|
||||||
import "flatpickr/dist/flatpickr.js";
|
import "flatpickr/dist/flatpickr.js";
|
||||||
import "flatpickr/dist/plugins/confirmDate/confirmDate.js";
|
import "flatpickr/dist/plugins/confirmDate/confirmDate.js";
|
||||||
import "error-stack-parser/dist/error-stack-parser.min.js";
|
|
||||||
import "sortablejs/Sortable.js";
|
import "sortablejs/Sortable.js";
|
||||||
import "../../generated/emoji/emoji_codes.js";
|
import "../../generated/emoji/emoji_codes.js";
|
||||||
import "../../generated/pygments_data.js";
|
import "../../generated/pygments_data.js";
|
||||||
|
|
|
@ -521,8 +521,8 @@ exports.initialize = function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
// this will hide the alerts that you click "x" on.
|
// this will hide the alerts that you click "x" on.
|
||||||
$("body").on("click", ".alert .exit", function () {
|
$("body").on("click", ".alert-box > div .exit", function () {
|
||||||
var $alert = $(this).closest(".alert");
|
var $alert = $(this).closest(".alert-box > div");
|
||||||
$alert.addClass("fade-out");
|
$alert.addClass("fade-out");
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
$alert.removeClass("fade-out show");
|
$alert.removeClass("fade-out show");
|
||||||
|
@ -533,6 +533,10 @@ exports.initialize = function () {
|
||||||
settings_toggle.toggle_org_setting_collapse();
|
settings_toggle.toggle_org_setting_collapse();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$(".alert-box").on("click", ".stackframe .expand", function () {
|
||||||
|
$(this).parent().siblings(".code-context").toggle("fast");
|
||||||
|
});
|
||||||
|
|
||||||
// COMPOSE
|
// COMPOSE
|
||||||
|
|
||||||
// NB: This just binds to current elements, and won't bind to elements
|
// NB: This just binds to current elements, and won't bind to elements
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
declare module "*.hbs" {
|
||||||
|
const render: (context: unknown) => string;
|
||||||
|
export = render;
|
||||||
|
}
|
|
@ -1,5 +1,11 @@
|
||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
|
"baseUrl": ".",
|
||||||
|
"paths": {
|
||||||
|
"*": ["types/*"],
|
||||||
|
},
|
||||||
|
"typeRoots": ["types"],
|
||||||
|
|
||||||
/* Typescript 3.4 added the --incremental flag but its API is not
|
/* Typescript 3.4 added the --incremental flag but its API is not
|
||||||
* currently public so ts-loader cannot use it yet.
|
* currently public so ts-loader cannot use it yet.
|
||||||
* Tracking issue: https://github.com/microsoft/TypeScript/issues/29978
|
* Tracking issue: https://github.com/microsoft/TypeScript/issues/29978
|
||||||
|
@ -8,8 +14,8 @@
|
||||||
|
|
||||||
/* Basic options */
|
/* Basic options */
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"target": "es5",
|
"target": "ES2019",
|
||||||
"module": "es6",
|
"module": "ES6",
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
|
@ -25,5 +31,8 @@
|
||||||
"noUnusedParameters": true,
|
"noUnusedParameters": true,
|
||||||
"noImplicitReturns": true,
|
"noImplicitReturns": true,
|
||||||
"noFallthroughCasesInSwitch": true,
|
"noFallthroughCasesInSwitch": true,
|
||||||
}
|
},
|
||||||
|
"exclude": [
|
||||||
|
"types",
|
||||||
|
],
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
// https://github.com/stacktracejs/stackframe/pull/27
|
||||||
|
/// <reference types="stackframe/stackframe" />
|
||||||
|
|
||||||
|
import SourceMap from "source-map";
|
||||||
|
|
||||||
|
declare namespace StackTraceGPS {
|
||||||
|
type StackTraceGPSOptions = {
|
||||||
|
sourceCache?: { [url: string]: string };
|
||||||
|
sourceMapConsumerCache?: { [sourceMappingUrl: string]: SourceMap.SourceMapConsumer };
|
||||||
|
offline?: boolean;
|
||||||
|
ajax?(url: string): Promise<string>;
|
||||||
|
atob?(base64: string): string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-redeclare
|
||||||
|
declare class StackTraceGPS {
|
||||||
|
constructor(options?: StackTraceGPS.StackTraceGPSOptions);
|
||||||
|
pinpoint(stackframe: StackFrame.StackFrame): Promise<StackFrame.StackFrame>;
|
||||||
|
findFunctionName(stackframe: StackFrame.StackFrame): Promise<StackFrame.StackFrame>;
|
||||||
|
getMappedLocation(stackframe: StackFrame.StackFrame): Promise<StackFrame.StackFrame>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export = StackTraceGPS;
|
||||||
|
|
||||||
|
export as namespace StackTraceGPS; // global for non-module UMD users
|
|
@ -48,6 +48,104 @@ $alert-error-red: hsl(0, 80%, 40%);
|
||||||
width: 900px;
|
width: 900px;
|
||||||
margin-left: calc(50% - 450px);
|
margin-left: calc(50% - 450px);
|
||||||
z-index: 220;
|
z-index: 220;
|
||||||
|
max-height: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
|
overscroll-behavior: contain;
|
||||||
|
|
||||||
|
.stacktrace {
|
||||||
|
@extend .alert-display;
|
||||||
|
}
|
||||||
|
.stacktrace {
|
||||||
|
@extend .alert-animations;
|
||||||
|
|
||||||
|
font-size: 1rem;
|
||||||
|
color: hsl(0, 80%, 40%);
|
||||||
|
|
||||||
|
margin-top: 5px;
|
||||||
|
padding: 1rem 0;
|
||||||
|
|
||||||
|
background-color: hsl(0, 100%, 98%);
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid hsl(0, 80%, 40%);
|
||||||
|
box-shadow: 0 0 2px hsl(0, 80%, 40%);
|
||||||
|
|
||||||
|
.stacktrace-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.message {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.warning-symbol,
|
||||||
|
.exit {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
font-size: 1.3rem;
|
||||||
|
padding: 0 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.exit::after {
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 2.3rem;
|
||||||
|
content: "\d7";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.stacktrace-content {
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
|
||||||
|
margin-top: 1rem;
|
||||||
|
|
||||||
|
.stackframe {
|
||||||
|
padding-left: calc(3.3rem - 14px);
|
||||||
|
padding-right: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.expand {
|
||||||
|
cursor: pointer;
|
||||||
|
color: hsl(0, 32%, 83%);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: hsl(0, 0%, 20%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtle {
|
||||||
|
color: hsl(0, 7%, 45%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-context {
|
||||||
|
color: hsl(0, 7%, 15%);
|
||||||
|
background-color: hsl(0, 7%, 98%);
|
||||||
|
background-color: hsl(0, 7%, 98%);
|
||||||
|
box-shadow:
|
||||||
|
inset 0px 11px 10px -10px hsl(0, 7%, 70%),
|
||||||
|
inset 0px -11px 10px -10px hsl(0, 7%, 70%);
|
||||||
|
|
||||||
|
margin-top: 1em;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
|
||||||
|
.code-context-content {
|
||||||
|
padding: 1rem 0;
|
||||||
|
white-space: pre;
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line-number {
|
||||||
|
width: 3rem;
|
||||||
|
display: inline-block;
|
||||||
|
text-align: right;
|
||||||
|
color: hsl(0, 7%, 35%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.focus-line {
|
||||||
|
background-color: hsl(0, 7%, 90%);
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.alert {
|
.alert {
|
||||||
@extend .alert-animations;
|
@extend .alert-animations;
|
||||||
|
@ -107,11 +205,6 @@ $alert-error-red: hsl(0, 80%, 40%);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.browser-alert .error::before {
|
|
||||||
content: "Browser Error: ";
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* animation section */
|
/* animation section */
|
||||||
|
|
|
@ -462,6 +462,7 @@ on a dark background, and don't change the dark labels dark either. */
|
||||||
}
|
}
|
||||||
|
|
||||||
.alert-box .alert,
|
.alert-box .alert,
|
||||||
|
.alert-box .stacktrace,
|
||||||
.alert.alert-error {
|
.alert.alert-error {
|
||||||
background-color: hsl(318, 12%, 21%);
|
background-color: hsl(318, 12%, 21%);
|
||||||
color: inherit;
|
color: inherit;
|
||||||
|
@ -472,6 +473,34 @@ on a dark background, and don't change the dark labels dark either. */
|
||||||
color: 1px solid hsl(0, 75%, 65%);
|
color: 1px solid hsl(0, 75%, 65%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.alert-box .stacktrace {
|
||||||
|
color: hsl(314, 22%, 85%);
|
||||||
|
|
||||||
|
.expand {
|
||||||
|
color: hsl(318, 14%, 36%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtle {
|
||||||
|
color: hsl(314, 19%, 63%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-context {
|
||||||
|
color: hsl(314, 27%, 82%);
|
||||||
|
background-color: hsl(312, 7%, 14%);
|
||||||
|
box-shadow:
|
||||||
|
inset 0px 11px 10px -10px hsl(0, 0%, 6%),
|
||||||
|
inset 0px -11px 10px -10px hsl(0, 0%, 6%);
|
||||||
|
|
||||||
|
.line-number {
|
||||||
|
color: hsl(318, 14%, 44%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.focus-line {
|
||||||
|
background-color: hsl(307, 9%, 19%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Popover: */
|
/* Popover: */
|
||||||
.hotspot.overlay .hotspot-popover,
|
.hotspot.overlay .hotspot-popover,
|
||||||
#hotspot_intro_reply_icon {
|
#hotspot_intro_reply_icon {
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
<div class="stacktrace-header">
|
||||||
|
<div class="warning-symbol">
|
||||||
|
<i class="fa fa-exclamation-triangle"></i>
|
||||||
|
</div>
|
||||||
|
<div class="message"><strong>Error:</strong> {{ error }}</div>
|
||||||
|
<div class="exit"></div>
|
||||||
|
</div>
|
||||||
|
<div class="stacktrace-content">
|
||||||
|
{{#each stackframes}}
|
||||||
|
<div data-full-path="{{ full_path }}" data-line-no="{{ line_number }}">
|
||||||
|
<div class="stackframe">
|
||||||
|
<i class="fa fa-caret-right expand"></i>
|
||||||
|
<span class="subtle">at</span>
|
||||||
|
{{#if function_name}}
|
||||||
|
{{ function_name.scope }}<b>{{ function_name.name }}</b>
|
||||||
|
{{/if}}
|
||||||
|
<span class="subtle">{{ show_path }}:{{ line_number }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="code-context" style="display: none">
|
||||||
|
<div class="code-context-content">
|
||||||
|
{{~#each context~}}
|
||||||
|
<div {{#if focus}}class="focus-line"{{/if}}><span class="line-number">{{ line_number }}</span> {{ line }}</div>
|
||||||
|
{{~/each~}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
|
@ -26,4 +26,4 @@ LATEST_RELEASE_ANNOUNCEMENT = "https://blog.zulip.org/2019/03/01/zulip-2-0-relea
|
||||||
# historical commits sharing the same major version, in which case a
|
# historical commits sharing the same major version, in which case a
|
||||||
# minor version bump suffices.
|
# minor version bump suffices.
|
||||||
|
|
||||||
PROVISION_VERSION = '62.0'
|
PROVISION_VERSION = '62.1'
|
||||||
|
|
27
yarn.lock
27
yarn.lock
|
@ -915,6 +915,13 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/node" "*"
|
"@types/node" "*"
|
||||||
|
|
||||||
|
"@types/jquery@^3.3.31":
|
||||||
|
version "3.3.31"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-3.3.31.tgz#27c706e4bf488474e1cb54a71d8303f37c93451b"
|
||||||
|
integrity sha512-Lz4BAJihoFw5nRzKvg4nawXPzutkv7wmfQ5121avptaSIXlDNJCUuxZxX/G+9EVidZGuO0UBlk+YjKbwRKJigg==
|
||||||
|
dependencies:
|
||||||
|
"@types/sizzle" "*"
|
||||||
|
|
||||||
"@types/json-schema@^7.0.3":
|
"@types/json-schema@^7.0.3":
|
||||||
version "7.0.3"
|
version "7.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.3.tgz#bdfd69d61e464dcc81b25159c270d75a73c1a636"
|
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.3.tgz#bdfd69d61e464dcc81b25159c270d75a73c1a636"
|
||||||
|
@ -953,6 +960,11 @@
|
||||||
"@types/express-serve-static-core" "*"
|
"@types/express-serve-static-core" "*"
|
||||||
"@types/mime" "*"
|
"@types/mime" "*"
|
||||||
|
|
||||||
|
"@types/sizzle@*":
|
||||||
|
version "2.3.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/sizzle/-/sizzle-2.3.2.tgz#a811b8c18e2babab7d542b3365887ae2e4d9de47"
|
||||||
|
integrity sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg==
|
||||||
|
|
||||||
"@types/source-list-map@*":
|
"@types/source-list-map@*":
|
||||||
version "0.1.2"
|
version "0.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/@types/source-list-map/-/source-list-map-0.1.2.tgz#0078836063ffaf17412349bba364087e0ac02ec9"
|
resolved "https://registry.yarnpkg.com/@types/source-list-map/-/source-list-map-0.1.2.tgz#0078836063ffaf17412349bba364087e0ac02ec9"
|
||||||
|
@ -9353,7 +9365,7 @@ regenerate@^1.4.0:
|
||||||
resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11"
|
resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11"
|
||||||
integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==
|
integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==
|
||||||
|
|
||||||
regenerator-runtime@^0.13.2:
|
regenerator-runtime@^0.13.2, regenerator-runtime@^0.13.3:
|
||||||
version "0.13.3"
|
version "0.13.3"
|
||||||
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz#7cf6a77d8f5c6f60eb73c5fc1955b2ceb01e6bf5"
|
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz#7cf6a77d8f5c6f60eb73c5fc1955b2ceb01e6bf5"
|
||||||
integrity sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==
|
integrity sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==
|
||||||
|
@ -10323,6 +10335,11 @@ source-map-url@^0.4.0:
|
||||||
resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3"
|
resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3"
|
||||||
integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=
|
integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=
|
||||||
|
|
||||||
|
source-map@0.5.6:
|
||||||
|
version "0.5.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412"
|
||||||
|
integrity sha1-dc449SvwczxafwwRjYEzSiu19BI=
|
||||||
|
|
||||||
"source-map@>= 0.1.2":
|
"source-map@>= 0.1.2":
|
||||||
version "0.7.3"
|
version "0.7.3"
|
||||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
|
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
|
||||||
|
@ -10495,6 +10512,14 @@ stackframe@^1.1.0:
|
||||||
resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.1.0.tgz#e3fc2eb912259479c9822f7d1f1ff365bd5cbc83"
|
resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.1.0.tgz#e3fc2eb912259479c9822f7d1f1ff365bd5cbc83"
|
||||||
integrity sha512-Vx6W1Yvy+AM1R/ckVwcHQHV147pTPBKWCRLrXMuPrFVfvBUc3os7PR1QLIWCMhPpRg5eX9ojzbQIMLGBwyLjqg==
|
integrity sha512-Vx6W1Yvy+AM1R/ckVwcHQHV147pTPBKWCRLrXMuPrFVfvBUc3os7PR1QLIWCMhPpRg5eX9ojzbQIMLGBwyLjqg==
|
||||||
|
|
||||||
|
stacktrace-gps@^3.0.3:
|
||||||
|
version "3.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/stacktrace-gps/-/stacktrace-gps-3.0.3.tgz#b89f84cc13bb925b96607e737b617c8715facf57"
|
||||||
|
integrity sha512-51Rr7dXkyFUKNmhY/vqZWK+EvdsfFSRiQVtgHTFlAdNIYaDD7bVh21yBHXaNWAvTD+w+QSjxHg7/v6Tz4veExA==
|
||||||
|
dependencies:
|
||||||
|
source-map "0.5.6"
|
||||||
|
stackframe "^1.1.0"
|
||||||
|
|
||||||
state-toggle@^1.0.0:
|
state-toggle@^1.0.0:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/state-toggle/-/state-toggle-1.0.2.tgz#75e93a61944116b4959d665c8db2d243631d6ddc"
|
resolved "https://registry.yarnpkg.com/state-toggle/-/state-toggle-1.0.2.tgz#75e93a61944116b4959d665c8db2d243631d6ddc"
|
||||||
|
|
Loading…
Reference in New Issue