Skip to content
Open
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
133 changes: 133 additions & 0 deletions src/components/eventConfiguration.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import * as React from "react";
import { Button, SelectMenu, TextInput } from "@primer/components";
import { ChevronDownIcon } from "@primer/octicons-v2-react";
import {
Event,
} from "../github-actions-interpreter";
import { ChangeEvent } from "react";

type EventConfigurationProps = {
event: Event;
resetEventTypeConfiguration: (eventType: string) => void;
setSelectedBranch: (branch: ChangeEvent<HTMLInputElement>) => void;
setSelectedFiles: (files: ChangeEvent<HTMLInputElement>) => void;
setSelectedActionType: (actionType: string) => void;
removeEvent: () => void;
};

export const EventConfiguration: React.FC<EventConfigurationProps> = ({
event,
resetEventTypeConfiguration,
setSelectedBranch,
setSelectedFiles,
setSelectedActionType,
removeEvent,
}) => {
return (
<div className="flex items-center my-3">
<SelectMenu>
<Button as="summary">
Event type: {event.event} <ChevronDownIcon />
</Button>
<SelectMenu.Modal>
<SelectMenu.List>
{["push", "pull_request", "issues"].map((eventType) => (
<SelectMenu.Item
key={eventType}
selected={eventType === event.event}
onClick={() => {
resetEventTypeConfiguration(eventType);
}}
>
{eventType}
</SelectMenu.Item>
))}
</SelectMenu.List>
</SelectMenu.Modal>
</SelectMenu>
{(event.event === "push" || event.event === "pull_request") && (
<>
<TextInput aria-label="Branch name" name="branch-name" placeholder="Branch name" value={event.branch} onChange={setSelectedBranch} className="ml-2" />
<TextInput aria-label="File" name="files" placeholder="Files" value={event.files?.join(", ")} onChange={setSelectedFiles} className="ml-2"/>
</>
)}
{event.event === "pull_request" && (
<SelectMenu className="ml-2">
<Button as="summary">
Action: {event.action} <ChevronDownIcon />
</Button>
<SelectMenu.Modal>
<SelectMenu.List>
{[
"assigned",
"unassigned",
"labeled",
"unlabeled",
"opened",
"edited",
"closed",
"reopened",
"synchronize",
"ready_for_review",
"locked",
"unlocked",
"review_requested",
"review_request_removed"
].map((actionType) => (
<SelectMenu.Item
key={actionType}
selected={actionType === event.action}
onClick={() => {
setSelectedActionType(actionType);
}}
>
{actionType}
</SelectMenu.Item>
))}
</SelectMenu.List>
</SelectMenu.Modal>
</SelectMenu>
)}
{event.event === "issues" && (
<SelectMenu className="ml-2">
<Button as="summary">
Action: {event.action} <ChevronDownIcon />
</Button>
<SelectMenu.Modal>
<SelectMenu.List>
{[
"opened",
"edited",
"deleted",
"transferred",
"pinned",
"unpinned",
"closed",
"reopened",
"assigned",
"unassigned",
"labeled",
"unlabeled",
"locked",
"unlocked",
"milestoned",
"demilestoned",
].map((actionType) => (
<SelectMenu.Item
key={actionType}
selected={actionType === event.action}
onClick={() => {
setSelectedActionType(actionType);
}}
>
{actionType}
</SelectMenu.Item>
))}
</SelectMenu.List>
</SelectMenu.Modal>
</SelectMenu>
)}
<Button className="ml-2" onClick={removeEvent}>-</Button>
</div>
);
};
129 changes: 112 additions & 17 deletions src/pages/playground.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,25 @@ import { PlaygroundWorkflows } from "../playground/workflows";
import { YAMLException } from "js-yaml";
import { useRouter } from "next/router";
import { wait } from "../utils/wait";
import { EventConfiguration } from "../components/eventConfiguration";

