mirror of
https://github.com/open-webui/open-webui.git
synced 2026-10-11 03:38:02 +00:00
refac
This commit is contained in:
parent
371ed44b2c
commit
a3cd6158bb
4 changed files with 93 additions and 5 deletions
|
|
@ -237,7 +237,7 @@ def parse_import(
|
|||
'name': str(name),
|
||||
'description': package.get('description', fm.get('description', '')),
|
||||
'meta': package.get('meta') or {},
|
||||
'is_active': package.get('is_active', True),
|
||||
**({'is_active': package['is_active']} if 'is_active' in package else {}),
|
||||
'files': files,
|
||||
}
|
||||
)
|
||||
|
|
|
|||
|
|
@ -43,6 +43,40 @@
|
|||
import Badge from '$lib/components/common/Badge.svelte';
|
||||
import Switch from '../common/Switch.svelte';
|
||||
import SkillMenu from './Skills/SkillMenu.svelte';
|
||||
import CommunityDiscover from './common/CommunityDiscover.svelte';
|
||||
import { config } from '$lib/stores';
|
||||
let stopSkillShare = () => {};
|
||||
const shareHandler = (skill: { id: string }) => {
|
||||
stopSkillShare();
|
||||
const tab = window.open('https://openwebui.com/post?type=skill', '_blank');
|
||||
if (!tab) {
|
||||
toast.error($i18n.t('Please allow popups to share your skill.'));
|
||||
return;
|
||||
}
|
||||
const receiveLoaded = async (event: MessageEvent) => {
|
||||
if (
|
||||
event.origin !== 'https://openwebui.com' ||
|
||||
event.source !== tab ||
|
||||
event.data !== 'loaded'
|
||||
)
|
||||
return;
|
||||
stopSkillShare();
|
||||
try {
|
||||
const exported = JSON.parse(
|
||||
await (await exportSkillBundle(localStorage.token, 'json', [skill.id])).text()
|
||||
);
|
||||
const { id, name, description, files } = Array.isArray(exported) ? exported[0] : exported;
|
||||
const data = JSON.stringify({ id, name, description, files });
|
||||
if (new Blob([data]).size > 15 * 1024 * 1024)
|
||||
throw new Error('Community skill JSON exceeds 15 MiB');
|
||||
tab.postMessage(data, 'https://openwebui.com');
|
||||
} catch (error) {
|
||||
toast.error(skillError(error));
|
||||
}
|
||||
};
|
||||
window.addEventListener('message', receiveLoaded);
|
||||
stopSkillShare = () => window.removeEventListener('message', receiveLoaded);
|
||||
};
|
||||
import SkillImport from './Skills/SkillImport.svelte';
|
||||
import ImportModal from '$lib/components/ImportModal.svelte';
|
||||
import { cloneSkill, exportSkillBundle, loadSkillByUrl, skillError } from '$lib/apis/skills';
|
||||
|
|
@ -289,6 +323,7 @@
|
|||
});
|
||||
|
||||
onDestroy(() => {
|
||||
stopSkillShare();
|
||||
searchController?.abort();
|
||||
clearTimeout(searchDebounceTimer);
|
||||
});
|
||||
|
|
@ -564,6 +599,7 @@
|
|||
{:else}
|
||||
<div class="flex shrink-0 flex-row items-center gap-1.5 self-center">
|
||||
<SkillMenu
|
||||
shareHandler={() => shareHandler(skill)}
|
||||
accessHandler={() => accessModal.open(skill.id)}
|
||||
show={openSkillMenuId === skill.id}
|
||||
editHandler={() => {
|
||||
|
|
@ -655,6 +691,13 @@
|
|||
<span class=" font-normal">{resolveLocalizedResource(selectedSkill, $i18n.language)}</span>.
|
||||
</div>
|
||||
</DeleteConfirmDialog>
|
||||
{#if $config?.features?.enable_community_sharing}
|
||||
<CommunityDiscover
|
||||
href="https://openwebui.com/search?type=skill"
|
||||
title={$i18n.t('Discover a skill')}
|
||||
description={$i18n.t('Discover, download, and explore community skills')}
|
||||
/>
|
||||
{/if}
|
||||
{:else}
|
||||
<div class="w-full h-full flex justify-center items-center">
|
||||
<Spinner className="size-5" />
|
||||
|
|
|
|||
|
|
@ -8,13 +8,14 @@
|
|||
import Tooltip from '$lib/components/common/Tooltip.svelte';
|
||||
import DocumentDuplicate from '$lib/components/icons/DocumentDuplicate.svelte';
|
||||
import Download from '$lib/components/icons/Download.svelte';
|
||||
import { user } from '$lib/stores';
|
||||
import { user, config } from '$lib/stores';
|
||||
|
||||
const i18n = getContext<typeof import('$lib/i18n').default>('i18n');
|
||||
|
||||
export let editHandler: Function;
|
||||
export let cloneHandler: Function;
|
||||
export let exportHandler: Function;
|
||||
export let shareHandler: (() => void) | null = null;
|
||||
export let deleteHandler: Function;
|
||||
export let accessHandler: (() => void) | null = null;
|
||||
export let onClose: Function;
|
||||
|
|
@ -90,6 +91,16 @@
|
|||
<div class="flex items-center">{$i18n.t('Clone')}</div>
|
||||
</button>
|
||||
|
||||
{#if shareHandler && $config?.features?.enable_community_sharing && ($user?.role === 'admin' || $user?.permissions?.workspace?.skills_export)}
|
||||
<button
|
||||
type="button"
|
||||
class="flex h-7 w-full items-center gap-2 px-2 text-[0.8125rem]"
|
||||
on:click={() => {
|
||||
shareHandler?.();
|
||||
closeMenu();
|
||||
}}>{$i18n.t('Share to Community')}</button
|
||||
>
|
||||
{/if}
|
||||
{#if $user?.role === 'admin' || $user?.permissions?.workspace?.skills_export}
|
||||
<button
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[0.8125rem] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<script lang="ts">
|
||||
import { toast } from 'svelte-sonner';
|
||||
import { goto } from '$app/navigation';
|
||||
import { skills } from '$lib/stores';
|
||||
import { skills, user, config } from '$lib/stores';
|
||||
import { COMMUNITY_ORIGINS } from '$lib/constants';
|
||||
import { onMount, getContext } from 'svelte';
|
||||
|
||||
const i18n = getContext<any>('i18n');
|
||||
|
|
@ -32,7 +32,40 @@
|
|||
}
|
||||
};
|
||||
|
||||
onMount(async () => {
|
||||
onMount(() => {
|
||||
const receiveSkill = (event: MessageEvent) => {
|
||||
if (!COMMUNITY_ORIGINS.includes(event.origin) || event.source !== window.opener) return;
|
||||
if (
|
||||
!$config?.features?.enable_community_sharing ||
|
||||
($user?.role !== 'admin' && !$user?.permissions?.workspace?.skills_import)
|
||||
)
|
||||
return;
|
||||
try {
|
||||
const data = JSON.parse(event.data);
|
||||
if (
|
||||
!Array.isArray(data.files) ||
|
||||
typeof data.id !== 'string' ||
|
||||
typeof data.name !== 'string'
|
||||
)
|
||||
throw new Error('Invalid skill JSON');
|
||||
skill = {
|
||||
id: data.id,
|
||||
name: data.name,
|
||||
description: data.description ?? '',
|
||||
files: data.files,
|
||||
content:
|
||||
data.files.find((file: { path: string }) => file.path === 'SKILL.md')?.content ?? '',
|
||||
is_active: true,
|
||||
access_grants: []
|
||||
};
|
||||
window.removeEventListener('message', receiveSkill);
|
||||
} catch (error) {
|
||||
toast.error(error instanceof Error ? error.message : 'Invalid skill JSON');
|
||||
}
|
||||
};
|
||||
window.addEventListener('message', receiveSkill);
|
||||
if (window.opener) window.opener.postMessage('loaded', '*');
|
||||
|
||||
if (sessionStorage.skill) {
|
||||
const _skill = JSON.parse(sessionStorage.skill);
|
||||
sessionStorage.removeItem('skill');
|
||||
|
|
@ -49,6 +82,7 @@
|
|||
access_grants: _skill.access_grants !== undefined ? _skill.access_grants : []
|
||||
};
|
||||
}
|
||||
return () => window.removeEventListener('message', receiveSkill);
|
||||
});
|
||||
</script>
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue