appwrite/app/views/general/error.phtml

543 lines
18 KiB
PHTML
Raw Normal View History

2019-05-09 06:54:39 +00:00
<?php
2025-12-07 20:29:45 +00:00
use Utopia\Config\Config;
2025-04-22 11:22:29 +00:00
use Utopia\System\System;
2021-07-17 18:59:54 +00:00
$development = $this->getParam('development', false);
2023-07-31 19:55:02 +00:00
$type = $this->getParam('type', 'general_server_error');
2019-05-09 06:54:39 +00:00
$code = $this->getParam('code', 500);
$message = $this->getParam('message', '');
2021-07-17 18:59:54 +00:00
$trace = $this->getParam('trace', []);
2025-04-02 18:29:43 +00:00
$title = $this->getParam('title', 'Error');
2025-04-09 04:43:54 +00:00
$exception = $this->getParam('exception', null);
2025-04-02 18:29:43 +00:00
2025-04-15 09:40:32 +00:00
$isSimpleMessage = true;
2025-04-02 18:29:43 +00:00
$label = '';
$labelClass = '';
$buttons = [];
2025-04-22 11:22:29 +00:00
$protocol = System::getEnv('_APP_OPTIONS_FORCE_HTTPS') == 'disabled' ? 'http' : 'https';
2025-12-07 20:29:45 +00:00
$platform = Config::getParam('platform', []);
2025-12-11 18:36:11 +00:00
$hostname = $platform['consoleHostname'] ?? '';
2025-04-22 11:22:29 +00:00
// TODO: remove this later
if (System::getEnv('_APP_ENV') === 'development') {
$hostname = 'localhost';
}
$url = $protocol . '://' . $hostname;
2025-04-15 09:40:32 +00:00
if($exception !== null && method_exists($exception, 'getCTAs')) {
2025-04-10 11:09:37 +00:00
foreach ($exception->getCTAs() as $index => $cta) {
$class = ($index === 0) ? 'bordered-button' : 'button';
$buttons[] = [
'text' => $cta['label'],
'url' => $cta['url'],
'class' => $class
];
}
}
2025-04-09 04:43:54 +00:00
2025-04-02 18:29:43 +00:00
switch ($type) {
2025-04-15 13:17:43 +00:00
case 'proxy_error_override':
2025-04-15 12:16:04 +00:00
$type = '';
$label = 'Error ' . $code;
$message = $code >= 500 ? 'An unexpected server error occured.' : 'An unexpected client error occured.';
switch($code) {
case 401:
$message = 'You must sign in to access this page.';
break;
case 403:
$message = 'You are not authorized to access this page.';
break;
case 404:
$message = 'The page you are looking for does not exist.';
break;
case 504:
$message = 'The server did not respond in time.';
break;
case 501:
$message = 'This page is not implemented yet.';
break;
}
break;
case 'function_execute_permission_missing':
$label = 'Execution not permitted';
$labelClass = 'warning';
break;
2025-04-02 18:29:43 +00:00
case 'build_not_ready':
$label = 'Deployment is still building';
$message = 'The page will update after the build completes.';
$labelClass = 'warning';
break;
case 'build_failed':
$label = 'Deployment build failed';
$message = 'An error occurred during the build process.';
$labelClass = 'error';
break;
case 'rule_not_found':
$label = 'Nothing is here yet';
$message = 'This page is empty, but you can make it yours.';
break;
2025-04-03 13:19:41 +00:00
case 'deployment_not_found':
2025-04-15 12:16:04 +00:00
$label = 'No active deployments';
2025-04-07 09:08:06 +00:00
$message = 'This page is empty, activate a deployment to make it live.';
2025-04-03 13:19:41 +00:00
break;
case 'build_canceled':
2025-04-07 07:26:51 +00:00
$label = 'Deployment build canceled';
2025-04-07 09:08:06 +00:00
$message = 'This build was canceled and won\'t be deployed.';
2025-04-03 13:19:41 +00:00
break;
2025-04-09 18:05:08 +00:00
case 'general_route_not_found':
$label = 'Page not found';
$message = 'The page you\'re looking for doesn\'t exist.';
break;
2025-04-02 18:29:43 +00:00
default:
$label = 'Error ' . $code;
$message = $message;
2025-04-15 09:40:32 +00:00
$isSimpleMessage = false;
2025-04-02 18:29:43 +00:00
break;
}
2019-05-09 06:54:39 +00:00
?>
2022-11-17 12:37:59 +00:00
<!DOCTYPE html>
<html lang="en">
<head>
2025-04-02 18:29:43 +00:00
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
2025-04-22 11:22:29 +00:00
<link rel="icon" type="image/svg+xml" href="<?php echo $url; ?>/images/logos/appwrite-icon.svg" />
<link rel="mask-icon" type="image/png" href="<?php echo $url; ?>/images/logos/appwrite-icon.png" />
2025-08-22 10:12:33 +00:00
<link rel="preconnect" href="https://assets.appwrite.io/" crossorigin>
<style>
@font-face {
font-family: 'Inter';
2025-08-22 10:12:33 +00:00
src: url('https://assets.appwrite.io/fonts/inter/Inter-Regular.woff2') format('woff2');
font-weight: 400;
font-style: normal;
2025-08-20 09:32:06 +00:00
font-display: swap;
}
@font-face {
font-family: 'Inter';
2025-08-22 10:12:33 +00:00
src: url('https://assets.appwrite.io/fonts/inter/Inter-Medium.woff2') format('woff2');
font-weight: 500;
font-style: normal;
2025-08-20 09:32:06 +00:00
font-display: swap;
}
@font-face {
font-family: 'Fira Code';
2025-08-22 10:12:33 +00:00
src: url('https://assets.appwrite.io/fonts/fira-code/FiraCode-Regular.woff2') format('woff2');
font-weight: 400;
font-style: normal;
2025-08-20 09:32:06 +00:00
font-display: swap;
}
</style>
<title><?php echo $this->print($title); ?></title>
2023-07-31 19:55:02 +00:00
<style>
2025-04-02 18:29:43 +00:00
* {
margin: 0;
padding: 0;
}
body {
background-color: #FFFFFF;
}
.main {
display: flex;
min-height: 100vh;
width: 100vw;
align-items: center;
justify-content: center;
}
.content {
margin-left: auto;
margin-right: auto;
max-width: 400px;
}
span {
padding: var(--space-1, 2px) var(--space-3, 6px);
border-radius: var(--border-radius-XS, 6px);
background: var(--color-overlay-on-neutral, rgba(0, 0, 0, 0.06));
color: var(--color-fgColor-neutral-secondary, #56565C);
text-align: center;
font-family: var(--font-family-sansSerif, Inter), sans-serif;
font-size: var(--font-size-S, 14px);
font-style: normal;
font-weight: 400;
line-height: 140%;
letter-spacing: -0.063px;
}
h1 {
color: var(--color-fgColor-neutral-primary, #2D2D31);
text-align: center;
font-family: var(--font-family-sansSerif, Inter), sans-serif;
font-size: var(--font-size-XXXL, 32px);
font-style: normal;
font-weight: 400;
line-height: 140%;
letter-spacing: -0.144px;
margin-top: 8px;
margin-bottom: 32px;
}
2025-04-15 09:40:32 +00:00
.content h1 {
2025-04-02 18:29:43 +00:00
margin-bottom: 20px;
}
2025-04-15 09:40:32 +00:00
.content.small-error h1 {
font-size: var(--font-size-M, 20px);
}
.content.large-error h1 {
font-size: var(--font-size-XXXL, 32px);
}
2025-04-02 18:29:43 +00:00
.bordered-button {
border-radius: var(--border-radius-S, 8px);
font-family: var(--font-family-sansSerif, Inter), sans-serif;
font-size: var(--font-size-S, 14px);
font-style: normal;
font-weight: 500;
line-height: 140%;
letter-spacing: -0.063px;
padding: var(--space-3, 6px) var(--space-5, 10px);
cursor: pointer;
border: var(--border-width-S, 1px) solid var(--color-border-neutral-strong, #D8D8DB);
background: var(--color-bgColor-neutral-primary, #FFF);
color: var(--color-fgColor-neutral-secondary, #56565C);
}
button {
border-radius: var(--border-radius-S, 8px);
font-family: var(--font-family-sansSerif, Inter), sans-serif;
font-size: var(--font-size-S, 14px);
font-style: normal;
font-weight: 500;
line-height: 140%;
letter-spacing: -0.063px;
padding: var(--space-3, 6px) var(--space-5, 10px);
cursor: pointer;
border: var(--border-width-S, 1px) solid transparent;
background: var(--color-bgColor-neutral-primary, #FFF);
color: var(--color-fgColor-neutral-secondary, #56565C);
}
.center {
display: flex;
justify-content: center;
gap: 8px;
}
.brand {
position: absolute;
width: 100%;
bottom: 32px;
display: flex;
justify-content: center;
align-items: center;
gap: 8px;
}
.brand p {
font-family: var(--font-family-monospace, "Fira Code"), monospace;
font-size: var(--font-size-XS, 12px);
font-style: normal;
font-weight: 400;
line-height: 130%;
letter-spacing: 0.96px;
text-transform: uppercase;
color: var(--color-fgColor-neutral-secondary, #56565C);
}
.brand svg {
height: 20px;
}
.warning {
background: var(--color-overlay-on-neutral, rgba(254, 124, 67, 0.16));
color: var(--color-fgColor-neutral-secondary, #61250A);
}
.error {
background: var(--color-overlay-on-neutral, rgba(255, 69, 58, 0.16));
color: var(--color-fgColor-neutral-secondary, #B31212);
}
.logo-dark {
display: none;
}
.logo-light {
display: block;
}
.type {
padding: var(--space-1, 2px) var(--space-3, 6px);
border-radius: var(--border-radius-XS, 6px);
border: var(--border-width-S, 1px) solid var(--color-border-neutral-strong, #EDEDF0);
background: var(--color-overlay-on-neutral, rgba(250, 250, 251, 1));
color: var(--color-fgColor-neutral-secondary, #56565C);
text-align: center;
font-family: var(--font-family-monospace, "Fira Code"), monospace;
font-size: var(--font-size-XS, 12px);
font-style: normal;
font-weight: 400;
line-height: 140%;
letter-spacing: 0px;
}
2025-04-10 11:09:37 +00:00
.error-trace {
2025-04-15 10:48:25 +00:00
max-width: 900px;
2025-04-10 11:09:37 +00:00
padding: 20px;
font-family: var(--font-family-sansSerif, Inter), sans-serif;
}
.back-button {
2025-04-15 12:16:04 +00:00
margin-bottom: 12px;
2025-04-10 11:09:37 +00:00
display: flex;
align-items: center;
gap: 8px;
color: var(--color-fgColor-neutral-secondary, #56565C);
font-family: var(--font-family-sansSerif, Inter), sans-serif;
font-size: var(--font-size-S, 14px);
font-style: normal;
font-weight: 500;
line-height: 140%;
letter-spacing: -0.45px;
}
2025-04-15 12:16:04 +00:00
.back-button:hover {
text-decoration: underline;
}
2025-04-10 11:09:37 +00:00
.trace-grid {
display: grid;
grid-template-columns: auto 1fr;
gap: 16px;
background: var(--color-bgColor-neutral-secondary, #FFFFFF);
padding: 10px 12px;
border: var(--border-width-S, 1px) solid var(--color-border-neutral-strong, #EDEDF0);
}
.trace-grid-header {
display: flex;
align-items: center;
padding: 10px 12px;
background: var(--color-bgColor-neutral-secondary, #FAFAFB);
border-radius: 8px 8px 0 0;
border: var(--border-width-S, 1px) solid var(--color-border-neutral-strong, #EDEDF0);
font-family: var(--font-family-sansSerif, Inter), sans-serif;
font-size: var(--font-size-S, 14px);
font-weight: 400;
line-height: 140%;
letter-spacing: -0.45px;
color: var(--color-fgColor-neutral-secondary, #56565C);
}
.trace-label {
font-family: var(--font-family-sansSerif, Inter), sans-serif;
font-size: var(--font-size-S, 14px);
font-weight: 400;
line-height: 140%;
letter-spacing: -0.45px;
color: var(--color-fgColor-neutral-secondary, #56565C);
}
.trace-value {
color: var(--color-fgColor-neutral-secondary, #56565C);
font-family: var(--font-family-monospace, "Fira Code"), monospace;
font-size: var(--font-size-S, 14px);
font-weight: 400;
line-height: 140%;
letter-spacing: 0px;
}
.trace-args {
/* grid-column: 1 / -1; */
padding: 10px 12px;
/* white-space: pre-wrap; */
overflow-x: auto;
font-family: var(--font-family-monospace, "Fira Code"), monospace;
font-size: var(--font-size-S, 14px);
font-weight: 400;
line-height: 140%;
color: var(--color-fgColor-neutral-secondary, #56565C);
}
2025-04-02 18:29:43 +00:00
@media (max-width: 768px) {
.content {
margin-left: 16px;
margin-right: 16px;
}
h1 {
font-size: 28px;
}
}
@media (prefers-color-scheme: dark) {
body {
background-color: #1D1D21;
}
h1 {
color: var(--color-fgColor-neutral-primary, #EDEDF0);
}
span {
background: var(--color-overlay-on-neutral, rgba(255, 255, 255, 0.2));
color: var(--color-fgColor-neutral-secondary, #C3C3C6);
}
.bordered-button {
border: var(--border-width-S, 1px) solid var(--color-border-neutral-strong, #414146);
background: var(--color-bgColor-neutral-primary, #1D1D21);
color: var(--color-fgColor-neutral-secondary, #C3C3C6);
}
button {
background: var(--color-bgColor-neutral-primary, #1D1D21);
color: var(--color-fgColor-neutral-secondary, #C3C3C6);
}
.brand p {
color: var(--color-fgColor-neutral-secondary, #C3C3C6);
}
.warning {
background: var(--color-overlay-on-neutral, rgba(254, 124, 67, 0.24));
color: var(--color-fgColor-neutral-secondary, #FFD5C2);
}
.error {
background: var(--color-overlay-on-neutral, rgba(255, 69, 58, 0.28));
color: var(--color-fgColor-neutral-secondary, #FFD5D4);
}
.logo-light {
display: none;
}
.logo-dark {
display: block;
}
.type {
background: var(--color-overlay-on-neutral, rgba(25, 25, 28, 1));
color: var(--color-fgColor-neutral-secondary, #C3C3C6);
2025-04-15 10:48:25 +00:00
border: var(--border-width-S, 1px) solid var(--color-border-neutral-strong, #414146);
}
.back-button {
color: var(--color-fgColor-neutral-secondary, #C3C3C6);
}
.trace-grid {
background: var(--color-bgColor-neutral-secondary, #1D1D21);
2025-04-02 18:29:43 +00:00
border: var(--border-width-S, 1px) solid var(--color-border-neutral-strong, #2D2D31);
2023-07-31 19:55:02 +00:00
}
2025-04-15 10:48:25 +00:00
.trace-grid-header {
background: var(--color-bgColor-neutral-secondary, #19191C);
border: var(--border-width-S, 1px) solid var(--color-border-neutral-strong, #2D2D31);
color: var(--color-fgColor-neutral-secondary, #C3C3C6);
}
.trace-label {
color: var(--color-fgColor-neutral-secondary, #C3C3C6);
}
.trace-value {
color: var(--color-fgColor-neutral-secondary, #C3C3C6);
}
.trace-args {
color: var(--color-fgColor-neutral-secondary, #C3C3C6);
}
2023-07-31 19:55:02 +00:00
}
</style>
2022-11-17 12:37:59 +00:00
</head>
<body>
2025-04-02 18:29:43 +00:00
<div class="main">
<div id="views-error" class="content <?php echo $isSimpleMessage ? 'large-error' : 'small-error' ?>">
2025-04-15 09:40:32 +00:00
<div class="center"><span class="<?php echo $this->print($labelClass); ?>"><?php echo $this->print($label); ?></span></div>
2025-04-02 18:29:43 +00:00
<h1><?php echo $this->print($message); ?></h1>
2025-04-15 12:16:04 +00:00
<?php if (!empty($type)): ?>
<div class="center">
<span class='type'><?php echo $this->print($type); ?></span>
</div>
<?php endif; ?>
2025-04-15 09:40:32 +00:00
<div class="center" style="margin-top: 20px;">
2025-04-02 18:29:43 +00:00
<?php if (!empty($buttons)): ?>
<?php foreach ($buttons as $button): ?>
<a href="<?php echo htmlspecialchars($button['url']); ?>">
2025-04-15 09:40:32 +00:00
<button class="<?php echo htmlspecialchars($button['class']); ?>">
2025-04-02 18:29:43 +00:00
<?php echo htmlspecialchars($button['text']); ?>
</button>
</a>
2023-07-31 19:55:02 +00:00
<?php endforeach; ?>
<?php endif; ?>
2025-04-15 09:40:32 +00:00
<?php if ($development) : ?>
<button class="<?php echo count($buttons) === 0 ? 'bordered-button' : 'button' ?>" onclick="openTraceView()">View error trace</button>
2025-04-02 18:29:43 +00:00
<?php endif; ?>
2023-07-31 19:55:02 +00:00
</div>
2025-04-10 11:09:37 +00:00
</div>
<?php if ($development) : ?>
2025-08-20 09:21:21 +00:00
<div id="views-trace" style="display: none;" class="error-trace">
<button class="back-button" onclick="openErrorView()">
Back
</button>
<div class="trace-grid-header">Error trace</div>
<?php foreach ($trace as $index => $traceItem): ?>
<div class="trace-grid">
<?php if (isset($traceItem['file'])): ?>
<div class="trace-label">file</div>
<div class="trace-value"><?php echo $this->print($traceItem['file']); ?></div>
<?php endif; ?>
<?php if (isset($traceItem['line'])): ?>
<div class="trace-label">line</div>
<div class="trace-value"><?php echo $this->print($traceItem['line']); ?></div>
<?php endif; ?>
<?php if (isset($traceItem['function'])): ?>
<div class="trace-label">function</div>
<div class="trace-value"><?php echo $this->print($traceItem['function']); ?></div>
<?php endif; ?>
<?php if (isset($traceItem['args'])): ?>
<div class="trace-label">args</div>
<div class="trace-args"><pre><?php echo $this->print(\var_export($traceItem['args'], true)); ?></pre></div>
<?php endif; ?>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
2025-04-02 18:29:43 +00:00
</div>
<script>
function openErrorView() {
2025-08-20 09:21:21 +00:00
document.getElementById('views-trace').style.display = 'none';
document.getElementById('views-error').style.display = 'block';
}
function openTraceView() {
2025-08-20 09:21:21 +00:00
document.getElementById('views-trace').style.display = 'block';
document.getElementById('views-error').style.display = 'none';
}
</script>
2022-11-17 12:37:59 +00:00
</body>
2021-07-17 18:59:54 +00:00
2025-12-07 20:29:45 +00:00
</html>