Login on focus (#1969)
Browse files* login on focus too
* fix: fetch url logs
* fix: fetch url logs
* include the dropdown
* lint
---------
Co-authored-by: rtrm <remy.trompier@gmail.com>
Dockerfile
CHANGED
|
@@ -90,4 +90,6 @@ ENV BODY_SIZE_LIMIT=15728640
|
|
| 90 |
COPY --from=builder --chown=1000 /app/build /app/build
|
| 91 |
COPY --from=builder --chown=1000 /app/node_modules /app/node_modules
|
| 92 |
|
|
|
|
|
|
|
| 93 |
CMD ["/bin/bash", "-c", "/app/entrypoint.sh"]
|
|
|
|
| 90 |
COPY --from=builder --chown=1000 /app/build /app/build
|
| 91 |
COPY --from=builder --chown=1000 /app/node_modules /app/node_modules
|
| 92 |
|
| 93 |
+
RUN apt -y update && apt-get install -y curl dnsutils
|
| 94 |
+
|
| 95 |
CMD ["/bin/bash", "-c", "/app/entrypoint.sh"]
|
src/lib/components/chat/ChatInput.svelte
CHANGED
|
@@ -25,6 +25,7 @@
|
|
| 25 |
toggleServer,
|
| 26 |
} from "$lib/stores/mcpServers";
|
| 27 |
import { getMcpServerFaviconUrl } from "$lib/utils/favicon";
|
|
|
|
| 28 |
|
| 29 |
interface Props {
|
| 30 |
files?: File[];
|
|
@@ -76,6 +77,7 @@
|
|
| 76 |
let fileInputEl: HTMLInputElement | undefined = $state();
|
| 77 |
let isUrlModalOpen = $state(false);
|
| 78 |
let isMcpManagerOpen = $state(false);
|
|
|
|
| 79 |
|
| 80 |
function openPickerWithAccept(accept: string) {
|
| 81 |
if (!fileInputEl) return;
|
|
@@ -107,6 +109,7 @@
|
|
| 107 |
: Promise.resolve();
|
| 108 |
|
| 109 |
async function focusTextarea() {
|
|
|
|
| 110 |
if (!textareaElement || textareaElement.disabled || isVirtualKeyboard()) return;
|
| 111 |
if (typeof document !== "undefined" && document.activeElement === textareaElement) return;
|
| 112 |
|
|
@@ -177,6 +180,9 @@
|
|
| 177 |
}
|
| 178 |
|
| 179 |
function handleFocus() {
|
|
|
|
|
|
|
|
|
|
| 180 |
if (blurTimeout) {
|
| 181 |
clearTimeout(blurTimeout);
|
| 182 |
blurTimeout = null;
|
|
@@ -251,7 +257,16 @@
|
|
| 251 |
accept={mimeTypes.join(",")}
|
| 252 |
/>
|
| 253 |
|
| 254 |
-
<DropdownMenu.Root
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 255 |
<DropdownMenu.Trigger
|
| 256 |
class="btn size-7 rounded-full border bg-white text-black shadow transition-none enabled:hover:bg-white enabled:hover:shadow-inner dark:border-transparent dark:bg-gray-600/50 dark:text-white dark:hover:enabled:bg-gray-600"
|
| 257 |
disabled={loading}
|
|
|
|
| 25 |
toggleServer,
|
| 26 |
} from "$lib/stores/mcpServers";
|
| 27 |
import { getMcpServerFaviconUrl } from "$lib/utils/favicon";
|
| 28 |
+
import { page } from "$app/state";
|
| 29 |
|
| 30 |
interface Props {
|
| 31 |
files?: File[];
|
|
|
|
| 77 |
let fileInputEl: HTMLInputElement | undefined = $state();
|
| 78 |
let isUrlModalOpen = $state(false);
|
| 79 |
let isMcpManagerOpen = $state(false);
|
| 80 |
+
let isDropdownOpen = $state(false);
|
| 81 |
|
| 82 |
function openPickerWithAccept(accept: string) {
|
| 83 |
if (!fileInputEl) return;
|
|
|
|
| 109 |
: Promise.resolve();
|
| 110 |
|
| 111 |
async function focusTextarea() {
|
| 112 |
+
if (page.data.shared && page.data.loginEnabled && !page.data.user) return;
|
| 113 |
if (!textareaElement || textareaElement.disabled || isVirtualKeyboard()) return;
|
| 114 |
if (typeof document !== "undefined" && document.activeElement === textareaElement) return;
|
| 115 |
|
|
|
|
| 180 |
}
|
| 181 |
|
| 182 |
function handleFocus() {
|
| 183 |
+
if (requireAuthUser()) {
|
| 184 |
+
return;
|
| 185 |
+
}
|
| 186 |
if (blurTimeout) {
|
| 187 |
clearTimeout(blurTimeout);
|
| 188 |
blurTimeout = null;
|
|
|
|
| 257 |
accept={mimeTypes.join(",")}
|
| 258 |
/>
|
| 259 |
|
| 260 |
+
<DropdownMenu.Root
|
| 261 |
+
bind:open={isDropdownOpen}
|
| 262 |
+
onOpenChange={(open) => {
|
| 263 |
+
if (open && requireAuthUser()) {
|
| 264 |
+
isDropdownOpen = false;
|
| 265 |
+
return;
|
| 266 |
+
}
|
| 267 |
+
isDropdownOpen = open;
|
| 268 |
+
}}
|
| 269 |
+
>
|
| 270 |
<DropdownMenu.Trigger
|
| 271 |
class="btn size-7 rounded-full border bg-white text-black shadow transition-none enabled:hover:bg-white enabled:hover:shadow-inner dark:border-transparent dark:bg-gray-600/50 dark:text-white dark:hover:enabled:bg-gray-600"
|
| 272 |
disabled={loading}
|
src/lib/components/chat/UrlFetchModal.svelte
CHANGED
|
@@ -82,8 +82,7 @@
|
|
| 82 |
const txt = await res.text();
|
| 83 |
throw new Error(txt || `Failed to fetch (${res.status})`);
|
| 84 |
}
|
| 85 |
-
const forwardedType =
|
| 86 |
-
res.headers.get("x-forwarded-content-type");
|
| 87 |
const blob = await res.blob();
|
| 88 |
const mimeType = pickSafeMime(forwardedType, blob.type, trimmed);
|
| 89 |
// Optional client-side mime filter (same wildcard semantics as dropzone)
|
|
|
|
| 82 |
const txt = await res.text();
|
| 83 |
throw new Error(txt || `Failed to fetch (${res.status})`);
|
| 84 |
}
|
| 85 |
+
const forwardedType = res.headers.get("x-forwarded-content-type");
|
|
|
|
| 86 |
const blob = await res.blob();
|
| 87 |
const mimeType = pickSafeMime(forwardedType, blob.type, trimmed);
|
| 88 |
// Optional client-side mime filter (same wildcard semantics as dropzone)
|
src/lib/utils/loadAttachmentsFromUrls.ts
CHANGED
|
@@ -91,8 +91,7 @@ export async function loadAttachmentsFromUrls(
|
|
| 91 |
return;
|
| 92 |
}
|
| 93 |
|
| 94 |
-
const forwardedType =
|
| 95 |
-
response.headers.get("x-forwarded-content-type");
|
| 96 |
const blob = await response.blob();
|
| 97 |
const mimeType = pickSafeMime(forwardedType, blob.type, url);
|
| 98 |
const contentDisposition = response.headers.get("content-disposition");
|
|
|
|
| 91 |
return;
|
| 92 |
}
|
| 93 |
|
| 94 |
+
const forwardedType = response.headers.get("x-forwarded-content-type");
|
|
|
|
| 95 |
const blob = await response.blob();
|
| 96 |
const mimeType = pickSafeMime(forwardedType, blob.type, url);
|
| 97 |
const contentDisposition = response.headers.get("content-disposition");
|