mirror of
https://github.com/muety/wakapi.git
synced 2023-08-10 21:12:56 +03:00
refactor(wip): finish settings page
This commit is contained in:
parent
7b7fa8bdf3
commit
0557a5000f
2
static/assets/vendor/petite-vue.min.js
vendored
2
static/assets/vendor/petite-vue.min.js
vendored
File diff suppressed because one or more lines are too long
@ -1,12 +1,12 @@
|
|||||||
{{ if .Error }}
|
{{ if .Error }}
|
||||||
<div class="flex justify-center w-full">
|
<div class="flex justify-center w-full">
|
||||||
<div class="p-4 text-white text-sm bg-red-500 rounded mt-16 shadow flex-grow max-w-lg">
|
<div class="p-4 font-semibold text-white text-sm bg-red-500 rounded mt-16 shadow flex-grow max-w-lg">
|
||||||
Error: {{ .Error | capitalize }}
|
Error: {{ .Error | capitalize }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{ else if .Success }}
|
{{ else if .Success }}
|
||||||
<div class="flex justify-center w-full">
|
<div class="flex justify-center w-full">
|
||||||
<div class="p-4 text-white text-sm bg-green-500 rounded mt-16 shadow flex-grow max-w-lg">
|
<div class="p-4 font-semibold text-white text-sm bg-green-500 rounded mt-16 shadow flex-grow max-w-lg">
|
||||||
{{ .Success | capitalize }}
|
{{ .Success | capitalize }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -5,17 +5,45 @@
|
|||||||
<script src="assets/timezones.js"></script>
|
<script src="assets/timezones.js"></script>
|
||||||
|
|
||||||
<script type="module">
|
<script type="module">
|
||||||
|
// Constants
|
||||||
const defaultTab = 'account'
|
const defaultTab = 'account'
|
||||||
|
const userTimeZone = {{ .User.Location }}
|
||||||
|
const userTzOffset = {{ .User.TZOffset.Hours }} // TODO: fix this!
|
||||||
|
const defaultTzOption = { value: 'Local', text: `Local server time (UTC+${userTzOffset})` }
|
||||||
|
|
||||||
|
// Elements
|
||||||
|
const formRegenerate = document.querySelector('#form-regenerate-summaries')
|
||||||
|
const formImportWakatime = document.querySelector('#form-import-wakatime')
|
||||||
|
const formDelete = document.querySelector('#form-delete-user')
|
||||||
|
|
||||||
PetiteVue.createApp({
|
PetiteVue.createApp({
|
||||||
$delimiters: ['${', '}'],
|
//$delimiters: ['${', '}'], // https://github.com/vuejs/petite-vue/pull/100
|
||||||
activeTab: defaultTab,
|
activeTab: defaultTab,
|
||||||
|
selectedTimezone: userTimeZone,
|
||||||
|
get tzOptions() {
|
||||||
|
return [defaultTzOption, ...tzs.sort().map(tz => ({ value: tz, text: tz }))]
|
||||||
|
},
|
||||||
updateTab() {
|
updateTab() {
|
||||||
this.activeTab = window.location.hash.slice(1) || defaultTab
|
this.activeTab = window.location.hash.slice(1) || defaultTab
|
||||||
},
|
},
|
||||||
isActive(tab) {
|
isActive(tab) {
|
||||||
return this.activeTab === tab
|
return this.activeTab === tab
|
||||||
},
|
},
|
||||||
|
confirmRegenerate() {
|
||||||
|
if (confirm('Are you sure?')) {
|
||||||
|
formRegenerate.submit()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
confirmWakatimeImport() {
|
||||||
|
if (confirm('Are you sure? The import can not be undone.')) {
|
||||||
|
formImportWakatime.submit()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
confirmDeleteAccount() {
|
||||||
|
if (confirm('Are you sure? This can not be undone!')) {
|
||||||
|
formDelete.submit()
|
||||||
|
}
|
||||||
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.updateTab()
|
this.updateTab()
|
||||||
window.addEventListener('hashchange', () => this.updateTab())
|
window.addEventListener('hashchange', () => this.updateTab())
|
||||||
@ -24,7 +52,6 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<body class="bg-gray-900 text-gray-700 p-4 pt-10 flex flex-col min-h-screen max-w-screen-xl mx-auto justify-center">
|
<body class="bg-gray-900 text-gray-700 p-4 pt-10 flex flex-col min-h-screen max-w-screen-xl mx-auto justify-center">
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.inline-bullet-list li a {
|
.inline-bullet-list li a {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
@ -76,8 +103,8 @@
|
|||||||
<span class="block text-sm text-gray-600">Time Zone, which you are located in. Relevant for displaying daily statistics.</span>
|
<span class="block text-sm text-gray-600">Time Zone, which you are located in. Relevant for displaying daily statistics.</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-1/2 ml-4">
|
<div class="w-1/2 ml-4">
|
||||||
<select name="location" id="select-timezone"
|
<select name="location" id="select-timezone" class="appearance-none bg-gray-850 focus:bg-gray-800 text-gray-300 outline-none rounded py-2 px-4 w-full cursor-pointer" v-model="selectedTimezone">
|
||||||
class="appearance-none bg-gray-850 focus:bg-gray-800 text-gray-300 outline-none rounded py-2 px-4 w-full cursor-pointer">
|
<option v-for="o in tzOptions" :value="o.value">{{ "{{" }}o.text{{ "}}" }}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -102,7 +129,7 @@
|
|||||||
<span class="block text-sm text-gray-600">Opt in to receive a summary of your coding activity once a week.</span>
|
<span class="block text-sm text-gray-600">Opt in to receive a summary of your coding activity once a week.</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-1/2 ml-4">
|
<div class="w-1/2 ml-4">
|
||||||
<select autocomplete="off" name="reports_weekly"
|
<select autocomplete="off" id="reports_weekly" name="reports_weekly"
|
||||||
class="appearance-none bg-gray-850 focus:bg-gray-800 text-gray-300 outline-none rounded py-2 px-4 w-full cursor-pointer">
|
class="appearance-none bg-gray-850 focus:bg-gray-800 text-gray-300 outline-none rounded py-2 px-4 w-full cursor-pointer">
|
||||||
<option value="false" class="cursor-pointer" {{ if not .User.ReportsWeekly }} selected{{ end }}>Disabled</option>
|
<option value="false" class="cursor-pointer" {{ if not .User.ReportsWeekly }} selected{{ end }}>Disabled</option>
|
||||||
<option value="true" class="cursor-pointer" {{ if .User.ReportsWeekly }} selected {{ end }}>Enabled</option>
|
<option value="true" class="cursor-pointer" {{ if .User.ReportsWeekly }} selected {{ end }}>Enabled</option>
|
||||||
@ -369,42 +396,37 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="permissions" class="tab flex flex-col space-y-4" v-if="isActive('permissions')">
|
<div id="permissions" class="tab flex flex-col space-y-4" v-if="isActive('permissions')">
|
||||||
<!-- TODO -->
|
<!-- Public Data -->
|
||||||
<details class="mb-8 pb-8 border-b border-gray-700" id="details-public-data">
|
<form action="" method="post" class="w-3/4">
|
||||||
<summary class="cursor-pointer">
|
<div class="flex mb-8">
|
||||||
<h2 class="font-semibold text-lg text-white m-0 border-b-2 border-green-700 inline-block">
|
<div class="w-1/2 mr-4 inline-block">
|
||||||
Public Data
|
<span class="font-semibold text-gray-300 text-lg">Aliases</span>
|
||||||
</h2>
|
<p class="block text-sm text-gray-600">
|
||||||
</summary>
|
Some features require public access to your data without authentication. This mainly includes badges ("shields" endpoint) and the integration with GitHub Readme Stats ("stats" endpoint). You can choose which data to share publicly through these endpoints.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div class="flex-col w-1/2 ml-4 inline-block space-y-4">
|
||||||
<p class="text-gray-300 text-sm mb-4 mt-6">Some features require public access to your data without
|
|
||||||
authentication. This mainly includes <strong>Badges</strong> and the integration with <strong>GitHub
|
|
||||||
Readme Stats</strong>, corresponding to these API endpoints:</p>
|
|
||||||
<ul class="list-disc list-inside text-gray-300">
|
|
||||||
<li class="ml-2"><span class="text-white text-xs bg-gray-900 rounded py-1 px-2 font-mono">/api/compat/shields/v1/{user}</span>
|
|
||||||
</li>
|
|
||||||
<li class="ml-2"><span class="text-white text-xs bg-gray-900 rounded py-1 px-2 font-mono">/api/v1/users/{user}/stats/{range}</span>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<form action="" method="post" class="mt-8">
|
|
||||||
<input type="hidden" name="action" value="update_sharing">
|
<input type="hidden" name="action" value="update_sharing">
|
||||||
<div class="flex items-center w-full text-gray-300 text-sm justify-between my-2">
|
|
||||||
<span class="mr-2">Publicly accessible data range:<br><span class="text-xs text-gray-500">(in days; 0 = not public, -1 = unlimited)</span></span>
|
<div class="flex space-x-8">
|
||||||
<div>
|
<div class="flex-grow">
|
||||||
<input class="shadow appearance-nonshadow appearance-none bg-gray-800 focus:bg-gray-700 text-gray-300 border-green-700 focus:border-gray-500 border rounded py-1 px-3"
|
<label class="font-semibold text-gray-300" for="max_days">Time Range</label>
|
||||||
style="width: 70px;" type="number" id="max_days" name="max_days" min="-1" required
|
<span class="block text-sm text-gray-600">(in days; 0 = not public, -1 = unlimited)</span>
|
||||||
|
</div>
|
||||||
|
<div >
|
||||||
|
<input class="appearance-none bg-gray-850 focus:bg-gray-800 text-gray-300 outline-none rounded py-2 px-4"
|
||||||
|
style="max-width: 80px" type="number" id="max_days" name="max_days" min="-1" required
|
||||||
value="{{ .User.ShareDataMaxDays }}">
|
value="{{ .User.ShareDataMaxDays }}">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center w-full text-gray-300 text-sm justify-between my-2">
|
|
||||||
<div class="flex justify-start">
|
<div class="flex space-x-8">
|
||||||
<span class="mr-2">Share projects: </span>
|
<div class="flex-grow">
|
||||||
|
<label class="font-semibold text-gray-300" for="share_projects">Share Projects</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-end">
|
<div >
|
||||||
<select autocomplete="off" name="share_projects"
|
<select autocomplete="off" id="share_projects" name="share_projects" class="flex-grow appearance-none bg-gray-850 focus:bg-gray-800 text-gray-300 outline-none rounded py-2 px-4 cursor-pointer">
|
||||||
class="cursor-pointer shadow appearance-nonshadow appearance-none bg-gray-800 focus:bg-gray-700 text-gray-300 border-green-700 focus:border-gray-500 border rounded py-1 px-3">
|
|
||||||
<option value="false" class="cursor-pointer" {{ if not .User.ShareProjects }} selected {{ end }}>No
|
<option value="false" class="cursor-pointer" {{ if not .User.ShareProjects }} selected {{ end }}>No
|
||||||
</option>
|
</option>
|
||||||
<option value="true" class="cursor-pointer" {{ if .User.ShareProjects }} selected {{ end }}>Yes
|
<option value="true" class="cursor-pointer" {{ if .User.ShareProjects }} selected {{ end }}>Yes
|
||||||
@ -412,13 +434,13 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center w-full text-gray-300 text-sm justify-between my-2">
|
|
||||||
<div class="flex justify-start">
|
<div class="flex space-x-8">
|
||||||
<span class="mr-2">Share languages: </span>
|
<div class="flex-grow">
|
||||||
|
<label class="font-semibold text-gray-300" for="share_languages">Share Languages</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-end">
|
<div >
|
||||||
<select autocomplete="off" name="share_languages"
|
<select autocomplete="off" id="share_languages" name="share_languages" class="flex-grow appearance-none bg-gray-850 focus:bg-gray-800 text-gray-300 outline-none rounded py-2 px-4 cursor-pointer">
|
||||||
class="cursor-pointer shadow appearance-nonshadow appearance-none bg-gray-800 focus:bg-gray-700 text-gray-300 border-green-700 focus:border-gray-500 border rounded py-1 px-3">
|
|
||||||
<option value="false" class="cursor-pointer" {{ if not .User.ShareLanguages }} selected {{ end }}>No
|
<option value="false" class="cursor-pointer" {{ if not .User.ShareLanguages }} selected {{ end }}>No
|
||||||
</option>
|
</option>
|
||||||
<option value="true" class="cursor-pointer" {{ if .User.ShareLanguages }} selected {{ end }}>Yes
|
<option value="true" class="cursor-pointer" {{ if .User.ShareLanguages }} selected {{ end }}>Yes
|
||||||
@ -426,13 +448,13 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center w-full text-gray-300 text-sm justify-between my-2">
|
|
||||||
<div class="flex justify-start">
|
<div class="flex space-x-8">
|
||||||
<span class="mr-2">Share editors: </span>
|
<div class="flex-grow">
|
||||||
|
<label class="font-semibold text-gray-300" for="share_editors">Share Editors</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-end">
|
<div >
|
||||||
<select autocomplete="off" name="share_editors"
|
<select autocomplete="off" id="share_editors" name="share_editors" class="flex-grow appearance-none bg-gray-850 focus:bg-gray-800 text-gray-300 outline-none rounded py-2 px-4 cursor-pointer">
|
||||||
class="cursor-pointer shadow appearance-nonshadow appearance-none bg-gray-800 focus:bg-gray-700 text-gray-300 border-green-700 focus:border-gray-500 border rounded py-1 px-3">
|
|
||||||
<option value="false" class="cursor-pointer" {{ if not .User.ShareEditors }} selected {{ end }}>No
|
<option value="false" class="cursor-pointer" {{ if not .User.ShareEditors }} selected {{ end }}>No
|
||||||
</option>
|
</option>
|
||||||
<option value="true" class="cursor-pointer" {{ if .User.ShareEditors }} selected {{ end }}>Yes
|
<option value="true" class="cursor-pointer" {{ if .User.ShareEditors }} selected {{ end }}>Yes
|
||||||
@ -440,28 +462,27 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center w-full text-gray-300 text-sm justify-between my-2">
|
|
||||||
<div class="flex justify-start">
|
<div class="flex space-x-8">
|
||||||
<span class="mr-2">Share operating systems: </span>
|
<div class="flex-grow">
|
||||||
|
<label class="font-semibold text-gray-300" for="share_oss">Share OS'</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-end">
|
<div >
|
||||||
<select autocomplete="off" name="share_oss"
|
<select autocomplete="off" id="share_oss" name="share_oss" class="flex-grow appearance-none bg-gray-850 focus:bg-gray-800 text-gray-300 outline-none rounded py-2 px-4 cursor-pointer">
|
||||||
class="cursor-pointer shadow appearance-nonshadow appearance-none bg-gray-800 focus:bg-gray-700 text-gray-300 border-green-700 focus:border-gray-500 border rounded py-1 px-3">
|
|
||||||
<option value="false" class="cursor-pointer" {{ if not .User.ShareOSs }} selected {{ end }}>No
|
<option value="false" class="cursor-pointer" {{ if not .User.ShareOSs }} selected {{ end }}>No
|
||||||
</option>
|
</option>
|
||||||
<option value="true" class="cursor-pointer" {{ if .User.ShareOSs }} selected {{ end }}>
|
<option value="true" class="cursor-pointer" {{ if .User.ShareOSs }} selected {{ end }}>Yes
|
||||||
Yes
|
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center w-full text-gray-300 text-sm justify-between my-2">
|
|
||||||
<div class="flex justify-start">
|
<div class="flex space-x-8">
|
||||||
<span class="mr-2">Share machines: </span>
|
<div class="flex-grow">
|
||||||
|
<label class="font-semibold text-gray-300" for="share_machines">Share Machines</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-end">
|
<div >
|
||||||
<select autocomplete="off" name="share_machines"
|
<select autocomplete="off" id="share_machines" name="share_machines" class="flex-grow appearance-none bg-gray-850 focus:bg-gray-800 text-gray-300 outline-none rounded py-2 px-4 cursor-pointer">
|
||||||
class="cursor-pointer shadow appearance-nonshadow appearance-none bg-gray-800 focus:bg-gray-700 text-gray-300 border-green-700 focus:border-gray-500 border rounded py-1 px-3">
|
|
||||||
<option value="false" class="cursor-pointer" {{ if not .User.ShareMachines }} selected {{ end }}>No
|
<option value="false" class="cursor-pointer" {{ if not .User.ShareMachines }} selected {{ end }}>No
|
||||||
</option>
|
</option>
|
||||||
<option value="true" class="cursor-pointer" {{ if .User.ShareMachines }} selected {{ end }}>Yes
|
<option value="true" class="cursor-pointer" {{ if .User.ShareMachines }} selected {{ end }}>Yes
|
||||||
@ -469,13 +490,13 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center w-full text-gray-300 text-sm justify-between my-2">
|
|
||||||
<div class="flex justify-start">
|
<div class="flex space-x-8">
|
||||||
<span class="mr-2">Share project labels: </span>
|
<div class="flex-grow">
|
||||||
|
<label class="font-semibold text-gray-300" for="share_labels">Share Project Labels</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-end">
|
<div >
|
||||||
<select autocomplete="off" name="share_labels"
|
<select autocomplete="off" id="share_labels" name="share_labels" class="flex-grow appearance-none bg-gray-850 focus:bg-gray-800 text-gray-300 outline-none rounded py-2 px-4 cursor-pointer">
|
||||||
class="cursor-pointer shadow appearance-nonshadow appearance-none bg-gray-800 focus:bg-gray-700 text-gray-300 border-green-700 focus:border-gray-500 border rounded py-1 px-3">
|
|
||||||
<option value="false" class="cursor-pointer" {{ if not .User.ShareLabels }} selected {{ end }}>No
|
<option value="false" class="cursor-pointer" {{ if not .User.ShareLabels }} selected {{ end }}>No
|
||||||
</option>
|
</option>
|
||||||
<option value="true" class="cursor-pointer" {{ if .User.ShareLabels }} selected {{ end }}>Yes
|
<option value="true" class="cursor-pointer" {{ if .User.ShareLabels }} selected {{ end }}>Yes
|
||||||
@ -483,327 +504,184 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div class="flex justify-between float-right mt-4">
|
|
||||||
<button type="submit"
|
|
||||||
class="py-1 px-3 rounded bg-green-700 hover:bg-green-800 text-white text-sm"
|
|
||||||
style="width: 100px;">
|
|
||||||
Save
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
</details>
|
|
||||||
|
<div class="flex justify-end mt-4">
|
||||||
|
<button type="submit" class="py-2 px-4 font-semibold rounded bg-green-700 hover:bg-green-800 text-white text-sm">
|
||||||
|
Save
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="integrations" class="tab flex flex-col space-y-4" v-if="isActive('integrations')">
|
<div id="integrations" class="tab flex flex-col space-y-4" v-if="isActive('integrations')">
|
||||||
<!-- TODO -->
|
<form action="" method="post" class="w-3/4">
|
||||||
<details class="mb-8 pb-8 border-b border-gray-700" id="details-integrations">
|
<input type="hidden" name="action" value="toggle_wakatime">
|
||||||
<summary class="cursor-pointer">
|
|
||||||
<h2 class="font-semibold text-lg text-white m-0 border-b-2 border-green-700 inline-block"
|
|
||||||
id="integrations">
|
|
||||||
Integrations
|
|
||||||
</h2>
|
|
||||||
</summary>
|
|
||||||
<div class="w-full">
|
|
||||||
<div class="mt-8 text-gray-300 text-sm">
|
|
||||||
<h3 class="inline-block font-semibold text-md mb-4 border-b border-green-700">
|
|
||||||
WakaTime
|
|
||||||
</h3>
|
|
||||||
|
|
||||||
<div class="flex space-x-4">
|
{{ $placeholderText := "WakaTime API key" }}
|
||||||
<img alt="WakaTime Logo"
|
{{ if .User.WakatimeApiKey }}
|
||||||
width="55px"
|
{{ $placeholderText = "********" }}
|
||||||
src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzQwIiBoZWlnaHQ9IjM0MCIgdmlld0JveD0iMCAwIDM0MCAzNDAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNMTcwIDIwQzg3LjE1NiAyMCAyMCA4Ny4xNTYgMjAgMTcwQzIwIDI1Mi44NDQgODcuMTU2IDMyMCAxNzAgMzIwQzI1Mi44NDQgMzIwIDMyMCAyNTIuODQ0IDMyMCAxNzBDMzIwIDg3LjE1NiAyNTIuODQ0IDIwIDE3MCAyMFYyMFYyMFoiIHN0cm9rZT0id2hpdGUiIHN0cm9rZS13aWR0aD0iNDAiLz4KPHBhdGggZD0iTTE5MC4xODMgMjEzLjU0MUMxODguNzQgMjE1LjQ0MyAxODYuNTc2IDIxNi42NjcgMTg0LjE1MSAyMTYuNjY3QzE4My45MTMgMjE2LjY2NyAxODMuNjc3IDIxNi42NTEgMTgzLjQ0MyAyMTYuNjI3QzE4My4wNDIgMjE2LjU3OSAxODIuODIzIDIxNi41NDUgMTgyLjYwNiAyMTYuNDk3QzE4Mi4zMzcgMjE2LjQzNCAxODIuMTM3IDIxNi4zNzUgMTgxLjk0IDIxNi4zMDhDMTgxLjU2MSAyMTYuMTc2IDE4MS4zOTIgMjE2LjEwOSAxODEuMjI4IDIxNi4wMzVDMTgwLjg0MyAyMTUuODQ5IDE4MC43MDcgMjE1Ljc3OCAxODAuNTcyIDIxNS43MDFDMTgwLjIwNSAyMTUuNDc4IDE4MC4xMDkgMjE1LjQxMiAxODAuMDE0IDIxNS4zNDVDMTc5Ljg1NiAyMTUuMjMzIDE3OS42OTggMjE1LjExNyAxNzkuNTQ3IDIxNC45OTJDMTc5LjI1MSAyMTQuNzQ2IDE3OS4xNDcgMjE0LjY1IDE3OS4wNDQgMjE0LjU1MkMxNzguNzMxIDIxNC4yNDEgMTc4LjUzMSAyMTQuMDE4IDE3OC4zNDEgMjEzLjc4NUMxNzcuOTgyIDIxMy4zMzEgMTc3LjY5IDIxMi44ODggMTc3LjQzOCAyMTIuNDE1TDE2OC42IDE5OC4yMTRMMTU5Ljc2NiAyMTIuNDE1QzE1OC4zOCAyMTQuOTM5IDE1NS44NzQgMjE2LjY2NyAxNTIuOTk1IDIxNi42NjdDMTUwLjEwNiAyMTYuNjY3IDE0Ny41ODggMjE0LjkyNiAxNDYuMjQzIDIxMi4zNDZMMTA3LjYwNyAxNTYuMDYxQzEwNi4zMzcgMTU0LjUyOSAxMDUuNTU2IDE1Mi40OTkgMTA1LjU1NiAxNTAuMjU4QzEwNS41NTYgMTQ1LjUxNCAxMDkuMDQzIDE0MS42NjUgMTEzLjM0NCAxNDEuNjY1QzExNi4xMjcgMTQxLjY2NSAxMTguNTY0IDE0My4yODIgMTE5Ljk0MiAxNDUuNzA4TDE1Mi41NTUgMTkzLjlMMTYxLjczNSAxNzguOTUyQzE2My4wNTggMTc2LjI4OCAxNjUuNjI2IDE3NC40NzggMTY4LjU3NSAxNzQuNDc4QzE3MS4yNzMgMTc0LjQ3OCAxNzMuNjUyIDE3NS45OTYgMTc1LjA0OSAxNzguMjk4TDE4NC41MTcgMTkzLjgzOUwyMzUuNjg0IDEyMC41ODNDMjM3LjA3NSAxMTguMjI2IDIzOS40NzUgMTE2LjY2NyAyNDIuMjEzIDExNi42NjdDMjQ2LjUxNCAxMTYuNjY3IDI1MCAxMjAuNTE0IDI1MCAxMjUuMjU4QzI1MCAxMjcuMzMyIDI0OS4zMzcgMTI5LjIzMiAyNDguMjMgMTMwLjcxNUwxOTAuMTgzIDIxMy41NDFWMjEzLjU0MVoiIGZpbGw9IndoaXRlIiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjEwIi8+Cjwvc3ZnPgo=">
|
{{ end }}
|
||||||
<p class="text-sm">You can connect Wakapi with the official <a class="underline"
|
|
||||||
href="https://wakatime.com"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
target="_blank">WakaTime</a> in a
|
|
||||||
way
|
|
||||||
that all heartbeats sent to Wakapi are relayed. This way, you can use both services
|
|
||||||
at
|
|
||||||
the same time. To get started, <a class="underline"
|
|
||||||
href="https://wakatime.com/developers#authentication"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
target="_blank">get your API key</a> and paste it here.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<form action="" method="post">
|
<div class="flex mb-8">
|
||||||
<input type="hidden" name="action" value="toggle_wakatime">
|
<div class="w-1/2 mr-4 inline-block">
|
||||||
|
<label class="font-semibold text-gray-300" for="select-timezone">WakaTime</label>
|
||||||
{{ $placeholderText := "Paste your WakaTime API key here ..." }}
|
<span class="block text-sm text-gray-600">
|
||||||
{{ if .User.WakatimeApiKey }}
|
You can connect Wakapi with the official WakaTime in a way that all heartbeats sent to Wakapi are relayed. This way, you can use both services at the same time. To get started, get <a class="text-gray-400 hover:text-gray-300 font-semibold" href="https://wakatime.com/developers#authentication" rel="noopener noreferrer" target="_blank">your API key</a> and paste it here.<br><br>
|
||||||
{{ $placeholderText = "********" }}
|
Please note: When enabling this feature, the operators of this server will, in theory, have unlimited access to your data stored in WakaTime. If you are concerned about your privacy, please do not enable this integration or wait for OAuth 2 authentication (<a
|
||||||
{{ end }}
|
class="font-semibold text-gray-400 hover:text-gray-300" target="_blank" href="https://github.com/muety/wakapi/issues/94" rel="noopener noreferrer">#94</a>) to be implemented.
|
||||||
|
|
||||||
<div class="flex items-center mt-8 space-x-2">
|
|
||||||
<label class="text-gray-500 font-semibold">API Key:</label>
|
|
||||||
<input type="password" name="api_key" id="wakatime_api_key"
|
|
||||||
class="flex-grow shadow appearance-nonshadow appearance-none bg-gray-800 text-gray-300 border-green-700 border rounded py-1 px-3 {{ if not .User.WakatimeApiKey }}focus:bg-gray-700 focus:border-gray-500{{ end }}"
|
|
||||||
placeholder="{{ $placeholderText }}" {{ if .User.WakatimeApiKey }}readonly{{ end }}>
|
|
||||||
<div class="flex-grow flex justify-end">
|
|
||||||
{{ if not .User.WakatimeApiKey }}
|
|
||||||
<button type="submit"
|
|
||||||
class="py-1 px-3 my-3 rounded bg-green-700 hover:bg-green-800 text-white text-sm">
|
|
||||||
Connect
|
|
||||||
</button>
|
|
||||||
{{ else }}
|
|
||||||
<button type="submit"
|
|
||||||
class="py-1 px-3 rounded bg-red-500 hover:bg-red-600 text-white text-sm"
|
|
||||||
style="width: 130px">Disconnect
|
|
||||||
</button>
|
|
||||||
{{ end }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{ if .User.WakatimeApiKey }}
|
|
||||||
<div class="flex justify-end">
|
|
||||||
<button id="btn-import-wakatime" type="button" style="width: 130px"
|
|
||||||
class="py-1 px-3 my-3 rounded bg-green-700 hover:bg-green-800 text-white text-sm">
|
|
||||||
<span class="iconify inline" data-icon="eva:corner-right-down-fill"></span> Import Data
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
{{ end }}
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<form action="" method="post" id="form-import-wakatime" class="mt-6">
|
|
||||||
<input type="hidden" name="action" value="import_wakatime">
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<p class="mt-6">
|
|
||||||
<span class="font-semibold"><span class="iconify inline"
|
|
||||||
data-icon="emojione-v1:backhand-index-pointing-right"></span> Please note:</span>
|
|
||||||
<span>When enabling this feature, the operators of this server will, in theory (!), have unlimited access to your data stored in WakaTime. If you are concerned about your privacy, please do not enable this integration or wait for OAuth 2 authentication (<a
|
|
||||||
class="underline" target="_blank" href="https://github.com/muety/wakapi/issues/94"
|
|
||||||
rel="noopener noreferrer">#94</a>) to be implemented.</span>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mt-10 text-gray-300 text-sm">
|
|
||||||
<h3 class="inline-block font-semibold text-md mb-4 border-b border-green-700">
|
|
||||||
Badges (Shields.io)
|
|
||||||
</h3>
|
|
||||||
|
|
||||||
{{ if ne .User.ShareDataMaxDays 0 }}
|
|
||||||
<div class="flex space-x-1">
|
|
||||||
<h3 class="font-semibold">Examples:</h3>
|
|
||||||
<span class="text-xs text-gray-500">(Only available on public instances, not on localhost)</span>
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-col mb-4 mt-2">
|
|
||||||
<div class="flex justify-between my-2">
|
|
||||||
<div>
|
|
||||||
<img class="with-url-src"
|
|
||||||
src="https://img.shields.io/endpoint?url=%s/api/compat/shields/v1/{{ .User.ID }}/interval:today&style=flat-square&color=blue&label=today"
|
|
||||||
alt="Shields.io badge"/>
|
|
||||||
</div>
|
|
||||||
<span class="with-url-inner text-xs bg-gray-900 rounded py-1 px-2 font-mono whitespace-no-wrap overflow-auto"
|
|
||||||
style="max-width: 300px;">
|
|
||||||
https://img.shields.io/endpoint?url=%s/api/compat/shields/v1/{{ .User.ID }}/interval:today&style=flat-square&color=blue&label=today
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div class="flex justify-between my-2">
|
|
||||||
<div>
|
|
||||||
<img class="with-url-src"
|
|
||||||
src="https://img.shields.io/endpoint?url=%s/api/compat/shields/v1/{{ .User.ID }}/interval:30_days&style=flat-square&color=blue&label=last 30d"
|
|
||||||
alt="Shields.io badge"/>
|
|
||||||
</div>
|
|
||||||
<span class="with-url-inner text-xs bg-gray-900 rounded py-1 px-2 font-mono whitespace-no-wrap overflow-auto"
|
|
||||||
style="max-width: 300px;">
|
|
||||||
https://img.shields.io/endpoint?url=%s/api/compat/shields/v1/{{ .User.ID }}/interval:30_days&style=flat-square&color=blue&label=last 30d
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p>You can also add <span class="text-xs bg-gray-900 rounded py-1 px-2 font-mono">/project:your-cool-project</span>
|
|
||||||
to the URL to filter by project.</p>
|
|
||||||
{{ else }}
|
|
||||||
<p>You have the ability to create badges from your coding statistics using <a
|
|
||||||
href="https://shields.io" target="_blank" class="border-b border-green-800"
|
|
||||||
rel="noopener noreferrer">Shields.io</a>. To do so, you need to grant public, unauthorized
|
|
||||||
access to the respective endpoint. See <a href="settings#details-public-data" class="underline">Public
|
|
||||||
Data</a> setting.</p>
|
|
||||||
{{ end }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mt-10 text-gray-300 text-sm">
|
|
||||||
<h3 class="inline-block font-semibold text-md mb-4 border-b border-green-700">
|
|
||||||
GitHub Readme Stats
|
|
||||||
</h3>
|
|
||||||
|
|
||||||
<p class="mb-4">Wakapi intregrates with <a
|
|
||||||
href="https://github.com/anuraghazra/github-readme-stats#wakatime-week-stats"
|
|
||||||
class="underline" target="_blank" rel="noopener noreferrer">GitHub Readme Stats</a> to
|
|
||||||
generate fancy cards for you.</p>
|
|
||||||
|
|
||||||
{{ if ne .User.ShareDataMaxDays 0 }}
|
|
||||||
<div class="flex space-x-1">
|
|
||||||
<h3 class="font-semibold">Example:</h3>
|
|
||||||
<span class="text-xs text-gray-500">(Only available on public instances, not on localhost)</span>
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-col mb-4 mt-2">
|
|
||||||
<img src="https://github-readme-stats.vercel.app/api/wakatime?username={{ .User.ID }}&api_domain=%s&bg_color=2D3748&title_color=2F855A&icon_color=2F855A&text_color=ffffff&custom_title=Wakapi%20Week%20Stats&layout=compact"
|
|
||||||
class="with-url-src-no-scheme" alt="Readme Stats Card">
|
|
||||||
<p class="mt-2"><strong>Source URL:</strong>
|
|
||||||
<span class="break-words text-xs bg-gray-900 rounded py-1 px-2 font-mono with-url-inner-no-scheme">
|
|
||||||
https://github-readme-stats.vercel.app/api/wakatime?username={{ .User.ID }}&api_domain=%s&bg_color=2D3748&title_color=2F855A&icon_color=2F855A&text_color=ffffff&custom_title=Wakapi%20Week%20Stats&layout=compact
|
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</div>
|
||||||
|
<div class="w-1/2 ml-4">
|
||||||
|
<input type="password" name="api_key" id="wakatime_api_key"
|
||||||
|
class="w-full appearance-none bg-gray-850 text-gray-300 outline-none rounded py-2 px-4 {{ if not .User.WakatimeApiKey }}focus:bg-gray-800{{ end }} {{ if .User.WakatimeApiKey }}cursor-not-allowed{{ end }}"
|
||||||
|
placeholder="{{ $placeholderText }}" {{ if .User.WakatimeApiKey }}readonly{{ end }}>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex justify-end mt-4">
|
||||||
|
{{ if not .User.WakatimeApiKey }}
|
||||||
|
<button type="submit" class="py-2 px-4 font-semibold rounded bg-green-700 hover:bg-green-800 text-white text-sm">Connect</button>
|
||||||
|
{{ else }}
|
||||||
|
<button id="btn-import-wakatime" type="button" class="py-2 px-4 font-semibold rounded bg-gray-850 hover:bg-gray-800 text-white text-sm mr-1" @click.stop="confirmWakatimeImport">Import Data</button>
|
||||||
|
<button type="submit" class="py-2 px-4 font-semibold rounded bg-red-600 hover:bg-red-700 text-white text-sm ml-1">Disconnect</button>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<form action="" method="post" id="form-import-wakatime">
|
||||||
|
<input type="hidden" name="action" value="import_wakatime">
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div class="w-3/4">
|
||||||
|
<hr class="border-t border-gray-800 mb-4">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="w-3/4">
|
||||||
|
<div class="flex mb-8">
|
||||||
|
<div class="w-1/2 mr-4 inline-block">
|
||||||
|
<label class="font-semibold text-gray-300" for="select-timezone">Badges (Shields.IO)</label>
|
||||||
|
<span class="block text-sm text-gray-600">
|
||||||
|
The integration with <a class="font-semibold text-gray-400 hover:text-gray-300" href="https://shields.io" target="_blank" rel="noreferrer noopener">Shields.IO</a> allows to generate badges for README pages or forums. To enable this feature, you need to grant public, unauthorized access to the respective endpoints. See <a class="font-semibold text-gray-400 hover:text-gray-300" href="settings#permissions">Permissions</a>.<br><br>
|
||||||
|
Only available on public instances, not on localhost.
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="w-1/2 ml-4">
|
||||||
|
{{ if ne .User.ShareDataMaxDays 0 }}
|
||||||
|
<div class="flex space-x-4 mb-4">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<img class="with-url-src"
|
||||||
|
src="https://img.shields.io/endpoint?url=%s/api/compat/shields/v1/{{ .User.ID }}/interval:today&style=flat-square&color=2F855A&label=today"
|
||||||
|
alt="Shields.io badge"
|
||||||
|
style="width: 128px; max-width: inherit;"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
class="flex-shrink w-full font-mono text-xs appearance-none bg-gray-850 text-gray-500 outline-none rounded py-2 px-4 cursor-not-allowed"
|
||||||
|
value="https://img.shields.io/endpoint?url=%s/api/compat/shields/v1/{{ .User.ID }}/interval:today&style=flat-square&color=2F855A&label=today"
|
||||||
|
readonly
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex space-x-4 mt-4">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<img class="with-url-src"
|
||||||
|
src="https://img.shields.io/endpoint?url=%s/api/compat/shields/v1/{{ .User.ID }}/interval:30_days&style=flat-square&color=2F855A&label=last 30d"
|
||||||
|
alt="Shields.io badge"
|
||||||
|
style="width: 128px; max-width: inherit;"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
class="flex-shrink w-full font-mono text-xs appearance-none bg-gray-850 text-gray-500 outline-none rounded py-2 px-4 cursor-not-allowed"
|
||||||
|
value="https://img.shields.io/endpoint?url=%s/api/compat/shields/v1/{{ .User.ID }}/interval:30_days&style=flat-square&color=2F855A&label=last 30d"
|
||||||
|
readonly
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</details>
|
</div>
|
||||||
|
|
||||||
|
<div class="w-3/4">
|
||||||
|
<hr class="border-t border-gray-800 mb-4">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="w-3/4">
|
||||||
|
<div class="flex mb-8">
|
||||||
|
<div class="w-1/2 mr-4 inline-block">
|
||||||
|
<label class="font-semibold text-gray-300" for="select-timezone">GitHub Readme Stats</label>
|
||||||
|
<span class="block text-sm text-gray-600">
|
||||||
|
Wakapi intregrates with <a class="font-semibold text-gray-400 hover:text-gray-300" href="https://github.com/anuraghazra/github-readme-stats#wakatime-week-stats" target="_blank" rel="noreferrer noopener">GitHub Readme Stats</a> to generate fancy cards for you. To enable this feature, you need to grant public, unauthorized access to the respective endpoints. See <a class="font-semibold text-gray-400 hover:text-gray-300" href="settings#permissions">Permissions</a>.<br><br>
|
||||||
|
Only available on public instances, not on localhost.
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="w-1/2 ml-4">
|
||||||
|
{{ if ne .User.ShareDataMaxDays 0 }}
|
||||||
|
<div class="flex items-center mb-2">
|
||||||
|
<img src="https://github-readme-stats.vercel.app/api/wakatime?username={{ .User.ID }}&api_domain=%s&bg_color=1A202C&title_color=2F855A&icon_color=2F855A&text_color=ffffff&custom_title=Wakapi%20Week%20Stats&layout=compact"
|
||||||
|
class="with-url-src-no-scheme" alt="Readme Stats Card">
|
||||||
|
</div>
|
||||||
|
<textarea
|
||||||
|
class="flex-shrink w-full font-mono text-xs appearance-none bg-gray-850 text-gray-500 outline-none rounded py-2 px-4 cursor-not-allowed mt-2"
|
||||||
|
rows="5" style="resize: none"
|
||||||
|
readonly>https://github-readme-stats.vercel.app/api/wakatime?username={{ .User.ID }}&api_domain=%s&bg_color=1A202C&title_color=2F855A&icon_color=2F855A&text_color=ffffff&custom_title=Wakapi%20Week%20Stats&layout=compact</textarea>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="danger_zone" class="tab flex flex-col space-y-4" v-if="isActive('danger_zone')">
|
<div id="danger_zone" class="tab flex flex-col space-y-4" v-if="isActive('danger_zone')">
|
||||||
<!-- TODO -->
|
<div class="w-3/4">
|
||||||
<details class="mb-8 pb-8" id="details-danger-zone">
|
<form action="" method="post" class="flex mb-8" id="form-regenerate-summaries">
|
||||||
<summary class="cursor-pointer">
|
<input type="hidden" name="action" value="regenerate_summaries">
|
||||||
<h2 class="font-semibold text-lg text-white m-0 border-b-2 border-green-700 inline-block" id="danger">
|
|
||||||
<span class="iconify inline" data-icon="emojione-v1:warning"></span> Danger Zone
|
|
||||||
</h2>
|
|
||||||
</summary>
|
|
||||||
<div class="w-full">
|
|
||||||
<div class="mt-10 text-gray-300 text-sm">
|
|
||||||
<h3 class="font-semibold text-md mb-4 border-b border-green-700 inline-block">
|
|
||||||
Regenerate summaries
|
|
||||||
</h3>
|
|
||||||
<p>
|
|
||||||
Wakapi improves its efficiency and speed by automatically aggregating individual heartbeats to
|
|
||||||
summaries on a per-day basis.
|
|
||||||
That is, historic summaries, i.e. such from past days, are generated once and only fetched from
|
|
||||||
the
|
|
||||||
database in a static fashion afterwards, unless you pass <span
|
|
||||||
class="font-mono font-normal bg-gray-900 p-1 rounded whitespace-no-wrap">&recompute=true</span>
|
|
||||||
with your request.
|
|
||||||
</p>
|
|
||||||
<p class="mt-2">
|
|
||||||
If, for some reason, these aggregated summaries are faulty or preconditions have change (e.g.
|
|
||||||
you
|
|
||||||
modified language mappings retrospectively), you may want to re-generate them from raw
|
|
||||||
heartbeats.
|
|
||||||
</p>
|
|
||||||
<p class="mt-2">
|
|
||||||
<strong>Note:</strong> Only run this action if you know what you are doing. Data might be lost
|
|
||||||
is
|
|
||||||
case heartbeats were deleted after the respective summaries had been generated.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div class="mt-6 flex justify-center">
|
|
||||||
<form action="" method="post" id="form-regenerate-summaries">
|
|
||||||
<input type="hidden" name="action" value="regenerate_summaries">
|
|
||||||
<button type="button" class="py-1 px-3 rounded bg-red-500 hover:bg-red-600 text-white text-sm"
|
|
||||||
id="btn-regenerate-summaries">
|
|
||||||
Clear & Regenerate
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mt-10 text-gray-300 text-sm">
|
<div class="w-1/2 mr-4 inline-block">
|
||||||
<h3 class="font-semibold text-md mb-4 border-b border-green-700 inline-block" id="apikey">
|
<span class="font-semibold text-gray-300">Regenerate Summaries</span>
|
||||||
Reset API Key
|
<span class="block text-sm text-gray-600">
|
||||||
</h3>
|
Regenerate all pre-computed summaries from raw heartbeat data. This may be useful if, for some reason, summaries are faulty or preconditions have change (e.g. you modified language mappings retrospectively). This may take some time. Be careful and only run this action if you know, what your are doing, as data loss might occur.
|
||||||
|
</span>
|
||||||
<form class="mt-2" action="" method="post">
|
|
||||||
<input type="hidden" name="action" value="reset_apikey">
|
|
||||||
<div class="text-gray-300 text-sm mb-4">
|
|
||||||
<strong>⚠️ Caution:</strong> Resetting your API key requires you to update your <span
|
|
||||||
class="font-mono">.wakatime.cfg</span> files on all of your computers to make the
|
|
||||||
WakaTime
|
|
||||||
client send heartbeats again.
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex justify-center">
|
|
||||||
<button type="submit"
|
|
||||||
class="mt-2 py-1 px-3 rounded bg-red-500 hover:bg-red-600 text-white text-sm">
|
|
||||||
Reset API Key
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="w-1/2 ml-4">
|
||||||
|
<button type="button" class="py-2 px-4 font-semibold rounded bg-red-600 hover:bg-red-700 text-white text-sm ml-1" @click.stop="confirmRegenerate">Clear and regenerate</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
<div class="mt-10 text-gray-300 text-sm">
|
<form action="" method="post" class="flex mb-8">
|
||||||
<h3 class="font-semibold text-md mb-4 border-b border-green-700 inline-block">
|
<input type="hidden" name="action" value="reset_apikey">
|
||||||
Delete Account
|
|
||||||
</h3>
|
<div class="w-1/2 mr-4 inline-block">
|
||||||
<p>
|
<span class="font-semibold text-gray-300">Reset API Key</span>
|
||||||
Deleting your account will cause all data, including all your heartbeats, to be erased from the
|
<span class="block text-sm text-gray-600">
|
||||||
server immediately. This action is irreversible. <strong>Be careful!</strong>
|
Please note that resetting your API key requires you to update your .wakatime.cfg files on all of your computers to make the WakaTime client send heartbeats again.
|
||||||
</p>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-6 flex justify-center">
|
<div class="w-1/2 ml-4">
|
||||||
<form action="" method="post" id="form-delete-user">
|
<button type="submit" class="py-2 px-4 font-semibold rounded bg-red-600 hover:bg-red-700 text-white text-sm ml-1">Reset API key</button>
|
||||||
<input type="hidden" name="action" value="delete_account">
|
|
||||||
<button type="button" class="py-1 px-3 rounded bg-red-500 hover:bg-red-600 text-white text-sm"
|
|
||||||
id="btn-confirm-delete-user">
|
|
||||||
Delete my Account
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</form>
|
||||||
</details>
|
|
||||||
|
<form action="" method="post" class="flex mb-8" id="form-delete-user">
|
||||||
|
<input type="hidden" name="action" value="delete_account">
|
||||||
|
|
||||||
|
<div class="w-1/2 mr-4 inline-block">
|
||||||
|
<span class="font-semibold text-gray-300">Delete Account</span>
|
||||||
|
<span class="block text-sm text-gray-600">
|
||||||
|
Deleting your account will cause all data, including all your heartbeats, to be erased from the server immediately. This action is irreversible. Be careful!
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="w-1/2 ml-4">
|
||||||
|
<button type="button" class="py-2 px-4 font-semibold rounded bg-red-600 hover:bg-red-700 text-white text-sm ml-1" @click.stop="confirmDeleteAccount">Delete account</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<script type="text/javascript">
|
|
||||||
const btnRegenerate = document.querySelector('#btn-regenerate-summaries')
|
|
||||||
const formRegenerate = document.querySelector('#form-regenerate-summaries')
|
|
||||||
btnRegenerate.addEventListener('click', () => {
|
|
||||||
if (confirm('Are you sure?')) {
|
|
||||||
formRegenerate.submit()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const btnDelete = document.querySelector('#btn-confirm-delete-user')
|
|
||||||
const formDelete = document.querySelector('#form-delete-user')
|
|
||||||
btnDelete.addEventListener('click', () => {
|
|
||||||
if (confirm('Are you sure? This can not be undone!')) {
|
|
||||||
formDelete.submit()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const btnImportWakatime = document.querySelector('#btn-import-wakatime')
|
|
||||||
const formImportWakatime = document.querySelector('#form-import-wakatime')
|
|
||||||
if (btnImportWakatime) {
|
|
||||||
btnImportWakatime.addEventListener('click', () => {
|
|
||||||
if (confirm('Are you sure? The import can not be undone.')) {
|
|
||||||
formImportWakatime.submit()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Time zone stuff
|
|
||||||
|
|
||||||
const userTimeZone = {{ .User.Location }}
|
|
||||||
const userTzOffset = {{ .User.TZOffset.Hours }}
|
|
||||||
const selectTimezone = document.getElementById('select-timezone')
|
|
||||||
const createTzOption = (tz) => {
|
|
||||||
if (!tz) tz = 'Local'
|
|
||||||
const option = document.createElement('option')
|
|
||||||
option.setAttribute('value', tz)
|
|
||||||
option.innerText = tz
|
|
||||||
if (tz === userTimeZone) option.setAttribute('selected', 'true')
|
|
||||||
return option
|
|
||||||
}
|
|
||||||
|
|
||||||
const defaultOption = createTzOption('Local')
|
|
||||||
defaultOption.value = 'Local'
|
|
||||||
defaultOption.innerText = `Local server time (UTC+${userTzOffset})`
|
|
||||||
selectTimezone.appendChild(defaultOption)
|
|
||||||
|
|
||||||
tzs.sort()
|
|
||||||
.map(createTzOption)
|
|
||||||
.forEach(o => selectTimezone.appendChild(o))
|
|
||||||
|
|
||||||
const hash = location.hash.replace('#', '')
|
|
||||||
if (hash) {
|
|
||||||
const elem = document.getElementById(hash)
|
|
||||||
if (elem) elem.open = true
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{{ template "footer.tpl.html" . }}
|
{{ template "footer.tpl.html" . }}
|
||||||
|
|
||||||
{{ template "foot.tpl.html" . }}
|
{{ template "foot.tpl.html" . }}
|
||||||
|
Loading…
Reference in New Issue
Block a user