(text "{% extends \"root.html\" %} {% block head %}") (title (text "{{ app.title }} - {{ config.name }}")) (text "{% endblock %} {% block body %} {{ macros::nav() }}") (main ("class" "flex flex-col gap-2") (div ("class" "w-full flex flex-col gap-2") (div ("id" "manage_fields") ("class" "card lowered flex flex-col gap-2") (text "{% if is_helper -%}") (div ("class" "card-nest") (div ("class" "card small") (b (str (text "developer:label.change_quota_status")))) (div ("class" "card") (select ("onchange" "save_quota_status(event)") (option ("value" "Limited") ("selected" "{% if app.quota_status == 'Limited' -%}true{% else %}false{%- endif %}") (text "Limited")) (option ("value" "Unlimited") ("selected" "{% if app.quota_status == 'Unlimited' -%}true{% else %}false{%- endif %}") (text "Unlimited"))))) (text "{%- endif %}") (div ("class" "card-nest") (div ("class" "card small") (b (str (text "developer:label.change_title")))) (form ("class" "card flex flex-col gap-2") ("onsubmit" "change_title(event)") (div ("class" "flex flex-col gap-1") (label ("for" "title") (text "{{ text \"communities:label.new_title\" }}")) (input ("type" "text") ("name" "title") ("id" "title") ("placeholder" "new title") ("required" "") ("minlength" "2"))) (button ("class" "primary") (text "{{ icon \"check\" }}") (span (text "{{ text \"general:action.save\" }}"))))) (div ("class" "card-nest") (div ("class" "card small") (b (str (text "developer:label.change_homepage")))) (form ("class" "card flex flex-col gap-2") ("onsubmit" "change_homepage(event)") (div ("class" "flex flex-col gap-1") (label ("for" "homepage") (text "{{ text \"developer:label.homepage\" }}")) (input ("type" "url") ("name" "homepage") ("id" "homepage") ("placeholder" "new homepage") ("required" "") ("minlength" "2"))) (button ("class" "primary") (text "{{ icon \"check\" }}") (span (text "{{ text \"general:action.save\" }}"))))) (div ("class" "card-nest") (div ("class" "card small") (b (str (text "developer:label.change_redirect")))) (form ("class" "card flex flex-col gap-2") ("onsubmit" "change_redirect(event)") (div ("class" "flex flex-col gap-1") (label ("for" "redirect") (text "{{ text \"developer:label.redirect\" }}")) (input ("type" "url") ("name" "redirect") ("id" "redirect") ("placeholder" "new redirect URL") ("required" "") ("minlength" "2"))) (button ("class" "primary") (text "{{ icon \"check\" }}") (span (text "{{ text \"general:action.save\" }}"))))) (div ("class" "card-nest") (div ("class" "card small") (b (str (text "developer:label.manage_scopes")))) (form ("class" "card flex flex-col gap-2") ("onsubmit" "change_scopes(event)") (div ("class" "flex flex-col gap-1") (label ("for" "scopes") (text "{{ text \"developer:label.scopes\" }}")) (input ("type" "text") ("name" "scopes") ("id" "scopes") ("placeholder" "new scopes") ("required" "") ("minlength" "2") ("value" "{% for scope in app.scopes -%} {{ scope }} {% endfor %}"))) (pre ("class" "hidden red w-full") (code ("id" "scope_error_message") ("style" "white-space: pre-wrap"))) (details (summary ("class" "button lowered small") (icon (text "circle-help")) (text "Help")) (div ("class" "card flex flex-col gap-1") (span ("class" "fade") (text "Scopes should be separated by a single space.")) (a ("class" "button") ("href" "https://tetratto.com/reference/tetratto/model/oauth/enum.AppScope.html#variants") ("target" "_blank") (icon (text "external-link")) (text "Docs")))) (button ("class" "primary") (text "{{ icon \"check\" }}") (span (text "{{ text \"general:action.save\" }}")))))) (div ("class" "card flex flex-col gap-2") (ul (li (b (text "Homepage: ")) (text "{{ app.homepage }}")) (li (b (text "Redirect URL: ")) (text "{{ app.redirect }}")) (li (b (text "Quota status: ")) (text "{{ app.quota_status }}")) (li (b (text "User grants: ")) (text "{{ app.grants }}")) (li (b (text "Grant URL: ")) (text "{{ config.host }}/auth/connections_link/app/{{ app.id }}"))) (a ("class" "button") ("href" "https://tetratto.com/reference/tetratto/model/apps/struct.ThirdPartyApp.html#structfield.redirect") ("target" "_blank") (icon (text "external-link")) (text "Docs"))) (div ("class" "card-nest") (div ("class" "card small flex gap-1 items-center red") (text "{{ icon \"skull\" }}") (b (text "{{ text \"communities:label.danger_zone\" }}"))) (div ("class" "card flex flex-wrap gap-2") (button ("class" "red lowered") ("onclick" "delete_app()") (text "{{ icon \"trash\" }}") (span (str (text "developer:action.delete")))))) (div ("class" "flex gap-2 flex-wrap") (a ("href" "/developer") ("class" "button secondary") (text "{{ icon \"arrow-left\" }}") (span (text "{{ text \"general:action.back\" }}")))))) (script (text "setTimeout(() => { globalThis.save_quota_status = (event) => { const selected = event.target.selectedOptions[0]; fetch(\"/api/v1/apps/{{ app.id }}/quota_status\", { method: \"POST\", headers: { \"Content-Type\": \"application/json\", }, body: JSON.stringify({ quota_status: selected.value, }), }) .then((res) => res.json()) .then((res) => { trigger(\"atto::toast\", [ res.ok ? \"success\" : \"error\", res.message, ]); }); }; globalThis.change_title = async (e) => { e.preventDefault(); if ( !(await trigger(\"atto::confirm\", [ \"Are you sure you would like to do this?\", ])) ) { return; } fetch(\"/api/v1/apps/{{ app.id }}/title\", { method: \"POST\", headers: { \"Content-Type\": \"application/json\", }, body: JSON.stringify({ title: e.target.title.value, }), }) .then((res) => res.json()) .then((res) => { trigger(\"atto::toast\", [ res.ok ? \"success\" : \"error\", res.message, ]); }); }; globalThis.change_homepage = async (e) => { e.preventDefault(); if ( !(await trigger(\"atto::confirm\", [ \"Are you sure you would like to do this?\", ])) ) { return; } fetch(\"/api/v1/apps/{{ app.id }}/homepage\", { method: \"POST\", headers: { \"Content-Type\": \"application/json\", }, body: JSON.stringify({ homepage: e.target.homepage.value, }), }) .then((res) => res.json()) .then((res) => { trigger(\"atto::toast\", [ res.ok ? \"success\" : \"error\", res.message, ]); }); }; globalThis.change_redirect = async (e) => { e.preventDefault(); if ( !(await trigger(\"atto::confirm\", [ \"Are you sure you would like to do this?\", ])) ) { return; } fetch(\"/api/v1/apps/{{ app.id }}/redirect\", { method: \"POST\", headers: { \"Content-Type\": \"application/json\", }, body: JSON.stringify({ redirect: e.target.redirect.value, }), }) .then((res) => res.json()) .then((res) => { trigger(\"atto::toast\", [ res.ok ? \"success\" : \"error\", res.message, ]); }); }; globalThis.change_scopes = async (e) => { e.preventDefault(); if ( !(await trigger(\"atto::confirm\", [ \"Are you sure you would like to do this? This will only impact new grants.\", ])) ) { return; } fetch(\"/api/v1/apps/{{ app.id }}/scopes\", { method: \"POST\", headers: { \"Content-Type\": \"application/json\", }, body: JSON.stringify({ scopes: e.target.scopes.value.trim().split(\" \"), }), }) .then((res) => res.text()) .then((res) => { if (res.startsWith(\"{\")) { const r = JSON.parse(res); trigger(\"atto::toast\", [r.ok ? \"success\" : \"error\", r.message]); document.getElementById(\"scope_error_message\").parentElement.classList.add(\"hidden\"); } else { document.getElementById(\"scope_error_message\").innerText = res; document.getElementById(\"scope_error_message\").parentElement.classList.remove(\"hidden\"); document.getElementById(\"scope_error_message\").parentElement.parentElement.querySelector(\"details\").setAttribute(\"open\", \"\"); } }); }; globalThis.delete_app = async () => { if ( !(await trigger(\"atto::confirm\", [ \"Are you sure you would like to do this? This action is permanent.\", ])) ) { return; } fetch(`/api/v1/apps/{{ app.id }}`, { method: \"DELETE\", }) .then((res) => res.json()) .then((res) => { trigger(\"atto::toast\", [ res.ok ? \"success\" : \"error\", res.message, ]); }); }; }, 250);")) (text "{% endblock %}")