Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support package managers (NPM, PYPI, PUB) #328

Merged
merged 7 commits into from
Aug 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions web/.vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [{
"type": "chrome",
"request": "launch",
"name": "Launch Chrome against localhost",
"url": "http://localhost:5173",
"webRoot": "${workspaceFolder}/src",
"breakOnLoad": true,
"sourceMaps": true,
"sourceMapPathOverrides": {
"webpack:///src/*": "${webRoot}/*"
}
}
]
}
1 change: 1 addition & 0 deletions web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"@lottiefiles/svelte-lottie-player": "^0.3.1",
"@microsoft/applicationinsights-web": "^3.3.1",
"@tailwindcss/typography": "^0.5.13",
"cheerio": "^1.0.0",
"dotenv": "^16.4.5",
"highlight.js": "^11.10.0",
"isomorphic-dompurify": "^2.14.0",
Expand Down
128 changes: 72 additions & 56 deletions web/src/lib/components/CreateAgentDialog.svelte
Original file line number Diff line number Diff line change
@@ -1,98 +1,114 @@
<script lang="ts">
import { base } from "$app/paths";
import { clickOutside } from "$lib/actions/clickOutside";
import { goto } from "$app/navigation";
import { toastStore } from "$lib/stores/ToastStores";
import { ToastType } from "$lib/types/Toast";
import appInsights from "$lib/utils/appInsights"; // Import the appInsights instance
import appInsights from "$lib/utils/appInsights";
import IconClose from "~icons/carbon/close";
import CarbonSearch from "~icons/carbon/search";
import CarbonGithub from "~icons/carbon/logo-github";
import { validateURL } from "$lib/utils/validateURL";

export let showModal: boolean;
export let onClose: () => void;

let dialog: HTMLDialogElement;
let value: string = "";
let selectedPlatform: string = "github";

