Skip to content

Commit a44e74e

Browse files
authored
Docs Trigger & Components, Blog GRPC & Dynamic form (windmill-labs#452)
1 parent 944328c commit a44e74e

File tree

29 files changed

+323
-65
lines changed

29 files changed

+323
-65
lines changed
-42.3 KB
Binary file not shown.

blog/2023-12-15-query-grcp-service/index.md renamed to blog/2023-12-22-query-grcp-service/index.md

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,17 @@ slug: query-grpc-service
33
title: Querying gRPC service in Windmill
44
authors: [guillaumebouv]
55
tags: ['Windmill', 'gRPC', 'Developer tools']
6+
description: 'Learn how to query gRPC service in Windmill'
67
image: ./wmill_grpc.png
78
---
89

10+
Learn how to query [gRPC](https://grpc.io/) service in Windmill.
11+
12+
![gRPC Windmill](./wmill_grpc.png)
13+
914
To query a gRPC service, the client needs to know about its API definition (i.e. the `.proto` files). In some situations, the proto files are compiled in the desired language by the owner of the service and published as a package in the package repository. But when it's not the case, it can be cumbersome to query such a service.
1015

11-
In this post, we're going to see how you can easily workaround this limitation in Windmill using Bun and gRPC javascript `proto-loader` package.
16+
In this post, we're going to see how you can easily workaround this limitation in Windmill using Bun and gRPC JavaScript `proto-loader` package.
1217

1318
### Example stack
1419

@@ -43,11 +48,11 @@ message HelloReply {
4348

4449
As said in the intro, most language requires to manually "compile" the `.proto` files to be able to use them (we explain below how this can also be done in Windmill).
4550

46-
Thankfully, Javascript has is able to dynamically build a client from the raw `.proto` files. Here we're going to use Bun which recently added support for the HTTP2 protocol used by gRPC.
51+
Thankfully, JavaScript has is able to dynamically build a client from the raw `.proto` files. Here we're going to use Bun which recently added support for the HTTP2 protocol used by gRPC.
4752

4853
First, we need to save the content of the `.proto` file. We're going to use a Windmill variable so that it can be used in multiple scripts. Here we save it to a variable named `service_proto`.
4954

50-
Once it's done, we create a Bun script in Windmill with the following content:
55+
Once it's done, we create a [Bun script in Windmill](/docs/getting_started/scripts_quickstart/typescript) with the following content:
5156

5257
```js
5358
import * as wmill from "windmill-client"
@@ -106,20 +111,20 @@ This canonical script can be used in Flows to easily query the service and proce
106111

107112
### Statically defined gRPC services
108113

109-
If the `.proto` are not compiled by the service owner and you want to use another language than typescript (if if you're using javascript but don't want dynamic loading), you will have no other choice than to compile the `.proto` yourself. And then, to use the compiled service definition in Windmill, the easiest is to publish the files to a private package registry.
114+
If the `.proto` are not compiled by the service owner and you want to use another language than typescript (if if you're using JavaScript but don't want dynamic loading), you will have no other choice than to compile the `.proto` yourself. And then, to use the compiled service definition in Windmill, the easiest is to publish the files to a private package registry.
110115

111116
For Python for example, you can compile the `.proto` with:
112117

113118
```bash
114119
protoc --python_out=./ ./helloworld.proto
115120
```
116121

117-
This will generate a python file corresponding to your service definition in Python. You can then add this file to a python package of your choice, and publish it to a private Pypi repository (like [pypiserver](https://pypi.org/project/pypiserver/)). You can then (configure Windmill to use this repository)[https://www.windmill.dev/docs/advanced/imports#private-pypi-repository] and you will be able to pull the pre-compiled service definition from any python script in Windmill.
122+
This will generate a Python file corresponding to your service definition in Python. You can then add this file to a Python package of your choice, and publish it to a private Pypi repository (like [pypiserver](https://pypi.org/project/pypiserver/)). You can then ([configure Windmill to use this repository](/docs/advanced/imports#private-pypi-repository)) and you will be able to pull the pre-compiled service definition from any [Python script](/docs/getting_started/scripts_quickstart/python) in Windmill.
118123

119-
The same can be done for javascript. To compile the `.proto`, simply run:
124+
The same can be done for JavaScript. To compile the `.proto`, simply run:
120125

121126
```bash
122127
grpc_tools_node_protoc --js_out=import_style=commonjs,binary:./ --grpc_out=grpc_js:./ helloworld.proto
123128
```
124129

125-
And then upload the content as a NPM package to a private NPM registry (like [verdaccio](https://verdaccio.org/)) and (configure Windmill to pull package from it)[https://www.windmill.dev/docs/advanced/imports#private-npm-registry].
130+
And then upload the content as a NPM package to a private NPM registry (like [verdaccio](https://verdaccio.org/)) and ([configure Windmill to pull package from it](/docs/advanced/imports#private-npm-registry)).
Loading
2.74 MB
Loading

blog/2023-12-28-dynamic-form/index.md

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
---
2+
slug: dynamic-form
3+
title: Create a Dynamic Form Empowered by Code
4+
authors: [henricourdent]
5+
tags: ['Dynamic Form', 'App', 'Supabase']
6+
description: 'Create your own TypeForm-like dynamic form and embed scripts & flows'
7+
image: ./dynamic_form.png
8+
---
9+
10+
Create your own TypeForm-like dynamic form and embed scripts & flows.
11+
12+
![Dynamic Form](./dynamic_form.png "Dynamic Form")
13+
14+
Dynamic forms are essential tools to allow users to interactively input data in a way that adapts to their specific needs. Unlike static forms, dynamic forms can change in real-time based on user input. With code, you could even go forward and trigger actions from the form (send email, ask for refund, get more information).
15+
16+
Windmill's [Decision tree](/docs/apps/app_configuration_settings/decision_tree) component allows to define a flow-like structure with frames ordered by conditions. Each node in the tree represents a decision point and can lead to one or more subsequent nodes based on specified conditions.
17+
18+
By combining it with other components such as the [form](/docs/apps/app_configuration_settings/form_input) component or [buttons](/docs/apps/app_configuration_settings/button), it is possible to create a completely customized dynamic form yourself, with the incorporation of [scripts](/docs/script_editor) and [flows](/docs/flows/flow_editor) to trigger powerful actions.
19+
20+
## Tutorial
21+
22+
The tutorial video below shows the creation of a dynamic form collecting consumer feedback, sending a message on [Slack](https://hub.windmill.dev/scripts/slack/1432/send-direct-message-slack) or [Gmail](https://hub.windmill.dev/scripts/gmail/1291/-send-email-gmail), before [storing the responses](#insert-row-to-supabase) in a PostgreSQL table in Supabase.
23+
24+
<iframe
25+
style={{ aspectRatio: '16/9' }}
26+
src="https://www.youtube.com/embed/MTGZTO1AduM?vq=hd1080"
27+
title="Dynamic Form Tutorial"
28+
frameBorder="0"
29+
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
30+
allowFullScreen
31+
className="border-2 rounded-xl object-cover w-full dark:border-gray-800"
32+
></iframe>
33+
34+
<br/>
35+
36+
## Code used
37+
38+
### App and decision tree
39+
40+
The app can be found on [WindmillHub](https://hub.windmill.dev/apps/21/dynamic-form-example).
41+
42+
### Insert row to Supabase
43+
44+
Script wrote with [WindmillAI](/docs/core_concepts/ai_generation):
45+
46+
```ts
47+
import { createClient } from "npm:@supabase/supabase-js";
48+
49+
// Define the Supabase resource type as specified
50+
type Supabase = {
51+
key: string;
52+
url: string;
53+
};
54+
55+
export async function main(
56+
supabaseResource: Supabase,
57+
tableName: string,
58+
rowData: Record<string, any>,
59+
) {
60+
// Initialize the Supabase client
61+
const supabase = createClient(supabaseResource.url, supabaseResource.key);
62+
63+
// Insert a row into the specified table
64+
const { data, error } = await supabase
65+
.from(tableName)
66+
.insert([rowData]);
67+
68+
// Return the result or throw an error if the operation failed
69+
if (error) {
70+
throw error;
71+
}
72+
73+
return data;
74+
}
75+
```
76+
77+
with `rowData` =
78+
79+
```
80+
{
81+
"name": b.values.first_name,
82+
"city": b.values.City,
83+
"email": c.values.Email,
84+
"contact": c.values.Contact,
85+
"rating": f.result,
86+
"feedback": bg_0.result
87+
}
88+
```
89+
90+
### Flow to send Slack or Email to user based on their choice
91+
92+
The flow can be found on [WindmillHub](https://hub.windmill.dev/flows/52/send-slack-or-email-to-user-based-on-their-choice).
93+
94+
### Return feedback from both form components (positive and negative) into a single string
95+
96+
Script wrote with [WindmillAI](/docs/core_concepts/ai_generation):
97+
98+
```py
99+
from typing import Optional, TypedDict
100+
101+
102+
# Define the main function with optional parameters 'positive' and 'negative'
103+
def main(positive: Optional[str] = None, negative: Optional[str] = None) -> str:
104+
# Check if both 'positive' and 'negative' are provided
105+
if positive and negative:
106+
return f"{positive}.{negative}"
107+
# Return 'positive' if only 'positive' is provided
108+
elif positive:
109+
return positive
110+
# Return 'negative' if only 'negative' is provided
111+
elif negative:
112+
return negative
113+
# Return an empty string if neither is provided
114+
else:
115+
return ""
116+
```

docs/advanced/1_self_host/index.mdx

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,12 +157,34 @@ In the docker-compose, set the number of windmill_worker and windmill_worker_nat
157157

158158
### Enterprise Edition
159159

160-
To use the [enterprise edition](../../misc/7_plans_details/index.mdx), you need pass the license key in the instance settings (Superadmin settings -> Instance settings)
160+
To use the [enterprise edition](../../misc/7_plans_details/index.mdx), you need pass the license key in the instance settings (Superadmin settings -> Instance settings).
161161

162162
You can then set the number of replicas of the multiplayer container to 1 in the docker-compose.
163163

164164
You will be provided a license key when you purchase the enterprise edition. Contact us at contact@windmill.dev to get a trial license key. Pricing is at [https://windmill.dev/pricing](https://windmill.dev/pricing). You will benefit from support, SLA and all the [additional features](../../misc/7_plans_details/index.mdx) of the enterprise edition.
165165

166+
<iframe
167+
style={{ aspectRatio: '16/9' }}
168+
src="https://www.youtube.com/embed/YAoLXwayjT8?vq=hd1080"
169+
title="YouTube video player"
170+
frameBorder="0"
171+
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
172+
allowFullScreen
173+
className="border-2 rounded-xl object-cover w-full dark:border-gray-800"
174+
></iframe>
175+
176+
<br/>
177+
178+
More details at:
179+
180+
<div class="grid grid-cols-2 gap-6 mb-4">
181+
<DocCard
182+
title="Upgrade to Enterprise Edition"
183+
description="Docs on how to upgrade to the Enterprise Edition of a Self-Hosted Windmill instance."
184+
href="/docs/misc/plans_details#self-host"
185+
/>
186+
</div>
187+
166188
### Configuring Domain and Reverse Proxy
167189

168190
To deploy Windmill to the `windmill.example.com` domain, make sure to set "Base Url" correctly in the Instance Settings (Superadmin Settings -> Instance Settings -> Base Url)

docs/apps/4_app_configuration_settings/1_app_component_library.mdx

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,25 @@ The layout components are used to organize the components in the app canvas.
113113
alt="stepper"
114114
/>
115115

116+
### [Carousel List](./carousel.mdx)
117+
118+
The Carousel List component enables duplication of cards or rows with consistent structure in a carousel, allowing for containment of other components. By default, editing or moving a component will apply changes to all cards or rows, while still allowing customization and exceptions for unique values per component.
119+
120+
<video
121+
className="border-2 rounded-xl object-cover w-full h-full dark:border-gray-800"
122+
autoPlay
123+
controls
124+
src="/videos/carousel_component.mp4"
125+
alt="carousel list component"
126+
/>
127+
128+
### [Decision Tree](./decision_tree.mdx)
129+
130+
This component allows you to create a decision tree. The decision tree is controlled by a flow-like structure. Each node in the tree represents a decision point and can lead to one or more subsequent nodes based on specified conditions.
131+
132+
![Decision Tree](../../assets/apps/4_app_component_library/decision-tree.png.webp)
133+
134+
116135
## Tabs
117136

118137
### [Tabs](./tabs.mdx)
@@ -174,7 +193,7 @@ The layout components are used to organize the components in the app canvas.
174193

175194
### [Form](./form_input.mdx)
176195

177-
![Form Input API](../../assets/apps/4_app_component_library/form_input.png.webp)
196+
![Form](../../assets/apps/4_app_component_library/form_input.png.webp)
178197

179198
### [Text Input](./text_input.mdx)
180199

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import DocCard from '@site/src/components/DocCard';
2+
3+
# Carousel List
4+
5+
The Carousel List component enables duplication of cards or rows with consistent structure in a carousel, allowing for containment of other components. By default, editing or moving a component will apply changes to all cards or rows, while still allowing customization and exceptions for unique values per component.
6+
7+
<video
8+
className="border-2 rounded-xl object-cover w-full h-full dark:border-gray-800"
9+
autoPlay
10+
controls
11+
src="/videos/carousel_component.mp4"
12+
alt="carousel list component"
13+
/>
14+
<br/>
15+
16+
To add a component to a card, you can either click on `Insert` while you select the container, or you can move an existing component by copy/pasting it.
17+
18+
Editing or moving a component will apply changes to all cards or rows.
19+
20+
To customize the settings of components within each time, you can use `iter.index` and `iter.value`.
21+
22+
- `iter.index` will retrieve the index number of each card (0, 1, 2 etc.).
23+
24+
- `iter.value.key` will retrieve the value of each key defined in the `items` section.
25+
26+
![iter.index](../../assets/apps/4_app_component_library/iter_value.png)
27+
28+
List components also support having inputs set inside them. Retrieve the values of each in the `inputs` field of the List component in the [outputs](../2_outputs.mdx) menu.
29+
30+
<video
31+
className="border-2 rounded-xl object-cover w-full h-full dark:border-gray-800"
32+
autoPlay
33+
controls
34+
src="/videos/list_inputs.mp4"
35+
alt="List inputs"
36+
/>
37+
<br/>
38+
39+
The following section details Carousel List component's specific settings. For more details on the App Editor, check the [dedicated documentation](../0_app_editor/index.mdx) or the App Editor [Quickstart](../../getting_started/7_apps_quickstart/index.mdx):
40+
41+
<div class="grid grid-cols-2 gap-6 mb-4">
42+
<DocCard
43+
color="orange"
44+
title="App Editor Documentation"
45+
description="The app editor is a low-code builder to create custom User Interfaces with a mix of drag-and-drop and code."
46+
href="/docs/apps/app_editor"
47+
/>
48+
<DocCard
49+
color="orange"
50+
title="Apps Quickstart"
51+
description="Learn how to build your first app in a matter of minutes."
52+
href="/docs/getting_started/apps_quickstart"
53+
/>
54+
</div>
55+
56+
## Carousel List configuration
57+
58+
| Name | Type | Connectable | Templatable | Default | Description |
59+
| ------------ | :----: | :---------: | :---------: | :-------------------: | -------------------------------- |
60+
| Items | array | true | false | 3 items | The Carousel List items in JSON. |
61+
| Timing Fonctions | select ("linear", "ease", "ease-in", "ease-out", "ease-in-out") | true | false | "linear" | Sets how an animation progresses through the duration of each cycle, see https://developer.mozilla.org/en-US/docs/Web/CSS/animation-timing-function |
62+
63+
## Outputs
64+
65+
| Name | Type | Description |
66+
| ------- | :-----: | --------------------------------------- |
67+
| result | any | The result of the list component. |
68+
| loading | boolean | The loading state of the component. |
69+
| inputs | any | The inputs of the component. |

docs/apps/4_app_configuration_settings/container.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Containers allow you to host other components in a box. Moving a container means
1414
/>
1515
<br/>
1616

17-
To add a component to a container, you can either click on `Insert` while you selected the container,or your can move an existing component by copy/pasting it.
17+
To add a component to a container, you can either click on `Insert` while you select the container,or you can move an existing component by copy/pasting it.
1818

1919
The following section details Container component's specific settings. For more details on the App Editor, check the [dedicated documentation](../0_app_editor/index.mdx) or the App Editor [Quickstart](../../getting_started/7_apps_quickstart/index.mdx):
2020

docs/apps/4_app_configuration_settings/drawer.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ The drawer is container called by a button. Once you click on the button, a side
1414
/>
1515
<br/>
1616

17-
To add a component to a container, you can either click on `Insert` while you selected the opened drawer, or your can move an existing component by copy/pasting it.
17+
To add a component to a container, you can either click on `Insert` while you selected the opened drawer, or you can move an existing component by copy/pasting it.
1818

1919
The following section details Drawer component's specific settings. For more details on the App Editor, check the [dedicated documentation](../0_app_editor/index.mdx) or the App Editor [Quickstart](../../getting_started/7_apps_quickstart/index.mdx):
2020

0 commit comments

Comments
 (0)