tutorial step 1
unknown
typescript
3 years ago
10 kB
6
Indexable
import filter from "lodash/filter"; import { Vue3Instance } from "vue/types/v3-component-public-instance"; import { SearchEntityType } from "@/proto/search/search_pb"; import { axii } from "@/assets/icons/icons-svg"; import { findDrawflowNodeByName, waitForElement } from "@/tutorial/index"; //@ts-ignore export const createDraftSteps = async (context: Vue3Instance) => { const svg = document.createElement("div"); svg.classList.add("svg__wrapper"); svg.innerHTML = axii; const paragraph = document.createElement("p"); paragraph.classList.add("content"); paragraph.innerText = "Welcome to Part 1 of AXII Tutorial. In this tutorial we show you the basics of the application: \ how to build and execute a simple ML workflow."; const wrapper = document.createElement("div"); wrapper.appendChild(svg); wrapper.appendChild(paragraph); const nodesMap: { iris: string | null; statistics: string | null } = { iris: null, statistics: null, }; const steps = [ { canClickTarget: false, text: wrapper, classes: "welcome-step", buttons: [context.buttonStart], }, { attachTo: { element: "#drafts-link", on: "right" }, text: "We create the workflow in the Drafts view. Please click here to proceed.", modalOverlayOpeningPadding: 10, advanceOn: { selector: "#drafts-link", event: "click" }, }, { text: "A Draft is a workflow in the 'work in progress' stage.<br /><br />Click on this button to \ start composing your first Draft.", attachTo: { element: "#add-new-draft__btn", on: "left" }, modalOverlayOpeningPadding: 10, advanceOn: { selector: "#add-new-draft__btn", event: "click" }, beforeShowPromise: () => { return new Promise((resolve) => context.resolveIfMounted(resolve, "Drafts")); }, }, { text: "The Draft Editor lets you build workflows in a graphical way.<br /><br />We begin with adding \ a DataSource, which is a static piece of data (e.g. dataset). In this tutorial we use \ the Iris dataset.", beforeShowPromise: () => { return new Promise((resolve) => context.resolveIfMounted(resolve, "Draft")); }, buttons: [context.buttonNext], }, { attachTo: { element: "#draft-editor", on: "top", }, text: "To add it, right click anywhere on the canvas and then click <b>Add DataSource</b>", beforeShowPromise: () => { return new Promise((resolve) => waitForElement("#draft-editor", () => resolve(true))); }, when: { show: () => { waitForElement( `#context-menu-search-bar \ [class~=search-bar-entity-type__${SearchEntityType.SEARCH_ENTITY_TYPE_DATA_SOURCE}]`, () => context.tour.next() ); }, }, }, { attachTo: { element: "#draft-editor", on: "top", }, text: "You should see a search bar and some results. Please start typing <b>Iris</b> \ to find the right one now (it is named <b>Iris Data Set</b>). Click on it when you see it.", beforeShowPromise: () => { return new Promise((resolve) => { waitForElement("div[class=search-bar__wrapper]", () => resolve(true)); }); }, when: { show: () => { const interval = setInterval(() => { const searchedNode = findDrawflowNodeByName(/^Iris Data Set.*/i); if (searchedNode) { nodesMap.iris = (searchedNode as HTMLElement).id; context.tour.next(); clearInterval(interval); } }, 1000); console.debug("base.ts, show", document.activeElement); }, }, }, { attachTo: { element: () => document.querySelector(`#${nodesMap.iris}`), on: "right", }, text: "A block representing the DataSource appeared on the canvas.", modalOverlayOpeningPadding: 10, buttons: [context.buttonNext], }, { attachTo: { element: "#draft-editor", on: "top", }, text: "Next, we add a Task block. Task is something that is executed to process the data.<br /><br />\ Similarly as before, right click on the canvas and then on <b>Add Task</b>.", when: { show: () => { const interval = setInterval(() => { const addDataSourceBtn = filter(document.querySelectorAll(".v-list-item__content"), (node) => { return !!node?.textContent?.includes("Add Task"); }); if (addDataSourceBtn.length > 0) { addDataSourceBtn[0].addEventListener("click", () => { context.tour.next(); }); clearInterval(interval); } }, 1000); }, }, }, { attachTo: { element: "#draft-editor", on: "top", }, text: "Search for <b>Dataset Statistics</b> Task and click on it when you see it.", when: { show: () => { const interval = setInterval(() => { const searchedNode = findDrawflowNodeByName(/^Dataset Statistics.*/i); if (searchedNode) { nodesMap.statistics = (searchedNode as HTMLElement).id; context.tour.next(); clearInterval(interval); } }, 1000); }, }, }, { attachTo: { element: () => document.querySelector(`#${nodesMap.statistics}`), on: "right", }, text: "The Task block appeared on the canvas.<br /><br />We now connect this two blocks to define \ how the data flows between them.", buttons: [context.buttonNext], }, { attachTo: { element: "#draft-editor", on: "top", }, text: "Blocks might have some number of Inputs and Outputs. They are represented by semicircles on the \ edges of the block.<br /><br />Click on the Iris Data Set's output (right edge) and drag it to \ the Dataset Statistics' input (left edge) to create the connection.", when: { show: () => { waitForElement(`.connection.node_out_${nodesMap.iris}.node_in_${nodesMap.statistics}`, () => context.tour.next() ); }, }, }, { attachTo: { element: () => document.querySelector("#draft-name__input"), on: "bottom", }, modalOverlayOpeningPadding: 10, text: "The Draft is almost ready to be executed. Let's give it a meaningful name: <b>Hello AXII</b>.", when: { show: () => { waitForElement( "#draft-name__input", () => context.tour.next(), (el: Element): boolean => { return Boolean((el as HTMLInputElement).value.match(/.*Hello AXII.*/i)); } ); }, }, }, { attachTo: { element: "#submit-btn", on: "left", }, text: "Good to go. The execution of a Draft is called an Experiment. \ Click on this button to submit it for execution.", modalOverlayOpeningPadding: 10, when: { show: () => { const submitBtn = document.querySelector("#submit-btn"); if (submitBtn) { submitBtn.addEventListener("click", () => { const interval = setInterval(() => { const id = document.querySelector(".v-snack__content a")?.textContent; if (id) { clearInterval(interval); context.$router.push(`/experiment/${id}`); context.tour.next(); } }, 1000); }); } }, }, }, { attachTo: { element: "#experiment-state", on: "right", }, text: "Let's wait untill the Experiment is in <b>Done</b> state.", beforeShowPromise: () => { return new Promise((resolve) => { context.resolveIfMounted(resolve, "Experiment"); }); }, when: { show: () => { waitForElement( "#experiment-state", () => context.tour.next(), (el: Element) => { return el.textContent == "Done"; } ); }, }, }, { attachTo: { element: () => document.querySelector(`#${nodesMap.statistics}`), on: "top", }, text: "When the Experiment is finished, we can inspect what outputs (Artifacts) the Task produced.<br /><br />\ Click on the Dataset Statistics node to inspect it.", when: { show: () => { waitForElement("#node-status-viewer", () => context.tour.next()); }, }, }, { attachTo: { element: () => document.querySelector("#node-status-viewer"), on: "left", }, text: "Node preview appeared on the right. You can find there some details about the executed Task and \ the list of generated Artifacts.", buttons: [context.buttonNext], }, { attachTo: { element: "#preview-data-btn", on: "top", }, text: "Click on the Preview button to peek inside the <b>stats_csv</b> artifact.", advanceOn: { selector: "#preview-data-btn", event: "click", }, }, { attachTo: { element: "#preview-dialog", on: "top", }, text: "This is the preview of the CSV file with computed statistics.", buttons: [context.buttonNext], }, { text: "Congratulations, you have just completed Part 1 of the tutorial. You can now explore AXII on \ your own or move on to Part 2, where we show you how you can find and reuse whole Experiments.", buttons: [context.buttonFinish, context.buttonNextTutorial], when: { show: () => { localStorage.setItem(context.tutorialStorageKey, "true"); }, }, }, ]; return steps; };
Editor is loading...