Skip to content
Closed
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
8 changes: 7 additions & 1 deletion docs/docs/developers/guides/clone-a-project.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,16 @@ cd <project-name>

<img src = '/img/tutorials/rill-advanced/status.png' class='rounded-gif' />
<br />

If your project is not synced to a GitHub repository, use:
```bash
# Clone from Rill
rill project clone <project-name>
```
If your project is synced to a GitHub repository, use:

```bash
rill start https://github.com/username/rill-project.git
```

## Step 2: Explore the Project Structure

Expand Down
136 changes: 136 additions & 0 deletions web-admin/src/features/projects/status/ProjectClone.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
<script lang="ts">
import { createAdminServiceGetProject } from "@rilldata/web-admin/client";
import Button from "@rilldata/web-common/components/button/Button.svelte";
import Check from "@rilldata/web-common/components/icons/Check.svelte";
import CopyIcon from "@rilldata/web-common/components/icons/CopyIcon.svelte";
import * as Popover from "@rilldata/web-common/components/popover";
import { copyToClipboard } from "@rilldata/web-common/lib/actions/copy-to-clipboard";
import { getGitUrlFromRemote } from "@rilldata/web-common/features/project/deploy/github-utils";

let open = false;

export let organization: string;
export let project: string;

$: proj = createAdminServiceGetProject(organization, project);
$: gitRemote = $proj.data?.project?.gitRemote;
$: managedGitId = $proj.data?.project?.managedGitId;
$: isGithubConnected = !!gitRemote && !managedGitId;
$: githubUrl = gitRemote ? getGitUrlFromRemote(gitRemote) : "";

// CLI commands
$: cloneCommand = `rill project clone ${project}`;
$: rillStartCommand = `rill start ${githubUrl}.git`;
$: envPullCommand = `rill env pull --project ${project}`;

let copiedCommand: string | null = null;

function onCopy(command: string) {
copyToClipboard(command, "Command copied to clipboard", false);
copiedCommand = command;
setTimeout(() => {
copiedCommand = null;
}, 2000);
}
</script>

{#if $proj.data}
<div class="flex flex-col gap-y-1">
<span
class="uppercase text-gray-500 font-semibold text-[10px] leading-none"
>
Local Development
</span>
<Popover.Root bind:open>
<Popover.Trigger asChild let:builder>
<Button type="secondary" builders={[builder]}>Download project</Button>
</Popover.Trigger>

<Popover.Content class="w-[380px]" align="end" sideOffset={8}>
<div class="flex flex-col gap-y-3">
<span class="text-sm text-gray-600">
Clone this project to develop locally.
<a
href="https://docs.rilldata.com/developers/guides/clone-a-project"
target="_blank"
class="text-primary-600"
>
Learn more ->
</a>
</span>

<div class="flex flex-col gap-y-2">
{#if isGithubConnected}
<button
class="command-box"
title={rillStartCommand}
on:click={() => onCopy(rillStartCommand)}
>
<code class="text-xs truncate">{rillStartCommand}</code>
<span class="text-gray-400">
{#if copiedCommand === rillStartCommand}
<Check size="14px" color="#22c55e" />
{:else}
<CopyIcon size="14px" />
{/if}
</span>
</button>

<div class="env-note">
<span class="text-[11px] text-gray-500">
Then pull environment variables:
</span>
<button
class="command-box"
title={envPullCommand}
on:click={() => onCopy(envPullCommand)}
>
<code class="text-[11px] truncate">{envPullCommand}</code>
<span class="text-gray-400">
{#if copiedCommand === envPullCommand}
<Check size="14px" color="#22c55e" />
{:else}
<CopyIcon size="14px" />
{/if}
</span>
</button>
</div>
{:else}
<button
class="command-box"
title={cloneCommand}
on:click={() => onCopy(cloneCommand)}
>
<code class="text-xs truncate">{cloneCommand}</code>
<span class="text-gray-400">
{#if copiedCommand === cloneCommand}
<Check size="14px" color="#22c55e" />
{:else}
<CopyIcon size="14px" />
{/if}
</span>
</button>
{/if}
</div>
</div>
</Popover.Content>
</Popover.Root>
</div>
{/if}

<style lang="postcss">
.command-box {
@apply flex items-center justify-between gap-x-2;
@apply bg-gray-50 border border-gray-200 rounded px-2 py-1;
@apply font-mono text-gray-800 text-left;
@apply cursor-pointer w-full;
}

.command-box:hover {
@apply bg-gray-100;
}

.env-note {
@apply flex flex-col gap-y-1 mt-1 pt-2 border-t border-gray-100;
}
</style>
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<script lang="ts">
import { page } from "$app/stores";
import ContentContainer from "@rilldata/web-admin/components/layout/ContentContainer.svelte";
import ProjectClone from "@rilldata/web-admin/features/projects/status/ProjectClone.svelte";
import ProjectDeploymentStatus from "@rilldata/web-admin/features/projects/status/ProjectDeploymentStatus.svelte";
import ProjectGithubConnection from "@rilldata/web-admin/features/projects/github/ProjectGithubConnection.svelte";
import ProjectParseErrors from "@rilldata/web-admin/features/projects/status/ProjectParseErrors.svelte";
Expand All @@ -10,11 +11,18 @@
$: project = $page.params.project;
</script>

<ContentContainer title="Project status" maxWidth={1100}>
<ContentContainer maxWidth={1100} showTitle={false}>
<div class="flex flex-col gap-y-4 size-full">
<div class="flex gap-x-20 items-start">
<ProjectGithubConnection {organization} {project} />
<ProjectDeploymentStatus {organization} {project} />
<h1 class="text-2xl font-semibold" aria-label="Container title">
Project status
</h1>

<div class="flex flex-wrap justify-between items-start gap-4">
<div class="flex flex-wrap gap-x-20 gap-y-4 items-start">
<ProjectGithubConnection {organization} {project} />
<ProjectDeploymentStatus {organization} {project} />
</div>
<ProjectClone {organization} {project} />
</div>

<ProjectResources />
Expand Down
25 changes: 25 additions & 0 deletions web-admin/tests/projects.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,29 @@ test.describe("Projects", () => {
adminPage.getByRole("link", { name: "Settings" }),
).toBeVisible();
});

test("status page should show Local Development section", async ({
adminPage,
}) => {
await adminPage.goto("/e2e/openrtb/-/status");

// Check Local Development header is visible
await expect(adminPage.getByText("Local Development")).toBeVisible();

// Click the Download project button to open popover
await adminPage.getByRole("button", { name: "Download project" }).click();

// Check Learn more link is visible in popover (filter by surrounding text to avoid ambiguity)
await expect(
adminPage
.locator("span")
.filter({ hasText: "Clone this project to develop locally" })
.getByRole("link", { name: "Learn more ->" }),
).toBeVisible();

// Check clone command is visible (for non-GitHub connected project)
await expect(
adminPage.getByText("rill project clone openrtb"),
).toBeVisible();
});
});
Loading