const validateGithubURL = (url: string): boolean => {
const githubUrlPattern =
/^(https:\/\/github\.com\/[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+\/?)$/;
return githubUrlPattern.test(url);
};

const addGithubURL = (url: string) => {
value = url;
};
const platforms = [
{ id: 'github', icon: CarbonGithub, label: 'GitHub', placeholder: 'https://github.com/user/repo' },
{ id: 'npm', icon: 'npm.png', label: 'NPM', placeholder: 'https://www.npmjs.com/package/name' },
{ id: 'pypi', icon: 'python.png', label: 'PyPI', placeholder: 'https://pypi.org/project/name' },
{ id: 'pub', icon: 'icons8-dart-96.png', label: 'Pub', placeholder: 'https://pub.dev/packages/name' },
];

const onCreateAgent = () => {
if (validateGithubURL(value)) {
// Track custom event for form submission
value = value.trim();
const { isValid } = validateURL(value, selectedPlatform);
if (isValid) {
appInsights.trackEvent({
name: "CreateAgentSubmitted",
properties: {
githubUrl: value,
},
properties: { platform: selectedPlatform, url: value },
});

goto(`${base}/agent?github=${value}`);
goto(`${base}/agent?${selectedPlatform}=${value}`);
} else {
toastStore.set({
message: "Please enter valid Github URL",
message: `Please enter a valid ${selectedPlatform} URL`,
type: ToastType.ERROR,
});
}
};

$: if (showModal) {
// Track custom event for dialog opened
appInsights.trackEvent({
name: "CreateAgentDialogOpened",
});
appInsights.trackEvent({ name: "CreateAgentDialogOpened" });
}
</script>

{#if showModal}
<div
class="fixed inset-0 z-20 flex items-center justify-center bg-transparent backdrop-blur-sm"
>
<dialog
bind:this={dialog}
class="flex flex-col content-center items-center gap-x-10 gap-y-3 overflow-hidden rounded-xl border bg-gray-50/50 px-4 py-6 text-center shadow hover:bg-gray-50 hover:shadow-inner sm:h-64 sm:pb-4 xl:pt-8 dark:border-gray-800/70 dark:bg-gray-950 dark:hover:bg-gray-950 max-sm:w-[85dvw] max-sm:px-6 md:w-96 md:grid-cols-3 md:grid-rows-[auto,1fr] md:p-8"
on:close={() => dialog.close()}
open={showModal}
>
<div class="absolute right-0 top-0 mr-2 mt-2">
<button
class="flex items-center px-2.5 py-1 text-sm text-white"
on:click={onClose}
>
<IconClose class="mr-1.5 text-xl" />
<div class="fixed inset-0 z-20 flex items-center justify-center bg-black bg-opacity-50">
<div class="bg-gray-900 rounded-lg p-6 w-full max-w-md border border-gray-700">
<div class="flex justify-between items-center mb-4">
<h2 class="text-xl font-bold text-gray-100">Create Agent with URL</h2>
<button on:click={onClose} class="text-gray-400 hover:text-gray-200">
<IconClose />
</button>
</div>
<h1 class="text-xl font-bold text-white">Create Agent with Github</h1>
<div
class="relative flex h-[50px] min-w-full items-center rounded-md border px-2 has-[:focus]:border-gray-400 sm:w-64 dark:border-gray-600"
>
<CarbonGithub
height="1.5em"
width="1.5em"
class="pointer-events-none absolute left-2 text-xs text-gray-400"
/>

<div class="flex flex-wrap justify-center gap-4 mb-6">
{#each platforms as platform}
<button
on:click={() => selectedPlatform = platform.id}
class="flex flex-col items-center focus:outline-none transition-all duration-200 ease-in-out"
class:selected={selectedPlatform === platform.id}
>
<div class="relative">
{#if platform.id === 'github'}
<svelte:component this={platform.icon} class="w-10 h-10 mb-1 text-black-600" />
{:else}
<img src={platform.icon} alt={platform.label} class="w-10 h-10 mb-1" />
{/if}

</div>
<span class="text-xs text-gray-300">{platform.label}</span>
</button>
{/each}
</div>

<div class="relative mb-4">
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
{#if selectedPlatform === 'github'}
<CarbonGithub class="w-5 h-5 text-gray-400" />
{:else}
<img
src={platforms.find(p => p.id === selectedPlatform).icon}
alt={selectedPlatform}
class="w-5 h-5"
/>
{/if}
</div>
<input
class="h-[50px] w-full bg-transparent pl-7 focus:outline-none text-white"
placeholder="Github Repo URL"
type="url"
{value}
on:input={(e) => addGithubURL(e.currentTarget.value)}
bind:value
placeholder={platforms.find(p => p.id === selectedPlatform).placeholder}
class="w-full pl-10 pr-3 py-2 bg-gray-800 border border-gray-700 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 text-gray-100 placeholder-gray-500"
/>
</div>

<button
on:click={onCreateAgent}
class="mt-4 w-full rounded bg-gray-300 px-4 py-3 font-semibold text-black"
class="w-full bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50 transition-colors duration-200"
>
Submit
</button>
</dialog>
</div>
</div>
{/if}
{/if}

<style>
.selected {
transform: scale(1.1);
}
.selected span {
color: #60a5fa; /* blue-400 */
font-weight: bold;
}
</style>
17 changes: 17 additions & 0 deletions web/src/lib/utils/validateURL.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// src/lib/utils/validateURL.ts

export const validateURL = (url: string, platform: string): { isValid: boolean, packageName: string } => {
const patterns = {
github: /^(https:\/\/github\.com\/[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+\/?)$/,
npm: /^(https:\/\/www\.npmjs\.com\/package\/(@?[A-Za-z0-9_.-]+\/?[A-Za-z0-9_.-]+))\/?.*$/,
pypi: /^(https:\/\/pypi\.org\/project\/([A-Za-z0-9_.-]+))\/?.*$/,
pub: /^(https:\/\/pub\.dev\/packages\/([A-Za-z0-9_.-]+))\/?.*$/,
};

const match = url.match(patterns[platform]);
if (match) {
return { isValid: true, packageName: match[2] };
} else {
return { isValid: false, packageName: "" };
}
};
2 changes: 1 addition & 1 deletion web/src/routes/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@
showModal = true;
}}
>
<CarbonGithub />Create Agent
<CarbonAdd />Create Agent
</button>
</div>
<div class="mt-6 flex flex-wrap gap-2 items-center">
Expand Down
55 changes: 51 additions & 4 deletions web/src/routes/agent/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import { error as pageError } from "@sveltejs/kit";
import { page } from "$app/stores";
import appInsights from "$lib/utils/appInsights";
import { validateURL } from "$lib/utils/validateURL";

import ChatWindow from "$lib/components/chat/ChatWindow.svelte";
import { type Agent } from "$lib/types/Agent";
Expand All @@ -11,14 +12,60 @@
let currentAgentDetails: Agent;
let errorMessage: string = "Something went wrong";
let agentDataSources: Array<any> = [];

const limit: number = 10;

$: loading = true;

onMount(async () => {
loading = true;
const ref: string = $page.url.searchParams.get("github") || "";
const githubRef: string = $page.url.searchParams.get("github") || "";
const npmRef: string = $page.url.searchParams.get("npm") || "";
const pypiRef: string = $page.url.searchParams.get("pypi") || "";
const pubRef: string = $page.url.searchParams.get("pub") || "";

let referrer = "";
let referrer_kind = "";

if (githubRef) {
referrer = githubRef;
referrer_kind = "github";
} else if (npmRef) {
const { isValid, packageName } = validateURL(npmRef, "npm");
if (!isValid) {
loading = false;
errorMessage = "Invalid NPM URL";
appInsights.trackException({ error: new Error(errorMessage) }); // Track exception
throw pageError(400, errorMessage);
}
referrer = packageName;
referrer_kind = "npm";
} else if (pypiRef) {
const { isValid, packageName } = validateURL(pypiRef, "pypi");
if (!isValid) {
loading = false;
errorMessage = "Invalid PyPI URL";
appInsights.trackException({ error: new Error(errorMessage) }); // Track exception
throw pageError(400, errorMessage);
}
referrer = packageName;
referrer_kind = "pypi";
} else if (pubRef) {
const { isValid, packageName } = validateURL(pubRef, "pub");
if (!isValid) {
loading = false;
errorMessage = "Invalid Pub URL";
appInsights.trackException({ error: new Error(errorMessage) }); // Track exception
throw pageError(400, errorMessage);
}
referrer = packageName;
referrer_kind = "pub";
} else {
loading = false;
errorMessage = "A source is required";
appInsights.trackException({ error: new Error(errorMessage) }); // Track exception
throw pageError(400, errorMessage);
}

appInsights.trackPageView({
name: "AgentPage",
Expand All @@ -31,7 +78,7 @@
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ referrer: ref }),
body: JSON.stringify({ referrer, referrer_kind }),
},
);

Expand Down Expand Up @@ -100,4 +147,4 @@
<h1 class="text-2xl">Error:</h1>
<h1 class="text-xl">{errorMessage}</h1>
</div>
{/if}
{/if}
Binary file added web/static/github.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added web/static/go.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added web/static/icons8-dart-96.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added web/static/icons8-github-80.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added web/static/npm.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added web/static/python.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading