Skip to content

Commit

Permalink
Merge pull request #1224 from rainlanguage/1223-optionally-provide-en…
Browse files Browse the repository at this point in the history
…tire-dotrian-document-in-deploy-mode

Add textbox for raw strat
  • Loading branch information
hardyjosh authored Feb 4, 2025
2 parents 6faccfe + adcf9f2 commit 7edd54f
Show file tree
Hide file tree
Showing 8 changed files with 197 additions and 109 deletions.
22 changes: 21 additions & 1 deletion packages/ui-components/src/__tests__/StrategySection.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,27 @@ describe('StrategySection', () => {
vi.clearAllMocks();
});

it('renders strategy details successfully', async () => {
it('renders strategy details successfully with rawDotrain', async () => {
const mockDotrain = 'mock dotrain content';
const mockStrategyDetails = {
name: 'Test Strategy',
description: 'Test Description'
};
vi.mocked(DotrainOrderGui.getStrategyDetails).mockResolvedValueOnce(mockStrategyDetails);

render(StrategySection, {
props: {
rawDotrain: mockDotrain
}
});

await waitFor(() => {
expect(screen.getByText('Test Strategy')).toBeInTheDocument();
expect(screen.getByText('Test Description')).toBeInTheDocument();
});
});

it('renders strategy details successfully from fetch', async () => {
const mockDotrain = 'mock dotrain content';
const mockStrategyDetails = {
name: 'Test Strategy',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,22 @@
import { DotrainOrderGui, type NameAndDescription } from '@rainlanguage/orderbook/js_api';
import DeploymentsSection from './DeploymentsSection.svelte';
export let strategyUrl: string;
export let strategyName: string;
export let strategyUrl: string = '';
export let strategyName: string = '';
export let rawDotrain: string = '';
let strategyDetails: NameAndDescription;
let dotrain: string;
let error: string;
let errorDetails: string;
const getStrategy = async () => {
try {
const response = await fetch(strategyUrl);
const data = await response.text();
dotrain = data;
if (rawDotrain) {
dotrain = rawDotrain;
} else {
const response = await fetch(strategyUrl);
dotrain = await response.text();
}
try {
strategyDetails = await DotrainOrderGui.getStrategyDetails(dotrain);
} catch (e: unknown) {
Expand Down
3 changes: 3 additions & 0 deletions packages/webapp/src/lib/stores/raw-dotrain.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { writable } from 'svelte/store';

export const rawDotrain = writable('');
5 changes: 5 additions & 0 deletions packages/webapp/src/lib/stores/registry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { writable } from 'svelte/store';

export const registryUrl = writable<string>(
'https://raw.githubusercontent.com/rainlanguage/rain.strategies/refs/heads/main/strategies/dev/registry'
);
26 changes: 0 additions & 26 deletions packages/webapp/src/routes/deploy/+layout.ts

This file was deleted.

81 changes: 51 additions & 30 deletions packages/webapp/src/routes/deploy/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,49 +1,67 @@
<script lang="ts">
import { StrategySection } from '@rainlanguage/ui-components';
import { page } from '$app/stores';
import { Button, Input, Spinner, Toggle } from 'flowbite-svelte';
const { files } = $page.data;
let _registryUrl = '';
let _files = files;
import { Button, Input, Spinner, Toggle, Textarea } from 'flowbite-svelte';
import { registryUrl } from '$lib/stores/registry';
import { getFileRegistry } from './getFileRegistry';
import { onMount } from 'svelte';
import { rawDotrain } from '$lib/stores/raw-dotrain';
let files: { name: string; url: string }[] = [];
let inputDotrain = '';
let error = '';
let errorDetails = '';
let loading = false;
let advancedMode = false;
const getFileRegistry = async (url: string) => {
onMount(() => {
fetchFilesFromRegistry($registryUrl);
});
const fetchFilesFromRegistry = async (url: string) => {
loading = true;
try {
const response = await fetch(url);
const files = await response.text();
_files = files
.split('\n')
.filter((line) => line.trim())
.map((line) => {
const [name, url] = line.split(' ');
return { name, url };
});
files = await getFileRegistry(url);
} catch (e) {
error = 'Error getting registry';
errorDetails = e instanceof Error ? e.message : 'Unknown error';
}
loading = false;
return;
};
const loadStrategy = () => {
if (inputDotrain.trim()) {
files = [];
$rawDotrain = inputDotrain;
inputDotrain = '';
}
};
</script>

<div class="flex flex-col">
<div class="flex h-12 w-full items-center justify-end gap-4">
<div class="flex w-full flex-col">
<div class="flex items-start justify-end gap-4">
{#if advancedMode}
<Input
id="strategy-url"
type="url"
placeholder="Enter URL to raw strategy registry file"
bind:value={_registryUrl}
class="max-w-lg"
/>
<Button on:click={() => getFileRegistry(_registryUrl)}>Load</Button>
<div class="mb-12 flex w-2/3 flex-col items-start gap-4">
<div class="flex w-full items-start gap-4">
<Input
id="strategy-url"
type="url"
placeholder="Enter URL to raw strategy registry file"
bind:value={$registryUrl}
/>
<Button class="text-nowrap" on:click={() => fetchFilesFromRegistry($registryUrl)}>
Load URL
</Button>
</div>
<div class="flex w-full items-start gap-4">
<Textarea
id="textarea-id"
placeholder="Raw strategy"
rows="8"
bind:value={inputDotrain}
/>
<Button class="text-nowrap" on:click={loadStrategy}>Load Strategy</Button>
</div>
</div>
{/if}
<Toggle on:change={() => (advancedMode = !advancedMode)}>
{'Advanced Mode'}
Expand All @@ -55,11 +73,14 @@
{:else if error}
<p>{error}</p>
<p>{errorDetails}</p>
{:else if _files.length > 0}
<div class="flex flex-col gap-36">
{#each _files as { name, url }}
{/if}
{#if files.length > 0}
<div class="mb-36 flex flex-col gap-8">
{#each files as { name, url }}
<StrategySection strategyUrl={url} strategyName={name} />
{/each}
</div>
{:else if $rawDotrain}
<StrategySection rawDotrain={$rawDotrain} strategyName={'raw'} />
{/if}
</div>
Original file line number Diff line number Diff line change
@@ -1,63 +1,62 @@
import { registryUrl } from '$lib/stores/registry';
import { rawDotrain } from '$lib/stores/raw-dotrain';
import { DotrainOrderGui } from '@rainlanguage/orderbook/js_api';
import { get } from 'svelte/store';
import type { PageLoad } from './$types';

export const load = async ({
fetch,
params
}: {
fetch: typeof globalThis.fetch;
params: { strategyName: string; deploymentKey: string };
}) => {
export const load: PageLoad = async ({ fetch, params }) => {
try {
const response = await fetch(
'https://raw.githubusercontent.com/rainlanguage/rain.strategies/refs/heads/main/strategies/dev/registry'
);
const files = await response.text();
const { strategyName, deploymentKey } = params;

const fileList = files
.split('\n')
.filter(Boolean)
.map((line: string) => {
const [name, url] = line.split(' ');
return { name, url };
});
let dotrain;
if (strategyName === 'raw' && get(rawDotrain)) {
dotrain = get(rawDotrain);
} else {
const _registryUrl = get(registryUrl);
const response = await fetch(_registryUrl);
const files = await response.text();

const fileList = files
.split('\n')
.filter(Boolean)
.map((line: string) => {
const [name, url] = line.split(' ');
return { name, url };
});

const strategy = fileList.find((file: { name: string }) => file.name === strategyName);
const strategy = fileList.find((file: { name: string }) => file.name === strategyName);
if (!strategy) {
throw new Error(`Strategy ${strategyName} not found`);
}

if (strategy) {
const dotrainResponse = await fetch(strategy.url);
const dotrain = await dotrainResponse.text();
dotrain = await dotrainResponse.text();
}

const deploymentWithDetails = await DotrainOrderGui.getDeploymentDetails(dotrain);
// Process deployments for both raw and registry strategies
const deploymentWithDetails = await DotrainOrderGui.getDeploymentDetails(dotrain);
const deployments = Array.from(deploymentWithDetails, ([key, details]) => ({
key,
...details
}));

const deployments = Array.from(deploymentWithDetails, ([key, details]) => ({
key,
...details
}));
const deployment = deployments.find(
(deployment: { key: string }) => deployment.key === deploymentKey
);
const deployment = deployments.find(
(deployment: { key: string }) => deployment.key === deploymentKey
);

if (!deployment) {
throw new Error(`Deployment ${deploymentKey} not found`);
}
if (!deployment) {
throw new Error(`Deployment ${deploymentKey} not found`);
}

const { key, name, description } = deployment;
const { key, name, description } = deployment;

return {
dotrain,
strategyName,
key,
name,
description
};
} else {
return {
dotrain: null,
strategyName: null,
deploymentKey: null
};
}
return {
dotrain,
strategyName,
key,
name,
description
};
} catch {
return {
dotrain: null,
Expand Down
62 changes: 62 additions & 0 deletions packages/webapp/src/routes/deploy/getFileRegistry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
export const getFileRegistry = async (url: string) => {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error('Failed to fetch registry.');
}
const filesList = await response.text();
const files = filesList
.split('\n')
.filter((line) => line.trim())
.map((line) => {
const [name, url] = line.split(' ');
return { name, url };
});
if (!files) {
throw new Error('Invalid stategy registry.');
}
return files;
} catch (e) {
throw new Error(e instanceof Error ? e.message : 'Unknown error.');
}
};

if (import.meta.vitest) {
const { describe, it, expect, vi } = import.meta.vitest;

describe('getFileRegistry', () => {
it('should parse registry file content correctly', async () => {
const mockResponse = `file1.js https://example.com/file1.js
file2.js https://example.com/file2.js`;

global.fetch = vi.fn().mockResolvedValue({
ok: true,
text: () => Promise.resolve(mockResponse)
});

const result = await getFileRegistry('https://example.com/registry');
expect(result).toEqual([
{ name: 'file1.js', url: 'https://example.com/file1.js' },
{ name: 'file2.js', url: 'https://example.com/file2.js' }
]);
});

it('should handle failed fetch response', async () => {
global.fetch = vi.fn().mockResolvedValue({
ok: false
});

await expect(getFileRegistry('https://example.com/registry')).rejects.toThrow(
'Failed to fetch registry'
);
});

it('should handle network errors', async () => {
global.fetch = vi.fn().mockRejectedValue(new Error('Network error'));

await expect(getFileRegistry('https://example.com/registry')).rejects.toThrow(
'Network error'
);
});
});
}

0 comments on commit 7edd54f

Please sign in to comment.