const defaultEvents: Event[] = [
{
const defaultEventConfiguration: { [key: string]: Event } = {
push: {
event: "push",
branch: "master",
files: [],
},
];
pull_request: {
event: "pull_request",
branch: "feature-branch",
action: "opened",
files: [],
},
issues: {
event: "issues",
action: "closed",
},
};

const PlaygroundPage: NextPage = () => {
const { query } = useRouter();
Expand All @@ -43,22 +55,35 @@ const PlaygroundPage: NextPage = () => {
console.log(w);
if (w) {
const workflowText = decompressFromEncodedURIComponent(w);
setSelectedWorkflow({
name: "Custom",
workflow: workflowText,
});
setInput(workflowText);
if (workflowText) {
setSelectedWorkflow({
name: "Custom",
workflow: workflowText,
});
setInput(workflowText);
}
}
const e: string | undefined = query.e as string;
console.log(e);
if (e) {
const eventText = decompressFromEncodedURIComponent(e);
if (eventText) {
const event = JSON.parse(eventText);
setEventConfiguration(event);
}
}
}, [query]);

const [selectedWorkflow, setSelectedWorkflow] = React.useState(
PlaygroundWorkflows[0]
);
const [eventConfiguration, setEventConfiguration] = React.useState<Record<number, Event>>({0: defaultEventConfiguration["push"]});
const [input, setInput] = React.useState(selectedWorkflow.workflow);
const [copied, setCopied] = React.useState(false);
const copyContent = React.useCallback(async () => {
const urlContent = compressToEncodedURIComponent(input);
const url = `https://github-actions-hero.now.sh/playground?w=${urlContent}`;
const workflowUrlContent = compressToEncodedURIComponent(input);
const eventUrlContent = compressToEncodedURIComponent(JSON.stringify(eventConfiguration));
const url = `https://github-actions-hero.now.sh/playground?w=${workflowUrlContent}&e=${eventUrlContent}`;
await navigator.clipboard.writeText(url);
setCopied(true);
await wait(2000);
Expand All @@ -71,22 +96,71 @@ const PlaygroundPage: NextPage = () => {
try {
const parsedWorkflow = parse(input);

for (const event of defaultEvents) {
for (const [index, event] of Object.entries(eventConfiguration)) {
const result = run(
event,
`.github/workflows/workflow.yaml`,
parsedWorkflow
);

workflowExecution[event.event] = result;
}
workflowExecution[index] = result;
};

err = undefined;
} catch (e) {
workflowExecution = {};
err = e;
}

const resetEventTypeConfiguration = (index, eventType) => {
const newEventConfiguration = { ...eventConfiguration };
newEventConfiguration[index] = defaultEventConfiguration[eventType];
setEventConfiguration(newEventConfiguration);
}

const setSelectedBranch = (index, changeEvent) => {
const newEventConfiguration = { ...eventConfiguration[index] };
if (newEventConfiguration.event === "pull_request" || newEventConfiguration.event === "push") {
newEventConfiguration.branch = changeEvent.target.value;
const newConfig = { ...eventConfiguration };
newConfig[index] = newEventConfiguration;
setEventConfiguration(newConfig);
}
}

const setSelectedFiles = (index, changeEvent) => {
const newEventConfiguration = { ...eventConfiguration[index] };
if (newEventConfiguration.event === "pull_request" || newEventConfiguration.event === "push") {
newEventConfiguration.files = changeEvent.target.value.split(", ");
const newConfig = { ...eventConfiguration };
newConfig[index] = newEventConfiguration;
setEventConfiguration(newConfig);
}
}

const setSelectedActionType = (index, actionType) => {
const newEventConfiguration = { ...eventConfiguration[index] };
if (newEventConfiguration.event === "pull_request" || newEventConfiguration.event === "issues") {
newEventConfiguration.action = actionType;
const newConfig = { ...eventConfiguration };
newConfig[index] = newEventConfiguration;
setEventConfiguration(newConfig);
}
}

const addEvent = () => {
const newEventConfiguration = { ...eventConfiguration };
const newIndex = Object.keys(newEventConfiguration).length;
newEventConfiguration[newIndex] = defaultEventConfiguration["push"];
setEventConfiguration(newEventConfiguration);
};

const removeEvent = (index) => {
const newEventConfiguration = { ...eventConfiguration };
delete newEventConfiguration[index];
setEventConfiguration(newEventConfiguration);
};

return (
<div className="flex flex-row h-screen">
<div
Expand Down Expand Up @@ -141,14 +215,35 @@ const PlaygroundPage: NextPage = () => {
</div>
</div>

<div className="flex flex-col flex-1">
<div className="flex flex-col">
<DynamicEditor
workflow={selectedWorkflow.workflow}
change={(v) => setInput(v)}
everythingEditable={true}
/>
</div>

<div className="flex items-center my-3">
<div className="flex-1 justify-start">
<h2>Event</h2>
</div>
<div className="flex flex-initial justify-end">
<Button onClick={addEvent}>+</Button>
</div>
</div>

{Object.entries(eventConfiguration).map(([index, event]) => (
<EventConfiguration
key={index}
event={event}
resetEventTypeConfiguration={(eventType) => resetEventTypeConfiguration(index, eventType)}
setSelectedBranch={(branchName => setSelectedBranch(index, branchName))}
setSelectedFiles={files => setSelectedFiles(index, files)}
setSelectedActionType={action => setSelectedActionType(index, action)}
removeEvent={() => removeEvent(index)}
/>
))}

{err && (
<div className="mt-2">
<Flash scheme="red">
Expand All @@ -174,12 +269,12 @@ const PlaygroundPage: NextPage = () => {
</div>

<div className="flex-1 bg-gray-300 p-3 h-screen overflow-auto flex flex-row justify-center flex-wrap">
{defaultEvents.map((event, idx) => (
{Object.entries(eventConfiguration).map(([index, event], idx) => (
<WorkflowExecution
key={event.event}
key={index}
id={idx}
events={[event]}
executionModel={workflowExecution[event.event]}
executionModel={workflowExecution[index]}
/>
))}
</div>
Expand Down
Loading