feat: add plugin system (#1034)
* feat: add plugin system * fix db docker build * fix hammerhead readme, add strava subscription news to docs * fixes and sdk improvements * fix: reduce Meilisearch load, debounce federation sync (#1012) * optimize meili trail index * several fixes --------- Co-authored-by: Flomp <Flomp@users.noreply.github.com> * Bump svelte from 5.55.5 to 5.56.0 in /docs (#1032) Bumps [svelte](https://github.com/sveltejs/svelte/tree/HEAD/packages/svelte) from 5.55.5 to 5.56.0. - [Release notes](https://github.com/sveltejs/svelte/releases) - [Changelog](https://github.com/sveltejs/svelte/blob/main/packages/svelte/CHANGELOG.md) - [Commits](https://github.com/sveltejs/svelte/commits/svelte@5.56.0/packages/svelte) --- updated-dependencies: - dependency-name: svelte dependency-version: 5.56.0 dependency-type: direct:production ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Flomp <Flomp@users.noreply.github.com> * Release v0.19.2 (#1035) * chore: release v0.19.2 * add changelog --------- Co-authored-by: Flomp <26000991+Flomp@users.noreply.github.com> Co-authored-by: Christian Beutel <> * speed up plugin sync and several small fixes * concepts for security improvements and process stability * improve concept * security concept implemented * remove insecure TLS * worker concept implemented * fixes and cleanup * fixes * docu * mermaid, namings * WASM plugin host improvements, plugin logging * fix db migration * Improve plugin config and category mapping UI * fixes * further fixes * remove manual test sync * fix db migration and strava mapping * type added, UI improvements * fix plugin card toggle clickable area * optimize synch status card layout * plugin type 'trails' instead of 'integration' * session auth validation in UI * fix komoot date and waypoints * improve category mapping * fix send to hammerhead: trail name * plugin setup error handling improved * fix review findings * re-mapping added * rename remote_category --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Flomp <Flomp@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Flomp <26000991+Flomp@users.noreply.github.com>
This commit is contained in:
@@ -3,11 +3,6 @@
|
||||
import { page } from "$app/state";
|
||||
import type { List } from "$lib/models/list";
|
||||
import type { Trail } from "$lib/models/trail";
|
||||
import {
|
||||
integrations,
|
||||
integrations_index,
|
||||
uploadGpx,
|
||||
} from "$lib/stores/integration_store";
|
||||
import {
|
||||
lists_add_trail,
|
||||
lists_index,
|
||||
@@ -25,9 +20,8 @@
|
||||
import { trail2gpx } from "$lib/util/gpx_util";
|
||||
import { gpx } from "$lib/vendor/toGeoJSON/toGeoJSON";
|
||||
import JSZip from "jszip";
|
||||
import { onMount, type Snippet } from "svelte";
|
||||
import { type Snippet } from "svelte";
|
||||
import { _ } from "svelte-i18n";
|
||||
import { get } from "svelte/store";
|
||||
import Dropdown, { type DropdownItem } from "../base/dropdown.svelte";
|
||||
import ConfirmModal from "../confirm_modal.svelte";
|
||||
import ListSearchModal from "../list/list_search_modal.svelte";
|
||||
@@ -43,6 +37,7 @@
|
||||
import type { MergeSelection, MergeSettings } from "./trail_merge_modal.svelte";
|
||||
import MergeDialog from "$lib/components/trail/trail_merge_dialog.svelte";
|
||||
import { trail_merge } from "$lib/stores/trail_merge_api";
|
||||
import { hasSendCapablePlugin } from "$lib/stores/plugin_store";
|
||||
|
||||
export interface MergeResult {
|
||||
targetTrail: Trail;
|
||||
@@ -65,58 +60,11 @@
|
||||
let confirmModal: ConfirmModal;
|
||||
let listSelectModal: ListSearchModal;
|
||||
let trailExportModal: TrailExportModal;
|
||||
let trailSendModal: TrailSendModal;
|
||||
let trailShareModal: TrailShareModal;
|
||||
let trailMergeModal: TrailMergeModal;
|
||||
let trailSendModal: TrailSendModal;
|
||||
|
||||
const hammerheadIntegration = $derived(
|
||||
$integrations.find((integration) =>
|
||||
Boolean(integration.hammerhead?.active)
|
||||
)
|
||||
);
|
||||
|
||||
let lists: List[] = $state([]);
|
||||
let integrationsLoading = false;
|
||||
let integrationsLoadedForUser: string | undefined;
|
||||
|
||||
onMount(() => {
|
||||
const unsubscribe = currentUser.subscribe(async (user) => {
|
||||
if (!user) {
|
||||
integrationsLoadedForUser = undefined;
|
||||
return;
|
||||
}
|
||||
|
||||
const existing = get(integrations);
|
||||
if (
|
||||
existing.length &&
|
||||
existing[0]?.user === user.id
|
||||
) {
|
||||
integrationsLoadedForUser = user.id;
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
integrationsLoading ||
|
||||
integrationsLoadedForUser === user.id
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
integrationsLoading = true;
|
||||
try {
|
||||
await integrations_index();
|
||||
integrationsLoadedForUser = user.id;
|
||||
} catch (error) {
|
||||
console.error("Failed to load integrations", error);
|
||||
} finally {
|
||||
integrationsLoading = false;
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
unsubscribe();
|
||||
};
|
||||
});
|
||||
|
||||
let loading: boolean = $state(false);
|
||||
|
||||
@@ -214,6 +162,16 @@
|
||||
return !isMultiselectMode();
|
||||
}
|
||||
|
||||
function allowSend(): boolean {
|
||||
return (
|
||||
hasTrail() &&
|
||||
!isMultiselectMode() &&
|
||||
hasGpx() &&
|
||||
Boolean($currentUser) &&
|
||||
$hasSendCapablePlugin
|
||||
);
|
||||
}
|
||||
|
||||
function allowPublish(): boolean {
|
||||
if (mode !== "multi-select") return false;
|
||||
|
||||
@@ -240,7 +198,7 @@
|
||||
});
|
||||
const allowListManagement = isFromCurrentUser();
|
||||
const allowShareSingleTrail = !isMultiselectMode() && isFromCurrentUser();
|
||||
const allowSingleOutput = canExport() || (!isMultiselectMode() && hammerheadIntegration && canExport());
|
||||
const allowSingleOutput = canExport();
|
||||
|
||||
if (isMultiselectMode()) {
|
||||
return [
|
||||
@@ -389,7 +347,7 @@
|
||||
},
|
||||
]
|
||||
: []),
|
||||
...(!isMultiselectMode() && hammerheadIntegration && canExport()
|
||||
...(allowSend()
|
||||
? [
|
||||
{
|
||||
text: $_("send-to"),
|
||||
@@ -528,6 +486,8 @@
|
||||
}
|
||||
} else if (ddVal == "share") {
|
||||
trailShareModal.openModal();
|
||||
} else if (ddVal == "send-to") {
|
||||
trailSendModal.openModal();
|
||||
} else if (ddVal == "download") {
|
||||
trailExportModal.openModal();
|
||||
} else if (ddVal == "edit") {
|
||||
@@ -548,8 +508,6 @@
|
||||
if (trail()) {
|
||||
await trailMergeModal.openSimilarTrailsModal(trail()!);
|
||||
}
|
||||
} else if (item.value == "send-to") {
|
||||
trailSendModal.openModal();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -605,49 +563,6 @@
|
||||
await trail_merge(trailSource.id, trailTarget.id, settings);
|
||||
onProgress?.(1);
|
||||
}
|
||||
async function uploadToHammerhead() {
|
||||
if (!hammerheadIntegration || !hasTrail()) {
|
||||
console.error("No Hammerhead integration found.");
|
||||
return;
|
||||
}
|
||||
|
||||
for (const uTrail of trails!) {
|
||||
try {
|
||||
if (uTrail.gpx) {
|
||||
const gpxData = await trail2gpx(uTrail, $currentUser);
|
||||
const formData = new FormData();
|
||||
const gpxFile = new File(
|
||||
[gpxData],
|
||||
`${uTrail.name || "trail"}.gpx`,
|
||||
{ type: "application/gpx+xml" },
|
||||
);
|
||||
formData.append("file", gpxFile);
|
||||
|
||||
await uploadGpx("hammerhead", gpxFile);
|
||||
|
||||
show_toast({
|
||||
type: "success",
|
||||
icon: "check",
|
||||
text: $_("uploaded-trail-to-hammerhead"),
|
||||
});
|
||||
} else {
|
||||
show_toast({
|
||||
type: "error",
|
||||
icon: "close",
|
||||
text: $_("trail-has-no-gpx"),
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
show_toast({
|
||||
type: "error",
|
||||
icon: "close",
|
||||
text: $_("error-uploading-trail-to-hammerhead"),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function updateTrailsVisibility() {
|
||||
const newVisibility = !majorityOfSelectedTrailsArePublic();
|
||||
|
||||
@@ -926,17 +841,14 @@
|
||||
onsave={handleShareUpdate}
|
||||
bind:this={trailShareModal}
|
||||
></TrailShareModal>
|
||||
<TrailSendModal
|
||||
trail={trail()}
|
||||
share={page.url.searchParams.get("share") ?? undefined}
|
||||
bind:this={trailSendModal}
|
||||
></TrailSendModal>
|
||||
<TrailMergeModal
|
||||
bind:this={trailMergeModal}
|
||||
onmerge={(settings, selection) => mergeTrails(settings, selection)}
|
||||
></TrailMergeModal>
|
||||
|
||||
<MergeDialog/>
|
||||
<TrailSendModal
|
||||
bind:this={trailSendModal}
|
||||
onsend={async (settings) => {
|
||||
if (settings.integrationName === "hammerhead") {
|
||||
await uploadToHammerhead();
|
||||
}
|
||||
}}
|
||||
></TrailSendModal>
|
||||
|
||||
Reference in New Issue
Block a user