Files
kestrelos/app/pages/settings.vue
Madison Grubb b0e8dd7ad9
Some checks failed
ci/woodpecker/pr/pr Pipeline failed
make kestrel a tak server, so that it can send and receive pois as cots data
2026-02-17 10:42:53 -05:00

198 lines
5.6 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="p-6">
<h2 class="kestrel-page-heading mb-4">
Settings
</h2>
<section class="mb-8">
<h3 class="kestrel-section-label">
Map & offline
</h3>
<div class="kestrel-card p-4">
<p class="mb-3 text-sm text-kestrel-text">
Clear saved map tiles to free storage. The map will load tiles from the network again when you use it.
</p>
<p
v-if="tilesStored !== null"
class="mb-2 text-xs text-kestrel-muted"
>
{{ tilesStored > 0 ? `${tilesStored} tiles stored.` : 'No tiles stored.' }}
</p>
<p
v-if="tilesMessage"
class="mb-2 text-sm"
:class="tilesMessageSuccess ? 'text-green-400' : 'text-red-400'"
>
{{ tilesMessage }}
</p>
<button
type="button"
class="kestrel-btn-secondary disabled:opacity-50"
:disabled="tilesLoading"
@click="onClearTiles"
>
{{ tilesLoading ? 'Clearing…' : 'Clear saved map tiles' }}
</button>
</div>
</section>
<section class="mb-8">
<h3 class="kestrel-section-label">
TAK Server (ATAK / iTAK)
</h3>
<div class="kestrel-card p-4">
<p class="mb-3 text-sm text-kestrel-text">
Scan this QR code with iTAK (or ATAK) to add this KestrelOS server. Youll be prompted for your KestrelOS username and password after scanning.
</p>
<div
v-if="takQrDataUrl"
class="inline-block rounded-lg border border-kestrel-border bg-white p-3"
>
<img
:src="takQrDataUrl"
alt="TAK Server QR code"
class="h-48 w-48"
width="192"
height="192"
>
</div>
<p
v-else-if="takQrError"
class="text-sm text-red-400"
>
{{ takQrError }}
</p>
<p
v-else
class="text-sm text-kestrel-muted"
>
Loading QR code
</p>
<p
v-if="takServerString"
class="mt-3 text-xs text-kestrel-muted break-all"
>
{{ takServerString }}
</p>
<template v-if="cotConfig?.ssl">
<p class="mt-3 text-sm text-kestrel-text">
This server uses a self-signed certificate. iTAK will not connect until it trusts the cert.
</p>
<ol class="mt-2 list-decimal list-inside space-y-1 text-sm text-kestrel-text">
<li>
<strong>Upload server package:</strong> Download below, then in iTAK tap Add Server (+) Upload server package and select the zip; enter KestrelOS username and password when prompted.
</li>
<li>
<strong>Plain TCP:</strong> Remove or rename <code class="bg-kestrel-surface px-1 rounded">.dev-certs</code>, restart, then in iTAK add the server with SSL disabled.
</li>
</ol>
<a
href="/api/cot/server-package"
download="kestrelos-itak-server-package.zip"
class="kestrel-btn-secondary mt-3 inline-block"
>
Download server package (zip)
</a>
</template>
</div>
</section>
<section>
<h3 class="kestrel-section-label">
About
</h3>
<div class="kestrel-card p-4">
<p class="font-medium text-kestrel-text">
KestrelOS
</p>
<p
v-if="version"
class="mt-1 text-sm text-kestrel-muted"
>
Version {{ version }}
</p>
<p class="mt-2 text-xs text-kestrel-muted">
Tactical Operations Center for OSINT feeds.
</p>
</div>
</section>
</div>
</template>
<script setup>
const config = useRuntimeConfig()
const version = config.public?.version ?? null
const tilesStored = ref(null)
const tilesMessage = ref('')
const tilesMessageSuccess = ref(false)
const tilesLoading = ref(false)
const cotConfig = ref(null)
const takQrDataUrl = ref('')
const takQrError = ref('')
const takServerString = ref('')
async function loadTilesStored() {
if (typeof window === 'undefined') return
try {
const offline = await import('leaflet.offline')
if (offline.getStorageLength) {
const n = await offline.getStorageLength()
tilesStored.value = n
}
}
catch {
tilesStored.value = null
}
}
async function onClearTiles() {
tilesMessage.value = ''
tilesLoading.value = true
try {
const offline = await import('leaflet.offline')
if (offline.truncate) {
await offline.truncate()
tilesStored.value = 0
tilesMessage.value = 'Saved map tiles cleared.'
tilesMessageSuccess.value = true
}
else {
tilesMessage.value = 'Could not clear tiles.'
tilesMessageSuccess.value = false
}
}
catch (e) {
tilesMessage.value = e?.message ?? 'Failed to clear tiles.'
tilesMessageSuccess.value = false
}
finally {
tilesLoading.value = false
}
}
async function loadTakQr() {
if (typeof window === 'undefined') return
try {
const res = await $fetch('/api/cot/config')
cotConfig.value = res
const hostname = window.location.hostname
const port = res?.port ?? 8089
const protocol = res?.ssl ? 'ssl' : 'tcp'
const str = `KestrelOS,${hostname},${port},${protocol}`
takServerString.value = str
const QRCode = (await import('qrcode')).default
takQrDataUrl.value = await QRCode.toDataURL(str, { width: 192, margin: 1 })
}
catch (e) {
takQrError.value = e?.data?.error ?? e?.message ?? 'Could not load TAK server config.'
}
}
onMounted(() => {
loadTilesStored()
loadTakQr()
})
</script>