mirror of
https://github.com/aleksilassila/reiverr.git
synced 2026-04-21 08:15:12 +02:00
fix: And refactor onboarding integration components
This commit is contained in:
@@ -7,55 +7,59 @@
|
||||
import { derived, get } from 'svelte/store';
|
||||
|
||||
const dispatch = createEventDispatcher<{
|
||||
change: { baseUrl: string; apiKey: string; stale: boolean };
|
||||
'click-user': { user: JellyfinUser | undefined; users: JellyfinUser[] };
|
||||
'click-user': {
|
||||
user: JellyfinUser | undefined;
|
||||
users: JellyfinUser[];
|
||||
setJellyfinUser: typeof setJellyfinUser;
|
||||
};
|
||||
}>();
|
||||
|
||||
export let baseUrl = get(user)?.settings.jellyfin.baseUrl || '';
|
||||
export let apiKey = get(user)?.settings.jellyfin.apiKey || '';
|
||||
let baseUrl = get(user)?.settings.jellyfin.baseUrl || '';
|
||||
let apiKey = get(user)?.settings.jellyfin.apiKey || '';
|
||||
export let jellyfinUser: JellyfinUser | undefined = undefined;
|
||||
const originalBaseUrl = derived(user, (user) => user?.settings.jellyfin.baseUrl || '');
|
||||
const originalApiKey = derived(user, (user) => user?.settings.jellyfin.apiKey || '');
|
||||
const originalUserId = derived(user, (user) => user?.settings.jellyfin.userId || undefined);
|
||||
|
||||
let timeout: ReturnType<typeof setTimeout>;
|
||||
export let jellyfinUsers: Promise<JellyfinUser[]> | undefined = undefined;
|
||||
|
||||
let stale = false;
|
||||
let error = '';
|
||||
let jellyfinUsers: Promise<JellyfinUser[]> | undefined = undefined;
|
||||
export let jellyfinUser: JellyfinUser | undefined;
|
||||
|
||||
$: {
|
||||
if ($originalBaseUrl !== baseUrl && $originalApiKey !== apiKey) handleChange();
|
||||
else dispatch('change', { baseUrl, apiKey, stale: false });
|
||||
jellyfinUser;
|
||||
$originalBaseUrl;
|
||||
$originalApiKey;
|
||||
$originalUserId;
|
||||
stale = getIsStale();
|
||||
}
|
||||
|
||||
$: if (jellyfinUser)
|
||||
dispatch('change', {
|
||||
baseUrl,
|
||||
apiKey,
|
||||
stale:
|
||||
baseUrl && apiKey ? jellyfinUser?.Id !== get(user)?.settings.jellyfin.userId : !jellyfinUser
|
||||
});
|
||||
|
||||
handleChange();
|
||||
|
||||
function getIsStale() {
|
||||
return (
|
||||
(!!jellyfinUser?.Id || (!baseUrl && !apiKey && !jellyfinUser)) &&
|
||||
($originalBaseUrl !== baseUrl ||
|
||||
$originalApiKey !== apiKey ||
|
||||
$originalUserId !== jellyfinUser?.Id)
|
||||
);
|
||||
}
|
||||
|
||||
function handleChange() {
|
||||
clearTimeout(timeout);
|
||||
stale = false;
|
||||
error = '';
|
||||
jellyfinUsers = undefined;
|
||||
jellyfinUser = undefined;
|
||||
|
||||
if (baseUrl === '' || apiKey === '') {
|
||||
stale = getIsStale();
|
||||
return;
|
||||
}
|
||||
|
||||
const baseUrlCopy = baseUrl;
|
||||
const apiKeyCopy = apiKey;
|
||||
|
||||
dispatch('change', {
|
||||
baseUrl: '',
|
||||
apiKey: '',
|
||||
stale:
|
||||
baseUrl === '' &&
|
||||
apiKey === '' &&
|
||||
jellyfinUser === undefined &&
|
||||
(baseUrl !== $originalBaseUrl || apiKey !== $originalApiKey)
|
||||
});
|
||||
|
||||
if (baseUrlCopy === '' || apiKeyCopy === '') return;
|
||||
|
||||
timeout = setTimeout(async () => {
|
||||
jellyfinUsers = jellyfinApi.getJellyfinUsers(baseUrl, apiKey);
|
||||
|
||||
@@ -64,28 +68,38 @@
|
||||
|
||||
if (users.length) {
|
||||
jellyfinUser = users.find((u) => u.Id === get(user)?.settings.jellyfin.userId);
|
||||
const stale =
|
||||
(baseUrlCopy !== $originalBaseUrl || apiKeyCopy !== $originalApiKey) &&
|
||||
jellyfinUser !== undefined;
|
||||
dispatch('change', { baseUrl: baseUrlCopy, apiKey: apiKeyCopy, stale });
|
||||
// stale = !!jellyfinUser?.Id && getIsStale();
|
||||
} else {
|
||||
error = 'Could not connect';
|
||||
stale = false;
|
||||
}
|
||||
|
||||
// if (res.status !== 200) {
|
||||
// error =
|
||||
// res.status === 404
|
||||
// ? 'Server not found'
|
||||
// : res.status === 401
|
||||
// ? 'Invalid api key'
|
||||
// : 'Could not connect';
|
||||
//
|
||||
// return; // TODO add notification
|
||||
// } else {
|
||||
// dispatch('change', { baseUrl: baseUrlCopy, apiKey: apiKeyCopy, stale });
|
||||
// }
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
const setJellyfinUser = (u: JellyfinUser) => (jellyfinUser = u);
|
||||
|
||||
async function handleSave() {
|
||||
if (!stale) return;
|
||||
|
||||
return user.updateUser((prev) => ({
|
||||
...prev,
|
||||
settings: {
|
||||
...prev.settings,
|
||||
jellyfin: {
|
||||
...prev.settings.jellyfin,
|
||||
baseUrl,
|
||||
apiKey,
|
||||
userId: jellyfinUser?.Id || ''
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
$: empty = !baseUrl && !apiKey && !jellyfinUser;
|
||||
$: unchanged =
|
||||
$originalBaseUrl === baseUrl &&
|
||||
$originalApiKey === apiKey &&
|
||||
$originalUserId === jellyfinUser?.Id;
|
||||
</script>
|
||||
|
||||
<div class="space-y-4 mb-4">
|
||||
@@ -109,7 +123,8 @@
|
||||
{#if users?.length}
|
||||
<SelectField
|
||||
value={jellyfinUser?.Name || 'Select User'}
|
||||
on:clickOrSelect={() => dispatch('click-user', { user: jellyfinUser, users })}
|
||||
on:clickOrSelect={() =>
|
||||
dispatch('click-user', { user: jellyfinUser, users, setJellyfinUser })}
|
||||
class="mb-4"
|
||||
>
|
||||
User
|
||||
@@ -120,3 +135,5 @@
|
||||
{#if error}
|
||||
<div class="text-red-500 mb-4">{error}</div>
|
||||
{/if}
|
||||
|
||||
<slot {handleSave} {stale} {empty} {unchanged} />
|
||||
|
||||
@@ -5,48 +5,51 @@
|
||||
import { user } from '../../stores/user.store';
|
||||
import { derived, get } from 'svelte/store';
|
||||
|
||||
const dispatch = createEventDispatcher<{
|
||||
change: { baseUrl: string; apiKey: string; stale: boolean };
|
||||
}>();
|
||||
|
||||
export let baseUrl = get(user)?.settings.radarr.baseUrl || '';
|
||||
export let apiKey = get(user)?.settings.radarr.apiKey || '';
|
||||
let baseUrl = get(user)?.settings.radarr.baseUrl || '';
|
||||
let apiKey = get(user)?.settings.radarr.apiKey || '';
|
||||
const originalBaseUrl = derived(user, (user) => user?.settings.radarr.baseUrl || '');
|
||||
const originalApiKey = derived(user, (user) => user?.settings.radarr.apiKey || '');
|
||||
let timeout: ReturnType<typeof setTimeout>;
|
||||
|
||||
let stale = false;
|
||||
let error = '';
|
||||
let timeout: ReturnType<typeof setTimeout>;
|
||||
let healthCheck: Promise<boolean> | undefined;
|
||||
|
||||
$: {
|
||||
if ($originalBaseUrl !== baseUrl && $originalApiKey !== apiKey) handleChange();
|
||||
else dispatch('change', { baseUrl, apiKey, stale: false });
|
||||
$originalBaseUrl;
|
||||
$originalApiKey;
|
||||
stale = getIsStale();
|
||||
}
|
||||
|
||||
handleChange();
|
||||
|
||||
function getIsStale() {
|
||||
return (
|
||||
(!!healthCheck || (!baseUrl && !apiKey)) &&
|
||||
($originalBaseUrl !== baseUrl || $originalApiKey !== apiKey)
|
||||
);
|
||||
}
|
||||
|
||||
function handleChange() {
|
||||
clearTimeout(timeout);
|
||||
stale = false;
|
||||
error = '';
|
||||
healthCheck = undefined;
|
||||
|
||||
if (baseUrl === '' || apiKey === '') {
|
||||
stale = getIsStale();
|
||||
return;
|
||||
}
|
||||
|
||||
const baseUrlCopy = baseUrl;
|
||||
const apiKeyCopy = apiKey;
|
||||
const stale = baseUrlCopy !== $originalBaseUrl || apiKeyCopy !== $originalApiKey;
|
||||
|
||||
dispatch('change', {
|
||||
baseUrl: '',
|
||||
apiKey: '',
|
||||
stale: baseUrl === '' && apiKey === '' && stale
|
||||
});
|
||||
|
||||
if (baseUrlCopy === '' || apiKeyCopy === '') return;
|
||||
|
||||
timeout = setTimeout(async () => {
|
||||
const p = radarrApi.getHealth(baseUrlCopy, apiKeyCopy);
|
||||
healthCheck = p.then((res) => res.status === 200);
|
||||
|
||||
const res = await p;
|
||||
if (baseUrlCopy !== baseUrl || apiKeyCopy !== apiKey) return;
|
||||
|
||||
if (res.status !== 200) {
|
||||
error =
|
||||
res.status === 404
|
||||
@@ -55,12 +58,29 @@
|
||||
? 'Invalid api key'
|
||||
: 'Could not connect';
|
||||
|
||||
return; // TODO add notification
|
||||
stale = false; // TODO add notification
|
||||
} else {
|
||||
dispatch('change', { baseUrl: baseUrlCopy, apiKey: apiKeyCopy, stale });
|
||||
stale = getIsStale();
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
async function handleSave() {
|
||||
return user.updateUser((prev) => ({
|
||||
...prev,
|
||||
settings: {
|
||||
...prev.settings,
|
||||
radarr: {
|
||||
...prev.settings.radarr,
|
||||
baseUrl,
|
||||
apiKey
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
$: empty = !baseUrl && !apiKey;
|
||||
$: unchanged = baseUrl === $originalBaseUrl && apiKey === $originalApiKey;
|
||||
</script>
|
||||
|
||||
<div class="space-y-4 mb-4">
|
||||
@@ -73,3 +93,5 @@
|
||||
{#if error}
|
||||
<div class="text-red-500 mb-4">{error}</div>
|
||||
{/if}
|
||||
|
||||
<slot {handleSave} {stale} {empty} {unchanged} />
|
||||
|
||||
@@ -5,50 +5,51 @@
|
||||
import { user } from '../../stores/user.store';
|
||||
import { derived, get } from 'svelte/store';
|
||||
|
||||
const dispatch = createEventDispatcher<{
|
||||
change: { baseUrl: string; apiKey: string; stale: boolean };
|
||||
}>();
|
||||
|
||||
export let baseUrl = get(user)?.settings.sonarr.baseUrl || '';
|
||||
export let apiKey = get(user)?.settings.sonarr.apiKey || '';
|
||||
let baseUrl = get(user)?.settings.sonarr.baseUrl || '';
|
||||
let apiKey = get(user)?.settings.sonarr.apiKey || '';
|
||||
const originalBaseUrl = derived(user, (u) => u?.settings.sonarr.baseUrl || '');
|
||||
const originalApiKey = derived(user, (u) => u?.settings.sonarr.apiKey || '');
|
||||
let timeout: ReturnType<typeof setTimeout>;
|
||||
|
||||
let stale = false;
|
||||
let error = '';
|
||||
let timeout: ReturnType<typeof setTimeout>;
|
||||
let healthCheck: Promise<boolean> | undefined;
|
||||
|
||||
$: {
|
||||
if ($originalBaseUrl !== baseUrl && $originalApiKey !== apiKey) handleChange();
|
||||
else dispatch('change', { baseUrl, apiKey, stale: false });
|
||||
$originalBaseUrl;
|
||||
$originalApiKey;
|
||||
stale = getIsStale();
|
||||
}
|
||||
|
||||
handleChange();
|
||||
|
||||
function handleChange() {
|
||||
console.log('handleChange', $originalBaseUrl, baseUrl, $originalApiKey, apiKey);
|
||||
function getIsStale() {
|
||||
return (
|
||||
(!!healthCheck || (!baseUrl && !apiKey)) &&
|
||||
($originalBaseUrl !== baseUrl || $originalApiKey !== apiKey)
|
||||
);
|
||||
}
|
||||
|
||||
function handleChange() {
|
||||
clearTimeout(timeout);
|
||||
stale = false;
|
||||
error = '';
|
||||
healthCheck = undefined;
|
||||
|
||||
if (baseUrl === '' || apiKey === '') {
|
||||
stale = getIsStale();
|
||||
return;
|
||||
}
|
||||
|
||||
const baseUrlCopy = baseUrl;
|
||||
const apiKeyCopy = apiKey;
|
||||
const stale = baseUrlCopy !== $originalBaseUrl || apiKeyCopy !== $originalApiKey;
|
||||
|
||||
dispatch('change', {
|
||||
baseUrl: '',
|
||||
apiKey: '',
|
||||
stale: baseUrl === '' && apiKey === '' && stale
|
||||
});
|
||||
|
||||
if (baseUrlCopy === '' || apiKeyCopy === '') return;
|
||||
|
||||
timeout = setTimeout(async () => {
|
||||
const p = sonarrApi.getHealth(baseUrlCopy, apiKeyCopy);
|
||||
healthCheck = p.then((res) => res.status === 200);
|
||||
|
||||
const res = await p;
|
||||
if (baseUrlCopy !== baseUrl || apiKeyCopy !== apiKey) return;
|
||||
|
||||
if (res.status !== 200) {
|
||||
error =
|
||||
res.status === 404
|
||||
@@ -57,12 +58,29 @@
|
||||
? 'Invalid api key'
|
||||
: 'Could not connect';
|
||||
|
||||
return; // TODO add notification
|
||||
stale = false; // TODO add notification
|
||||
} else {
|
||||
dispatch('change', { baseUrl: baseUrlCopy, apiKey: apiKeyCopy, stale });
|
||||
stale = getIsStale();
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
async function handleSave() {
|
||||
return user.updateUser((prev) => ({
|
||||
...prev,
|
||||
settings: {
|
||||
...prev.settings,
|
||||
sonarr: {
|
||||
...prev.settings.sonarr,
|
||||
baseUrl,
|
||||
apiKey
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
$: empty = !baseUrl && !apiKey;
|
||||
$: unchanged = baseUrl === $originalBaseUrl && apiKey === $originalApiKey;
|
||||
</script>
|
||||
|
||||
<div class="space-y-4 mb-4">
|
||||
@@ -75,3 +93,5 @@
|
||||
{#if error}
|
||||
<div class="text-red-500 mb-4">{error}</div>
|
||||
{/if}
|
||||
|
||||
<slot {handleSave} {stale} {empty} {unchanged} />
|
||||
|
||||
@@ -1,76 +1,48 @@
|
||||
<script lang="ts">
|
||||
import TextField from '../TextField.svelte';
|
||||
import { sonarrApi } from '../../apis/sonarr/sonarr-api';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import { tmdbApi } from '../../apis/tmdb/tmdb-api';
|
||||
import { user } from '../../stores/user.store';
|
||||
import SelectField from '../SelectField.svelte';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import Button from '../Button.svelte';
|
||||
import { ArrowRight, Trash } from 'radix-icons-svelte';
|
||||
import { derived } from 'svelte/store';
|
||||
import classNames from 'classnames';
|
||||
|
||||
const dispatch = createEventDispatcher<{
|
||||
change: { baseUrl: string; apiKey: string; stale: boolean };
|
||||
}>();
|
||||
export let handleConnectTmdb: () => void;
|
||||
|
||||
export let baseUrl = '';
|
||||
export let apiKey = '';
|
||||
let originalBaseUrl: string | undefined;
|
||||
let originalApiKey: string | undefined;
|
||||
let timeout: ReturnType<typeof setTimeout>;
|
||||
let error = '';
|
||||
let healthCheck: Promise<boolean> | undefined;
|
||||
const dispatch = createEventDispatcher<{ 'click-user': null }>();
|
||||
const userId = derived(user, (user) => user?.settings.tmdb.userId);
|
||||
|
||||
user.subscribe((user) => {
|
||||
baseUrl = baseUrl || user?.settings.sonarr.baseUrl || '';
|
||||
apiKey = apiKey || user?.settings.sonarr.apiKey || '';
|
||||
$: connectedTmdbAccount = !!$userId && tmdbApi.getAccountDetails();
|
||||
|
||||
originalBaseUrl = baseUrl;
|
||||
originalApiKey = apiKey;
|
||||
|
||||
handleChange();
|
||||
});
|
||||
|
||||
function handleChange() {
|
||||
clearTimeout(timeout);
|
||||
error = '';
|
||||
healthCheck = undefined;
|
||||
|
||||
const baseUrlCopy = baseUrl;
|
||||
const apiKeyCopy = apiKey;
|
||||
const stale = baseUrlCopy !== originalBaseUrl || apiKeyCopy !== originalApiKey;
|
||||
|
||||
dispatch('change', {
|
||||
baseUrl: '',
|
||||
apiKey: '',
|
||||
stale: baseUrl === '' && apiKey === ''
|
||||
});
|
||||
|
||||
if (baseUrlCopy === '' || apiKeyCopy === '') return;
|
||||
|
||||
timeout = setTimeout(async () => {
|
||||
const p = sonarrApi.getHealth(baseUrlCopy, apiKeyCopy);
|
||||
healthCheck = p.then((res) => res.status === 200);
|
||||
|
||||
const res = await p;
|
||||
if (baseUrlCopy !== baseUrl || apiKeyCopy !== apiKey) return;
|
||||
if (res.status !== 200) {
|
||||
error =
|
||||
res.status === 404
|
||||
? 'Server not found'
|
||||
: res.status === 401
|
||||
? 'Invalid api key'
|
||||
: 'Could not connect';
|
||||
|
||||
return; // TODO add notification
|
||||
} else {
|
||||
dispatch('change', { baseUrl: baseUrlCopy, apiKey: apiKeyCopy, stale });
|
||||
async function handleDisconnectTmdb() {
|
||||
return user.updateUser((prev) => ({
|
||||
...prev,
|
||||
settings: {
|
||||
...prev.settings,
|
||||
tmdb: {
|
||||
...prev.settings.tmdb,
|
||||
userId: '',
|
||||
sessionId: ''
|
||||
}
|
||||
}
|
||||
}, 1000);
|
||||
}));
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="space-y-4 mb-4">
|
||||
<TextField bind:value={baseUrl} isValid={healthCheck} on:change={handleChange}>Base Url</TextField
|
||||
>
|
||||
<TextField bind:value={apiKey} isValid={healthCheck} on:change={handleChange}>API Key</TextField>
|
||||
</div>
|
||||
|
||||
{#if error}
|
||||
<div class="text-red-500 mb-4">{error}</div>
|
||||
{/if}
|
||||
{#await connectedTmdbAccount then tmdbAccount}
|
||||
{#if tmdbAccount}
|
||||
<SelectField value={tmdbAccount.username || ''} action={handleDisconnectTmdb} class="mb-4">
|
||||
Connected to
|
||||
<Trash slot="icon" let:size let:iconClass {size} class={classNames(iconClass, '')} />
|
||||
</SelectField>
|
||||
{:else}
|
||||
<slot>
|
||||
<div class="flex space-x-4">
|
||||
<Button type="primary-dark" iconAfter={ArrowRight} on:clickOrSelect={handleConnectTmdb}>
|
||||
Connect
|
||||
</Button>
|
||||
</div>
|
||||
</slot>
|
||||
{/if}
|
||||
{/await}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import Container from '../../../Container.svelte';
|
||||
import { tmdbApi } from '../../apis/tmdb/tmdb-api';
|
||||
import Button from '../Button.svelte';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import { createEventDispatcher, onMount } from 'svelte';
|
||||
import { ExternalLink } from 'radix-icons-svelte';
|
||||
import { user } from '../../stores/user.store';
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
let tmdbConnectQrCode: string | undefined = undefined;
|
||||
let tmdbError: string = '';
|
||||
|
||||
handleGenerateTMDBLink();
|
||||
|
||||
async function handleGenerateTMDBLink() {
|
||||
return tmdbApi.getConnectAccountLink().then((res) => {
|
||||
if (res?.status_code !== 1) return; // TODO add notification
|
||||
@@ -66,9 +68,9 @@
|
||||
{/if}
|
||||
|
||||
<Container direction="horizontal" class="flex space-x-4 *:flex-1">
|
||||
{#if !tmdbConnectRequestToken}
|
||||
<Button type="primary-dark" action={handleGenerateTMDBLink}>Generate Link</Button>
|
||||
{:else if tmdbConnectLink}
|
||||
<!--{#if !tmdbConnectRequestToken}-->
|
||||
<!-- <Button type="primary-dark" action={handleGenerateTMDBLink}>Generate Link</Button>-->
|
||||
{#if tmdbConnectLink}
|
||||
<Button type="primary-dark" action={completeTMDBConnect}>Complete Connection</Button>
|
||||
<Button type="primary-dark" on:clickOrSelect={() => window.open(tmdbConnectLink)}>
|
||||
Open Link
|
||||
|
||||
Reference in New Issue
Block a user