From 5120630036e9fe0dcf6f183d6964dc5c1e985ded Mon Sep 17 00:00:00 2001 From: tbedford Date: Fri, 12 Apr 2024 16:09:54 +0100 Subject: [PATCH 01/12] [wip] - rework cli build pipeline tutorial --- docs/get-started/build-cli.md | 92 ------------------------- docs/get-started/cli-add-destination.md | 3 + docs/get-started/cli-add-source.md | 13 ++++ docs/get-started/cli-add-transform.md | 75 ++++++++++++++++++++ docs/get-started/cli-create-project.md | 47 +++++++++++++ docs/get-started/cli-sync-to-cloud.md | 46 +++++++++++++ docs/get-started/process.md | 2 +- docs/get-started/welcome.md | 2 +- mkdocs.yml | 10 ++- 9 files changed, 194 insertions(+), 96 deletions(-) delete mode 100644 docs/get-started/build-cli.md create mode 100644 docs/get-started/cli-add-destination.md create mode 100644 docs/get-started/cli-add-source.md create mode 100644 docs/get-started/cli-add-transform.md create mode 100644 docs/get-started/cli-create-project.md create mode 100644 docs/get-started/cli-sync-to-cloud.md diff --git a/docs/get-started/build-cli.md b/docs/get-started/build-cli.md deleted file mode 100644 index e0b14cc7..00000000 --- a/docs/get-started/build-cli.md +++ /dev/null @@ -1,92 +0,0 @@ -# Build a pipeline using Quix CLI - -In previous sections of the documentation you explored using Quix Streams. You now continue on your command-line journey by installing the Quix CLI, and then using it to connect with Quix Cloud. You create a simple project on the command line, and sync it with your Quix Cloud pipeline view. - -## Step 1: Install Quix CLI - -``` -curl -fsSL https://github.com/quixio/quix-cli/raw/main/install.sh | sudo bash -``` - -For further details on installation, including instructions for Microsoft Windows, see the [install guide](https://github.com/quixio/quix-cli?tab=readme-ov-file#installation-of-quix-cli){target=_blank}. - -## Step 2: Sign up to Quix Cloud for free - -Sign up [here](https://portal.platform.quix.io/self-sign-up){target=_blank}. - -!!! tip - - If you are prompted to create a project, you can stop at this point, and proceed to the next step in this tutorial. You will come back to complete the project creation wizard at a later step, because you are going to base your Quix project on a Git project you are yet to create. - -## Step 3: Log in using the CLI - -``` -quix login -``` - -If you're not logged into Cloud, you'll be prompted to log in. - -## Step 4: Create a Git repository - -Create a Git repo where you can store your files, for example you could use GitHub. Create a repo initialized with a `README.md` file, so it can be cloned more easily. - -## Step 5: Clone your Git repo into your local project directory - -For example, if your GitHub repo is named `cli-app`: - -``` -git clone /cli-app -cd cli-app -``` - -## Step 6: Initialize your project as a Quix project - -In your Git project directory, enter: - -``` -quix local init -``` - -This initializes your Quix project with a `quix.yaml` file, which describes your Quix project. - - -## Step 7: Create your application locally - -Now create a sample application: - -``` -quix local app create starter-transformation -``` - -This creates a starter transformation for you. You can explore the files created locally for you. The `main.py` code will look familiar to you if you've tried the [previous sections](./welcome.md) of the documentation. - - -## Step 8: Sync your application - -To sync your application, change into the `Starter transformation` directory and enter: - -``` -quix local deploy --push --sync -``` - -This updates your `quix.yaml` project file, and pushes all changes to your Git repository. - -## Step 9: In Quix Cloud create a project - -In this step you create a project in Quix Cloud from your Git repository. - -1. Return to Quix Cloud. -2. Select `Quix advanced configuration` to continue creation of your project. -3. Select your Git provider. -4. Link the project to your Git repository using the guide provided for your chosen Git provider. -4. Sync Quix Cloud to your project by clicking the `Sync environment` button. - -## Step 10: See your pipeline running - -Go to pipeline view, and see your pipeline running, with your Starter transformation. - -![Pipeline running](../images/starter-transform.png) - -## Next steps - -* [Read the Quix CLI documentation](../kb/cli.md). diff --git a/docs/get-started/cli-add-destination.md b/docs/get-started/cli-add-destination.md new file mode 100644 index 00000000..bb292268 --- /dev/null +++ b/docs/get-started/cli-add-destination.md @@ -0,0 +1,3 @@ +# Add destination + +TBD \ No newline at end of file diff --git a/docs/get-started/cli-add-source.md b/docs/get-started/cli-add-source.md new file mode 100644 index 00000000..aa46bbf7 --- /dev/null +++ b/docs/get-started/cli-add-source.md @@ -0,0 +1,13 @@ +# Add a source + +Now create a sample application. In this case you'll first add a data source. In your project directory enter the following command: + +``` +quix local app create +``` + +You will be prompted to select a library item using the interactive menu. Select `Source` and then `Demo Data`. This will give you a source that generates F1 racing car data from a CSV file. Give the application a suitable name, such as `F1 demo data`. + +## Next step + +* [Add a transform](./cli-add-transform.md) diff --git a/docs/get-started/cli-add-transform.md b/docs/get-started/cli-add-transform.md new file mode 100644 index 00000000..150fa872 --- /dev/null +++ b/docs/get-started/cli-add-transform.md @@ -0,0 +1,75 @@ +# Add a transform + +Now add a transform: + +``` +quix local app create starter-transformation +``` + +This creates a starter transformation for you. Alternatively, you could type `quix local app create` and then interactively select the starter transform. You saw an example of this when adding the demo data source. + +Now, you'll modify the starter transform code to do something more useful. Let's say you want to calculate the average speed from the race car. You could do that with a tumbling window with a time window of say 30 seconds: + +``` python +import os +from quixstreams import Application +from datetime import timedelta + +# for local dev, load env vars from a .env file +from dotenv import load_dotenv +load_dotenv() + +# create a Quix Streams application +app = Application() + +# JSON deserializers/serializers used by default +input_topic = app.topic(os.environ["input"]) +output_topic = app.topic(os.environ["output"]) + +# consume from input topic +sdf = app.dataframe(input_topic) + +# calculate average speed using a 30 second tumbling window +sdf = sdf.apply(lambda row: row["Speed"]) \ + .tumbling_window(timedelta(seconds=30)).mean().final() \ + .apply(lambda value: { + 'average-speed': value['value'], + 'time': value['end'] + }) + +# print every row +sdf = sdf.update(lambda row: print(row)) + +# publish to output topic +sdf = sdf.to_topic(output_topic) + +if __name__ == "__main__": + app.run(sdf) +``` + +Now take a look at the `app.yaml` file for your transform: + +``` json +name: transformer +language: Python +variables: + - name: input + inputType: InputTopic + description: Name of the input topic to listen to. + defaultValue: csv-data + required: false + - name: output + inputType: OutputTopic + description: Name of the output topic to write to. + defaultValue: transform + required: false +dockerfile: dockerfile +runEntryPoint: main.py +defaultFile: main.py +``` + +Note that the input topic is `csv-data`, but you need to change that to `f1-data`. + +To do that... + +Make sure you use `--override-with-default-values` diff --git a/docs/get-started/cli-create-project.md b/docs/get-started/cli-create-project.md new file mode 100644 index 00000000..a578bf10 --- /dev/null +++ b/docs/get-started/cli-create-project.md @@ -0,0 +1,47 @@ +--- +title: Create a project +description: You install the Quix CLI and create a simple project, with a pipeline consisting of one data source application, which you then sync up with Quix Cloud. +--- + +# Create a project + +In previous sections of the documentation you explored using Quix Streams. You now continue your journey on the command line by installing the Quix CLI, and then using it to connect with Quix Cloud. From your Git repository, you create a simple project on the command line, add a data source application, and then sync it with your Quix Cloud pipeline view. + +!!! tip + + If you'd rather use the cloud, sign up to [Quix Cloud for free](https://portal.platform.quix.io/self-sign-up){target=_blank}, and then build a stream processing pipeline with Quix Streams and Quix Cloud in under ten minutes. + +## Step 1: Create a Git repository + +Create a Git repo where you can store your files, for example you could use GitHub. Create a repo initialized with a `README.md` file, so it can be cloned more easily. + +## Step 2: Clone your Git repo into your local project directory + +For example, if your GitHub repo is named `cli-app`: + +``` +git clone /cli-app +cd cli-app +``` + +## Step 3: Install Quix CLI + +``` +curl -fsSL https://github.com/quixio/quix-cli/raw/main/install.sh | sudo bash +``` + +For further details on installation, including instructions for Microsoft Windows, see the [install guide](https://github.com/quixio/quix-cli?tab=readme-ov-file#installation-of-quix-cli){target=_blank}. + +## Step 4: Initialize your project as a Quix project + +In your Git project directory, enter: + +``` +quix local init +``` + +This initializes your Quix project with a `quix.yaml` file, which describes your Quix project. + +## Next step + +* [Add a source](./cli-add-source.md) diff --git a/docs/get-started/cli-sync-to-cloud.md b/docs/get-started/cli-sync-to-cloud.md new file mode 100644 index 00000000..bbc91255 --- /dev/null +++ b/docs/get-started/cli-sync-to-cloud.md @@ -0,0 +1,46 @@ +# Sync to Quix Cloud + +## Step 1: Sign up to Quix Cloud for free + +Sign up [here](https://portal.platform.quix.io/self-sign-up){target=_blank}. + +When you log into Quix Cloud, you'll be prompted to create a project. + +## Step 2: In Quix Cloud create a project + +In this step you create a project in Quix Cloud based on your Git repository. + +1. Select `Quix advanced configuration` to continue creation of your project. +2. Select your Git provider (for example, GitHub). +3. Link the project to your Git repository using the guide provided for your chosen Git provider. +4. Use PROD for your environment, and make sure the main branch is selected. + +If you need help on creating a project, you can [read the documentation](../create/create-project.md). + +When you've created the project, switch back to the command line. + + +## Step 3: Log in using the CLI + +Log into Quix Cloud using the CLI using the following command: + +``` +quix login +``` + +If you're not logged into Cloud, you'll be prompted to log in. + +## Step 4: Sync your application + +To sync your application, change into the `F1 demo data` directory and enter: + +``` +quix local deploy --push --sync +``` + +This updates your `quix.yaml` project file, and pushes all changes to your Git repository. + +## Step 5: See your pipeline running + +In Quix Cloud, go to pipeline view, and see your pipeline running, with your F1 demo data source running. + diff --git a/docs/get-started/process.md b/docs/get-started/process.md index 3f5f166a..ff1ab965 100644 --- a/docs/get-started/process.md +++ b/docs/get-started/process.md @@ -83,4 +83,4 @@ You'll notice the messages in the topic are in the JSON format. ## Next step -* [Build a pipeline](./build-cli.md) - build a pipeline using the Quix CLI. +* [Build a pipeline](./cli-create-project.md) - build a pipeline using the Quix CLI. diff --git a/docs/get-started/welcome.md b/docs/get-started/welcome.md index 48ca54a5..f588abfd 100644 --- a/docs/get-started/welcome.md +++ b/docs/get-started/welcome.md @@ -21,7 +21,7 @@ description: Welcome to the Quix Developer documentation. This documentation inc --- - You can [sign up for free](https://portal.platform.quix.io/self-sign-up){target=_blank}, and then build a stream processing pipeline with Quix Streams and Quix Cloud in under ten minutes. + You can sign up to [Quix Cloud for free](https://portal.platform.quix.io/self-sign-up){target=_blank}, and then build a stream processing pipeline with Quix Streams and Quix Cloud in under ten minutes. [Quix Cloud Quickstart :octicons-arrow-right-24:](../quix-cloud/quickstart.md) diff --git a/mkdocs.yml b/mkdocs.yml index 23877ef3..1a41babe 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -25,7 +25,13 @@ nav: - 'Produce data': 'get-started/produce.md' - 'Consume data': 'get-started/consume.md' - 'Process data': 'get-started/process.md' - - 'Build a pipeline': 'get-started/build-cli.md' + - 'Build a pipeline': + - 'Create a project': 'get-started/cli-create-project.md' + - 'Add a source': 'get-started/cli-add-source.md' + - 'Add a transform': 'get-started/cli-add-transform.md' + - 'Add a destination': 'get-started/cli-add-destination.md' + - 'Sync to Cloud': 'get-started/cli-sync-to-cloud.md' + # Mostly out of date # - 'Project templates': 'get-started/project-templates.md' - 'Quix Streams': '!import https://github.com/quixio/quix-streams?branch=main' @@ -328,7 +334,7 @@ plugins: 'get-started/what-is-kafka.md': 'kb/what-is-kafka.md' 'get-started/glossary.md': 'kb/glossary.md' 'get-started/contribute.md': 'kb/contribute.md' - + 'get-started/build-cli.md' : 'get-started/cli-create-project.md' theme: name: 'material' From c6911175b0855ecdfc7870c8ccfa3cf5350e44f4 Mon Sep 17 00:00:00 2001 From: tbedford Date: Mon, 15 Apr 2024 11:23:16 +0100 Subject: [PATCH 02/12] [wip] - add overview --- docs/get-started/cli-build-pipeline.md | 13 +++++++++++++ mkdocs.yml | 1 + 2 files changed, 14 insertions(+) create mode 100644 docs/get-started/cli-build-pipeline.md diff --git a/docs/get-started/cli-build-pipeline.md b/docs/get-started/cli-build-pipeline.md new file mode 100644 index 00000000..ca1e7a10 --- /dev/null +++ b/docs/get-started/cli-build-pipeline.md @@ -0,0 +1,13 @@ +# Build a pipeline using the Quix CLI + +In this tutorial you'll build a simple pipeline using the Quix CLI. The steps are: + +1. **Create a project** - you create your Git project. +2. **Add a source** - you add a demo data source. +3. **Add a transform** - you add a transform and perform some simple processing. +4. **Add a destination** - you add a simple destination. +5. **Sync to Quix Cloud** - you synchronize you CLI project with Quix Cloud. + +## Next step + +* [Create a project](./cli-create-project.md) diff --git a/mkdocs.yml b/mkdocs.yml index 1a41babe..f9edf344 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -26,6 +26,7 @@ nav: - 'Consume data': 'get-started/consume.md' - 'Process data': 'get-started/process.md' - 'Build a pipeline': + - 'Overview': 'get-started/cli-build-pipeline.md' - 'Create a project': 'get-started/cli-create-project.md' - 'Add a source': 'get-started/cli-add-source.md' - 'Add a transform': 'get-started/cli-add-transform.md' From 2a4d3db4c6146b29cd65c06c6190fbd6afd381af Mon Sep 17 00:00:00 2001 From: tbedford Date: Mon, 15 Apr 2024 13:30:11 +0100 Subject: [PATCH 03/12] [wip] - expand material --- docs/get-started/cli-add-destination.md | 14 +++++++++++++- docs/get-started/cli-add-transform.md | 24 ++++++++++++++++++------ docs/get-started/cli-sync-to-cloud.md | 11 +++++++++-- docs/images/cli-pipeline.png | Bin 0 -> 26942 bytes 4 files changed, 40 insertions(+), 9 deletions(-) create mode 100644 docs/images/cli-pipeline.png diff --git a/docs/get-started/cli-add-destination.md b/docs/get-started/cli-add-destination.md index bb292268..ef31b8ba 100644 --- a/docs/get-started/cli-add-destination.md +++ b/docs/get-started/cli-add-destination.md @@ -1,3 +1,15 @@ # Add destination -TBD \ No newline at end of file +Now add a destination using the CLI: + +``` +quix local app create starter-destination +``` + +This creates a starter destination for you. Alternatively, you could type `quix local app create` and then interactively select the starter destination. You saw an example of this when adding the demo data source. You can call the destination `destination`, or any other name you like. + +You are now ready to synchronize everything with Quix Cloud, and run your complete pipeline as a set of dockerized services in a cluster managed by Kubernetes, with nothing more than a single command. This is described in the next step. + +## Next step + +* [Sync to Cloud](./cli-sync-to-cloud.md) diff --git a/docs/get-started/cli-add-transform.md b/docs/get-started/cli-add-transform.md index 150fa872..d0019478 100644 --- a/docs/get-started/cli-add-transform.md +++ b/docs/get-started/cli-add-transform.md @@ -1,12 +1,14 @@ # Add a transform -Now add a transform: +Now add a transform using the CLI: ``` quix local app create starter-transformation ``` -This creates a starter transformation for you. Alternatively, you could type `quix local app create` and then interactively select the starter transform. You saw an example of this when adding the demo data source. +This creates a starter transformation for you. Alternatively, you could type `quix local app create` and then interactively select the starter transform. You saw an example of this when adding the demo data source. You can call the transform `transform`, or any other name you like. + +## Modify the transform code Now, you'll modify the starter transform code to do something more useful. Let's say you want to calculate the average speed from the race car. You could do that with a tumbling window with a time window of say 30 seconds: @@ -49,7 +51,7 @@ if __name__ == "__main__": Now take a look at the `app.yaml` file for your transform: -``` json +``` yaml name: transformer language: Python variables: @@ -68,8 +70,18 @@ runEntryPoint: main.py defaultFile: main.py ``` -Note that the input topic is `csv-data`, but you need to change that to `f1-data`. +Note that the input topic is `csv-data`, but you need to change that to `f1-data`. Edit the `app.yaml` file so that the input topic section is as follows: + +``` yaml + - name: input + inputType: InputTopic + description: Name of the input topic to listen to. + defaultValue: csv-data + required: false +``` + +Save your changes and proceed to the next step. -To do that... +## Next step -Make sure you use `--override-with-default-values` +* [Add a destination](./cli-add-destination.md) diff --git a/docs/get-started/cli-sync-to-cloud.md b/docs/get-started/cli-sync-to-cloud.md index bbc91255..4ff2e902 100644 --- a/docs/get-started/cli-sync-to-cloud.md +++ b/docs/get-started/cli-sync-to-cloud.md @@ -35,12 +35,19 @@ If you're not logged into Cloud, you'll be prompted to log in. To sync your application, change into the `F1 demo data` directory and enter: ``` -quix local deploy --push --sync +quix local deploy --push --sync --override-with-default-values ``` -This updates your `quix.yaml` project file, and pushes all changes to your Git repository. +This updates your `quix.yaml` project file, and pushes all changes to your Git repository. This also makes sure your Quix environment is synched with the corresponding Git repository, and that your changes to default values in the local `app.yaml` files are also reflected in the Quix environment. ## Step 5: See your pipeline running In Quix Cloud, go to pipeline view, and see your pipeline running, with your F1 demo data source running. +![CLI pipeline](../images/cli-pipeline.png) + +## Next steps + +* []() +* []() +* []() diff --git a/docs/images/cli-pipeline.png b/docs/images/cli-pipeline.png new file mode 100644 index 0000000000000000000000000000000000000000..c15a029c9019a88bb8d692cd1d6661df3bc69a3f GIT binary patch literal 26942 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

