198 lines
5.6 KiB
Vue
198 lines
5.6 KiB
Vue
<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. You'll 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>
|