From 1d1a93be4243e300a41204e7340f9e5fb2388a24 Mon Sep 17 00:00:00 2001 From: Mackenzie Date: Wed, 23 Feb 2022 14:20:34 -0800 Subject: [PATCH 1/8] Create RUNBOOK.md --- RUNBOOK.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 RUNBOOK.md diff --git a/RUNBOOK.md b/RUNBOOK.md new file mode 100644 index 00000000..e7d568e0 --- /dev/null +++ b/RUNBOOK.md @@ -0,0 +1,35 @@ +## Overview + + +## Access + + +**Database** + +## Deployment + +### Frontend + +**Configuration** + +**Preview Deployments** + + +### API + +**Configuration** + +**Preview Deployments** + + +### Database + + +## Debugging Deployments + +### Continuous integration + +### Database + +## Local Development + From 79fe86944c94e07356ad9f25685fe3556061ba66 Mon Sep 17 00:00:00 2001 From: Mackenzie Date: Wed, 23 Feb 2022 15:45:03 -0800 Subject: [PATCH 2/8] Adds overview and session gotchas. --- RUNBOOK.md | 76 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 46 insertions(+), 30 deletions(-) diff --git a/RUNBOOK.md b/RUNBOOK.md index e7d568e0..433f672c 100644 --- a/RUNBOOK.md +++ b/RUNBOOK.md @@ -1,35 +1,51 @@ ## Overview +The Flow Playground is an web-based interactive IDE for running Cadence code. +It also provides code for the tutorial projects found here: https://docs.onflow.org/cadence/tutorial/01-first-steps + +The Playground Web App is implemented in React. The major components are as follows: + +- GraphQL / Apollo Client + - All HTTP communication with the Playground API is donce via `GraphQL` using the `Apollo` client. + - The GrpahQL schema is defined by the Playground API here: https://github.com/onflow/flow-playground-api/blob/master/schema.graphql + - This project uses the Apollo clients localStorage interface as well. + - You can view the _local_ GraphQL schema here: https://github.com/onflow/flow-playground/blob/master/src/api/apollo/local.graphql + - CRUD methods (wrapped Apollo client) are implemented here: https://github.com/onflow/flow-playground/blob/master/src/providers/Project/projectMutator.ts + - Typescript typings, and CRUD methods for Apollo are auto-generated using: https://www.graphql-code-generator.com/ + - After making changes to the `schema.local` you'll need to run `npm run graphql:codegen` to auto-generate new typings and methods for Apollo client. + +- Monaco Editor + - The editor interface itself is implemented using https://microsoft.github.io/monaco-editor/ + - The editor component can be found here: https://github.com/onflow/flow-playground/tree/master/src/containers/Editor + - The Cadence language definition (for linting and syntax highlighting) for Monaco can be found here: https://github.com/onflow/flow-playground/blob/master/src/util/cadence.ts + +- Cadence Language Server + - The Cadence Language Server (protocol for Monaco) is implemented in WASM. + - You can read about it here: https://github.com/onflow/cadence/blob/master/languageserver/README.md + - The integration can be found here: + - https://github.com/onflow/flow-playground/blob/master/src/util/language-server.ts + - https://github.com/onflow/flow-playground/blob/master/src/util/language-client.ts + + +### Important Gotcha: User Sessions & Project "Forking" + +_The Playground will not function in browsers where cookies or localStorage are disabled._ + +#### How It Works + +The Playground determines what content to load into the UI based on a url query param named `projectId`. +- When a user first visits the Playground, the `projectId` param is set to `local-project`, indicating that this is a new project and has not been persisted. + - https://github.dev/onflow/flow-playground/blob/2e3323aba9504e6a07fc13d1b2cec0e703edce43/src/util/url.ts#L16-L17 +- At this point, a representation pf the Project _model_ has been boostrapped and persisted to the browser's localStorage using Apollo + - https://github.dev/onflow/flow-playground/blob/2e3323aba9504e6a07fc13d1b2cec0e703edce43/src/providers/Project/projectDefault.ts#L216 + - https://github.dev/onflow/flow-playground/blob/2e3323aba9504e6a07fc13d1b2cec0e703edce43/src/providers/Project/projectHooks.ts#L10-L11 +- When a user performs some action that updates any field in the project, or clicks the save button, the project is read from localStorage, and sent to the API to be persisted. + - https://github.dev/onflow/flow-playground/blob/2e3323aba9504e6a07fc13d1b2cec0e703edce43/src/providers/Project/projectMutator.ts#L54-L55 +- Once the mutation has returned successfully (The project state has been saved to the DB), another local value is set using Apollo/localstorage, to reflect the newly generated project's unique `id` (from the database) + - https://github.dev/onflow/flow-playground/blob/2e3323aba9504e6a07fc13d1b2cec0e703edce43/src/providers/Project/projectMutator.ts#L93-L94 +- The server response also sets a cookie **that links the current browser session with the new project ID** + - This is done so that if a user _shares_ a link to their new project (eg. https://play.onflow.org/46c7136f-803c-4166-9d46-25d8e927114c), to someone without the session cookie linking the ID and browser session, the UI will recognise (the save button becomes "fork") that this is the case, and on subsequent saves of the shared project, _will send a mutation to generate a new project based on the existing contents of the editor, preventing users from overwriting eachothers projects!_ + - The name of the cookie is `flow-playground` -## Access -**Database** - -## Deployment - -### Frontend - -**Configuration** - -**Preview Deployments** - - -### API - -**Configuration** - -**Preview Deployments** - - -### Database - - -## Debugging Deployments - -### Continuous integration - -### Database - -## Local Development - From d2da90cc99d2de1a78006e38a65c48b704034cda Mon Sep 17 00:00:00 2001 From: Mackenzie Date: Wed, 23 Feb 2022 15:46:23 -0800 Subject: [PATCH 3/8] Fixes typo. --- RUNBOOK.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RUNBOOK.md b/RUNBOOK.md index 433f672c..18368f06 100644 --- a/RUNBOOK.md +++ b/RUNBOOK.md @@ -36,7 +36,7 @@ _The Playground will not function in browsers where cookies or localStorage are The Playground determines what content to load into the UI based on a url query param named `projectId`. - When a user first visits the Playground, the `projectId` param is set to `local-project`, indicating that this is a new project and has not been persisted. - https://github.dev/onflow/flow-playground/blob/2e3323aba9504e6a07fc13d1b2cec0e703edce43/src/util/url.ts#L16-L17 -- At this point, a representation pf the Project _model_ has been boostrapped and persisted to the browser's localStorage using Apollo +- At this point, a representation of the `Project` _model_ has been boostrapped and persisted to the browser's localStorage using Apollo - https://github.dev/onflow/flow-playground/blob/2e3323aba9504e6a07fc13d1b2cec0e703edce43/src/providers/Project/projectDefault.ts#L216 - https://github.dev/onflow/flow-playground/blob/2e3323aba9504e6a07fc13d1b2cec0e703edce43/src/providers/Project/projectHooks.ts#L10-L11 - When a user performs some action that updates any field in the project, or clicks the save button, the project is read from localStorage, and sent to the API to be persisted. From 5db63c47beafbeccc85a4b7a1964e832f7dd3ee0 Mon Sep 17 00:00:00 2001 From: Mackenzie Date: Wed, 23 Feb 2022 16:01:12 -0800 Subject: [PATCH 4/8] Adds staging deployment steps. --- RUNBOOK.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/RUNBOOK.md b/RUNBOOK.md index 18368f06..8a01f4c0 100644 --- a/RUNBOOK.md +++ b/RUNBOOK.md @@ -3,6 +3,8 @@ The Flow Playground is an web-based interactive IDE for running Cadence code. It also provides code for the tutorial projects found here: https://docs.onflow.org/cadence/tutorial/01-first-steps +The overall project consists of the Web app (this) and an API backend: https://github.com/onflow/flow-playground-api + The Playground Web App is implemented in React. The major components are as follows: - GraphQL / Apollo Client @@ -26,6 +28,34 @@ The Playground Web App is implemented in React. The major components are as foll - https://github.com/onflow/flow-playground/blob/master/src/util/language-server.ts - https://github.com/onflow/flow-playground/blob/master/src/util/language-client.ts +## Deployment + +### Access + +To create a Playground deployment, your user must: +- Be added to the Flow/Dapper Labs Teamcity account +- Have write access to this repository for triggering Teamcity deploys (details below): https://github.com/dapperlabs/flow-playground +- Be connected to the Office VPN + +A request for these should be filed here: https://dapperlabs.happyfox.com/ + +### Deployment Workflow + +**Staging Deployment** + +Once your PR contribution has been successfully merged into the `master` branch, you must take the following steps: +1) Tag your commit, following [semver](https://semver.org/) conventions eg `git tag v0.42.0` + - To find the current tag use: `git fetch --all && git tag` to display a list of tags. +2) Push your tag to the main branch: `git push origin --tags` +3) To trigger a staging deployment, update the version number here: https://github.com/dapperlabs/flow-playground/blob/master/Makefile#L3 + - Make sure the version number here, matches your new tag, if you want your changes to be deployed. +4) Once updated visit: https://ci.eng.dapperlabs.com/buildConfiguration/Flow_FlowPlayground_FlowTestNetwork_BuildCiCdPlaygroundStaging#all-projects + - Here, you will see your deployment in the queue, and the build log output. +5) If the Teamcity build succeeds your chnges will be available to preview here: https://play.staging.onflow.org + +**Production Deployment** + +// TODO ### Important Gotcha: User Sessions & Project "Forking" From 6f79247a7a6b471b8eba45c7c086f2f289cc1b7f Mon Sep 17 00:00:00 2001 From: Mackenzie Date: Fri, 25 Feb 2022 09:04:04 -0800 Subject: [PATCH 5/8] Add production deployment steps. --- RUNBOOK.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/RUNBOOK.md b/RUNBOOK.md index 8a01f4c0..f37adabf 100644 --- a/RUNBOOK.md +++ b/RUNBOOK.md @@ -55,7 +55,9 @@ Once your PR contribution has been successfully merged into the `master` branch, **Production Deployment** -// TODO +Once a staging deployment has been verified. To move the changes into produciton, navigate to the production pipeline in Teamcity here: https://ci.eng.dapperlabs.com/buildConfiguration/Flow_FlowPlayground_FlowTestNetwork_BuildCiCdPlaygroundProduction#all-projects and click the "Deploy" button in the top right of the table. + +Procuction deployment progress can be viewed here: ### Important Gotcha: User Sessions & Project "Forking" From 33d96e43702246433bc9a1c9ca6d9b6ebbc06a71 Mon Sep 17 00:00:00 2001 From: Mackenzie Date: Fri, 25 Feb 2022 09:07:57 -0800 Subject: [PATCH 6/8] Add link to Notion page per review. --- RUNBOOK.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/RUNBOOK.md b/RUNBOOK.md index f37adabf..c27809cb 100644 --- a/RUNBOOK.md +++ b/RUNBOOK.md @@ -57,7 +57,12 @@ Once your PR contribution has been successfully merged into the `master` branch, Once a staging deployment has been verified. To move the changes into produciton, navigate to the production pipeline in Teamcity here: https://ci.eng.dapperlabs.com/buildConfiguration/Flow_FlowPlayground_FlowTestNetwork_BuildCiCdPlaygroundProduction#all-projects and click the "Deploy" button in the top right of the table. -Procuction deployment progress can be viewed here: +Procuction deployment progress can be viewed here: https://ci.eng.dapperlabs.com/buildConfiguration/Flow_FlowPlayground_FlowTestNetwork_BuildCiCdPlaygroundProduction#all-projects + +**Deployment Guide Notion Doc**: + +More details and screenshots regarding the deployment process can be found here. +https://www.notion.so/dapperlabs/Flow-Playground-Deployment-Process-6ca452adb63a4b41bbe5f3b56eda7021 ### Important Gotcha: User Sessions & Project "Forking" From fb85fae39edb059e9c7d6115264f3a6e2471ee4a Mon Sep 17 00:00:00 2001 From: Peter Siemens Date: Thu, 14 Apr 2022 13:47:45 -0700 Subject: [PATCH 7/8] Update runbook with Vercel information --- README.md | 23 ++++++++++++++--------- RUNBOOK.md | 14 +++++++------- vercel-deployment.png | Bin 0 -> 59400 bytes 3 files changed, 21 insertions(+), 16 deletions(-) create mode 100644 vercel-deployment.png diff --git a/README.md b/README.md index 697c92a8..7075fc14 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ -# Welcome +# Flow Playground -The Flow Playground is the best way to learn and try Cadence. For newcomers to Flow -the [Flow Developer Documentation](https://docs.onflow.org) has a guide on how to use the Playground. +The Flow Playground is the best way to learn and try Cadence. For newcomers to Flow, +the [Flow Developer Documentation](https://docs.onflow.org) includes a guide on how to use the Playground. ## Philosophy @@ -14,27 +14,28 @@ We built the Flow Playground as a static website or typical "JAM stack" website - Fast build and deploy cycles - We want to maximize the amount of potential contributions -### What Is the Playground? +### What is the Playground? We want the Playground to have features that help you build on Flow. We also want to balance functionality with learning. + The Playground is a learning tool first and an awesome development tool second, although the two go hand-in-hand. ## Contributing -### Read the [Contribution Guidelines](https://github.com/onflow/flow-playground/blob/master/CONTRIBUTING.md) +### Read the [Contribution Guidelines](CONTRIBUTING.md) -### Git workflow: +### Git Workflow - Use merge squashing, not commit merging [eg. here](https://blog.dnsimple.com/2019/01/two-years-of-squash-merge/). Squash merge is your friend. -- The master branch is the base branch, there is no dedicated development branch +- The `staging` branch is the base branch and contains the code deployed at https://play.staging.onflow.org. -# Developing +## Developing ### Pre-requisites You'll need to have Docker installed to develop. -## Installation +### Installation Clone the repo @@ -89,3 +90,7 @@ If you are using VSCode, you can use this debugging config (works with workspace ] } ``` + +## Deployment + +The runbook contains details on [how to deploy the Flow Playground web app](RUNBOOK.md). diff --git a/RUNBOOK.md b/RUNBOOK.md index c27809cb..97b99160 100644 --- a/RUNBOOK.md +++ b/RUNBOOK.md @@ -1,20 +1,20 @@ ## Overview -The Flow Playground is an web-based interactive IDE for running Cadence code. +The Flow Playground is a web-based interactive IDE for running Cadence code. It also provides code for the tutorial projects found here: https://docs.onflow.org/cadence/tutorial/01-first-steps -The overall project consists of the Web app (this) and an API backend: https://github.com/onflow/flow-playground-api +The overall project consists of the web app (this) and an [API backend](https://github.com/onflow/flow-playground-api). The Playground Web App is implemented in React. The major components are as follows: - GraphQL / Apollo Client - - All HTTP communication with the Playground API is donce via `GraphQL` using the `Apollo` client. - - The GrpahQL schema is defined by the Playground API here: https://github.com/onflow/flow-playground-api/blob/master/schema.graphql - - This project uses the Apollo clients localStorage interface as well. + - All HTTP communication with the Playground API is done via `GraphQL` using the `Apollo` client. + - The GraphQL schema is defined by the Playground API here: https://github.com/onflow/flow-playground-api/blob/master/schema.graphql + - This project uses Apollo Client's `localStorage` interface as well. - You can view the _local_ GraphQL schema here: https://github.com/onflow/flow-playground/blob/master/src/api/apollo/local.graphql - CRUD methods (wrapped Apollo client) are implemented here: https://github.com/onflow/flow-playground/blob/master/src/providers/Project/projectMutator.ts - - Typescript typings, and CRUD methods for Apollo are auto-generated using: https://www.graphql-code-generator.com/ - - After making changes to the `schema.local` you'll need to run `npm run graphql:codegen` to auto-generate new typings and methods for Apollo client. + - TypeScript typings and CRUD methods for Apollo are auto-generated using: https://www.graphql-code-generator.com/ + - After making changes to the `schema.local` you will need to run `npm run graphql:codegen` to auto-generate new typings and methods for Apollo Client. - Monaco Editor - The editor interface itself is implemented using https://microsoft.github.io/monaco-editor/ diff --git a/vercel-deployment.png b/vercel-deployment.png new file mode 100644 index 0000000000000000000000000000000000000000..e513b8c4ecb6c445be6f99bf31a690d3c4b46753 GIT binary patch literal 59400 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 Date: Thu, 14 Apr 2022 13:51:10 -0700 Subject: [PATCH 8/8] Update RUNBOOK.md --- RUNBOOK.md | 98 +++++++++++++++++++++++++++--------------------------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/RUNBOOK.md b/RUNBOOK.md index 97b99160..7c286305 100644 --- a/RUNBOOK.md +++ b/RUNBOOK.md @@ -1,74 +1,77 @@ ## Overview The Flow Playground is a web-based interactive IDE for running Cadence code. -It also provides code for the tutorial projects found here: https://docs.onflow.org/cadence/tutorial/01-first-steps +It also provides an environment for the [Cadence intro tutorials](https://docs.onflow.org/cadence/tutorial/01-first-steps). The overall project consists of the web app (this) and an [API backend](https://github.com/onflow/flow-playground-api). The Playground Web App is implemented in React. The major components are as follows: -- GraphQL / Apollo Client - - All HTTP communication with the Playground API is done via `GraphQL` using the `Apollo` client. - - The GraphQL schema is defined by the Playground API here: https://github.com/onflow/flow-playground-api/blob/master/schema.graphql - - This project uses Apollo Client's `localStorage` interface as well. - - You can view the _local_ GraphQL schema here: https://github.com/onflow/flow-playground/blob/master/src/api/apollo/local.graphql - - CRUD methods (wrapped Apollo client) are implemented here: https://github.com/onflow/flow-playground/blob/master/src/providers/Project/projectMutator.ts - - TypeScript typings and CRUD methods for Apollo are auto-generated using: https://www.graphql-code-generator.com/ - - After making changes to the `schema.local` you will need to run `npm run graphql:codegen` to auto-generate new typings and methods for Apollo Client. - -- Monaco Editor - - The editor interface itself is implemented using https://microsoft.github.io/monaco-editor/ - - The editor component can be found here: https://github.com/onflow/flow-playground/tree/master/src/containers/Editor - - The Cadence language definition (for linting and syntax highlighting) for Monaco can be found here: https://github.com/onflow/flow-playground/blob/master/src/util/cadence.ts - -- Cadence Language Server - - The Cadence Language Server (protocol for Monaco) is implemented in WASM. - - You can read about it here: https://github.com/onflow/cadence/blob/master/languageserver/README.md - - The integration can be found here: - - https://github.com/onflow/flow-playground/blob/master/src/util/language-server.ts - - https://github.com/onflow/flow-playground/blob/master/src/util/language-client.ts +### GraphQL / Apollo Client + +- All HTTP communication with the Playground API is done via `GraphQL` using the `Apollo` client. +- The GraphQL schema is defined by the Playground API in [schemal.graphql](https://github.com/onflow/flow-playground-api/blob/master/schema.graphql) + - This project uses Apollo Client's `localStorage` interface as well. + - You can view the _local_ GraphQL schema in [local.graphql](src/api/apollo/local.graphql). +- CRUD methods (wrapped Apollo client) are implemented in [projectMutator.ts](src/providers/Project/projectMutator.ts). +- TypeScript typings and CRUD methods for Apollo are auto-generated using [GraphQL Code Generator](https://www.graphql-code-generator.com/). +- After making changes to the `schema.local` you will need to run `npm run graphql:codegen` to auto-generate new typings and methods for Apollo Client. + +### Monaco Editor + +- The editor interface itself is implemented using [Monaco Editor](https://microsoft.github.io/monaco-editor/). +- The editor component can be found here: https://github.com/onflow/flow-playground/tree/master/src/containers/Editor +- The Cadence language definition (for linting and syntax highlighting) for Monaco can be found here: https://github.com/onflow/flow-playground/blob/master/src/util/cadence.ts + +### Cadence Language Server + +- The Cadence Language Server (protocol for Monaco) is implemented in Goland and compiled to WASM. + - The WASM bundle is built from [source files in the Cadence repository](https://github.com/onflow/cadence/tree/master/npm-packages/cadence-language-server) and [published on npm](https://www.npmjs.com/package/@onflow/cadence-language-server). +- You can read more about the Cadence Language Server in the [Cadence repository](https://github.com/onflow/cadence/blob/master/languageserver/README.md). +- The Playground integration can be found here: + - Server: https://github.com/onflow/flow-playground/blob/master/src/util/language-server.ts + - Client: https://github.com/onflow/flow-playground/blob/master/src/util/language-client.ts ## Deployment -### Access +The Playground Web App is deployed to [Vercel](https://vercel.com). You will see a link to join the Flow Vercel team when you open your first PR. You must be a member of the team to trigger deployments. + +### Staging Deployment + +URL: https://play.staging.onflow.org -To create a Playground deployment, your user must: -- Be added to the Flow/Dapper Labs Teamcity account -- Have write access to this repository for triggering Teamcity deploys (details below): https://github.com/dapperlabs/flow-playground -- Be connected to the Office VPN +The Playground Web App is deployed to https://play.staging.onflow.org each time a new commit is pushed to the `staging` branch on this repository. -A request for these should be filed here: https://dapperlabs.happyfox.com/ +1. Open a new pull request and select `staging` as the base branch. Vercel will trigger a new deployment once the PR is approved and merged. -### Deployment Workflow +2. Vercel will then report the deployment status on the `staging` branch: -**Staging Deployment** +![vercel-deployment](vercel-deployment.png) -Once your PR contribution has been successfully merged into the `master` branch, you must take the following steps: -1) Tag your commit, following [semver](https://semver.org/) conventions eg `git tag v0.42.0` - - To find the current tag use: `git fetch --all && git tag` to display a list of tags. -2) Push your tag to the main branch: `git push origin --tags` -3) To trigger a staging deployment, update the version number here: https://github.com/dapperlabs/flow-playground/blob/master/Makefile#L3 - - Make sure the version number here, matches your new tag, if you want your changes to be deployed. -4) Once updated visit: https://ci.eng.dapperlabs.com/buildConfiguration/Flow_FlowPlayground_FlowTestNetwork_BuildCiCdPlaygroundStaging#all-projects - - Here, you will see your deployment in the queue, and the build log output. -5) If the Teamcity build succeeds your chnges will be available to preview here: https://play.staging.onflow.org +### Production Deployment -**Production Deployment** +URL: https://play.onflow.org -Once a staging deployment has been verified. To move the changes into produciton, navigate to the production pipeline in Teamcity here: https://ci.eng.dapperlabs.com/buildConfiguration/Flow_FlowPlayground_FlowTestNetwork_BuildCiCdPlaygroundProduction#all-projects and click the "Deploy" button in the top right of the table. +Once a staging deployment has been verified, you can promote the changes to production. -Procuction deployment progress can be viewed here: https://ci.eng.dapperlabs.com/buildConfiguration/Flow_FlowPlayground_FlowTestNetwork_BuildCiCdPlaygroundProduction#all-projects +The Playground Web App is deployed to https://play.onflow.org each time a new commit is pushed to the `production` branch on this repository. -**Deployment Guide Notion Doc**: +1. Open a new pull request and select `production` as the base branch and `staging` as the source branch. Production deployments should always deploy the same code that is already live in staging. Vercel will trigger a new deployment once the PR is approved and merged. -More details and screenshots regarding the deployment process can be found here. -https://www.notion.so/dapperlabs/Flow-Playground-Deployment-Process-6ca452adb63a4b41bbe5f3b56eda7021 +2. Vercel will then report the deployment status on the `production` branch: -### Important Gotcha: User Sessions & Project "Forking" +![vercel-deployment](vercel-deployment.png) + +## Additional Details + +More details and screenshots regarding the deployment process [can be found on Notion]( +https://www.notion.so/dapperlabs/Flow-Playground-Deployment-Process-6ca452adb63a4b41bbe5f3b56eda7021). + +## Important Gotcha: User Sessions & Project "Forking" _The Playground will not function in browsers where cookies or localStorage are disabled._ -#### How It Works +### How It Works The Playground determines what content to load into the UI based on a url query param named `projectId`. - When a user first visits the Playground, the `projectId` param is set to `local-project`, indicating that this is a new project and has not been persisted. @@ -83,6 +86,3 @@ The Playground determines what content to load into the UI based on a url query - The server response also sets a cookie **that links the current browser session with the new project ID** - This is done so that if a user _shares_ a link to their new project (eg. https://play.onflow.org/46c7136f-803c-4166-9d46-25d8e927114c), to someone without the session cookie linking the ID and browser session, the UI will recognise (the save button becomes "fork") that this is the case, and on subsequent saves of the shared project, _will send a mutation to generate a new project based on the existing contents of the editor, preventing users from overwriting eachothers projects!_ - The name of the cookie is `flow-playground` - - -