j0zkvliizm z;q58!qRyLEhkovp`&UlD)|ZbL*@N!rEJS*;l%iX4{YAC4JPW74nq{?$>-g?`@oll0 z$kiV@IIZ^BfDY%6Rexx(o_3{c;9q#9i8(nqmk6QH zLLY$`c6t~_Bn>w-nkn>ZL)pl;YwLKYHwtJwb^ssqkAxhYtgeWJ(QjVfe}3ii_`#^z zrM}qObBv=;V!8EfO>uGClkSpBh4#T^u!;+*Nz~iw#c_C4;TFf zd`Y|{JqJ{U6cYu5KFd=)oC_0jn?#Y(FV~Rn;-8sKm)Q)=zr7@J;e&5=t=o}vCy&rL zDeD?VJZB`LjCe5#=d*5^g_LlFfOOlMAcoHamL&ri1t9e z*pCGptrN!^r|95NxUBP2{OD)UPcZVUdqQufqKrMhZf;_|_DD9BKvYiAyVt0}PyFZ* zqkb|z=>0CQaD^SjClymUD6JkkcPO^j@ISH>R5aMx@aj2(B@MyxK=UXlr- z;)8`IZ=@E%?gBQ5Rew6Fj?Zz{eCOPl#R7cLy=${!b9<8aM&oRJ@khFR?i)U^I+qy`{NcyFvMQv(nE(7oZs8P@vH%}4YX9sX z_*NciH)e4$mlZHC@hZ55Huvd($)Kaz7WU$&3 zyKK7Hbm;&o^nS{-dSj=zf%O!B;OvH&^01X$`x-tEf@dGNkgLd4KWwn{-T?h{p;3*( z#A%8*@|RBHOVT^%2fvlp1fyc4d1b`Hg%}s(SNqZ;kbP={*|;l1n)`vdQJJ{&vyNr^ z-=6atiWz%7WwF_}Ipp}~&d{?|eXu8>DlE55rkAVpr{F7EW>`&KXet6OfgY*9&{-p1 zFhHX&##2-~Tca>Mje^u4=4<%qmzV|~UD*{Yt*c-?oPUX(|HluPMb+DZn0nUNq zc*S~>u=DwXY@Qa$<6kT_hKJrAMlhClA6GY01}B|Y{nQ@))UHu2Sma2(Ab3&8trWAt zBpyq}&~v?RdgzKh!z9+{j>awE5c6%q2e=q}g==#8Z_L%0s1KhwcHoGAH0SxzFP$t8 zub;=kWS}W(q6O(yH&PAr@n)%>3!I7mgG8A;w(qGKo&b$&a?wZ}Kmlfn_fOCJEer^5N?l17sk)P`k>B%^Q>3gbhNM z_F`8`ExYw^-k;&QDdbSw6Uh?($k3s7%S-guG5l-_J+!t*ZCK%J*`>N^KYE+fB}(J{ zjhfA33O#$h-9fF>Sm390^QKKpOucR@cRK_DC%yuY*wLSWo-hv8Hi1nZT(sj~J+~RP z)eq6A_i-3~oBt!%Z`AXXrMBHONdKDj4u3%DWZAL9kM9)?T!od*$a-hW6gRX|R!qX? z_`VF4@Q*U`N;SZU67Dm%A1S0woZcZ`kVn2TI!3=Ly1#>sXYC1GU?Vvf|E{;m?Pf)R z!z8c3G&ZgxUE~-riQ2bNOe`Sq^~T2L^y6ff!TykLYLtZUM$|%gVtWJLwMMCHSHPsl zaMqIc=w>^zEvB0Ut^ad5JC)z$^`v!_bh)kE22Lo!9-%UJ<%ZyzGX1%Ur|=tFrFF{# zajz=V9QA>t^cDpE?4lZfV&ueWpgs>e3yM;)gCD0}ZD5QWtlCdSt7oIxv|4#+S)D`=0$;Az9?O!Y}-!i^Sy*^30lD%#7J0 zj6z7q=a?<989AFV)_&=F?9acbryAqmtxZ(zbPar#Srh-pZeAzXaHDQ6GGr~|t4vV) znM-1<3Eu}tv(GeZWFUI>n2y}y3ymN<5c=+Ea=NCyb}b%#$;pZujy-7G!(Sl4IQlLh z&y%Jewjy4#VUT+4Gao}Mu8ch!l56($+Gj#wt{LM}FWFP;k+i)*x!bzdBMPNFgnXg6 zv5snuA)~xr-Iyb}_ld%H?r|qqQLQCOpO)KUB_>=TI7Vo#7^lGGIhe-dWSE!GmySY1 zFYUe8s3G}5ucW(MLS?U)YjJ!?VL1**{}kP*M6vn>jr|O!L5+TQY-giIv#ykn7+V+| zu5&n#06K}2D z0T*u!3XT*i4~kdNF5g|p&$Uo9>} z{i#Y#9YR-aOv|MM4R_?4+U^@%NHVPV30FEa@sEy{($(M4n%xR0 zCc(0$;tgL1K(gu%XSuTGD>u(}*Yv-=v@ck)!*H6>wl%A9>f|6beZ4@)P`_*_eD(Ze zvqGwx{!%N*csU$@@e9SX^^Z~^t-K6HxC6P$gAj zZ2$4;_cI4a26^cCh13}{$AJ*q@gn5NXTV$p%*s+b$`|&W84$Hs{TU_83rqUr7vGKt z`Mn=+aKHKfGCA7}p7DYJ+~bysShzWTho}cyi6eO_81?J}s!=Lbf$jBdaDChh^<*2wqHdC~rdB!zG^PHgr}@p=CDe4ovU|K}$}MhBalR z#OX05^5t8f~z9eW<8Jal48Z)ngN2&gk=P2K+D6eGja`teigNF@XQ- zK{k1PJz%#ej|t~Wc;~95ck;gfntjPYR`*xDf~bD^wzy92Nn7>1d|q6iLVbo^Wn7-M zNu|C^>XeY_>2_yPU?c*KILs@mzrMa9MN@0zf z%n{baCuxI;5ku=JI*4WO)HNo7<-FkMz8_^mBm~l6l-87~pIBgmrzW&xIz@2t{fuO$ zWu`D!eSUVY&e0OgTGTzXW~+fTLr9`Y(rBScu5DkeB9qUr!tv+^xUuRTZ{>^=?>Ms? z0nf=kpqeqyVOGy2PDsm?@9{AC+#fX&KEXM4CkPdJm~aV<|#H)sP}E=)aI!;snfj2 zbkqBa(`sm%NtWZJYsI*c+louPv;)IC3)7@`%G`+OW_gXp(<3 zTj+AFYhK~vc(}2sPT>VHD*FfY%9=X%7|y03crnkpOA?37 zI|O*l23D|zIH;Sjx~&$tkJ5%NvBY_Qj`NuXD@$=*UW})2are}z^k`)+a zUDO#W6NTUVinn8-w$iUMGf7`=Aq_EwJ$IGs; zhLqu83Q)9cT)kdXJVVV`+)w~flFif7nLUDB%}fWUwQ5ae+daL;y>SdE$49#2z~?_{ zYE2z2vVv$7M@l zsTCUlZeDjefU`r58p_Zd(+^N(w7vmtbM3GyxjTNXHGa)u4M6FdzQLetuwDEx@{1YZzv~Qnt zRlm~EbAJBo^#gT-I`lzMY6T@}@;8W3-z@fPIg8REN_;uJz^)D^RQYnVQzEL^TTri+ z^iIo#Sw~w;iNsf$8}Ks?w|LDOa&I|2AT4_wfOGm@e!(@-v0YziBk~iLH9JITs<*Uv z-_Xd6!Uqn4DvUwK+)LeGPS{3t;&ngx|xbn98U7B^u{BQ;v~*0bU7DrxzbpAC87 z_C}iQMnvf-%O%H9Ot22#EFSMWF%&dDLNBqSY2GZQZXq+(c*h6){erXc2ThkG(L;M| z+zcW~8`IJCK6d}S>&tRgXF26ROZ`Fjw{uAY$DEv)o(xh}Lg;!$H|=2VWN2))oBcFR zT;Y3QRS|E2+AE)=sayu8D>67+=7eXZyx|ZW6#D9|}K^U)hYkMzS3sn3JYq(QpLncz#eT5&?of)&ZB2jEo;T~E;60q$l{j;%Ho@y;dRXZ!!=lj^b^JEuVyAx=ck3E1Q%nIDjP*+z< zR@XY8yM&h&v>Ro{YVz{XdA-|>v;?tKQOb4KG5qcgalA)rt+3gRD!RAF!xS_cV;1Qlf{xv%tj|ZT2b`0rgbl)GP~} zrjm@Cct-1Ib#nhYj2n_NqmA` zRY#V5au{&kI_OhKMX!h7eAwe>YsOdy@d19x`E^JvMagj(^-2o=V0~F)I$RPQ18KUo zvW{)w2N_Xn#UTfqlJ^H~Rb-e6;J8uQvKuTZc zoeA z25U(mb2kt>zJ;IltiUk1!Bah$I3zHkrSo+MQ%K08Z_o0wj0~B$s!sN6y1M6NH&=+8 zl0}TnMI2$h^^astMl;86J^IB1vZB7DM3}tSD5A=$b<0}9k#zm$8_U`5Ww?B;>~K|) z)%WM9e8y{SYD#V7#=Ce|8P5c}o%nY=&|D$g-l^zZ=%&wbnzy|TckOJ>M63i(XAZlr zv*!7{+w@eCc3wZlN2^N8I!;7FIZoJn-!N)aY(TQR2D(|y`>S91WF2ncvCuWv|4mC* z$aX=TNB`9NV?wUI*!%|;s<=+xRa2q9YS&jg(%&z#KNe?8QAIf1ytXv5=~*=&%eZjr znVDmJ;Tz=V`Ea4^WSvJ-kJO;tE++3P4~u+TZ9|8%pYi)G!(#&}X*&XGjaLMJ!tw_s z8!zM=RH*Ip^g`swFM{NmJk!N-bI6k&#XN2;fs^`5ojQ22{@Tl!;#@OFhO;7eX{27E}I(N{5*#l?l zt>-)Uv z4&H~pdwr0xv3Uk+IE=HH^vhOTL^nJudm;wZU!d?1d`IbhZD0aEUv!Fdz2q2Xdcr4Up^~+`$>zP5D6jP`vy^ z?5k-7!9#-fR07Z-lNWy1+wbItdZ z)=aGz>G;Duu2y*uMOL4Rs5u>s?QM%y{IgHCYCfONV%|At;h@V=wDt3C)ZHfXpaTueal7;l_C{<_kmb~jDFe{JBGdc2(T zEo_Eaja$&z^Cc|&Vns@8{mH?!ZYwM|LzvbA%Y#!V48WP{&d5~G5yauh5Jq`PU zN()2iS2$Q~4sfU@CfURIE+ge%DJcT-o>*=Q#)5T@Rh}~c3K^>nu3B? zVgbQKgAlA2;^|unOt^NRC)@a1yS<)*Q{r&(N%u;p!Zt0G{CQScsLRspT$jzMmNM=f z%WB7fC0bGfg6*HCn#sY&1G=WYqu3Bp8-SPMw zgLU0RXtM?TdC4W z0&NA*IGW$QVR%~pndh5`MZe#bA?ac7F0`tWW6ixS2adsCL%JsRj3^1#LGDw2-ch!<4s0?}-rpqUPFuLh6@^X~pi-|*l zQ4Qa19`m{^02N(3QIfyS$RQ(8Z4c(y*_4yCBbNw7sjMVuFpgVr!Q+I>QynyZYzts& z$FBWAZInxD`#!zKCPG}USt{$IM?J}iF)LQZqV_k< z%pcn-ceAAArrooIIo8>(nTTjPiL7aLT`ZvkWI7#U-!)^L%upQcX&Q|Nmw>Wt99iG` z1AHc!9s1UCGC;fY$q$v%qh@AA`Nckb0Itz}1&=iaML1$XzBF9Q5AU{fCB;IpF9(i+ zjv>Zs`I)CnWyct`DFvR=tG4FGBv?G@qm_2qm=HF1B_wpl^V?{C^+cQQPdNAT@F!C^ zp07-7q)Ak6p%nr2n9fH+Z7YCul0dq9@kgF6M4-g7K3F(Ub*;S=vbE*rs+kZj6l?bM zj4x+qLQWXnH$wBb8MFK1?|@7DmwV(Hso)TCEX;WkT>DxigElBTrsU$l0p{kf#(|{7VL`la`D>8wI0X8W_M=qAtBxE?QPZrWI745QSl8~M;y)0g+gYBL?6ZN@yQfO-TZ#q_np+CTT zwKQDF-e9(-196iOFBa|qLcbb1ge>}@hrNyj^4CjJ0Jh({zxXwXF>-CqE-`w&FFoiM z?0Cxwpy9M$n1hZOE_-Rg7Z&pWCVzc-4m>*3l9DTgp%IbXWRcPoG*i2FjX)cFBLAW< zO|Av~3Himam2`)ttj^y{83F??aRAm;_bNTNYgZMn80q``vF6*JIGwU`oDe z3nqjv6WPDU@SEM14hZO$gUe|M0@-Ps40uR)&00f0fj~;yj~?6Md``fO;^jBu@Btv; z?d*pSN=V3@ho9gV2h35SF$qBJ#*$oIcH5Ck2R317R-B`rqP{*UZ$rqvD5e5-#; z8liQ)%OGv}(wzSpDr(h#yp&TVd~4J3FIC&rl0}9jd!%N`b{C*HE3M3#&6wcnM+UNB zl+=pK1mQ`(PPow65(Z+PE9I7@ljQZAfyk=<0wknuPoLs-LGq{WoEpeRg?J4pDuqim zt_dL4t3Dyt<4qLX*n>V75GeRIKsl?WY5@*;s`F!20u`+Pj+F9PzZ1JK6@kXrNCHBH z(EyRw0GZoY5L|Bol6wSN=OAp-HwRq{+FxGu(6ygN$Cexm{+1>qu=eO_A^-@SjENGK zJb|#}3#FYU1la)l_`1kuJ+2TOtF-Ba9JmughvK|=3@bIZcXlunXY$Tb{)#Mnak=$3 zgYE;0?Nk(44^QWP0`D$bfVdiR*TSmSqyZL(V7V9H)L3AiG^V_8eyLL)q&q>5R`QDG zvQzyctDF}jBf2LBl)9Cr{3|uZ%qKoBw(46b03+yJOOa0MQiBI?N)l|d*3JzR5-&N zI1xpFRM`Z-E41wZcZmYo?C0#@ms6#lZU9OY7wVRCSu~ff8mPqut=m&m6fs(OLn%Vm zl_CCTzsK$i(?yWl_`apd}VMf`9MtaG)f;kH4ALwQK~EBDWyoPBKgXWQGz zw!v=$b0BCKn=I;%&E{}=G3{%BW?kD|9snm;JV+4eY*sb;!K_+AzAhn3C@s`)? zZ%X(w#(+)r-YA@q7%x?Qeh^5mL-jJYc&pN=2IwMnb18d9{fOUA1MN^rIDSgo_cn_a%utYTN9-wJ-RjK!S7-l}P z*b((fCs3fOPVp&tuZKV)$;~6Bo;n72Bqf#VMT>4d!r}me@8qX2W{W)!(o6S2G%5z9 zj|UAFm^9Q^39s=2=p#m{ttVO;QulnL5~H)jzBLsXEBW&sM)gWTI>6;>1aFU*uUhoy z>8e-ZHgM;8I!Qk%ZX}H28%{-^oxO15?tJHBM+>dVU67L;_4uvCUD@pRt}uF`cHHKr z{a%Ao%P`m@kD1ViYJiHgh2iL!X_UzzWQ-rTb1*$z+;&oCKpwd0p%kfAoFXKpl zyx$f<*+tSjR1V`+HOp;dUQehHch%2cMZl-{B#FOaZ*06%nhag@nw-~#Wc5d30~ zoxM|)3iIP|);b6Xy(QeCqiRrW>tsk%)X4K}kG|z-hxVO#(3IK0yLsWoBzt4N-7wX* zYEQt0eX0Lc+)V$_B@!f-POD8J?Q4#Y7Fk8}8<>=1xgQ9n(^fs3#n*ylWEE+o#dkOU zWx5Gz9n{{$>h{+s;O#D5AyHY1r}#5ns;>@*8@~=)08foMLXG4c!=T7o`EhQZp%}hR zXRO66>@C3Ys2*LgFA=tlZpB=7!vYAI?F4)68k}n^`{BySh=&+ha6P>J*;dSh{Y?@f ztpfq)1-rft5B@0_zA6OOttuwb-;9|Dw5jPt$Z@|gV~{&II5)C0o;qC8JAMCS&I7P= z^|tp$P@S(*)3ylfl?F3Roat^2`8=EAyWdgpV@+7e}5=| zRmY_;4sj@kR7-;NlZAu0x-1<+mN7VkM$npENbc%4Uk2K4egrU|>TI6XsO(R}{zrRf z9uL*q_wipO(XWkADU^`1lw_2#lx)@5cgB=m7{)RNAxe@oMaUkBiWvsOAY>h7%f2re z*|*7-8Owdm^xXGz-@oU+|9t*wAnkagC;G{M~vq)Bo%H{Y5POJyYux+_&2j+o- zY|0KRVmNfu+FahJ{6llIq%^3sjjlYNAX`53@w^>S-xcFhHZL`)fSK5~Dum6W-zn>O z_(Sy4#*&JV1B! z0vcKa4L^KNz^#Bva%i>6_nMa3A;hex$ooW+`>%HMV|OkflxF$5Uyc!!rqd_IJfKR@ z=NQW?k`$_jV1TvG&@T2lM0?hYEyfDZ!Lyf-&r1yWQu^#J5=jcw-kwNA;W|j9JV2aR z|N2CwUet~;KW*R54e!=fi}vd0?63g(Y*(cEabK~}6ANt=^^Syz#p{v^L)En2ccLA% zRsUh_s~h9dln-+GLmMTf$ghVL)q^mTRbaDM`#wD%_hR`h;?RjKdCWOJezBbRtm zY5c{*=KXh^JA(RHGnLzn)?U(qX<%83p0|#Q+)^u6^jWa<{q>zZ_cLMBc@TqrC1NLB z0&y~w^ z3IlmeOjouEyG{{Bs$|}Nrlj)cS3KHKFx90ky`+){XCd0H6L-IBwJ@8dhh`Ryr@h5_ zTUHyBi9u$>bcWIN4*r>skF#1-tfr2l9+@6N_EX#+*j^pK@RTgwtCf}H5jDO2nGc)$ zN#=q;&qpHzfuPNoZ!pl2T8h|QDXk$%)ON8fH_OrTtBmyF)jCS!TwG8n1qD2H{xC(P z3E4J4-NUWhMTahuwS96-@;e1(qyxnp-+&^m$52!F$DCx!O|*qMI|4d9P)n&EI_5iT z+IfLWI(uqD7+9%1Pmb_)J^~Bm$TQ7_=7hsoqhz{`(Ho&d=0bK_eSovnSg}-N%TClpNnGL3sS3k1`Z;h`lY~{gDhb7>xszjpvNlJRl%gfFCIyu+l zK8D)|_yXorMO^tHQ1Sx3G9=MBbA8WZcekDeXIc6dL21)nS|K4B-m)zPrM+LQH*YOZ z5tanDiOi0DJa0Rlz3^!MrHBn|QHZys9nr0?pk-!iu|?&f4D;PQ6AZX2jY=h>GdVhE zfX-aI8s^hjqJyy9yUEqr?3r4n)nz({S{(ikGG%>Zkz@dIC=ZWGqYy;7fClLBAuRdX zG0I0ri~4(lQ+{xtIzDV-Uz_qyk}X2p7f4#-HP$OHqdxZx1zX6)wt`|pozyUxV9pQD zI;Uj3&X3)3nhQXb{-@R8^I2|{G;8mX3hYg*Vf&rN9$A4Aw8cSsr}on0m2e?%574sz zfZn{+^&PnZ9&EvFDBg9_2tPNQZIo(C0|f`jRgzLT8AT<4BIJyC6%vUb>F2>*p={ zLG9K01-8|&UVC~)9V#VyBKy>x-TJYwy0$G=2_7cA5~jB7HO$Knn4^NZ)AMbpQn5?l zJ#!N|4oqTs#p)FjG1EtFKF*LHJKL3wEx96opEaY=IM-@uGm)pLE3-oK!Y@5_S5yIr zQf`&?6NE>UErIZYj(dkT8wpa(}gL_?5S!YX_@?Q30n~yH`Sxjkvucyi}oE7v?@4)VL{_JcR1V<`d z1(vKh!(Pqgcm_0N0UlLd{#7i9kjsN!#YyzeGl`<&H9V1ubrED-)2#~Hk|rv1Vo)r?SHO1JA4j8|0R@_IFIq(B-KPNR=AhYMnQdT<)*& zlpMCfhp4ooPz%sdFX&ox2b-+GY=j}doQosff88zPC@b)#-w;6cP6qM!JzlB;7GS9a zRo=A80l2K2{BQE~$ARLkL8(dY&Dr4UAOaszJ!GPcPiMEA)S%a*hu_;YoQ`w{%^5<%uE;(2Q{1bm=>Z?6Bh@l$lh=ruThTKSC4-ISg-RL%zK=FH zm!&5rT!;ZK0Zp&rxVzq!Rd8`q^6ah3LLMib4r%!NbV!o9!~S|&L-_C+xcjxqynyx4 z{>O=#9Hu?#JuuJI@0n#AG_zM_YmHfwkBGPStnaniqOH1SC+PwKjru$=kek;KSpz-B zID9DKxqn2FZhN;Pa=`DvN~S@C=s->R5^U1>v{jjrW4BA|lS$*a$V`weHvhEMK&w|3 zv!gh{?0jmK8F!hBt-5Z=y`$Wyjr68xbR=-uyOokW39@a!z8#|e;w#qtJjo$eSWNu| zI%45R1UW1bvzZO+E&}SmdBLuEl`{UleAvs{PVGMdO~@mH{k|WC z5V$Klpb>$&OQjH;+xYXiFM)Z~rzCywvcTe?nNYt-4PdIxf9xMgu5bHB{e|YnA`U(w zmj=F1*I61*P;!PtyK9Rg$h6}40mOUn%itNQ>VK!_epbt`BxjxceGEyO9>yK{p$(nb?xoYKFR-NT&R2!qUUvcoQ1*x^g75M~ zp3zB}abc$(eDco48}l}XZo6e)W=mI+MnjgjuuFg`1>B(*0tq>D|DyDAF3VK$d)2tNgfDwa^b)*blLE zz?SI0d%A}E_8l2Z{E=TYVdN7atFa$F;0jr0i5+NiSk1#_t`fciQR?7=|5&XShfRl+ zcp<4(mmmG57cg1E5}Fy5ArSGkwEQM^q&nu5s*)U)gbOFr`_&3}+ykt~dk`ADPxsM0 z8o{OZ)>E81(!>JmZ8kN2$Hz)eUORX&OiKs`8(`Th#b;M*|J;+k7pHI+mV6EJyt6iYnM=4v!P zhSJu)68#!j+koO2k2z7=RakGMxL&%biO4YDJi3iS^#(jPkHMU{8S2E0h&~~IC02720VoY-)VES;q%i<46lw))(ojlKf2R~%;goPv zKUbDXF8lU$2RiH1&i0))4Z14NeCD0c4M0*q$?V_z3ZOx`~)s@w+=ND&0Ijlo9+ovez-aUHsRKpYQ$nn4F6(6>W}Ki4KqyM59B}H*`$jdTG=L%yp`8tE zJ>{fmpT%f6d8C)mhBijkE)z#U*A(r(7tJfNQmAZ2_~XED15*Q_OwFfaHlvcWB)tuI zuy0X4q@IGw$~nGrzh@Pg&3r}6dF|^If@jcLUts1=??Cg27I<#%`?gU{Q-8MYF7+p5 z`axZ2PZ7X76(+)Of7+(uF*#e^_Sd0nf`2gMNsss5;N~l=#EhY=bsS|EYHdagGV4l| zwdeY*o%d#Bsl-nAH2P$5r3DTjsPgWOlvZ}Ckln%=J-Qry=~i?aD|-dc(pg)Q;&gMe z==2I|zgt`EaT@75RL!Ez(HU0m%OO=d;#6xHeIHL71yJ`P#r zPbCVP#XahZ^PkSs7Vf?AwpnKS+=a#WU-TF0qD6jw`#S_pKGh(Pr;13Aj^!@&@nh*d z$!6WMOV<5x>UAKR8mBC^%DKRbILlo}?>@ zNXL?;<1us2X8iXAskbBQ;9&Osz`vQFccacGfG|N@4Sz;fD?5y(Y|P&sx_tZ7bfREw%>WNxW(l+zcS42 zA4d6LpkDL};N@~ETieqQSh3o>UpMXv2Q0pUZ!PVrBDUTs3y|1HIe2cQ#Z~FSh}&LP zS}|bML=8E9;Bn5@lFr>Z;odQ%xE|ho8m0VLXQ16sM8#C55Yk!>I1k4}FW5JcUXP(b zs|O*5mQP};_^>|2Z!7p*syw6FS=agLq1Xdipz5Mdv5$&by*GwhTHH%vENfc(YPtAi zrMN%=>SJq^n1EP)5>80Bf47W`xPtrWz`J>;=lBXqA$MSC8hnc7_~ z9MfuP6LHHXiL}N_Iz0blh%aNOq`g}bKb6O?W3l?c%VO|zn=NiYRy7!C$$b!gt_sRWECxGz)NBz^sp)-e! z^yT#2c=q)}-ZD2F6H@t8Gc~%lMDy?A@+e-RJ+BHezqU|P)dLsU8JV1Umhfl0^hE4# zDV!z$2W%cg#irF46=lz`E&lbSzrQ{J7@fx4UH{UZ|K9O`mEA1Vk};<({5teBMB?{P1OK&pU0_ z*97%v0wj8WBNxQVZX~~IZkI*ridP~-TyVppj^}>glXy`klYu=>w`Ut@H>J&jbti3G z*23FAouHCzTX*}bg5GigItBnY{OeAGA6?sv&?Qm0z07?MX_A<|5U{)sr$3Afw}Z}P zu6vq4jgkSx+PM~8%7_3-7;S!4Zfql~erQ&Fh{Dsnwa zU9d4G%|WPU_sVfRqw5AT26x80Pl1G>s>c&@yzib541k7EdXM{jg-Y%;7}TRsNUIk@ z$iq*VtKje3N6P>a1kf|SNL>`MQ?&~_ud^teov9j>ZOoX5AK`G^*T*Bd; zk}+lbpOepXPJE%A%+B!d%Ch^>5}IEK@;m2rpzI)5^G+L-_@i@wJ%cqoA5w?56mp+9 zft^GSp2{v7Zw%@;iuO(P`P#JqOOW2}%y>Nn!}L4Jwjv%D*KhpFiqhRMxv#kQoG5*p zSv6T9;r!=mHnxh-V@j6~xn>7^azSpq7ueYQ ztVK|?0R1e6s1O(L2*TiXSFBSR?_i!vtZg5XbLE{?f0)bu57H0iR$hJ?096sj@iGfz zdGt=qV8u1I>5j}yiHqy2sZvdGZQ1D8cex`u$nhTLAH+Z&$zxYXcc<5tXgk1331|S6 z-htwU*Kz@hNhco`{nRzIgrD%C$%3wH3+@HBDH7M1(HKB4SJ6Eswn(`c|2#deWy>d zEQP^Gy725aW6ro~s8V^x0=)b7ZmB{x&9}+}n?Vk3ibJ!y#q!T?SlL}ZthA%C+Euv^ z5@FpfF@7=m;q_We4$+J*pmwh)}pWK{R<8T;Uj{89+b^K8v@I?o1CS_ z%Ebu8s0ewpNKt2S!4T?kWN#U?W?CF1Ia`;n;~3ARE{Hnoo_l9=oJ#Ua(s<6YYxmd3 zDy6^`uH@A}_*uka)qa@ml#k6~#j(zgV>5Re>zyXfGM@Yuu5YubrOSQrVq#|1a(nh# zr|7E(DVN4jXOCqvUgv2>CUwNqU=RezBF>Zj7=51Et$z{=Cc<-x>*^Qe4`;J$Fk!x$ zI>DoV9D$~!5HpRdSfskSun&Re9E=Y@pU7|T!8+9I>E0T<$Ry~i*zem-9vP+Do`4gg z^UaU(VZ2P;_P|4jBGVG_sZ2t1a3?1ww=eB+d56A*!J0t!gZ06~Seq^zUoaGJY}r2b z%<0w)JBe6aTI0=SZliSBG6V1>EW^&|_jeZyZM)9kGjfb?o}XrU{@g!o=>Ap)b6LuW zdjM&`gmq-cc8Z#VymO&G6SB+rd5`~p`Z?OH5$LPTubA|WKFWD+0LC07c{D!5bK#L8 zWKh<2$>4Lc&KSx*Mfo1UP}(uJ3>{|2mQCNc&wQYe3fNuHAjZu9_4$J`t1{sO0zMtl ztMM-~ac;5bKc5_Ym9YROj(w`~J?y`;G8o1qkWkcUAMIjDDE@LR_!`{A3phJ{lh}Tyy5KJ- z2T%B8ju)?*^SIT$nfdzv(ZK&-{{Qj2|0}4{vRM=FudvAYgB&e2?Hl;(cS8OK>QC6^ literal 0 HcmV?d00001 From 2475926447d21c838889685a39f407820cfccffd Mon Sep 17 00:00:00 2001 From: tbedford Date: Mon, 15 Apr 2024 14:48:47 +0100 Subject: [PATCH 04/12] [wip] - improve social card layout --- layouts/background.jpg | Bin 62749 -> 46331 bytes layouts/quix.yml | 31 +++++++++++++++---------------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/layouts/background.jpg b/layouts/background.jpg index 6dbc582c0db33cede04628336b93ef3e2fc06a26..11df2328e9dd3be7e1ec5e5522280b20e0885678 100644 GIT binary patch literal 46331 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 literal 62749 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 diff --git a/layouts/quix.yml b/layouts/quix.yml index ad93ab3c..8094de86 100644 --- a/layouts/quix.yml +++ b/layouts/quix.yml @@ -36,20 +36,20 @@ layers: image: layouts/background.jpg #Docs URL text - - size: { width: 150, height: 30 } - offset: { x: 144, y: 64 } + - size: { width: 160, height: 36 } + offset: { x: 200, y: 64 } typography: content: quix.io/docs - align: start + overflow: shrink + align: start center color: "#FFFFFF66" font: family: Inter style: SemiBold #Page title text -# - size: { width: 768, height: 336 } - - size: { width: 768, height: 190 } - offset: { x: 144, y: 126 } + - size: { width: 800, height: 240 } + offset: { x: 144, y: 136 } typography: content: *page_title overflow: shrink @@ -57,23 +57,22 @@ layers: color: white line: amount: 3 - height: 1.2 + height: 1.25 font: family: Inter style: SemiBold #Page description text - - size: { width: 768, height: 336 } -# offset: { x: 144, y: 235 } - offset: { x: 144, y: 245 } + - size: { width: 800, height: 144 } + offset: { x: 144, y: 422 } typography: content: *page_description - overflow: shrink - align: start - color: lightgrey + overflow: truncate + align: start bottom + color: white line: - amount: 5 - height: 2.5 + amount: 3 + height: 1.5 font: family: Inter - style: Normal + style: Regular From e57d1fd26f156f6a15e3e3d270fd2f588bcb92de Mon Sep 17 00:00:00 2001 From: tbedford Date: Wed, 17 Apr 2024 16:14:27 +0100 Subject: [PATCH 05/12] [add] - link to cli reference guide --- docs/get-started/cli-sync-to-cloud.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/get-started/cli-sync-to-cloud.md b/docs/get-started/cli-sync-to-cloud.md index 4ff2e902..692ec6f7 100644 --- a/docs/get-started/cli-sync-to-cloud.md +++ b/docs/get-started/cli-sync-to-cloud.md @@ -46,8 +46,6 @@ In Quix Cloud, go to pipeline view, and see your pipeline running, with your F1 ![CLI pipeline](../images/cli-pipeline.png) -## Next steps +## Next step -* []() -* []() -* []() +* [CLI reference guide](../kb/cli.md) From 5f2b123182c6704915df074195a254d555d1790e Mon Sep 17 00:00:00 2001 From: tbedford Date: Thu, 18 Apr 2024 14:55:05 +0100 Subject: [PATCH 06/12] [fix] - minor tweak --- docs/get-started/cli-sync-to-cloud.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/get-started/cli-sync-to-cloud.md b/docs/get-started/cli-sync-to-cloud.md index 692ec6f7..00b5c03e 100644 --- a/docs/get-started/cli-sync-to-cloud.md +++ b/docs/get-started/cli-sync-to-cloud.md @@ -1,5 +1,7 @@ # Sync to Quix Cloud +In this section you sync your local project with Quix Cloud. + ## Step 1: Sign up to Quix Cloud for free Sign up [here](https://portal.platform.quix.io/self-sign-up){target=_blank}. @@ -19,7 +21,6 @@ If you need help on creating a project, you can [read the documentation](../crea When you've created the project, switch back to the command line. - ## Step 3: Log in using the CLI Log into Quix Cloud using the CLI using the following command: From 478033ee858621f5c5b9b73e3560421ec7e673ff Mon Sep 17 00:00:00 2001 From: tbedford Date: Thu, 18 Apr 2024 17:18:07 +0100 Subject: [PATCH 07/12] [fix] - remove path to cloud --- docs/get-started/cli-create-project.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docs/get-started/cli-create-project.md b/docs/get-started/cli-create-project.md index a578bf10..22865858 100644 --- a/docs/get-started/cli-create-project.md +++ b/docs/get-started/cli-create-project.md @@ -7,10 +7,6 @@ description: You install the Quix CLI and create a simple project, with a pipeli In previous sections of the documentation you explored using Quix Streams. You now continue your journey on the command line by installing the Quix CLI, and then using it to connect with Quix Cloud. From your Git repository, you create a simple project on the command line, add a data source application, and then sync it with your Quix Cloud pipeline view. -!!! tip - - If you'd rather use the cloud, sign up to [Quix Cloud for free](https://portal.platform.quix.io/self-sign-up){target=_blank}, and then build a stream processing pipeline with Quix Streams and Quix Cloud in under ten minutes. - ## Step 1: Create a Git repository Create a Git repo where you can store your files, for example you could use GitHub. Create a repo initialized with a `README.md` file, so it can be cloned more easily. From 665dfa9cf82e854e134c84e4f87bdf78e3300bad Mon Sep 17 00:00:00 2001 From: tbedford Date: Fri, 19 Apr 2024 11:22:22 +0100 Subject: [PATCH 08/12] [update] - reorg of content --- .../cli-add-destination.md | 4 + docs/cli/cli-add-source.md | 47 ++++++++++ .../{get-started => cli}/cli-add-transform.md | 55 +++++++++-- docs/cli/cli-build-pipeline.md | 14 +++ docs/cli/cli-cloud-signup.md | 24 +++++ .../cli-create-project.md | 10 +- docs/{kb/cli.md => cli/cli-reference.md} | 21 ++--- docs/cli/cli-sync-to-cloud.md | 47 ++++++++++ docs/cli/overview.md | 23 +++++ docs/get-started/cli-add-source.md | 13 --- docs/get-started/cli-build-pipeline.md | 13 --- docs/get-started/cli-quickstart.md | 92 +++++++++++++++++++ docs/get-started/cli-sync-to-cloud.md | 52 ----------- docs/get-started/process.md | 2 +- docs/kb/what-is-quix.md | 2 +- mkdocs.yml | 21 +++-- 16 files changed, 323 insertions(+), 117 deletions(-) rename docs/{get-started => cli}/cli-add-destination.md (86%) create mode 100644 docs/cli/cli-add-source.md rename docs/{get-started => cli}/cli-add-transform.md (50%) create mode 100644 docs/cli/cli-build-pipeline.md create mode 100644 docs/cli/cli-cloud-signup.md rename docs/{get-started => cli}/cli-create-project.md (80%) rename docs/{kb/cli.md => cli/cli-reference.md} (86%) create mode 100644 docs/cli/cli-sync-to-cloud.md create mode 100644 docs/cli/overview.md delete mode 100644 docs/get-started/cli-add-source.md delete mode 100644 docs/get-started/cli-build-pipeline.md create mode 100644 docs/get-started/cli-quickstart.md delete mode 100644 docs/get-started/cli-sync-to-cloud.md diff --git a/docs/get-started/cli-add-destination.md b/docs/cli/cli-add-destination.md similarity index 86% rename from docs/get-started/cli-add-destination.md rename to docs/cli/cli-add-destination.md index ef31b8ba..f469cf7b 100644 --- a/docs/get-started/cli-add-destination.md +++ b/docs/cli/cli-add-destination.md @@ -10,6 +10,10 @@ This creates a starter destination for you. Alternatively, you could type `quix You are now ready to synchronize everything with Quix Cloud, and run your complete pipeline as a set of dockerized services in a cluster managed by Kubernetes, with nothing more than a single command. This is described in the next step. +!!! important + + Before you proceed to the next step, make sure you stop all your local code running. + ## Next step * [Sync to Cloud](./cli-sync-to-cloud.md) diff --git a/docs/cli/cli-add-source.md b/docs/cli/cli-add-source.md new file mode 100644 index 00000000..e009edf7 --- /dev/null +++ b/docs/cli/cli-add-source.md @@ -0,0 +1,47 @@ +# Add a source + +Now create a sample application. In this case you'll first add a data source application. In your project directory enter the following command: + +``` +quix local app create +``` + +You will be prompted to select a library item using the interactive menu. Select `Source` and then `Demo Data`. This will give you a source that generates F1 racing car data from a CSV file. Give the application a suitable name, such as `F1 demo data`. + +## Create your local variables + +To create your local variables for the source application, run the following command: + +``` +quix local variables export +``` + +This generates a `.env` file with several environment variables set for you, including the streaming token used for authenticating with your selected environment, and your input and output topics, for example: + +``` +Quix__Portal__Api=https://portal-api.platform.quix.io +Quix__Organisation__Id=yourorg +Quix__Workspace__Id=yourorg-tutorial-prod +Quix__Sdk__Token=sdk-349...dd +output=f1-data +``` + +## Run your code locally + +Run your source which will publish data to the `f1-data` topic. In the source application directory: + +``` +python3 main.py +``` + +If you get an error, you most likely need to create your local `.env` file, which you can do as before with `quix local variables export`. + +!!! tip + + The required topic(s) are created. If your program creates a timeout error, it means the topic(s) are still being created. Simply wait a few moments and then try running the program again. + +You can leave your code running, create a new shell tab, and proceed to the next step. + +## Next step + +* [Add a transform](./cli-add-transform.md) diff --git a/docs/get-started/cli-add-transform.md b/docs/cli/cli-add-transform.md similarity index 50% rename from docs/get-started/cli-add-transform.md rename to docs/cli/cli-add-transform.md index d0019478..cecc45ea 100644 --- a/docs/get-started/cli-add-transform.md +++ b/docs/cli/cli-add-transform.md @@ -10,7 +10,7 @@ This creates a starter transformation for you. Alternatively, you could type `qu ## Modify the transform code -Now, you'll modify the starter transform code to do something more useful. Let's say you want to calculate the average speed from the race car. You could do that with a tumbling window with a time window of say 30 seconds: +Now, you'll modify the starter transform code to do something more useful. Let's say you want to calculate the average speed from the race car. You could do that with a tumbling window with a time window of 30 seconds: ``` python import os @@ -49,6 +49,14 @@ if __name__ == "__main__": app.run(sdf) ``` +This generates a message with the following format every 30 seconds: + +``` json +{'average-speed': 249.04918032786884, 'time': 1713518340000} +``` + +## App.yaml file + Now take a look at the `app.yaml` file for your transform: ``` yaml @@ -70,17 +78,46 @@ runEntryPoint: main.py defaultFile: main.py ``` -Note that the input topic is `csv-data`, but you need to change that to `f1-data`. Edit the `app.yaml` file so that the input topic section is as follows: +This file defines the application, including its input and output topics. -``` yaml - - name: input - inputType: InputTopic - description: Name of the input topic to listen to. - defaultValue: csv-data - required: false +Note that the default input topic is `csv-data`, but you need your transform to subscribe to the `f1-data` topic. You'll fix this in the next section. + +## Local environment variables + +There are a couple of ways you can set the input topic of the transform, but a sensible way is to change the environment variable that sets the input topic. But as yet, there are no environment variables created. You can create them with the command you saw in the previous step, `quix local variables export`. + +You can then edit the `.env` file so that the input topic is `f1-data`. + +## Run your transform + +Now run your transform. In the transform application directory: + +``` +python3 main.py ``` -Save your changes and proceed to the next step. +## Testing + +There are a couple of ways you can test if this is working. One way is to switch to Quix Cloud, and navigate to the Topics section of the main menu - you will see active data on your topics. Another way is to run a command-line program to read the data on a topic. So, to read the `transform` topic, you could create some code `test.py` in your transform app directory: + +``` python +from quixstreams import Application +from dotenv import load_dotenv +import os + +load_dotenv() +app = Application() +topic = app.topic('transform') +sdf = app.dataframe(topic) +sdf = sdf.update(lambda row: print(row)) +app.run(sdf) +``` + +This reads the `transform` topic (the output of your transformer) and prints out the results. This proves data is being produced into the transform topic, by your transformer. + +!!! tip + + In your test program, you could have obtained the topic to read from the local `.env` file, rather than hard coding it, you'd load it with code similar to the following: `topic = app.topic(os.environ["output"])`. ## Next step diff --git a/docs/cli/cli-build-pipeline.md b/docs/cli/cli-build-pipeline.md new file mode 100644 index 00000000..c3a00c47 --- /dev/null +++ b/docs/cli/cli-build-pipeline.md @@ -0,0 +1,14 @@ +# Build a pipeline using the Quix CLI + +In this tutorial you'll build a simple pipeline using the Quix CLI. The steps are: + +1. **Create a project** - you create your Git project. +2. **Sign up to Cloud** - Sign up to Quix Cloud for free. +3. **Add a source** - you add a demo data source. +4. **Add a transform** - you add a transform and perform some simple processing. +5. **Add a destination** - you add a simple destination. +6. **Sync to Quix Cloud** - you synchronize you CLI project with Quix Cloud. + +## Next step + +* [Create a project](./cli-create-project.md) diff --git a/docs/cli/cli-cloud-signup.md b/docs/cli/cli-cloud-signup.md new file mode 100644 index 00000000..1d2bc014 --- /dev/null +++ b/docs/cli/cli-cloud-signup.md @@ -0,0 +1,24 @@ +# Sign up to Quix Cloud for free + +Sign up [here](https://portal.platform.quix.io/self-sign-up){target=_blank}. + +You need to sign up to Quix Cloud at this stage as you're going to be testing some of your code locally, and rather than set up a local broker, you'll use a Quix-hosted broker for your Kafka topics. + +When you log into Quix Cloud, you'll be prompted to create a project. + +## Create a Quix project + +In this step you create a project in Quix Cloud based on your Git repository. + +1. Select `Quix advanced configuration` to continue creation of your project. +2. Select your Git provider (for example, GitHub). +3. Link the Quix project to your Git repository using the **setup guide** provided for your chosen Git provider. +4. Use PROD for your environment, and make sure the `main` branch is selected. + +If you need help on creating a project, you can [read the documentation](../create/create-project.md). + +When you've created the project, switch back to the command line. + +## Next step + +* [Add a source](./cli-add-source.md) diff --git a/docs/get-started/cli-create-project.md b/docs/cli/cli-create-project.md similarity index 80% rename from docs/get-started/cli-create-project.md rename to docs/cli/cli-create-project.md index 22865858..4f9e89b6 100644 --- a/docs/get-started/cli-create-project.md +++ b/docs/cli/cli-create-project.md @@ -1,11 +1,13 @@ --- -title: Create a project +title: Create a Git project description: You install the Quix CLI and create a simple project, with a pipeline consisting of one data source application, which you then sync up with Quix Cloud. --- -# Create a project +# Create a Git project -In previous sections of the documentation you explored using Quix Streams. You now continue your journey on the command line by installing the Quix CLI, and then using it to connect with Quix Cloud. From your Git repository, you create a simple project on the command line, add a data source application, and then sync it with your Quix Cloud pipeline view. +In previous sections of the documentation you explored using Quix Streams. You now continue your journey on the command line by installing the Quix CLI, and then using it to connect with Quix Cloud. + +From your Git repository, you create a simple project on the command line, add a data source application, along with a transform and destination, test it, and then sync it with your Quix Cloud pipeline view. ## Step 1: Create a Git repository @@ -40,4 +42,4 @@ This initializes your Quix project with a `quix.yaml` file, which describes your ## Next step -* [Add a source](./cli-add-source.md) +* [Sign up to Cloud](./cli-cloud-signup.md) diff --git a/docs/kb/cli.md b/docs/cli/cli-reference.md similarity index 86% rename from docs/kb/cli.md rename to docs/cli/cli-reference.md index e50204d3..ac85c60d 100644 --- a/docs/kb/cli.md +++ b/docs/cli/cli-reference.md @@ -1,22 +1,13 @@ +# CLI Reference guide + --- -title: Quix CLI -status: new -description: The Quix Command-Line Interface. +title: Quix CLI Reference Guide +description: The Quix Command-Line Interface reference guide. --- -# Quix Command-Line Interface (CLI) - -The [Quix CLI](https://github.com/quixio/quix-cli){target=_blank} is a powerful command-line companion for seamlessly managing and interacting with the features of Quix Cloud. While Quix offers a robust UI for a user-friendly experience, the CLI empowers you with efficiency and flexibility, enabling you to streamline your workflow, and take control from the command line. - -* Effortless Control: Execute commands effortlessly to manage various aspects of your Quix organization. - -* Script Automation: Integrate Quix operations into your scripts for automated workflows and enhanced productivity. - -* Accessibility: Access and manipulate Quix features directly from the command line, providing an alternative interface for users who prefer terminal-based interactions. - -* Scalability: Seamlessly scale your Quix operations, whether you are working on a single instance or orchestrating tasks across multiple environments. +# Quix CLI Reference Guide -View information about the CLI in the [GitHub repository](https://github.com/quixio/quix-cli){target=_blank}. +This is the reference guide for the Quix CLI. ## Installation diff --git a/docs/cli/cli-sync-to-cloud.md b/docs/cli/cli-sync-to-cloud.md new file mode 100644 index 00000000..a6fdc75a --- /dev/null +++ b/docs/cli/cli-sync-to-cloud.md @@ -0,0 +1,47 @@ +# Sync to Quix Cloud + +In this section you sync your local project with Quix Cloud. + +## Log in using the CLI + +Log into Quix Cloud using the CLI using the following command: + +``` +quix login +``` + +If you're not logged into Cloud, you'll be prompted to log in. + +## Check your context + +The context for the CLI is the combination of the portal URL being used, and the environment you're connecting to. You can check this information with the following command: + +``` +quix context list +``` + +You should be connected to the default context with the Portal URL `https://portal-api.platform.quix.io`. You can have multiple contexts to enable you to have connections for production and development brokers, and potentially local brokers. See the [reference guide](cli-reference.md) for further informatin on more complex setups. + +## Sync your application + +To sync your application, change into the `F1 demo data` directory and enter: + +``` +quix local deploy --push --sync +``` + +This updates your `quix.yaml` project file. The `--push` option pushes all changes to your Git repository (it is similar to git add, git commit, git push). You can also add a commit message with the `--commit-message` option if you want. The `--sync` option ensures your Quix environment is synched with the updated Git repository. + +!!! important + + Although you are running this command in an application directory, the command notes any changes outside of the directory, and interactively prompts you to include those changes in the push or not. + +## See your pipeline running + +In Quix Cloud, go to pipeline view, and see your pipeline running, with your F1 demo data source running. + +![CLI pipeline](../images/cli-pipeline.png) + +## Next step + +* [Read the CLI reference guide](./cli-reference.md) diff --git a/docs/cli/overview.md b/docs/cli/overview.md new file mode 100644 index 00000000..63cf2f8a --- /dev/null +++ b/docs/cli/overview.md @@ -0,0 +1,23 @@ +--- +title: Quix CLI +description: The Quix Command-Line Interface. +--- + +# Quix Command-Line Interface (CLI) + +The [Quix CLI](https://github.com/quixio/quix-cli){target=_blank} is a powerful command-line companion for seamlessly managing and interacting with the features of Quix Cloud. While Quix offers a robust UI for a user-friendly experience, the CLI empowers you with efficiency and flexibility, enabling you to streamline your workflow, and take control from the command line. + +* Effortless Control: Execute commands effortlessly to manage various aspects of your Quix organization. + +* Script Automation: Integrate Quix operations into your scripts for automated workflows and enhanced productivity. + +* Accessibility: Access and manipulate Quix features directly from the command line, providing an alternative interface for users who prefer terminal-based interactions. + +* Scalability: Seamlessly scale your Quix operations, whether you are working on a single instance or orchestrating tasks across multiple environments. + +View information about the CLI in the [GitHub repository](https://github.com/quixio/quix-cli){target=_blank}. + +## next steps + +* [Step through a tutorial](./cli-build-pipeline.md) +* [Read the reference guide](./cli-reference.md) diff --git a/docs/get-started/cli-add-source.md b/docs/get-started/cli-add-source.md deleted file mode 100644 index aa46bbf7..00000000 --- a/docs/get-started/cli-add-source.md +++ /dev/null @@ -1,13 +0,0 @@ -# Add a source - -Now create a sample application. In this case you'll first add a data source. In your project directory enter the following command: - -``` -quix local app create -``` - -You will be prompted to select a library item using the interactive menu. Select `Source` and then `Demo Data`. This will give you a source that generates F1 racing car data from a CSV file. Give the application a suitable name, such as `F1 demo data`. - -## Next step - -* [Add a transform](./cli-add-transform.md) diff --git a/docs/get-started/cli-build-pipeline.md b/docs/get-started/cli-build-pipeline.md deleted file mode 100644 index ca1e7a10..00000000 --- a/docs/get-started/cli-build-pipeline.md +++ /dev/null @@ -1,13 +0,0 @@ -# Build a pipeline using the Quix CLI - -In this tutorial you'll build a simple pipeline using the Quix CLI. The steps are: - -1. **Create a project** - you create your Git project. -2. **Add a source** - you add a demo data source. -3. **Add a transform** - you add a transform and perform some simple processing. -4. **Add a destination** - you add a simple destination. -5. **Sync to Quix Cloud** - you synchronize you CLI project with Quix Cloud. - -## Next step - -* [Create a project](./cli-create-project.md) diff --git a/docs/get-started/cli-quickstart.md b/docs/get-started/cli-quickstart.md new file mode 100644 index 00000000..772eda61 --- /dev/null +++ b/docs/get-started/cli-quickstart.md @@ -0,0 +1,92 @@ +# Build a pipeline using Quix CLI + +In previous sections of the documentation you explored using Quix Streams. You now continue on your command-line journey by installing the Quix CLI, and then using it to connect with Quix Cloud. You create a simple project on the command line, and sync it with your Quix Cloud pipeline view. + +## Step 1: Install Quix CLI + +``` +curl -fsSL https://github.com/quixio/quix-cli/raw/main/install.sh | sudo bash +``` + +For further details on installation, including instructions for Microsoft Windows, see the [install guide](https://github.com/quixio/quix-cli?tab=readme-ov-file#installation-of-quix-cli){target=_blank}. + +## Step 2: Sign up to Quix Cloud for free + +Sign up [here](https://portal.platform.quix.io/self-sign-up){target=_blank}. + +!!! tip + + If you are prompted to create a project, you can stop at this point, and proceed to the next step in this tutorial. You will come back to complete the project creation wizard at a later step, because you are going to base your Quix project on a Git project you are yet to create. + +## Step 3: Log in using the CLI + +``` +quix login +``` + +If you're not logged into Cloud, you'll be prompted to log in. + +## Step 4: Create a Git repository + +Create a Git repo where you can store your files, for example you could use GitHub. Create a repo initialized with a `README.md` file, so it can be cloned more easily. + +## Step 5: Clone your Git repo into your local project directory + +For example, if your GitHub repo is named `cli-app`: + +``` +git clone /cli-app +cd cli-app +``` + +## Step 6: Initialize your project as a Quix project + +In your Git project directory, enter: + +``` +quix local init +``` + +This initializes your Quix project with a `quix.yaml` file, which describes your Quix project. + + +## Step 7: Create your application locally + +Now create a sample application: + +``` +quix local app create starter-transformation +``` + +This creates a starter transformation for you. You can explore the files created locally for you. The `main.py` code will look familiar to you if you've tried the [previous sections](./welcome.md) of the documentation. + + +## Step 8: Sync your application + +To sync your application, change into the `Starter transformation` directory and enter: + +``` +quix local deploy --push --sync +``` + +This updates your `quix.yaml` project file, and pushes all changes to your Git repository. + +## Step 9: In Quix Cloud create a project + +In this step you create a project in Quix Cloud from your Git repository. + +1. Return to Quix Cloud. +2. Select `Quix advanced configuration` to continue creation of your project. +3. Select your Git provider. +4. Link the project to your Git repository using the guide provided for your chosen Git provider. +4. Sync Quix Cloud to your project by clicking the `Sync environment` button. + +## Step 10: See your pipeline running + +Go to pipeline view, and see your pipeline running, with your Starter transformation. + +![Pipeline running](../images/starter-transform.png) + +## Next step + +* [See the CLI docs](../cli/overview.md) diff --git a/docs/get-started/cli-sync-to-cloud.md b/docs/get-started/cli-sync-to-cloud.md deleted file mode 100644 index 00b5c03e..00000000 --- a/docs/get-started/cli-sync-to-cloud.md +++ /dev/null @@ -1,52 +0,0 @@ -# Sync to Quix Cloud - -In this section you sync your local project with Quix Cloud. - -## Step 1: Sign up to Quix Cloud for free - -Sign up [here](https://portal.platform.quix.io/self-sign-up){target=_blank}. - -When you log into Quix Cloud, you'll be prompted to create a project. - -## Step 2: In Quix Cloud create a project - -In this step you create a project in Quix Cloud based on your Git repository. - -1. Select `Quix advanced configuration` to continue creation of your project. -2. Select your Git provider (for example, GitHub). -3. Link the project to your Git repository using the guide provided for your chosen Git provider. -4. Use PROD for your environment, and make sure the main branch is selected. - -If you need help on creating a project, you can [read the documentation](../create/create-project.md). - -When you've created the project, switch back to the command line. - -## Step 3: Log in using the CLI - -Log into Quix Cloud using the CLI using the following command: - -``` -quix login -``` - -If you're not logged into Cloud, you'll be prompted to log in. - -## Step 4: Sync your application - -To sync your application, change into the `F1 demo data` directory and enter: - -``` -quix local deploy --push --sync --override-with-default-values -``` - -This updates your `quix.yaml` project file, and pushes all changes to your Git repository. This also makes sure your Quix environment is synched with the corresponding Git repository, and that your changes to default values in the local `app.yaml` files are also reflected in the Quix environment. - -## Step 5: See your pipeline running - -In Quix Cloud, go to pipeline view, and see your pipeline running, with your F1 demo data source running. - -![CLI pipeline](../images/cli-pipeline.png) - -## Next step - -* [CLI reference guide](../kb/cli.md) diff --git a/docs/get-started/process.md b/docs/get-started/process.md index ff1ab965..3c12140c 100644 --- a/docs/get-started/process.md +++ b/docs/get-started/process.md @@ -83,4 +83,4 @@ You'll notice the messages in the topic are in the JSON format. ## Next step -* [Build a pipeline](./cli-create-project.md) - build a pipeline using the Quix CLI. +* [Build a pipeline](../cli/cli-build-pipeline.md) - build a pipeline using the Quix CLI. diff --git a/docs/kb/what-is-quix.md b/docs/kb/what-is-quix.md index ae0b383a..908bc384 100644 --- a/docs/kb/what-is-quix.md +++ b/docs/kb/what-is-quix.md @@ -214,7 +214,7 @@ Quix provides a suite of tools to enable you to monitor and manage your data. Th * Logs - Real-time logging information is displayed in a console tab. You also have the option of downloading your logs. * CPU monitor - you can monitor the CPU utilization of your deployment in real time. * Memory monitor - you can monitor the memory usage of the deployment in real time. -* CLI - a powerful command line interface (see the [CLI documentation](../kb/cli.md)). +* CLI - a powerful command line interface, see the [CLI documentation](../cli/overview.md). [See the Data Explorer in action](https://www.loom.com/share/0e3c24fb5f8c48038fe5cf02859b7ebc?sid=743fbdf7-fad5-4c26-831d-b6dad78b9b06). diff --git a/mkdocs.yml b/mkdocs.yml index f9edf344..f63fc314 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -25,13 +25,17 @@ nav: - 'Produce data': 'get-started/produce.md' - 'Consume data': 'get-started/consume.md' - 'Process data': 'get-started/process.md' - - 'Build a pipeline': - - 'Overview': 'get-started/cli-build-pipeline.md' - - 'Create a project': 'get-started/cli-create-project.md' - - 'Add a source': 'get-started/cli-add-source.md' - - 'Add a transform': 'get-started/cli-add-transform.md' - - 'Add a destination': 'get-started/cli-add-destination.md' - - 'Sync to Cloud': 'get-started/cli-sync-to-cloud.md' + - 'CLI quickstart': 'get-started/cli-quickstart.md' + - 'Quix CLI': + - 'Overview': 'cli/overview.md' + - 'Build a pipeline': + - 'Overview': 'cli/cli-build-pipeline.md' + - 'Create a project': 'cli/cli-create-project.md' + - 'Sign up to Quix Cloud': 'cli/cli-cloud-signup.md' + - 'Add a source': 'cli/cli-add-source.md' + - 'Add a transform': 'cli/cli-add-transform.md' + - 'Add a destination': 'cli/cli-add-destination.md' + - 'Sync to Cloud': 'cli/cli-sync-to-cloud.md' # Mostly out of date # - 'Project templates': 'get-started/project-templates.md' @@ -161,7 +165,6 @@ nav: - 'Why stream processing?': 'kb/why-stream-processing.md' - 'What is Kafka?': 'kb/what-is-kafka.md' - 'Reference': - - 'Quix CLI': 'kb/cli.md' - 'Glossary': 'kb/glossary.md' - 'Contribute': 'kb/contribute.md' - 'Tutorials': @@ -335,7 +338,7 @@ plugins: 'get-started/what-is-kafka.md': 'kb/what-is-kafka.md' 'get-started/glossary.md': 'kb/glossary.md' 'get-started/contribute.md': 'kb/contribute.md' - 'get-started/build-cli.md' : 'get-started/cli-create-project.md' + 'get-started/build-cli.md' : 'get-started/cli-quickstart.md' theme: name: 'material' From c320fd3da3ca2cbd7d416e0c1d7132cd2f9a7520 Mon Sep 17 00:00:00 2001 From: tbedford Date: Fri, 19 Apr 2024 12:13:45 +0100 Subject: [PATCH 09/12] [wip] - further improvements --- docs/cli/cli-add-destination.md | 70 +++++++++++++++++++++++++++++++++ docs/cli/cli-add-source.md | 4 +- docs/cli/cli-add-transform.md | 8 ++-- docs/cli/cli-cloud-signup.md | 9 +++-- docs/cli/overview.md | 2 +- 5 files changed, 81 insertions(+), 12 deletions(-) diff --git a/docs/cli/cli-add-destination.md b/docs/cli/cli-add-destination.md index f469cf7b..94cf9b1c 100644 --- a/docs/cli/cli-add-destination.md +++ b/docs/cli/cli-add-destination.md @@ -8,6 +8,76 @@ quix local app create starter-destination This creates a starter destination for you. Alternatively, you could type `quix local app create` and then interactively select the starter destination. You saw an example of this when adding the demo data source. You can call the destination `destination`, or any other name you like. +## Review the destination code + +The destination code is as follows: + +``` python +from quixstreams import Application +import os + +from dotenv import load_dotenv +load_dotenv() + +# you decide what happens here! +def sink(message): + value = message['mykey'] + # write_to_db(value) # implement your logic to write data or send alerts etc + + # for more help using QuixStreams see the docs: + # https://quix.io/docs/quix-streams/introduction.html + +app = Application.Quix("destination-v1", auto_offset_reset = "latest") + +input_topic = app.topic(os.environ["input"]) + +sdf = app.dataframe(input_topic) + +# call the sink function for every message received. +sdf = sdf.update(sink) + +# you can print the data row if you want to see what's going on. +sdf = sdf.update(lambda row: print(row)) + +if __name__ == "__main__": + app.run(sdf) +``` + +Modify this as follows: + +``` python +from quixstreams import Application +import os + +from dotenv import load_dotenv +load_dotenv() + +def sink(message): + print("Average speed is: ", message['average-speed']) + print("Timestamp at end of window is: ", message['time']) + +app = Application() +input_topic = app.topic(os.environ["input"]) +sdf = app.dataframe(input_topic) +sdf = sdf.update(sink) + +if __name__ == "__main__": + app.run(sdf) +``` + +The code is very simple, it just prints out the components of the message individually. You could perform any processing you want here, such as persisting the data, or displaying values on a real-time chart. + +## Test your destination code + +Start your source and transform if they are not already running locally. Now run your destination code. It outputs messages such as: + +``` +Average speed is: 282.27891156462584 +Timestamp at end of window is: 1713524910000 +``` + +## Get ready to sync to Cloud + You are now ready to synchronize everything with Quix Cloud, and run your complete pipeline as a set of dockerized services in a cluster managed by Kubernetes, with nothing more than a single command. This is described in the next step. !!! important diff --git a/docs/cli/cli-add-source.md b/docs/cli/cli-add-source.md index e009edf7..218d683e 100644 --- a/docs/cli/cli-add-source.md +++ b/docs/cli/cli-add-source.md @@ -34,11 +34,9 @@ Run your source which will publish data to the `f1-data` topic. In the source ap python3 main.py ``` -If you get an error, you most likely need to create your local `.env` file, which you can do as before with `quix local variables export`. - !!! tip - The required topic(s) are created. If your program creates a timeout error, it means the topic(s) are still being created. Simply wait a few moments and then try running the program again. + The required topic(s) are created. If your program generates a timeout error, it means the topic(s) are still being created. Simply wait a few moments and then try running the program again. You can leave your code running, create a new shell tab, and proceed to the next step. diff --git a/docs/cli/cli-add-transform.md b/docs/cli/cli-add-transform.md index cecc45ea..20650402 100644 --- a/docs/cli/cli-add-transform.md +++ b/docs/cli/cli-add-transform.md @@ -1,12 +1,12 @@ # Add a transform -Now add a transform using the CLI: +Now add a transform using the CLI. In you project directory run the command: ``` quix local app create starter-transformation ``` -This creates a starter transformation for you. Alternatively, you could type `quix local app create` and then interactively select the starter transform. You saw an example of this when adding the demo data source. You can call the transform `transform`, or any other name you like. +This creates a starter transformation for you. Alternatively, you could type `quix local app create` and then interactively select the starter transform. You saw an example of this interactivity when adding the demo data source. You can call the transform `transform`, or any other name you like. ## Modify the transform code @@ -49,7 +49,7 @@ if __name__ == "__main__": app.run(sdf) ``` -This generates a message with the following format every 30 seconds: +This publishes a message to the output topic, with the following format, every 30 seconds: ``` json {'average-speed': 249.04918032786884, 'time': 1713518340000} @@ -117,7 +117,7 @@ This reads the `transform` topic (the output of your transformer) and prints out !!! tip - In your test program, you could have obtained the topic to read from the local `.env` file, rather than hard coding it, you'd load it with code similar to the following: `topic = app.topic(os.environ["output"])`. + In your test program, you could have loaded the topic to read from the local `.env` file, rather than hard coding it. You'd load it with code such as the following: `topic = app.topic(os.environ["output"])`. This would enable you perhaps use the same test code in multiple applications, without needed to edit the code to change the topic name. ## Next step diff --git a/docs/cli/cli-cloud-signup.md b/docs/cli/cli-cloud-signup.md index 1d2bc014..8283e96a 100644 --- a/docs/cli/cli-cloud-signup.md +++ b/docs/cli/cli-cloud-signup.md @@ -10,10 +10,11 @@ When you log into Quix Cloud, you'll be prompted to create a project. In this step you create a project in Quix Cloud based on your Git repository. -1. Select `Quix advanced configuration` to continue creation of your project. -2. Select your Git provider (for example, GitHub). -3. Link the Quix project to your Git repository using the **setup guide** provided for your chosen Git provider. -4. Use PROD for your environment, and make sure the `main` branch is selected. +1. Give you project a suitable name, such as `Simple Pipeline`. +2. Select `Quix advanced configuration` to continue creation of your project. +3. Select your Git provider (for example, GitHub). +4. Link the Quix project to your Git repository using the **setup guide** provided for your chosen Git provider. +5. Use PROD for your environment, and make sure the `main` branch is selected. If you need help on creating a project, you can [read the documentation](../create/create-project.md). diff --git a/docs/cli/overview.md b/docs/cli/overview.md index 63cf2f8a..5f63c166 100644 --- a/docs/cli/overview.md +++ b/docs/cli/overview.md @@ -17,7 +17,7 @@ The [Quix CLI](https://github.com/quixio/quix-cli){target=_blank} is a powerful View information about the CLI in the [GitHub repository](https://github.com/quixio/quix-cli){target=_blank}. -## next steps +## Next steps * [Step through a tutorial](./cli-build-pipeline.md) * [Read the reference guide](./cli-reference.md) From 69ea04af9a56b31326cd2868b6b00556bced0c4f Mon Sep 17 00:00:00 2001 From: tbedford Date: Fri, 19 Apr 2024 12:21:54 +0100 Subject: [PATCH 10/12] [wip] - add reference guide --- docs/cli/cli-reference.md | 2 -- mkdocs.yml | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/cli/cli-reference.md b/docs/cli/cli-reference.md index ac85c60d..e91a2bfd 100644 --- a/docs/cli/cli-reference.md +++ b/docs/cli/cli-reference.md @@ -1,5 +1,3 @@ -# CLI Reference guide - --- title: Quix CLI Reference Guide description: The Quix Command-Line Interface reference guide. diff --git a/mkdocs.yml b/mkdocs.yml index f63fc314..0b90bdf6 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -36,6 +36,7 @@ nav: - 'Add a transform': 'cli/cli-add-transform.md' - 'Add a destination': 'cli/cli-add-destination.md' - 'Sync to Cloud': 'cli/cli-sync-to-cloud.md' + - 'Reference guide': 'cli/cli-reference.md' # Mostly out of date # - 'Project templates': 'get-started/project-templates.md' From f67feb9c287decd652775a6f868e206579acbc47 Mon Sep 17 00:00:00 2001 From: tbedford Date: Fri, 19 Apr 2024 14:43:32 +0100 Subject: [PATCH 11/12] [fix] - requirements.txt needs to be updated --- docs/cli/cli-add-destination.md | 44 ++++++++------------------------- docs/cli/cli-add-transform.md | 8 ++++++ 2 files changed, 18 insertions(+), 34 deletions(-) diff --git a/docs/cli/cli-add-destination.md b/docs/cli/cli-add-destination.md index 94cf9b1c..22556694 100644 --- a/docs/cli/cli-add-destination.md +++ b/docs/cli/cli-add-destination.md @@ -10,7 +10,7 @@ This creates a starter destination for you. Alternatively, you could type `quix ## Review the destination code -The destination code is as follows: +Replace the destination code completely with the following new code: ``` python from quixstreams import Application @@ -19,53 +19,29 @@ import os from dotenv import load_dotenv load_dotenv() -# you decide what happens here! +# called for every message def sink(message): - value = message['mykey'] - # write_to_db(value) # implement your logic to write data or send alerts etc - - # for more help using QuixStreams see the docs: - # https://quix.io/docs/quix-streams/introduction.html - -app = Application.Quix("destination-v1", auto_offset_reset = "latest") + print("Average speed is: ", message['average-speed']) + print("Timestamp at end of window is: ", message['time']) +app = Application() input_topic = app.topic(os.environ["input"]) - sdf = app.dataframe(input_topic) - -# call the sink function for every message received. sdf = sdf.update(sink) -# you can print the data row if you want to see what's going on. -sdf = sdf.update(lambda row: print(row)) - if __name__ == "__main__": app.run(sdf) ``` -Modify this as follows: - -``` python -from quixstreams import Application -import os - -from dotenv import load_dotenv -load_dotenv() +The code just prints out the components of the message individually. You could perform any processing you want here, such as persisting the data, or displaying values on a real-time chart. -def sink(message): - print("Average speed is: ", message['average-speed']) - print("Timestamp at end of window is: ", message['time']) +## Edit requirements.txt -app = Application() -input_topic = app.topic(os.environ["input"]) -sdf = app.dataframe(input_topic) -sdf = sdf.update(sink) +Check the `requirements.txt` file. Make sure you are using Quix Streams greater than or equal to 2.4.1: -if __name__ == "__main__": - app.run(sdf) ``` - -The code is very simple, it just prints out the components of the message individually. You could perform any processing you want here, such as persisting the data, or displaying values on a real-time chart. +quixstreams>=2.4.1 +``` ## Test your destination code diff --git a/docs/cli/cli-add-transform.md b/docs/cli/cli-add-transform.md index 20650402..4fd24c94 100644 --- a/docs/cli/cli-add-transform.md +++ b/docs/cli/cli-add-transform.md @@ -88,6 +88,14 @@ There are a couple of ways you can set the input topic of the transform, but a s You can then edit the `.env` file so that the input topic is `f1-data`. +## Edit requirements.txt + +Check the `requirements.txt` file. Make sure you are using Quix Streams greater than or equal to 2.4.1: + +``` +quixstreams>=2.4.1 +``` + ## Run your transform Now run your transform. In the transform application directory: From 14e17b074b31529cccaf91408c8194468f0c3e3d Mon Sep 17 00:00:00 2001 From: tbedford Date: Fri, 19 Apr 2024 15:20:29 +0100 Subject: [PATCH 12/12] [wip] - quix update now supported --- docs/cli/cli-create-project.md | 4 ++++ docs/get-started/cli-quickstart.md | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/docs/cli/cli-create-project.md b/docs/cli/cli-create-project.md index 4f9e89b6..8d612f5e 100644 --- a/docs/cli/cli-create-project.md +++ b/docs/cli/cli-create-project.md @@ -30,6 +30,10 @@ curl -fsSL https://github.com/quixio/quix-cli/raw/main/install.sh | sudo bash For further details on installation, including instructions for Microsoft Windows, see the [install guide](https://github.com/quixio/quix-cli?tab=readme-ov-file#installation-of-quix-cli){target=_blank}. +!!! tip + + To update Quix CLI just run `quix update` to get the latest version of Quix CLI. + ## Step 4: Initialize your project as a Quix project In your Git project directory, enter: diff --git a/docs/get-started/cli-quickstart.md b/docs/get-started/cli-quickstart.md index 772eda61..39b3f3e5 100644 --- a/docs/get-started/cli-quickstart.md +++ b/docs/get-started/cli-quickstart.md @@ -10,6 +10,10 @@ curl -fsSL https://github.com/quixio/quix-cli/raw/main/install.sh | sudo bash For further details on installation, including instructions for Microsoft Windows, see the [install guide](https://github.com/quixio/quix-cli?tab=readme-ov-file#installation-of-quix-cli){target=_blank}. +!!! tip + + To update Quix CLI just run `quix update` to get the latest version of Quix CLI. + ## Step 2: Sign up to Quix Cloud for free Sign up [here](https://portal.platform.quix.io/self-sign-up){target=_blank}.