diff --git a/.github/ISSUE_TEMPLATE/3.rfc.yml b/.github/ISSUE_TEMPLATE/3.rfc.yml
index a5eef95af73..e8e4a4c25b3 100644
--- a/.github/ISSUE_TEMPLATE/3.rfc.yml
+++ b/.github/ISSUE_TEMPLATE/3.rfc.yml
@@ -13,18 +13,15 @@ body:
attributes:
label: What's the problem? 🤔
description: Write a short paragraph or bulleted list to briefly explain what you're trying to do, what outcomes you're aiming for, and any other relevant details to help us understand the motivation behind this RFC.
-
- type: textarea
attributes:
label: What are the requirements? ❓
description: Provide a list of requirements that should be met by the accepted proposal.
-
- type: textarea
attributes:
label: What are our options? 💡
description: |
Have you considered alternative options for achieving your desired outcome? It's not necessary to go into too much detail here, but it can help strengthen your main proposal.
-
- type: textarea
attributes:
label: Proposed solution 🟢
@@ -35,7 +32,6 @@ body:
- using diagrams to help illustrate your ideas
- including code examples if you're proposing an interface or system contract
- linking to relevant project briefs or wireframes
-
- type: textarea
attributes:
label: Resources and benchmarks 🔗
diff --git a/.github/ISSUE_TEMPLATE/4.design.yml b/.github/ISSUE_TEMPLATE/4.design.yml
deleted file mode 100644
index f3cf6e5a2f4..00000000000
--- a/.github/ISSUE_TEMPLATE/4.design.yml
+++ /dev/null
@@ -1,28 +0,0 @@
-name: Design spec 💄
-description: Describe design requirements.
-labels: ['design']
-body:
- - type: textarea
- attributes:
- label: Description
- description: Description of the project. What is the problem you're trying to solve? Include any contextual links.
- - type: textarea
- attributes:
- label: Audience
- description: Who does this affect? Who will determine if this is successful (stakeholders)?
- - type: textarea
- attributes:
- label: Goals
- description: What is the purpose of this project? What are users/we getting out of this?
- - type: textarea
- attributes:
- label: Metrics
- description: How is success defined for this project? Are there specific KPIs tied to it?
- - type: textarea
- attributes:
- label: Timeline
- description: When is this due? Working backwards from there, include dates for a few drafts and feedback cycles
- - type: textarea
- attributes:
- label: Specs
- description: What are the constraints, sizes, etc? Include any links to spec sheets or detail pages.
diff --git a/.github/ISSUE_TEMPLATE/4.docs-feedback.yml b/.github/ISSUE_TEMPLATE/4.docs-feedback.yml
new file mode 100644
index 00000000000..ab07cd43ab4
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/4.docs-feedback.yml
@@ -0,0 +1,48 @@
+name: Docs feedback
+description: Improve documentation about MUI Toolpad.
+labels: ['status: waiting for maintainer', 'support: docs-feedback']
+title: '[docs] '
+body:
+ - type: markdown
+ attributes:
+ value: |
+ Please provide a searchable summary of the issue in the title above ⬆️.
+
+ Thanks for contributing by creating an issue! ❤️
+ - type: input
+ attributes:
+ label: Search keywords
+ description: Your issue may have already been reported! List the keywords you've used to search the [existing issues](https://github.com/mui/mui-toolpad/issues). This will also make your issue searchable for others.
+ placeholder: e.g. datagrid column resizing
+ validations:
+ required: true
+ - type: input
+ id: page-url
+ attributes:
+ label: Related page
+ description: Which page of the documentation is this about?
+ placeholder: https://mui.com/toolpad/
+ validations:
+ required: true
+ - type: dropdown
+ attributes:
+ label: Kind of issue
+ description: What kind of problem are you facing?
+ options:
+ - Unclear explanations
+ - Missing information
+ - Broken demo
+ - Other
+ validations:
+ required: true
+ - type: textarea
+ attributes:
+ label: Issue description
+ description: |
+ Let us know what went wrong when you were using this documentation and what we could do to improve it.
+ value: |
+ I was looking for ... and it appears that ...
+ - type: textarea
+ attributes:
+ label: Context 🔦
+ description: What are you trying to accomplish? What brought you to this page? Your context can help us to come up with solutions that benefit the community as a whole.
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index e93e80dcae1..96f7575b980 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -19,7 +19,7 @@ jobs:
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
- uses: github/codeql-action/init@c0d1daa7f7e14667747d73a7dbbe8c074bc8bfe2 # v2.22.9
+ uses: github/codeql-action/init@b374143c1149a9115d881581d29b8390bbcbb59c # v3.22.11
with:
languages: typescript
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -29,4 +29,4 @@ jobs:
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
- name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@c0d1daa7f7e14667747d73a7dbbe8c074bc8bfe2 # v2.22.9
+ uses: github/codeql-action/analyze@b374143c1149a9115d881581d29b8390bbcbb59c # v3.22.11
diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml
index 5d385d300ee..c45973dc7ca 100644
--- a/.github/workflows/scorecards.yml
+++ b/.github/workflows/scorecards.yml
@@ -44,6 +44,6 @@ jobs:
# Upload the results to GitHub's code scanning dashboard.
- name: Upload to code-scanning
- uses: github/codeql-action/upload-sarif@c0d1daa7f7e14667747d73a7dbbe8c074bc8bfe2 # v2.22.9
+ uses: github/codeql-action/upload-sarif@b374143c1149a9115d881581d29b8390bbcbb59c # v3.22.11
with:
sarif_file: results.sarif
diff --git a/.github/workflows/update-monorepo.yml b/.github/workflows/update-monorepo.yml
index 5be28393b16..7e7d719a79f 100644
--- a/.github/workflows/update-monorepo.yml
+++ b/.github/workflows/update-monorepo.yml
@@ -12,7 +12,7 @@ jobs:
issues: write
steps:
- name: Set up Node.js ⚙️
- uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4
+ uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4
with:
node-version: '18.x'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 199205ef1eb..3c07b5bdb82 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,33 @@
# Changelog
+## 0.1.42
+
+
+
+_Dec 22, 2023_
+
+A big thanks to the 5 contributors who made this release possible. Here are some highlights ✨:
+
+This week: a big overhaul to our query editor! Improved titles for pages in the sidebar. Support server-side row updates for the data grid.
+
+- Remove components from appDom (#3017) @Janpot
+- Introduce pagesManifest (#3016) @Janpot
+- Add labels to form validation properties (#3015) @Janpot
+- Guess proper default page titles based on page name (#3014) @Janpot
+- Remove functions worker (#3013) @Janpot
+- Add a new query panel (#2393) @bharatkashyap
+- Support updating rows in the data provider (#3001) @Janpot
+- Improve styling of the application navigation (#2993) @Janpot
+- Bring in some fixes from pnpm migration branch (#3010) @Janpot
+- Update yarn.lock (#3008) @apedroferreira
+- Update monorepo (#2998) @apedroferreira
+- fix 2527, customize page name (#2850) @JerryWu1234
+- Fix changelog (#2995) @apedroferreira
+- [docs] Update documentation for query panel (#3000) @bharatkashyap
+- [docs] Fix 301 links @oliviertassinari
+
+All contributors of this release in alphabetical order: @apedroferreira, @bharatkashyap, @Janpot, @JerryWu1234, @oliviertassinari
+
## 0.1.41
diff --git a/README.md b/README.md
index e7e922aa2d4..d7b1e1b17a4 100644
--- a/README.md
+++ b/README.md
@@ -51,7 +51,7 @@ pnpm create toolpad-app my-toolpad-app
## Documentation
-Check out our [documentation](https://mui.com/toolpad/getting-started/overview/).
+Check out our [documentation](https://mui.com/toolpad/getting-started/).
## Examples
diff --git a/docs/README.md b/docs/README.md
index 6b80fb9f73c..30fa5a8d45a 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -12,7 +12,7 @@ If you do not have yarn installed, select your OS and follow the instructions on
_DO NOT USE NPM, use Yarn to install the dependencies._
-Visit the [MUI Toolpad documentation](https://mui.com/toolpad/getting-started/overview/).
+Visit the [MUI Toolpad documentation](https://mui.com/toolpad/getting-started/).
## How can I add a new demo to the documentation?
diff --git a/docs/data/pages.ts b/docs/data/pages.ts
index e90801a2ca2..d4a097cd987 100644
--- a/docs/data/pages.ts
+++ b/docs/data/pages.ts
@@ -3,9 +3,9 @@ import componentsManifest from './toolpad/reference/components/manifest.json';
const pages: MuiPage[] = [
{
- pathname: '/toolpad/getting-started',
+ pathname: '/toolpad/getting-started-group',
children: [
- { pathname: '/toolpad/getting-started/overview' },
+ { pathname: '/toolpad/getting-started', title: 'Overview' },
{ pathname: '/toolpad/getting-started/installation' },
{ pathname: '/toolpad/getting-started/why-toolpad', title: 'Why Toolpad?' },
{ pathname: '/toolpad/getting-started/first-app', title: 'Build your first app' },
diff --git a/docs/data/toolpad/concepts/custom-functions.md b/docs/data/toolpad/concepts/custom-functions.md
index a16c97ff814..63e892c9f18 100644
--- a/docs/data/toolpad/concepts/custom-functions.md
+++ b/docs/data/toolpad/concepts/custom-functions.md
@@ -5,7 +5,7 @@
The most powerful way of bringing data into Toolpad is through your own code. You can define functions inside `toolpad/resources` and use them when creating a query of this type. The following video shows how you can use this feature to read data from PostgreSQL.
-
+
Your browser does not support the video tag.
@@ -36,7 +36,7 @@ You get the following response:
-{{"component": "modules/components/DocsImage.tsx", "src": "/static/toolpad/docs/concepts/connecting-to-data/query-8.png", "alt": "Server-side values", "caption": "Using server-side values in custom functions", "indent": 1 }}
+{{"component": "modules/components/DocsImage.tsx", "src": "/static/toolpad/docs/concepts/connecting-to-data/query-8.png", "alt": "Server-side values", "caption": "Using server-side values in custom functions", "indent": 1, "aspectRatio": 6 }}
@@ -67,7 +67,7 @@ export async function getAnimals(
}
```
-{{"component": "modules/components/DocsImage.tsx", "src": "/static/toolpad/docs/concepts/connecting-to-data/custom-function-params.png", "alt": "Controls for custom function parameters", "caption": "Controls for custom function parameters", "indent": 1, "zoom": false, "width": 639}}
+{{"component": "modules/components/DocsImage.tsx", "src": "/static/toolpad/docs/concepts/connecting-to-data/query-9.png", "alt": "Controls for custom function parameters", "caption": "Controls for custom function parameters", "indent": 1, "aspectRatio": 6}}
:::info
Toolpad also provides a `createFunction` API to be able to define your parameters when creating custom functions:
diff --git a/docs/data/toolpad/concepts/data-providers.md b/docs/data/toolpad/concepts/data-providers.md
index 4da860a5249..dccc79e9ed6 100644
--- a/docs/data/toolpad/concepts/data-providers.md
+++ b/docs/data/toolpad/concepts/data-providers.md
@@ -138,13 +138,32 @@ Uncheck the column option "sortable" if you want to disable sorting for a certai
{{"component": "modules/components/DocsImage.tsx", "src": "/static/toolpad/docs/concepts/data-providers/disable-sortable.png", "alt": "Disable sortable", "caption": "Disable sortable", "zoom": false, "width": 325 }}
-## Row editing 🚧
+## Row editing
-:::warning
-This feature isn't implemented yet.
+The data provider can be extended to automatically support row editing. To enable this, you'll have to add a `updateRecord` method to the data provider interface that accepts the `id` of the row that is to be deleted, and an object containing all the updated fields from the row editing operation.
-👍 Upvote [issue #2887](https://github.com/mui/mui-toolpad/issues/2887) if you want to see it land faster.
-:::
+```tsx
+export default createDataProvider({
+ async getRecords() {
+ return prisma.users.findMany();
+ },
+
+ async updateRecord(id, data) {
+ return prisma.users.update({ where: { id }, data });
+ },
+});
+```
+
+When this method is available in the data provider, each row will have an edit button. This edit button brings the row in edit mode. To commit the changes press the save button on the row that is in edit mode. To discard the changes use the cancel button.
+
+
+
+ Your browser does not support the video tag.
+
+
+You can disable the editing functionality for specific columns by unchecking the **Editable** option in the column definition.
+
+{{"component": "modules/components/DocsImage.tsx", "src": "/static/toolpad/docs/concepts/data-providers/disable-editable.png", "alt": "Disable editable", "caption": "Disable editable", "zoom": false, "width": 308 }}
## Row creation 🚧
diff --git a/docs/data/toolpad/concepts/http-requests.md b/docs/data/toolpad/concepts/http-requests.md
index d62f3eda8d7..5eb93daa4df 100644
--- a/docs/data/toolpad/concepts/http-requests.md
+++ b/docs/data/toolpad/concepts/http-requests.md
@@ -2,7 +2,7 @@
These offer a fast way to load external data from REST APIs, via a configurable interface.
-{{"component": "modules/components/DocsImage.tsx", "src": "/static/toolpad/docs/concepts/connecting-to-data/query-1.png", "alt": "Add HTTP request", "caption": "Adding a query via the HTTP Request editor" }}
+{{"component": "modules/components/DocsImage.tsx", "src": "/static/toolpad/docs/concepts/connecting-to-data/query-1.png", "alt": "Add HTTP request", "caption": "Adding a query via the HTTP Request panel" }}
## HTTP Request editor
@@ -13,7 +13,7 @@ The following options are configurable here:
You can add query parameters to your request here. These get appended to the request URL, like
`https://dog.ceo/api/breed/akita/images/random?param1=value1`
-{{"component": "modules/components/DocsImage.tsx", "src": "/static/toolpad/docs/concepts/connecting-to-data/query-2.png", "alt": "Add query params", "caption": "Adding a query parameter", "indent": 1 }}
+{{"component": "modules/components/DocsImage.tsx", "src": "/static/toolpad/docs/concepts/connecting-to-data/query-2.png", "alt": "Add query params", "caption": "Adding a query parameter", "indent": 1, "aspectRatio": 6 }}
- ### Body
@@ -25,13 +25,13 @@ The following options are configurable here:
> `GET` requests do not have a request body
-{{"component": "modules/components/DocsImage.tsx", "src": "/static/toolpad/docs/concepts/connecting-to-data/query-3.png", "alt": "Add request body", "caption": "Adding a request body", "indent": 1 }}
+{{"component": "modules/components/DocsImage.tsx", "src": "/static/toolpad/docs/concepts/connecting-to-data/query-3.png", "alt": "Add request body", "caption": "Adding a request body", "indent": 1, "aspectRatio": 6 }}
- ### Request headers
You can define extra headers to be sent along with the request in this tab.
-{{"component": "modules/components/DocsImage.tsx", "src": "/static/toolpad/docs/concepts/connecting-to-data/http-query-headers.png", "alt": "Add request header", "caption": "Adding a request header", "indent": 1 }}
+{{"component": "modules/components/DocsImage.tsx", "src": "/static/toolpad/docs/concepts/connecting-to-data/query-4.png", "alt": "Add request header", "caption": "Adding a request header", "indent": 1, "aspectRatio": 6 }}
- ### Response
@@ -43,13 +43,13 @@ The following options are configurable here:
- `raw`: Do not parse the response and return the response as text.
-{{"component": "modules/components/DocsImage.tsx", "src": "/static/toolpad/docs/concepts/connecting-to-data/query-5.png", "alt": "Add response parse format", "caption": "Adding a response parse format", "indent": 1 }}
+{{"component": "modules/components/DocsImage.tsx", "src": "/static/toolpad/docs/concepts/connecting-to-data/query-5.png", "alt": "Add response parse format", "caption": "Adding a response parse format", "indent": 1, "aspectRatio": 6 }}
- ### Transform
You can transform the response via a JavaScript expression in this tab. This expression must return a `data` variable.
-{{"component": "modules/components/DocsImage.tsx", "src": "/static/toolpad/docs/concepts/connecting-to-data/query-6.png", "alt": "Add transformation", "caption": "Transforming the response via JavaScript", "indent": 1 }}
+{{"component": "modules/components/DocsImage.tsx", "src": "/static/toolpad/docs/concepts/connecting-to-data/query-6.png", "alt": "Add transformation", "caption": "Transforming the response via JavaScript", "indent": 1, "aspectRatio": 6 }}
## Parameters
@@ -57,9 +57,9 @@ To be really useful, you need to connect these queries with data present on your
You can define these in the interface available in the HTTP Request query editor. You can bind a parameter to any value available on the page, and the parameter can be bound to any value in the query.
-{{"component": "modules/components/DocsImage.tsx", "src": "/static/toolpad/docs/concepts/connecting-to-data/example-parameter.png", "alt": "HTTP Request parameter", "caption": "Creating a parameter and binding it", "indent": 1 }}
+{{"component": "modules/components/DocsImage.tsx", "src": "/static/toolpad/docs/concepts/connecting-to-data/example-parameter.png", "alt": "HTTP Request parameter", "caption": "Creating a parameter and binding it", "indent": 1, "aspectRatio": 6 }}
-{{"component": "modules/components/DocsImage.tsx", "src": "/static/toolpad/docs/concepts/connecting-to-data/url-bound-parameter.png", "alt": "Server-side values", "caption": "Using the parameter in the query URL", "indent": 1 }}
+{{"component": "modules/components/DocsImage.tsx", "src": "/static/toolpad/docs/concepts/connecting-to-data/bound-parameter.png", "alt": "Server-side values", "caption": "Using the parameter in the query URL", "indent": 1, "aspectRatio": 6 }}
### Secrets
diff --git a/docs/data/toolpad/concepts/page-properties.md b/docs/data/toolpad/concepts/page-properties.md
index 3a5bcfc2ced..6a5564a4330 100644
--- a/docs/data/toolpad/concepts/page-properties.md
+++ b/docs/data/toolpad/concepts/page-properties.md
@@ -10,11 +10,13 @@
The possible options for the the display mode are:
-- **App shell**: Pages with their display mode set to this value will render within the navigation sidebar on the left, allowing for easy navigation between all pages:
+- **App shell**: Pages with their display mode set to this value will render within the navigation sidebar on the left, allowing for easy navigation between all pages.
+
+To display a different name for a page in the sidebar, the page **display name** can be set.
{{"component": "modules/components/DocsImage.tsx", "src": "/static/toolpad/docs/concepts/page-properties/app-shell.png", "alt": "App shell display mode ", "caption": "Page with display mode set to App shell", "indent": 1 }}
-- **No shell**: Pages with their display mode set to this value will render without the navigation sidebar
+- **No shell**: Pages with their display mode set to this value will render without the navigation sidebar.
{{"component": "modules/components/DocsImage.tsx", "src": "/static/toolpad/docs/concepts/page-properties/no-shell.png", "alt": "No shell display mode ", "caption": "Page with display mode set to No shell", "indent": 1}}
diff --git a/docs/data/toolpad/concepts/queries.md b/docs/data/toolpad/concepts/queries.md
index a0fba7b02d8..d178b606275 100644
--- a/docs/data/toolpad/concepts/queries.md
+++ b/docs/data/toolpad/concepts/queries.md
@@ -1,53 +1,47 @@
-# Queries
+# Connecting to data
-Be it a database table or an external API, Toolpad offers mechanisms to bring server-side data to the page.
-
-You can create two kinds of **queries** in Toolpad to bring data to your page.
-
-1. HTTP request
-2. Custom functions
+Be it a database table or an external API, Toolpad offers mechanisms to bring server-side data to the page as well as make mutations to external data sources.
:::info
-Toolpad uses `react-query` internally to run queries. Look into [its documentation](https://tanstack.com/query/latest/docs/react/guides/queries) for more details on query objects.
+Toolpad uses `react-query` internally to run queries and actions. Look into [its documentation](https://tanstack.com/query/latest/docs/react/guides/queries) for more details on query objects.
:::
-## Mode
+## Queries
-You can set the **mode** of the query to either be automatically refetched on page load, or only be called on manual action.
+Queries allow you to bring backend data to your Toolpad page. They are called automatically on page load, so that data is available as state on the page as soon as the user interacts with it. Toolpad will cache and regularly refresh the data. This means that your backend function will be called more than once. Queries are not suitable for backend functions that modify data. You can modify the following settings for queries:
-{{"component": "modules/components/DocsImage.tsx", "src": "/static/toolpad/docs/concepts/connecting-to-data/mode-query.gif", "alt": "Query mode", "caption": "Setting the query mode", "indent": 1, "aspectRatio": 6}}
+{{"component": "modules/components/DocsImage.tsx", "src": "/static/toolpad/docs/concepts/connecting-to-data/query-settings.png", "alt": "Query settings", "caption": "Settings for queries", "indent": 1, "aspectRatio": 6}}
-- ### Automatic
+- **`Mode`**
- You can configure the following settings in this mode:
+ You can turn a query into an action through this setting.
- - **Enabled**
+- **`Refetch interval`**
- You can use this option to enable or disable the query from running
+ You can configure the query to run on an interval, for example every 30s.
- - **Refetch interval**
+- **`Enabled`**
- You can configure the query to run on an interval, for example every 30s.
- To disable this option, keep the field empty.
+ You can use this option to enable or disable the query from running
- Queries set to the automatic mode may be re-fetched via the `refetch` function available on these query objects. For example, for a query named `getOrders`, we can add
+Queries may be programatically re-fetched via the `refetch` function available on these query objects. For example, for a query named `getOrders`, we can add
- ```js
- getOrders.refetch();
- ```
+```js
+getOrders.refetch();
+```
- in the `onClick` binding of a Button component.
+in the `onClick` binding of a Button component.
-- ### Manual
+## Actions
- Queries set to this mode can be called via a JavaScript expression in a binding. For example, for a query named `createCustomer`, we can add
+Actions allow performing updates to remote data sources (edit, update, delete) on a user interaction. Actions are not automatically called, they must be programtically called a JavaScript expression in a binding. For example, for a query named `createCustomer`, we can add
- ```js
- createCustomer.call();
- ```
+```js
+createCustomer.call();
+```
- in the `onClick` binding of a Button component. This will trigger this query when the Button is clicked.
+in the `onClick` binding of a Button component.
:::info
-See the [event handling](/toolpad/concepts/event-handling/) section for more details, and the [deleting data grid row](/toolpad/how-to-guides/delete-datagrid-row/) guide for a detailed usage example.
+See the [event handling](/toolpad/concepts/event-handling/) section for more details
:::
diff --git a/docs/data/toolpad/getting-started/first-app.md b/docs/data/toolpad/getting-started/first-app.md
index 610b136c793..5328d43ec16 100644
--- a/docs/data/toolpad/getting-started/first-app.md
+++ b/docs/data/toolpad/getting-started/first-app.md
@@ -50,29 +50,37 @@ Make sure to [install Node.js](https://nodejs.org/en) on your system.
### Fetch data
-1. Click anywhere inside the canvas (except on the components that you just added) to deselect all components.
+1. Locate the **+** (create new) button in the queries explorer. Press it and choose **REST API**.
-1. Locate the **Add query** button inside the inspector. Press it and choose **HTTP request**.
+{{"component": "modules/components/DocsImage.tsx", "src": "/static/toolpad/docs/getting-started/first-app/step-2.png", "alt":"Choose REST API", "caption":"The Add query menu", "zoom": false }}
-{{"component": "modules/components/DocsImage.tsx", "src": "/static/toolpad/docs/getting-started/first-app/step-2.png", "alt":"Choose HTTP request", "caption":"The Add query menu", "zoom": false }}
+2. We'll be using the [dog API](https://dog.ceo/dog-api/) for this tutorial. Set
-3. We'll be using the [dog API](https://dog.ceo/dog-api/) for this tutorial. First give the query a unique name: `dogQuery`. Then, set `https://dog.ceo/api/breeds/list/all` as the **URL**. Click the **Preview** button to inspect the result of this request, and expand the `message` object in the response. If all went well, it will look like this:
+ ```html
+ https://dog.ceo/api/breeds/list/all
+ ```
+
+ as the **URL**. Click the **Run** button to inspect the result of this request, and expand the `message` object in the response. If all went well, it will look like this:
-{{"component": "modules/components/DocsImage.tsx", "src": "/static/toolpad/docs/getting-started/first-app/step-3.png", "alt": "Fetch URL", "caption": "The dog API response", "indent": 1 }}
+{{"component": "modules/components/DocsImage.tsx", "src":"/static/toolpad/docs/getting-started/first-app/step-3.png", "alt": "Fetch URL", "caption": "The dog API response", "indent": 1 }}
-4. To transform the response according to our needs, we choose the **Transform** tab and enable the **Transform response** option. Write the JavaScript expression:
+3. To transform the response
+ according to our needs, we choose the **Transform** tab and enable the **Transform
+ response** option. Write the JavaScript expression:
```js
return Object.entries(data.message);
```
- in the editor. Click **Preview** again to verify the result.
+ in the editor. Click **Run** again to verify the result.
{{"component": "modules/components/DocsImage.tsx", "src": "/static/toolpad/docs/getting-started/first-app/step-4.png", "alt": "Transform response", "caption": "The dog API response transformed", "indent": 1 }}
+5. Click on **Save** to save the query, and then rename it to `dogQuery` by double clicking on it in the explorer.
+
### Bind data to UI
-1. Save the query and close the query editor. Next, we will bind this data to components on the page. Click the **Data Grid** component to select it.
+1. Next, we will bind this data to components on the page. Click the **Data Grid** component to select it.
1. Find the **rows** property in the inspector. Notice that there's a small **Bind** button to its right. Properties with this button next to them can be bound to state available on the page:
@@ -96,7 +104,9 @@ Make sure to [install Node.js](https://nodejs.org/en) on your system.
### Make the app interactive
-1. Now, we can make this app interactive by displaying a random image of the selected breed. We'll create another query which reacts to the selection inside the Data Grid component. Deselect all components and click on **Add query** → **HTTP request**. Name it "imageQuery" and add a `breed` parameter in the **Parameters** section on the bottom:
+1. Now, we can make this app interactive by displaying a random image of the selected breed. We'll create another query which reacts to the selection inside the Data Grid component.
+
+2. Create another query of the **REST API** type and add a `breed` parameter in the **Parameters** section on the right:
{{"component": "modules/components/DocsImage.tsx", "src": "/static/toolpad/docs/getting-started/first-app/step-8.png", "alt": "Breed parameter", "caption": "Editing imageQuery", "indent": 1 }}
@@ -120,7 +130,9 @@ Make sure to [install Node.js](https://nodejs.org/en) on your system.
4. Save the binding and close the binding editor. Save the query and exit the query editor.
-5. In the canvas select the **Image** component to view its properties in the inspector. Click on the **Bind** button next to the **src** prop to open the binding editor, and bind it to `imageQuery.data.message`.
+5. Rename the query to `imageQuery` by double clicking on it in the queries explorer.
+
+6. In the canvas select the **Image** component to view its properties in the inspector. Click on the **Bind** button next to the `src` prop to open the binding editor, and bind it to `imageQuery.data.message`.
{{"component": "modules/components/DocsImage.tsx", "src": "/static/toolpad/docs/getting-started/first-app/step-11.png", "alt": "Bind image src to Java", "caption": "Binding the Image src to the query response", "indent": 1 }}
diff --git a/docs/data/toolpad/getting-started/overview.md b/docs/data/toolpad/getting-started/overview.md
index 92d21179c16..4b05e5dc7ec 100644
--- a/docs/data/toolpad/getting-started/overview.md
+++ b/docs/data/toolpad/getting-started/overview.md
@@ -8,7 +8,7 @@ Toolpad is a self-hosted, low-code internal tool builder. It is open-sourced, an
Toolpad is designed for any developer who wants to create internal apps faster.
Drag and drop pre-built UI components, connect your data sources, release your app, and you're done! Check out the interactive product walkthrough of Toolpad below:
-
+
> You can check out the demo video [here](https://github.com/mui/mui-toolpad#product-walkthrough).
diff --git a/docs/data/toolpad/how-to-guides/render-deploy.md b/docs/data/toolpad/how-to-guides/render-deploy.md
index 231fa0e5c04..87b2e4503e1 100644
--- a/docs/data/toolpad/how-to-guides/render-deploy.md
+++ b/docs/data/toolpad/how-to-guides/render-deploy.md
@@ -78,7 +78,7 @@
:::info
-See the [Render documentation](https://render.com/docs/node-version) on Node versions for more information.
+See the [Render documentation](https://docs.render.com/docs/node-version) on Node versions for more information.
:::
@@ -92,4 +92,4 @@ That's it! We're up and running in a few minutes.
Make changes, push to GitHub, and your app will automatically redeploy each time.
-Check out the Render documentation for more advanced settings, like adding [environment variables](https://render.com/docs/configure-environment-variables) to your app.
+Check out the Render documentation for more advanced settings, like adding [environment variables](https://docs.render.com/docs/configure-environment-variables) to your app.
diff --git a/docs/data/toolpad/reference/components/autocomplete.md b/docs/data/toolpad/reference/components/autocomplete.md
index 1fe1956f210..cc253c02f9f 100644
--- a/docs/data/toolpad/reference/components/autocomplete.md
+++ b/docs/data/toolpad/reference/components/autocomplete.md
@@ -21,6 +21,4 @@ A text input with autocomplete suggestions. Uses the Material UI [Autocomplete](
| name | string | | Name of this input. Used as a reference in form data. |
| isRequired | boolean | false | Whether the input is required to have a value. |
| isInvalid | boolean | false | Whether the input value is invalid. |
-| minLength | number | 0 | Minimum value length. |
-| maxLength | number | 0 | Maximum value length. |
| sx | object | | The [`sx` prop](https://mui.com/system/getting-started/the-sx-prop/) is used for defining custom styles that have access to the theme. All MUI System properties are available via the `sx` prop. In addition, the `sx` prop allows you to specify any other CSS rules you may need. |
diff --git a/docs/next.config.mjs b/docs/next.config.mjs
index 572c3a73092..f44a1e940b2 100644
--- a/docs/next.config.mjs
+++ b/docs/next.config.mjs
@@ -22,6 +22,7 @@ const MONOREPO_PACKAGES = {
'@mui/lab': path.resolve(MONOREPO_PATH, './packages/mui-lab/src'),
'@mui/material': path.resolve(MONOREPO_PATH, './packages/mui-material/src'),
'@mui/material-next': path.resolve(MONOREPO_PATH, './packages/mui-material-next/src'),
+ '@mui/material-nextjs': path.resolve(MONOREPO_PATH, './packages/mui-material-nextjs/src'),
'@mui/private-theming': path.resolve(MONOREPO_PATH, './packages/mui-private-theming/src'),
'@mui/styled-engine': path.resolve(MONOREPO_PATH, './packages/mui-styled-engine/src'),
'@mui/styled-engine-sc': path.resolve(MONOREPO_PATH, './packages/mui-styled-engine-sc/src'),
@@ -43,6 +44,7 @@ export default withDocsInfra(
// SOURCE_CODE_ROOT_URL: 'https://github.com/mui/mui-toolpad/blob/master',
SOURCE_CODE_REPO: 'https://github.com/mui/mui-toolpad',
SOURCE_GITHUB_BRANCH: 'master',
+ GITHUB_TEMPLATE_DOCS_FEEDBACK: '4.docs-feedback.yml',
},
webpack: (config, options) => {
return {
diff --git a/docs/package.json b/docs/package.json
index 02b69787918..bc581fe4ffa 100644
--- a/docs/package.json
+++ b/docs/package.json
@@ -1,6 +1,6 @@
{
"name": "docs",
- "version": "0.1.41",
+ "version": "0.1.42",
"private": true,
"author": "MUI Toolpad",
"license": "MIT",
@@ -17,29 +17,31 @@
"typescript:transpile:dev": "cross-env BABEL_ENV=development babel-node --extensions \".tsx,.ts,.js\" scripts/formattedTSDemos --watch"
},
"dependencies": {
- "@babel/core": "7.23.5",
+ "@babel/core": "7.23.6",
"@babel/plugin-transform-object-assign": "7.23.3",
- "@babel/runtime-corejs2": "7.23.5",
+ "@babel/runtime-corejs2": "7.23.6",
"@date-io/date-fns-jalali": "2.17.0",
"@docsearch/react": "3.5.2",
"@emotion/cache": "11.11.0",
- "@emotion/react": "11.11.1",
+ "@emotion/react": "11.11.3",
"@emotion/server": "11.11.0",
"@emotion/styled": "11.11.0",
- "@mui/icons-material": "5.15.0",
- "@mui/material": "5.15.0",
+ "@mui/icons-material": "5.15.1",
+ "@mui/lab": "5.0.0-alpha.157",
+ "@mui/material": "5.15.1",
+ "@mui/material-nextjs": "^5.15.0",
"@mui/monorepo": "https://github.com/mui/material-ui.git",
- "@mui/styles": "5.15.0",
- "@mui/toolpad": "0.1.41",
- "@mui/utils": "5.15.0",
+ "@mui/styles": "5.15.1",
+ "@mui/toolpad": "0.1.42",
+ "@mui/utils": "5.15.1",
+ "@mui/x-data-grid-pro": "6.18.6",
"@trendmicro/react-interpolate": "0.5.5",
"@types/lodash": "4.14.202",
- "@types/react-dom": "18.2.17",
+ "@types/react-dom": "18.2.18",
"@types/react-router-dom": "5.3.3",
"accept-language": "3.0.18",
"ast-types": "0.14.2",
"autoprefixer": "10.4.16",
- "babel-plugin-macros": "3.1.0",
"babel-plugin-module-resolver": "5.0.0",
"babel-plugin-optimize-clsx": "2.6.2",
"babel-plugin-preval": "5.1.0",
@@ -53,7 +55,6 @@
"date-fns-jalali": "2.29.3-0",
"doctrine": "3.0.0",
"exceljs": "4.4.0",
- "express": "4.18.2",
"fg-loadcss": "3.1.0",
"fs-extra": "11.2.0",
"invariant": "2.2.4",
@@ -61,7 +62,7 @@
"lodash": "4.17.21",
"lz-string": "1.5.0",
"markdown-to-jsx": "7.3.2",
- "marked": "11.0.1",
+ "marked": "11.1.0",
"next": "13.4.19",
"nprogress": "0.2.0",
"postcss": "8.4.32",
@@ -71,16 +72,16 @@
"react": "18.2.0",
"react-docgen": "7.0.1",
"react-dom": "18.2.0",
- "react-hook-form": "7.49.0",
+ "react-hook-form": "7.49.2",
"react-is": "18.2.0",
- "react-router": "6.20.1",
- "react-router-dom": "6.20.1",
+ "react-router": "6.21.1",
+ "react-router-dom": "6.21.1",
"react-runner": "1.0.3",
"react-simple-code-editor": "0.13.1",
"react-transition-group": "4.4.5",
"recast": "0.23.4",
"rimraf": "5.0.5",
- "styled-components": "6.1.1",
+ "styled-components": "6.1.3",
"stylis": "4.3.0",
"stylis-plugin-rtl": "npm:stylis-plugin-rtl@^2.1.1",
"stylis-plugin-rtl-sc": "npm:stylis-plugin-rtl@^2.1.1",
@@ -92,6 +93,7 @@
"@types/doctrine": "0.0.9",
"@types/json-schema": "7.0.15",
"@types/react-is": "18.2.4",
+ "babel-plugin-macros": "3.1.0",
"cpy-cli": "5.0.0",
"cross-fetch": "4.0.0",
"gm": "1.25.0",
diff --git a/docs/pages/toolpad/getting-started/overview.js b/docs/pages/toolpad/getting-started/index.js
similarity index 100%
rename from docs/pages/toolpad/getting-started/overview.js
rename to docs/pages/toolpad/getting-started/index.js
diff --git a/docs/public/_redirects b/docs/public/_redirects
index cce54cd7038..ff3bbdaa9aa 100644
--- a/docs/public/_redirects
+++ b/docs/public/_redirects
@@ -3,8 +3,8 @@
# Legacy redirection
# 2022
-/toolpad/getting-started/setup/ /toolpad/getting-started/overview/ 301
-/toolpad/getting-started/tutorial/ /toolpad/getting-started/overview/ 301
+/toolpad/getting-started/setup/ /toolpad/getting-started/ 301
+/toolpad/getting-started/tutorial/ /toolpad/getting-started/ 301
/toolpad/data-fetching/rest/ /toolpad/concepts/http-requests/ 301
/toolpad/data-fetching/google-sheets/ /toolpad/how-to-guides/connect-to-googlesheets/ 301
@@ -34,6 +34,7 @@
/toolpad/concepts/display-mode/ /toolpad/concepts/page-properties/#display-mode 301
/toolpad/concepts/managing-state/ /toolpad/concepts/event-handling/ 301
/toolpad/reference/components/datagrid/ /toolpad/reference/components/data-grid/ 301
+/toolpad/getting-started/overview/ /toolpad/getting-started/ 301
# Create separate namespace on https://mui.com
/ /toolpad/
diff --git a/docs/public/static/toolpad/docs/concepts/connecting-to-data/bound-parameter.png b/docs/public/static/toolpad/docs/concepts/connecting-to-data/bound-parameter.png
new file mode 100644
index 00000000000..0046ccc6bcb
Binary files /dev/null and b/docs/public/static/toolpad/docs/concepts/connecting-to-data/bound-parameter.png differ
diff --git a/docs/public/static/toolpad/docs/concepts/connecting-to-data/bound-secret.png b/docs/public/static/toolpad/docs/concepts/connecting-to-data/bound-secret.png
index 62a1c1e8639..1a5bcd9121f 100644
Binary files a/docs/public/static/toolpad/docs/concepts/connecting-to-data/bound-secret.png and b/docs/public/static/toolpad/docs/concepts/connecting-to-data/bound-secret.png differ
diff --git a/docs/public/static/toolpad/docs/concepts/connecting-to-data/custom-function-params.png b/docs/public/static/toolpad/docs/concepts/connecting-to-data/custom-function-params.png
deleted file mode 100644
index f40444472c1..00000000000
Binary files a/docs/public/static/toolpad/docs/concepts/connecting-to-data/custom-function-params.png and /dev/null differ
diff --git a/docs/public/static/toolpad/docs/concepts/connecting-to-data/example-parameter.png b/docs/public/static/toolpad/docs/concepts/connecting-to-data/example-parameter.png
index 47cc97da193..ea95c4cf06e 100644
Binary files a/docs/public/static/toolpad/docs/concepts/connecting-to-data/example-parameter.png and b/docs/public/static/toolpad/docs/concepts/connecting-to-data/example-parameter.png differ
diff --git a/docs/public/static/toolpad/docs/concepts/connecting-to-data/http-query-headers.png b/docs/public/static/toolpad/docs/concepts/connecting-to-data/http-query-headers.png
deleted file mode 100644
index 13ea1123f7f..00000000000
Binary files a/docs/public/static/toolpad/docs/concepts/connecting-to-data/http-query-headers.png and /dev/null differ
diff --git a/docs/public/static/toolpad/docs/concepts/connecting-to-data/params-custom-fn.png b/docs/public/static/toolpad/docs/concepts/connecting-to-data/params-custom-fn.png
deleted file mode 100644
index cd3687683cf..00000000000
Binary files a/docs/public/static/toolpad/docs/concepts/connecting-to-data/params-custom-fn.png and /dev/null differ
diff --git a/docs/public/static/toolpad/docs/concepts/connecting-to-data/pg-function.mp4 b/docs/public/static/toolpad/docs/concepts/connecting-to-data/pg-function.mp4
deleted file mode 100644
index 5709c7791de..00000000000
Binary files a/docs/public/static/toolpad/docs/concepts/connecting-to-data/pg-function.mp4 and /dev/null differ
diff --git a/docs/public/static/toolpad/docs/concepts/connecting-to-data/postgres.mp4 b/docs/public/static/toolpad/docs/concepts/connecting-to-data/postgres.mp4
new file mode 100644
index 00000000000..b40158fe734
Binary files /dev/null and b/docs/public/static/toolpad/docs/concepts/connecting-to-data/postgres.mp4 differ
diff --git a/docs/public/static/toolpad/docs/concepts/connecting-to-data/query-1.png b/docs/public/static/toolpad/docs/concepts/connecting-to-data/query-1.png
index 5d890a711e3..d789dd725f4 100644
Binary files a/docs/public/static/toolpad/docs/concepts/connecting-to-data/query-1.png and b/docs/public/static/toolpad/docs/concepts/connecting-to-data/query-1.png differ
diff --git a/docs/public/static/toolpad/docs/concepts/connecting-to-data/query-2.png b/docs/public/static/toolpad/docs/concepts/connecting-to-data/query-2.png
index 5ec44ac856a..a1c41491047 100644
Binary files a/docs/public/static/toolpad/docs/concepts/connecting-to-data/query-2.png and b/docs/public/static/toolpad/docs/concepts/connecting-to-data/query-2.png differ
diff --git a/docs/public/static/toolpad/docs/concepts/connecting-to-data/query-3.png b/docs/public/static/toolpad/docs/concepts/connecting-to-data/query-3.png
index 4b4bd8d02c7..7673b7381ae 100644
Binary files a/docs/public/static/toolpad/docs/concepts/connecting-to-data/query-3.png and b/docs/public/static/toolpad/docs/concepts/connecting-to-data/query-3.png differ
diff --git a/docs/public/static/toolpad/docs/concepts/connecting-to-data/query-4.png b/docs/public/static/toolpad/docs/concepts/connecting-to-data/query-4.png
new file mode 100644
index 00000000000..0fee78d8a2d
Binary files /dev/null and b/docs/public/static/toolpad/docs/concepts/connecting-to-data/query-4.png differ
diff --git a/docs/public/static/toolpad/docs/concepts/connecting-to-data/query-5.png b/docs/public/static/toolpad/docs/concepts/connecting-to-data/query-5.png
index 3b848edda01..6711e701098 100644
Binary files a/docs/public/static/toolpad/docs/concepts/connecting-to-data/query-5.png and b/docs/public/static/toolpad/docs/concepts/connecting-to-data/query-5.png differ
diff --git a/docs/public/static/toolpad/docs/concepts/connecting-to-data/query-6.png b/docs/public/static/toolpad/docs/concepts/connecting-to-data/query-6.png
index 0754cc0bcca..8b3b775a7fc 100644
Binary files a/docs/public/static/toolpad/docs/concepts/connecting-to-data/query-6.png and b/docs/public/static/toolpad/docs/concepts/connecting-to-data/query-6.png differ
diff --git a/docs/public/static/toolpad/docs/concepts/connecting-to-data/query-8.png b/docs/public/static/toolpad/docs/concepts/connecting-to-data/query-8.png
index fefc516ef97..f84f4783671 100644
Binary files a/docs/public/static/toolpad/docs/concepts/connecting-to-data/query-8.png and b/docs/public/static/toolpad/docs/concepts/connecting-to-data/query-8.png differ
diff --git a/docs/public/static/toolpad/docs/concepts/connecting-to-data/query-9.png b/docs/public/static/toolpad/docs/concepts/connecting-to-data/query-9.png
new file mode 100644
index 00000000000..f626430c390
Binary files /dev/null and b/docs/public/static/toolpad/docs/concepts/connecting-to-data/query-9.png differ
diff --git a/docs/public/static/toolpad/docs/concepts/connecting-to-data/query-settings.png b/docs/public/static/toolpad/docs/concepts/connecting-to-data/query-settings.png
new file mode 100644
index 00000000000..1d440c3e2f4
Binary files /dev/null and b/docs/public/static/toolpad/docs/concepts/connecting-to-data/query-settings.png differ
diff --git a/docs/public/static/toolpad/docs/concepts/connecting-to-data/secrets-http-query.png b/docs/public/static/toolpad/docs/concepts/connecting-to-data/secrets-http-query.png
deleted file mode 100644
index cce9ab94233..00000000000
Binary files a/docs/public/static/toolpad/docs/concepts/connecting-to-data/secrets-http-query.png and /dev/null differ
diff --git a/docs/public/static/toolpad/docs/concepts/connecting-to-data/secrets.mp4 b/docs/public/static/toolpad/docs/concepts/connecting-to-data/secrets.mp4
index 6f30a1ea9a7..cd3bc5bc8a9 100644
Binary files a/docs/public/static/toolpad/docs/concepts/connecting-to-data/secrets.mp4 and b/docs/public/static/toolpad/docs/concepts/connecting-to-data/secrets.mp4 differ
diff --git a/docs/public/static/toolpad/docs/concepts/connecting-to-data/url-bound-parameter.png b/docs/public/static/toolpad/docs/concepts/connecting-to-data/url-bound-parameter.png
deleted file mode 100644
index 0376902f16d..00000000000
Binary files a/docs/public/static/toolpad/docs/concepts/connecting-to-data/url-bound-parameter.png and /dev/null differ
diff --git a/docs/public/static/toolpad/docs/concepts/data-providers/disable-editable.png b/docs/public/static/toolpad/docs/concepts/data-providers/disable-editable.png
new file mode 100644
index 00000000000..e29ccfcc0ee
Binary files /dev/null and b/docs/public/static/toolpad/docs/concepts/data-providers/disable-editable.png differ
diff --git a/docs/public/static/toolpad/docs/concepts/data-providers/editing.mp4 b/docs/public/static/toolpad/docs/concepts/data-providers/editing.mp4
new file mode 100644
index 00000000000..7b227c84eb0
Binary files /dev/null and b/docs/public/static/toolpad/docs/concepts/data-providers/editing.mp4 differ
diff --git a/docs/public/static/toolpad/docs/concepts/page-properties/display-mode.png b/docs/public/static/toolpad/docs/concepts/page-properties/display-mode.png
index d1685e7884b..28f741ae5ee 100644
Binary files a/docs/public/static/toolpad/docs/concepts/page-properties/display-mode.png and b/docs/public/static/toolpad/docs/concepts/page-properties/display-mode.png differ
diff --git a/docs/public/static/toolpad/docs/getting-started/first-app/step-1.png b/docs/public/static/toolpad/docs/getting-started/first-app/step-1.png
index e7739e1aac4..463f041b8ba 100644
Binary files a/docs/public/static/toolpad/docs/getting-started/first-app/step-1.png and b/docs/public/static/toolpad/docs/getting-started/first-app/step-1.png differ
diff --git a/docs/public/static/toolpad/docs/getting-started/first-app/step-10.png b/docs/public/static/toolpad/docs/getting-started/first-app/step-10.png
index 54c6f04dd67..645887aac3d 100644
Binary files a/docs/public/static/toolpad/docs/getting-started/first-app/step-10.png and b/docs/public/static/toolpad/docs/getting-started/first-app/step-10.png differ
diff --git a/docs/public/static/toolpad/docs/getting-started/first-app/step-11.png b/docs/public/static/toolpad/docs/getting-started/first-app/step-11.png
index a49bb7008b1..fd758ad732e 100644
Binary files a/docs/public/static/toolpad/docs/getting-started/first-app/step-11.png and b/docs/public/static/toolpad/docs/getting-started/first-app/step-11.png differ
diff --git a/docs/public/static/toolpad/docs/getting-started/first-app/step-12.png b/docs/public/static/toolpad/docs/getting-started/first-app/step-12.png
index 825dbf396e8..27310890188 100644
Binary files a/docs/public/static/toolpad/docs/getting-started/first-app/step-12.png and b/docs/public/static/toolpad/docs/getting-started/first-app/step-12.png differ
diff --git a/docs/public/static/toolpad/docs/getting-started/first-app/step-2.png b/docs/public/static/toolpad/docs/getting-started/first-app/step-2.png
index b2587d984cc..9bc7c0c5c44 100644
Binary files a/docs/public/static/toolpad/docs/getting-started/first-app/step-2.png and b/docs/public/static/toolpad/docs/getting-started/first-app/step-2.png differ
diff --git a/docs/public/static/toolpad/docs/getting-started/first-app/step-3.png b/docs/public/static/toolpad/docs/getting-started/first-app/step-3.png
index 8e7edd713aa..548b0743d44 100644
Binary files a/docs/public/static/toolpad/docs/getting-started/first-app/step-3.png and b/docs/public/static/toolpad/docs/getting-started/first-app/step-3.png differ
diff --git a/docs/public/static/toolpad/docs/getting-started/first-app/step-4.png b/docs/public/static/toolpad/docs/getting-started/first-app/step-4.png
index a8c46cac5f1..8aa4aa26bd8 100644
Binary files a/docs/public/static/toolpad/docs/getting-started/first-app/step-4.png and b/docs/public/static/toolpad/docs/getting-started/first-app/step-4.png differ
diff --git a/docs/public/static/toolpad/docs/getting-started/first-app/step-6.png b/docs/public/static/toolpad/docs/getting-started/first-app/step-6.png
index 3904524df50..1f62ff489b3 100644
Binary files a/docs/public/static/toolpad/docs/getting-started/first-app/step-6.png and b/docs/public/static/toolpad/docs/getting-started/first-app/step-6.png differ
diff --git a/docs/public/static/toolpad/docs/getting-started/first-app/step-7.png b/docs/public/static/toolpad/docs/getting-started/first-app/step-7.png
index dbdf3b18d1e..31fd46d8101 100644
Binary files a/docs/public/static/toolpad/docs/getting-started/first-app/step-7.png and b/docs/public/static/toolpad/docs/getting-started/first-app/step-7.png differ
diff --git a/docs/public/static/toolpad/docs/getting-started/first-app/step-8.png b/docs/public/static/toolpad/docs/getting-started/first-app/step-8.png
index fe17a6c1c50..51e72248deb 100644
Binary files a/docs/public/static/toolpad/docs/getting-started/first-app/step-8.png and b/docs/public/static/toolpad/docs/getting-started/first-app/step-8.png differ
diff --git a/docs/public/static/toolpad/docs/getting-started/first-app/step-9.png b/docs/public/static/toolpad/docs/getting-started/first-app/step-9.png
index eb91f024a25..cd6f36a9b14 100644
Binary files a/docs/public/static/toolpad/docs/getting-started/first-app/step-9.png and b/docs/public/static/toolpad/docs/getting-started/first-app/step-9.png differ
diff --git a/docs/schemas/v1/definitions.json b/docs/schemas/v1/definitions.json
index 059648c6283..03b26f27ae6 100644
--- a/docs/schemas/v1/definitions.json
+++ b/docs/schemas/v1/definitions.json
@@ -98,6 +98,10 @@
"spec": {
"type": "object",
"properties": {
+ "displayName": {
+ "type": "string",
+ "description": "Page name to display in the UI."
+ },
"id": {
"type": "string",
"description": "Serves as a canonical id of the page. Deprecated: use an alias instead."
@@ -413,7 +417,7 @@
"description": "Authorization configuration for this page."
},
"unstable_codeFile": {
- "type": "string",
+ "type": "boolean",
"description": "The content of the page as JSX. Experimental, do not use!."
},
"display": {
diff --git a/examples/basic-crud-app/package.json b/examples/basic-crud-app/package.json
index 0b60da9d819..630601fb769 100644
--- a/examples/basic-crud-app/package.json
+++ b/examples/basic-crud-app/package.json
@@ -8,6 +8,6 @@
"start": "toolpad start"
},
"dependencies": {
- "@mui/toolpad": "0.1.41"
+ "@mui/toolpad": "0.1.42"
}
}
diff --git a/examples/charts/package.json b/examples/charts/package.json
index 7c64253995b..439c5a47f42 100644
--- a/examples/charts/package.json
+++ b/examples/charts/package.json
@@ -8,6 +8,6 @@
"start": "toolpad start"
},
"dependencies": {
- "@mui/toolpad": "0.1.41"
+ "@mui/toolpad": "0.1.42"
}
}
diff --git a/examples/custom-datagrid-column/package.json b/examples/custom-datagrid-column/package.json
index 738164833c9..9656ea81327 100644
--- a/examples/custom-datagrid-column/package.json
+++ b/examples/custom-datagrid-column/package.json
@@ -8,6 +8,6 @@
"start": "toolpad start"
},
"dependencies": {
- "@mui/toolpad": "0.1.41"
+ "@mui/toolpad": "0.1.42"
}
}
diff --git a/examples/custom-server-nextjs/package.json b/examples/custom-server-nextjs/package.json
index 5216e666cbe..e13412ec850 100644
--- a/examples/custom-server-nextjs/package.json
+++ b/examples/custom-server-nextjs/package.json
@@ -9,7 +9,7 @@
"edit": "toolpad editor http://localhost:3001/my-toolpad-app"
},
"dependencies": {
- "@mui/toolpad": "0.1.41",
+ "@mui/toolpad": "0.1.42",
"next": "14.0.2"
},
"devDependencies": {}
diff --git a/examples/custom-server/package.json b/examples/custom-server/package.json
index c5fc563cbe1..288ab90d397 100644
--- a/examples/custom-server/package.json
+++ b/examples/custom-server/package.json
@@ -9,7 +9,7 @@
"edit": "toolpad editor http://localhost:3001/my-app"
},
"dependencies": {
- "@mui/toolpad": "0.1.41",
+ "@mui/toolpad": "0.1.42",
"express": "4.18.2"
},
"devDependencies": {}
diff --git a/examples/datagrid-columns/package.json b/examples/datagrid-columns/package.json
index 747b5dd6f71..46ca5c3b508 100644
--- a/examples/datagrid-columns/package.json
+++ b/examples/datagrid-columns/package.json
@@ -8,6 +8,6 @@
"start": "toolpad start"
},
"dependencies": {
- "@mui/toolpad": "0.1.41"
+ "@mui/toolpad": "0.1.42"
}
}
diff --git a/examples/dog-app/package.json b/examples/dog-app/package.json
index 4ef51036687..0fe848ed4bc 100644
--- a/examples/dog-app/package.json
+++ b/examples/dog-app/package.json
@@ -8,6 +8,6 @@
"start": "toolpad start"
},
"dependencies": {
- "@mui/toolpad": "0.1.41"
+ "@mui/toolpad": "0.1.42"
}
}
diff --git a/examples/google-sheet/package.json b/examples/google-sheet/package.json
index 8b87a52d46d..f8bc393b20f 100644
--- a/examples/google-sheet/package.json
+++ b/examples/google-sheet/package.json
@@ -8,7 +8,7 @@
"start": "toolpad start"
},
"dependencies": {
- "@mui/toolpad": "0.1.41",
+ "@mui/toolpad": "0.1.42",
"googleapis": "129.0.0"
}
}
diff --git a/examples/graphql/package.json b/examples/graphql/package.json
index 950ba04d185..5e306c16897 100644
--- a/examples/graphql/package.json
+++ b/examples/graphql/package.json
@@ -8,7 +8,7 @@
"start": "toolpad start"
},
"dependencies": {
- "@mui/toolpad": "0.1.41",
+ "@mui/toolpad": "0.1.42",
"graphql": "16.8.1",
"graphql-request": "6.1.0",
"graphql-tag": "2.12.6"
diff --git a/examples/npm-stats/package.json b/examples/npm-stats/package.json
index 75969c06e5a..48a09fdb33b 100644
--- a/examples/npm-stats/package.json
+++ b/examples/npm-stats/package.json
@@ -8,6 +8,6 @@
"start": "NODE_OPTIONS='--max-old-space-size=396' toolpad start"
},
"dependencies": {
- "@mui/toolpad": "0.1.41"
+ "@mui/toolpad": "0.1.42"
}
}
diff --git a/examples/qr-generator/package.json b/examples/qr-generator/package.json
index d5264654cec..62c380a4106 100644
--- a/examples/qr-generator/package.json
+++ b/examples/qr-generator/package.json
@@ -8,7 +8,7 @@
"start": "toolpad start"
},
"dependencies": {
- "@mui/toolpad": "0.1.41",
+ "@mui/toolpad": "0.1.42",
"qrcode": "^1.5.3"
},
"devDependencies": {
diff --git a/examples/react-pages/package.json b/examples/react-pages/package.json
index 6a5e263c509..244fc6c9a3c 100644
--- a/examples/react-pages/package.json
+++ b/examples/react-pages/package.json
@@ -8,10 +8,10 @@
"start": "toolpad start"
},
"dependencies": {
- "@mui/material": "5.15.0",
- "@mui/toolpad": "0.1.41",
- "@mui/x-data-grid": "6.18.4",
- "@tanstack/react-query": "5.13.4"
+ "@mui/material": "5.15.1",
+ "@mui/toolpad": "0.1.42",
+ "@mui/x-data-grid": "6.18.6",
+ "@tanstack/react-query": "5.14.6"
},
"devDependencies": {}
}
diff --git a/examples/stripe-script/package.json b/examples/stripe-script/package.json
index bb2cb5695df..549d710fffc 100644
--- a/examples/stripe-script/package.json
+++ b/examples/stripe-script/package.json
@@ -8,8 +8,8 @@
"start": "toolpad start"
},
"dependencies": {
- "@mui/toolpad": "0.1.41",
+ "@mui/toolpad": "0.1.42",
"archiver": "6.0.1",
- "stripe": "^14.8.0"
+ "stripe": "^14.10.0"
}
}
diff --git a/examples/supabase/package.json b/examples/supabase/package.json
index a8295d47f9a..11b937df8ee 100644
--- a/examples/supabase/package.json
+++ b/examples/supabase/package.json
@@ -8,7 +8,7 @@
"start": "toolpad start"
},
"dependencies": {
- "@mui/toolpad": "0.1.41",
- "@supabase/supabase-js": "2.39.0"
+ "@mui/toolpad": "0.1.42",
+ "@supabase/supabase-js": "2.39.1"
}
}
diff --git a/examples/with-prisma-data-provider/package.json b/examples/with-prisma-data-provider/package.json
index 1774ae45355..1cc5a35c3d2 100644
--- a/examples/with-prisma-data-provider/package.json
+++ b/examples/with-prisma-data-provider/package.json
@@ -9,12 +9,12 @@
"prisma": "prisma"
},
"dependencies": {
- "@mui/toolpad": "0.1.41",
- "@prisma/client": "5.7.0",
+ "@mui/toolpad": "0.1.42",
+ "@prisma/client": "5.7.1",
"qrcode": "^1.5.3"
},
"devDependencies": {
- "@types/node": "^20.10.4",
+ "@types/node": "^20.10.5",
"@types/qrcode": "^1.5.5",
"prisma": "^5.7.0",
"ts-node": "^10.9.2",
diff --git a/examples/with-prisma-data-provider/toolpad/resources/crud.ts b/examples/with-prisma-data-provider/toolpad/resources/crud.ts
index 8681f2212e5..b1e47b9e98c 100644
--- a/examples/with-prisma-data-provider/toolpad/resources/crud.ts
+++ b/examples/with-prisma-data-provider/toolpad/resources/crud.ts
@@ -100,8 +100,10 @@ export default createDataProvider({
},
async deleteRecord(id) {
- await model.delete({
- where: { id: Number(id) },
- });
+ await model.delete({ where: { id: Number(id) } });
+ },
+
+ async updateRecord(id, data) {
+ await model.update({ where: { id: Number(id) }, data });
},
});
diff --git a/examples/with-prisma/package.json b/examples/with-prisma/package.json
index 218f0e614ab..7d071ec7fe0 100644
--- a/examples/with-prisma/package.json
+++ b/examples/with-prisma/package.json
@@ -9,12 +9,12 @@
"prisma": "prisma"
},
"dependencies": {
- "@mui/toolpad": "0.1.41",
- "@prisma/client": "5.7.0",
+ "@mui/toolpad": "0.1.42",
+ "@prisma/client": "5.7.1",
"qrcode": "^1.5.3"
},
"devDependencies": {
- "@types/node": "^20.10.4",
+ "@types/node": "^20.10.5",
"@types/qrcode": "^1.5.5",
"prisma": "^5.7.0",
"ts-node": "^10.9.2",
diff --git a/examples/with-wasm/package.json b/examples/with-wasm/package.json
index c166f264398..661e6ac9185 100644
--- a/examples/with-wasm/package.json
+++ b/examples/with-wasm/package.json
@@ -8,7 +8,7 @@
"start": "toolpad start"
},
"dependencies": {
- "@mui/toolpad": "0.1.41"
+ "@mui/toolpad": "0.1.42"
},
"devDependencies": {
"assemblyscript": "0.27.22"
diff --git a/lerna.json b/lerna.json
index 53c1da6b23c..b4426a02733 100644
--- a/lerna.json
+++ b/lerna.json
@@ -1,5 +1,5 @@
{
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
- "version": "0.1.41",
+ "version": "0.1.42",
"npmClient": "yarn"
}
diff --git a/package.json b/package.json
index 3513a1208c9..99dcbc7d0a2 100644
--- a/package.json
+++ b/package.json
@@ -45,41 +45,40 @@
"devDependencies": {
"@argos-ci/core": "1.3.0",
"@mui/monorepo": "https://github.com/mui/material-ui.git",
- "@mui/x-charts": "6.18.3",
+ "@mui/x-charts": "6.18.4",
"@next/eslint-plugin-next": "14.0.4",
"@playwright/test": "1.39.0",
"@testing-library/react": "14.1.2",
"@types/archiver": "6.0.2",
"@types/gtag.js": "0.0.18",
- "@types/node": "20.10.4",
+ "@types/node": "20.10.5",
"@types/rimraf": "3.0.2",
- "@typescript-eslint/eslint-plugin": "6.13.2",
- "@typescript-eslint/parser": "6.13.2",
+ "@typescript-eslint/eslint-plugin": "6.14.0",
+ "@typescript-eslint/parser": "6.14.0",
"chalk": "5.3.0",
- "eslint": "8.55.0",
+ "eslint": "8.56.0",
"eslint-config-airbnb": "19.0.4",
"eslint-config-airbnb-typescript": "17.1.0",
"eslint-config-prettier": "9.1.0",
"eslint-import-resolver-webpack": "0.13.8",
"eslint-plugin-filenames": "1.3.2",
- "eslint-plugin-import": "2.29.0",
+ "eslint-plugin-import": "2.29.1",
"eslint-plugin-jsx-a11y": "6.8.0",
"eslint-plugin-mocha": "10.2.0",
"eslint-plugin-react": "7.33.2",
"eslint-plugin-react-hooks": "4.6.0",
"eslint-plugin-typescript-enum": "2.1.0",
"execa": "8.0.1",
- "express": "4.18.2",
"format-util": "1.0.5",
"globby": "14.0.0",
"jsdom": "23.0.1",
- "lerna": "8.0.0",
+ "lerna": "8.0.1",
"markdownlint-cli2": "0.11.0",
"prettier": "2.8.8",
"pretty-quick": "3.1.3",
"react-inspector": "6.0.2",
"recharts": "2.10.3",
- "regenerator-runtime": "0.14.0",
+ "regenerator-runtime": "0.14.1",
"rimraf": "5.0.5",
"typescript": "5.3.3",
"vitest-dom": "0.1.1",
@@ -94,11 +93,11 @@
"lodash": "4.17.21",
"semver": "7.5.4",
"tsup": "8.0.1",
- "tsx": "4.6.2",
- "vitest": "1.0.4",
+ "tsx": "4.7.0",
+ "vitest": "1.1.0",
"yargs": "17.7.2",
"zod": "3.22.4",
- "zod-to-json-schema": "3.22.1"
+ "zod-to-json-schema": "3.22.3"
},
"engines": {
"npm": "please-use-yarn",
diff --git a/packages/create-toolpad-app/package.json b/packages/create-toolpad-app/package.json
index ec535f6065e..5dd15bed1db 100644
--- a/packages/create-toolpad-app/package.json
+++ b/packages/create-toolpad-app/package.json
@@ -1,6 +1,6 @@
{
"name": "create-toolpad-app",
- "version": "0.1.41",
+ "version": "0.1.42",
"keywords": [
"react",
"toolpad",
@@ -30,7 +30,7 @@
"node": ">=18"
},
"dependencies": {
- "@mui/toolpad-utils": "0.1.41",
+ "@mui/toolpad-utils": "0.1.42",
"chalk": "5.3.0",
"execa": "8.0.1",
"inquirer": "9.2.12",
@@ -42,7 +42,7 @@
"devDependencies": {
"@types/inquirer": "9.0.7",
"@types/invariant": "2.2.37",
- "@types/node": "20.10.4",
+ "@types/node": "20.10.5",
"@types/semver": "7.5.6",
"@types/tar": "6.1.10",
"@types/yargs": "17.0.32"
diff --git a/packages/eslint-plugin-material-ui/package.json b/packages/eslint-plugin-material-ui/package.json
index 6debc972b63..efddf96d1cd 100644
--- a/packages/eslint-plugin-material-ui/package.json
+++ b/packages/eslint-plugin-material-ui/package.json
@@ -1,6 +1,6 @@
{
"name": "eslint-plugin-material-ui",
- "version": "0.1.41",
+ "version": "0.1.42",
"private": true,
"description": "Custom eslint rules for MUI.",
"main": "src/index.js",
@@ -8,8 +8,8 @@
"emoji-regex": "10.3.0"
},
"devDependencies": {
- "@types/eslint": "8.44.8",
- "@typescript-eslint/parser": "6.13.2"
+ "@types/eslint": "8.44.9",
+ "@typescript-eslint/parser": "6.14.0"
},
"scripts": {},
"repository": {
diff --git a/packages/toolpad-app/package.json b/packages/toolpad-app/package.json
index 8a7ecceedba..22d2ce20019 100644
--- a/packages/toolpad-app/package.json
+++ b/packages/toolpad-app/package.json
@@ -1,6 +1,6 @@
{
"name": "@mui/toolpad",
- "version": "0.1.41",
+ "version": "0.1.42",
"license": "MIT",
"bin": {
"toolpad": "./cli.mjs"
@@ -48,31 +48,31 @@
"dependencies": {
"@auth/core": "0.19.0",
"@emotion/cache": "11.11.0",
- "@emotion/react": "11.11.1",
+ "@emotion/react": "11.11.3",
"@emotion/server": "11.11.0",
"@emotion/styled": "11.11.0",
"@googleapis/drive": "8.4.0",
"@googleapis/sheets": "5.0.5",
- "@mui/icons-material": "5.15.0",
- "@mui/lab": "5.0.0-alpha.156",
- "@mui/material": "5.15.0",
- "@mui/system": "5.15.0",
- "@mui/toolpad-components": "0.1.41",
- "@mui/toolpad-core": "0.1.41",
- "@mui/toolpad-utils": "0.1.41",
+ "@mui/icons-material": "5.15.1",
+ "@mui/lab": "5.0.0-alpha.157",
+ "@mui/material": "5.15.1",
+ "@mui/system": "5.15.1",
+ "@mui/toolpad-components": "0.1.42",
+ "@mui/toolpad-core": "0.1.42",
+ "@mui/toolpad-utils": "0.1.42",
"@mui/types": "7.2.11",
- "@mui/utils": "5.15.0",
- "@mui/x-charts": "6.18.3",
- "@mui/x-data-grid": "6.18.4",
- "@mui/x-data-grid-pro": "6.18.4",
- "@mui/x-date-pickers": "6.18.4",
- "@mui/x-date-pickers-pro": "6.18.4",
+ "@mui/utils": "5.15.1",
+ "@mui/x-charts": "6.18.4",
+ "@mui/x-data-grid": "6.18.6",
+ "@mui/x-data-grid-pro": "6.18.6",
+ "@mui/x-date-pickers": "6.18.6",
+ "@mui/x-date-pickers-pro": "6.18.6",
"@mui/x-tree-view": "6.17.0",
- "@tanstack/react-query": "5.13.4",
- "@tanstack/react-query-devtools": "5.13.4",
+ "@tanstack/react-query": "5.14.6",
+ "@tanstack/react-query-devtools": "5.14.6",
"@types/cors": "2.8.17",
"@types/json-schema": "7.0.15",
- "@types/node": "20.10.4",
+ "@types/node": "20.10.5",
"@types/react-dev-utils": "9.0.15",
"@vitejs/plugin-react": "4.2.1",
"@webcontainer/env": "1.1.0",
@@ -87,7 +87,7 @@
"csstype": "3.1.3",
"dayjs": "1.11.10",
"dotenv": "16.3.1",
- "esbuild": "0.19.9",
+ "esbuild": "0.19.10",
"execa": "8.0.1",
"express": "4.18.2",
"find-up": "7.0.0",
@@ -102,7 +102,7 @@
"latest-version": "7.0.0",
"lodash-es": "4.17.21",
"markdown-to-jsx": "7.3.2",
- "mime": "4.0.0",
+ "mime": "4.0.1",
"mysql2": "3.6.5",
"nanoid": "5.0.4",
"node-fetch": "2.7.0",
@@ -111,27 +111,27 @@
"path-to-regexp": "6.2.1",
"perf-cascade": "3.0.3",
"pg": "8.11.3",
- "piscina": "4.2.0",
+ "piscina": "4.2.1",
"prettier": "2.8.8",
"pretty-bytes": "6.1.1",
"react": "18.2.0",
"react-dev-utils": "12.0.1",
"react-dom": "18.2.0",
- "react-error-boundary": "4.0.11",
- "react-hook-form": "7.49.0",
+ "react-error-boundary": "4.0.12",
+ "react-hook-form": "7.49.2",
"react-inspector": "6.0.2",
"react-is": "18.2.0",
- "react-resizable-panels": "0.0.63",
- "react-router-dom": "6.20.1",
+ "react-resizable-panels": "1.0.5",
+ "react-router-dom": "6.21.1",
"recharts": "2.10.3",
"semver": "7.5.4",
"serialize-javascript": "6.0.1",
"superjson": "2.0.0",
"typescript": "5.3.3",
- "vite": "5.0.7",
+ "vite": "5.0.10",
"vm-browserify": "1.1.2",
"whatwg-url": "14.0.0",
- "ws": "8.15.0",
+ "ws": "8.15.1",
"yaml": "2.3.4",
"yaml-diff-patch": "2.0.0",
"yargs": "17.7.2",
@@ -150,8 +150,8 @@
"@types/node-fetch": "2.6.9",
"@types/pg": "8.10.9",
"@types/prettier": "2.7.3",
- "@types/react": "18.2.43",
- "@types/react-dom": "18.2.17",
+ "@types/react": "18.2.45",
+ "@types/react-dom": "18.2.18",
"@types/react-is": "18.2.4",
"@types/semver": "7.5.6",
"@types/serialize-javascript": "5.0.4",
@@ -159,11 +159,10 @@
"@types/ws": "8.5.10",
"@types/yargs": "17.0.32",
"ajv": "8.12.0",
- "eslint": "8.55.0",
+ "eslint": "8.56.0",
"eslint-config-prettier": "9.1.0",
- "eslint-plugin-import": "2.29.0",
+ "eslint-plugin-import": "2.29.1",
"formidable": "3.5.1",
- "get-port": "7.0.0",
"monaco-editor": "0.45.0",
"react-devtools-inline": "5.0.0",
"react-transition-group": "4.4.5",
diff --git a/packages/toolpad-app/src/appDom/index.ts b/packages/toolpad-app/src/appDom/index.ts
index 5caa2e6a557..b854ded11d0 100644
--- a/packages/toolpad-app/src/appDom/index.ts
+++ b/packages/toolpad-app/src/appDom/index.ts
@@ -11,7 +11,7 @@ import {
} from '@mui/toolpad-core';
import invariant from 'invariant';
import { BoxProps, ThemeOptions as MuiThemeOptions } from '@mui/material';
-import { pascalCase, removeDiacritics, uncapitalize } from '@mui/toolpad-utils/strings';
+import { guessTitle, pascalCase, removeDiacritics, uncapitalize } from '@mui/toolpad-utils/strings';
import { mapProperties, mapValues, hasOwnProperty } from '@mui/toolpad-utils/collections';
import { AuthProvider, ConnectionStatus } from '../types';
import { omit, update, updateOrCreate } from '../utils/immutability';
@@ -41,15 +41,7 @@ export function compareFractionalIndex(index1: string, index2: string): number {
return index1 > index2 ? 1 : -1;
}
-type AppDomNodeType =
- | 'app'
- | 'connection'
- | 'theme'
- | 'page'
- | 'element'
- | 'codeComponent'
- | 'query'
- | 'mutation';
+type AppDomNodeType = 'app' | 'connection' | 'theme' | 'page' | 'element' | 'query' | 'mutation';
export interface AppDomNodeBase {
readonly id: NodeId;
@@ -101,7 +93,8 @@ export interface PageNode extends AppDomNodeBase {
readonly parameters?: [string, string][];
readonly module?: string;
readonly display?: PageDisplayMode;
- readonly codeFile?: string;
+ readonly codeFile?: boolean;
+ readonly displayName?: string;
readonly authorization?: {
readonly allowAll?: boolean;
readonly allowedRoles?: string[];
@@ -122,14 +115,6 @@ export interface ElementNode extends AppDomNodeBase {
};
}
-export interface CodeComponentNode extends AppDomNodeBase {
- readonly type: 'codeComponent';
- readonly attributes: {
- readonly code: string;
- readonly isNew?: boolean;
- };
-}
-
export type FetchMode = 'query' | 'mutation';
/**
@@ -177,7 +162,6 @@ type AppDomNodeOfType = {
theme: ThemeNode;
page: PageNode;
element: ElementNode;
- codeComponent: CodeComponentNode;
query: QueryNode;
mutation: MutationNode;
}[K];
@@ -187,7 +171,6 @@ type AllowedChildren = {
pages: 'page';
connections: 'connection';
themes: 'theme';
- codeComponents: 'codeComponent';
};
theme: {};
connection: {};
@@ -199,7 +182,6 @@ type AllowedChildren = {
element: {
[prop: string]: 'element';
};
- codeComponent: {};
query: {};
mutation: {};
};
@@ -331,14 +313,6 @@ export function assertIsConnection(node: AppDomNode): asserts node is Connect
assertIsType(node, 'connection');
}
-export function isCodeComponent(node: AppDomNode): node is CodeComponentNode {
- return isType(node, 'codeComponent');
-}
-
-export function assertIsCodeComponent(node: AppDomNode): asserts node is CodeComponentNode {
- assertIsType(node, 'codeComponent');
-}
-
export function isTheme(node: AppDomNode): node is ThemeNode {
return isType(node, 'theme');
}
@@ -841,7 +815,6 @@ export function saveNode(dom: AppDom, node: AppDomNode) {
if (!nodeExists(dom, node.id)) {
throw new Error(`Attempt to update node "${node.id}", but it doesn't exist in the dom`);
}
-
return update(dom, {
nodes: update(dom.nodes, {
[node.id]: update(dom.nodes[node.id], omit(node, ...RESERVED_NODE_PROPERTIES)),
@@ -1209,8 +1182,12 @@ export function getRequiredEnvVars(dom: AppDom): Set {
return new Set(allVars);
}
+export function getPageDisplayName(node: PageNode): string {
+ return node.attributes.displayName || guessTitle(node.name);
+}
+
export function getPageTitle(node: PageNode): string {
- return node.attributes.title || node.name;
+ return node.attributes.title || getPageDisplayName(node);
}
export function isCodePage(node: PageNode): boolean {
diff --git a/packages/toolpad-app/src/components/Devtools.tsx b/packages/toolpad-app/src/components/Devtools.tsx
index 769dcaee969..25d30349a89 100644
--- a/packages/toolpad-app/src/components/Devtools.tsx
+++ b/packages/toolpad-app/src/components/Devtools.tsx
@@ -1,7 +1,7 @@
import * as React from 'react';
import { TabPanel, TabContext, TabList } from '@mui/lab';
import { Box, IconButton, styled, SxProps, Tab } from '@mui/material';
-import { Har } from 'har-format';
+import type { Har } from 'har-format';
import DoDisturbIcon from '@mui/icons-material/DoDisturb';
import Console, { LogEntry } from './Console';
import lazyComponent from '../utils/lazyComponent';
@@ -62,7 +62,12 @@ export default function Devtools({ sx, log, onLogClear, har, onHarClear }: Devto
}, [activeTab, onHarClear, onLogClear]);
return (
-
+
-
- {log ? : null}
- {har ? : null}
-
{handleClearClick ? (
) : null}
+
+
+ {log ? (
+ `1px solid ${theme.palette.grey[300]}` }}
+ />
+ ) : null}
+ {har ? (
+ `1px solid ${theme.palette.grey[300]}` }}
+ />
+ ) : null}
+
+
{log ? (
diff --git a/packages/toolpad-app/src/components/EditableText.tsx b/packages/toolpad-app/src/components/EditableText.tsx
index 7a39ea9e281..661b4fefbe9 100644
--- a/packages/toolpad-app/src/components/EditableText.tsx
+++ b/packages/toolpad-app/src/components/EditableText.tsx
@@ -5,9 +5,9 @@ import {
TypographyVariant,
SxProps,
inputBaseClasses,
- formHelperTextClasses,
inputClasses,
} from '@mui/material';
+import invariant from 'invariant';
interface EditableTextProps {
defaultValue?: string;
@@ -48,6 +48,7 @@ const EditableText = React.forwardRef(
React.useEffect(() => {
const inputElement = appTitleInput.current;
+
if (inputElement) {
if (editable) {
inputElement.focus();
@@ -58,6 +59,8 @@ const EditableText = React.forwardRef(
}
}, [ref, editable]);
+ const readOnly = React.useMemo(() => disabled || !editable, [disabled, editable]);
+
const handleBlur = React.useCallback(
(event: React.FocusEvent) => {
// This is only triggered on a click away
@@ -73,15 +76,17 @@ const EditableText = React.forwardRef(
const handleChange = React.useCallback(
(event: React.ChangeEvent) => {
+ invariant(!readOnly, 'Readonly input should be disabled');
if (onChange) {
onChange(event.target.value);
}
},
- [onChange],
+ [readOnly, onChange],
);
const handleInput = React.useCallback(
(event: React.KeyboardEvent) => {
+ invariant(!readOnly, 'Readonly input should be disabled');
const inputElement = appTitleInput.current;
if (inputElement) {
if (event.key === 'Escape') {
@@ -105,20 +110,18 @@ const EditableText = React.forwardRef(
}
}
},
- [defaultValue, onChange, onSave, onClose],
+ [readOnly, defaultValue, onChange, onSave, onClose],
);
return (
({
// Handle overflow
@@ -136,18 +139,27 @@ const EditableText = React.forwardRef(
size={size ?? 'small'}
sx={{
...sx,
+ transition: (theme: Theme) =>
+ theme.transitions.create(['border-bottom'], {
+ duration: theme.transitions.duration.short,
+ }),
[`.${inputClasses.root}.${inputBaseClasses.root}:before, .${inputClasses.root}.${inputBaseClasses.root}:not(${inputBaseClasses.disabled}):hover:before`]:
{
borderBottom: editable ? `initial` : 'none',
},
- // TextField must not appear disabled if disabled state is controlled by `editable` prop
- [`.${inputClasses.root}.${inputBaseClasses.root}.${inputBaseClasses.disabled}, .${inputClasses.input}.${inputBaseClasses.input}.${inputBaseClasses.disabled}, .${formHelperTextClasses.root}.${inputBaseClasses.disabled}`]:
- disabled
- ? null
- : {
- WebkitTextFillColor: 'unset',
- color: 'unset',
- },
+ [`& .${inputClasses.root}.${inputBaseClasses.root}::after`]: readOnly
+ ? {
+ transform: 'scaleX(0)',
+ borderBottom: 'none',
+ transition: (theme: Theme) =>
+ theme.transitions.create(['transform'], {
+ duration: theme.transitions.duration.short,
+ }),
+ }
+ : {
+ transform: 'scaleX(1)',
+ borderBottom: '2px solid primary',
+ },
}}
value={value}
variant={'standard'}
diff --git a/packages/toolpad-app/src/components/HarViewer.tsx b/packages/toolpad-app/src/components/HarViewer.tsx
index 582cab2aa61..d46720f653b 100644
--- a/packages/toolpad-app/src/components/HarViewer.tsx
+++ b/packages/toolpad-app/src/components/HarViewer.tsx
@@ -1,6 +1,6 @@
import { fromHar } from 'perf-cascade';
import * as React from 'react';
-import { Har } from 'har-format';
+import type { Har } from 'har-format';
import { styled, SxProps } from '@mui/material';
import { useTheme, Theme } from '@mui/material/styles';
import { createHarLog } from '../utils/har';
diff --git a/packages/toolpad-app/src/constants.ts b/packages/toolpad-app/src/constants.ts
index 2a8c33796a1..5d0b6d21566 100644
--- a/packages/toolpad-app/src/constants.ts
+++ b/packages/toolpad-app/src/constants.ts
@@ -8,7 +8,7 @@ export const TOOLPAD_TARGET_CLOUD = 'CLOUD';
export const TOOLPAD_TARGET_PRO = 'PRO';
export const REPOSITORY_URL = 'https://github.com/mui/mui-toolpad';
export const LANDING_PAGE_URL = 'https://mui.com/toolpad/';
-export const DOCUMENTATION_URL = 'https://mui.com/toolpad/getting-started/overview/';
+export const DOCUMENTATION_URL = 'https://mui.com/toolpad/getting-started/';
export const DOCUMENTATION_INSTALLATION_URL =
'https://mui.com/toolpad/getting-started/installation/';
export const ROADMAP_URL = 'https://github.com/orgs/mui/projects/9';
diff --git a/packages/toolpad-app/src/runtime/AppLayout.tsx b/packages/toolpad-app/src/runtime/AppLayout.tsx
index 826b398e3b3..d86ca02b0e1 100644
--- a/packages/toolpad-app/src/runtime/AppLayout.tsx
+++ b/packages/toolpad-app/src/runtime/AppLayout.tsx
@@ -66,7 +66,11 @@ function AppPagesNavigation({
sx={{
width: DRAWER_WIDTH,
flexShrink: 0,
- [`& .MuiDrawer-paper`]: { width: DRAWER_WIDTH, boxSizing: 'border-box' },
+ [`& .MuiDrawer-paper`]: {
+ width: DRAWER_WIDTH,
+ boxSizing: 'border-box',
+ border: 'none',
+ },
}}
>
{clipped ? : null}
@@ -77,8 +81,8 @@ function AppPagesNavigation({
underline="none"
sx={{
ml: 3,
- mt: 1,
- mb: '4px',
+ mt: 2,
+ mb: 1,
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
@@ -100,9 +104,16 @@ function AppPagesNavigation({
MUI Toolpad
-
+
{pages.map((page) => (
-
+
({
}));
const internalComponents: ToolpadComponents = Object.fromEntries(
- [...INTERNAL_COMPONENTS].map(([name]) => {
- let builtIn = (builtIns as any)[name];
-
+ Object.entries(builtIns).map(([name, builtIn]) => {
if (!isToolpadComponent(builtIn)) {
builtIn = createToolpadComponentThatThrows(
new Error(`Imported builtIn "${name}" is not a ToolpadComponent`),
);
}
-
- return [name, builtIn];
+ return [name, builtIn] as [string, ToolpadComponent];
}),
);
@@ -565,8 +561,12 @@ function parseBindings(
}
if (appDom.isQuery(elm)) {
+ let kind: 'query' | 'action' = 'query';
+ if (elm.attributes.mode === 'mutation') {
+ kind = 'action';
+ }
scopeMeta[elm.name] = {
- kind: 'query',
+ kind,
};
if (elm.params) {
@@ -1557,7 +1557,7 @@ function ToolpadAppLayout({ dom, basename }: ToolpadAppLayoutProps) {
() =>
pages.map((page) => ({
slug: page.name,
- displayName: page.name,
+ displayName: appDom.getPageDisplayName(page),
hasShell: page?.attributes.display !== 'standalone',
})),
[pages],
diff --git a/packages/toolpad-app/src/runtime/toolpadComponents/index.tsx b/packages/toolpad-app/src/runtime/toolpadComponents/index.tsx
index 320afcca48e..6cc3ace9d01 100644
--- a/packages/toolpad-app/src/runtime/toolpadComponents/index.tsx
+++ b/packages/toolpad-app/src/runtime/toolpadComponents/index.tsx
@@ -1,156 +1,10 @@
-import { NodeId, ToolpadComponent } from '@mui/toolpad-core';
import * as appDom from '../../appDom';
-export interface ToolpadComponentDefinition {
- displayName: string;
- builtIn?: string;
- system?: boolean;
- codeComponentId?: NodeId;
- synonyms: string[];
- initialProps?: Record;
-}
-
-export type ToolpadComponentDefinitions = Record;
-export interface InstantiatedComponent extends ToolpadComponentDefinition {
- Component: ToolpadComponent;
-}
-export type InstantiatedComponents = Record;
-
export const PAGE_ROW_COMPONENT_ID = 'PageRow';
export const PAGE_COLUMN_COMPONENT_ID = 'PageColumn';
export const STACK_COMPONENT_ID = 'Stack';
export const FORM_COMPONENT_ID = 'Form';
-export const INTERNAL_COMPONENTS = new Map([
- [PAGE_ROW_COMPONENT_ID, { displayName: 'Row', builtIn: 'PageRow', system: true, synonyms: [] }],
- [
- PAGE_COLUMN_COMPONENT_ID,
- { displayName: 'Column', builtIn: 'PageColumn', system: true, synonyms: [] },
- ],
- [STACK_COMPONENT_ID, { displayName: 'Stack', builtIn: 'Stack', system: true, synonyms: [] }],
- [
- 'Autocomplete',
- {
- displayName: 'Autocomplete',
- builtIn: 'Autocomplete',
- synonyms: ['combobox', 'select', 'dropdown'],
- },
- ],
- [
- 'Button',
- {
- displayName: 'Button',
- builtIn: 'Button',
- synonyms: ['click', 'action'],
- },
- ],
- ['Image', { displayName: 'Image', builtIn: 'Image', synonyms: ['picture'] }],
- ['DataGrid', { displayName: 'Data Grid', builtIn: 'DataGrid', synonyms: ['table'] }],
- [
- 'Chart',
- {
- displayName: 'Chart',
- builtIn: 'Chart',
- synonyms: ['graph', 'bar chart', 'pie chart', 'line chart', 'plot'],
- },
- ],
- [
- 'TextField',
- { displayName: 'Text Field', builtIn: 'TextField', synonyms: ['input', 'field', 'password'] },
- ],
- ['DatePicker', { displayName: 'Date Picker', builtIn: 'DatePicker', synonyms: ['time'] }],
- ['FilePicker', { displayName: 'File Picker', builtIn: 'FilePicker', synonyms: [] }],
- ['Text', { displayName: 'Text', builtIn: 'Text', synonyms: ['markdown', 'link', 'output'] }],
- [
- 'Markdown',
- {
- displayName: 'Markdown',
- builtIn: 'Text',
- initialProps: {
- mode: 'markdown',
- },
- synonyms: [],
- },
- ],
- [
- 'Link',
- {
- displayName: 'Link',
- builtIn: 'Text',
- initialProps: {
- mode: 'link',
- },
- synonyms: [],
- },
- ],
- ['Select', { displayName: 'Select', builtIn: 'Select', synonyms: ['combobox', 'dropdown'] }],
- ['List', { displayName: 'List', builtIn: 'List', synonyms: ['repeat'] }],
- ['Paper', { displayName: 'Paper', builtIn: 'Paper', synonyms: ['surface'] }],
- ['Tabs', { displayName: 'Tabs', builtIn: 'Tabs', synonyms: [] }],
- ['Container', { displayName: 'Container', builtIn: 'Container', synonyms: [] }],
- ['Metric', { displayName: 'Metric', builtIn: 'Metric', synonyms: ['value', 'number', 'output'] }],
- [
- 'Checkbox',
- {
- displayName: 'Checkbox',
- initialProps: {
- mode: 'checkbox',
- },
- builtIn: 'Checkbox',
- synonyms: ['switch'],
- },
- ],
- [
- 'Switch',
- {
- displayName: 'Switch',
- initialProps: {
- mode: 'switch',
- },
- builtIn: 'Checkbox',
- synonyms: ['switch'],
- },
- ],
- [FORM_COMPONENT_ID, { displayName: 'Form', builtIn: 'Form', synonyms: [] }],
- [
- 'Password',
- {
- displayName: 'Password',
- builtIn: 'TextField',
- synonyms: [],
- initialProps: { password: true },
- },
- ],
-]);
-
-function createCodeComponent(domNode: appDom.CodeComponentNode): ToolpadComponentDefinition {
- return {
- displayName: domNode.name,
- codeComponentId: domNode.id,
- synonyms: [],
- };
-}
-
-export function getToolpadComponents(dom: appDom.AppDom): ToolpadComponentDefinitions {
- const app = appDom.getApp(dom);
- const { codeComponents = [] } = appDom.getChildNodes(dom, app);
- return Object.fromEntries([
- ...INTERNAL_COMPONENTS.entries(),
- ...codeComponents.map((codeComponent) => [
- `codeComponent.${codeComponent.name}`,
- createCodeComponent(codeComponent),
- ]),
- ]);
-}
-
-export function getToolpadComponent(
- components: ToolpadComponentDefinitions,
- componentId: string,
-): ToolpadComponentDefinition | null {
- const component = components[componentId];
- return component || null;
-}
-
export function getElementNodeComponentId(elementNode: appDom.ElementNode): string {
return elementNode.attributes.component;
}
diff --git a/packages/toolpad-app/src/runtime/useDataProvider.ts b/packages/toolpad-app/src/runtime/useDataProvider.ts
index f35118d0422..ad55a298060 100644
--- a/packages/toolpad-app/src/runtime/useDataProvider.ts
+++ b/packages/toolpad-app/src/runtime/useDataProvider.ts
@@ -39,6 +39,20 @@ export const useDataProvider: UseDataProviderHook = (id) => {
return api.methods.deleteDataProviderRecord(filePath, name, recordId);
}
: undefined,
+ updateRecord: introspection.hasUpdateRecord
+ ? async (recordId: GridRowId, values: Record) => {
+ invariant(id, 'id is required');
+ const [filePath, name] = id.split(':');
+ return api.methods.updateDataProviderRecord(filePath, name, recordId, values);
+ }
+ : undefined,
+ createRecord: introspection.hasCreateRecord
+ ? async (values: Record) => {
+ invariant(id, 'id is required');
+ const [filePath, name] = id.split(':');
+ return api.methods.createDataProviderRecord(filePath, name, values);
+ }
+ : undefined,
};
}, [id, introspection]);
diff --git a/packages/toolpad-app/src/server/FunctionsManager.ts b/packages/toolpad-app/src/server/FunctionsManager.ts
index a4111e8f8d8..5ca79621cba 100644
--- a/packages/toolpad-app/src/server/FunctionsManager.ts
+++ b/packages/toolpad-app/src/server/FunctionsManager.ts
@@ -17,11 +17,11 @@ import {
import { errorFrom } from '@mui/toolpad-utils/errors';
import { ToolpadDataProviderIntrospection } from '@mui/toolpad-core/runtime';
import * as url from 'node:url';
-import invariant from 'invariant';
import type { GridRowId } from '@mui/x-data-grid';
+import invariant from 'invariant';
import EnvManager from './EnvManager';
import { ProjectEvents, ToolpadProjectOptions } from '../types';
-import { createWorker as createDevWorker } from './functionsDevWorker';
+import * as functionsRuntime from './functionsRuntime';
import type { ExtractTypesParams, IntrospectionResult } from './functionsTypesWorker';
import { Awaitable } from '../utils/types';
import { format } from '../utils/prettier';
@@ -114,8 +114,6 @@ export default class FunctionsManager {
private buildErrors: esbuild.Message[] = [];
- private devWorker: ReturnType | undefined;
-
private extractedTypes: Awaitable | undefined;
private extractTypesWorker: Piscina | undefined;
@@ -252,24 +250,10 @@ export default class FunctionsManager {
resourcesWatcher.on('unlink', reinitializeWatcher);
}
- private async createRuntimeWorker() {
- const oldWorker = this.devWorker;
- this.devWorker = createDevWorker(this.project.envManager.getEnv());
- await oldWorker?.terminate();
- this.project.invalidateQueries();
- }
-
async start() {
- await this.createRuntimeWorker();
-
if (this.project.options.dev) {
await this.migrateLegacy();
-
await this.startWatchingFunctionFiles();
-
- this.project.events.subscribe('envChanged', async () => {
- await this.createRuntimeWorker();
- });
}
}
@@ -293,11 +277,7 @@ export default class FunctionsManager {
}
async dispose() {
- await Promise.all([
- this.disposeBuildcontext(),
- this.devWorker?.terminate(),
- this.extractTypesWorker?.destroy(),
- ]);
+ await Promise.all([this.disposeBuildcontext(), this.extractTypesWorker?.destroy()]);
}
async getBuiltOutputFilePath(fileName: string): Promise {
@@ -351,8 +331,7 @@ export default class FunctionsManager {
): Promise> {
const outputFilePath = await this.getBuiltOutputFilePath(fileName);
- invariant(this.devWorker, 'devWorker must be initialized');
- const data = await this.devWorker.execute(outputFilePath, name, parameters);
+ const data = await functionsRuntime.execute(outputFilePath, name, parameters);
return { data };
}
@@ -396,8 +375,13 @@ export default class FunctionsManager {
exportName: string = 'default',
): Promise {
const fullPath = await this.getBuiltOutputFilePath(fileName);
- invariant(this.devWorker, 'devWorker must be initialized');
- return this.devWorker.introspectDataProvider(fullPath, exportName);
+ const dataProvider = await functionsRuntime.loadDataProvider(fullPath, exportName);
+ return {
+ paginationMode: dataProvider.paginationMode,
+ hasDeleteRecord: !!dataProvider.deleteRecord,
+ hasUpdateRecord: !!dataProvider.updateRecord,
+ hasCreateRecord: !!dataProvider.createRecord,
+ };
}
async getDataProviderRecords(
@@ -406,8 +390,8 @@ export default class FunctionsManager {
params: GetRecordsParams,
): Promise> {
const fullPath = await this.getBuiltOutputFilePath(fileName);
- invariant(this.devWorker, 'devWorker must be initialized');
- return this.devWorker.getDataProviderRecords(fullPath, exportName, params);
+ const dataProvider = await functionsRuntime.loadDataProvider(fullPath, exportName);
+ return dataProvider.getRecords(params);
}
async deleteDataProviderRecord(
@@ -416,7 +400,31 @@ export default class FunctionsManager {
id: GridRowId,
): Promise {
const fullPath = await this.getBuiltOutputFilePath(fileName);
- invariant(this.devWorker, 'devWorker must be initialized');
- return this.devWorker.deleteDataProviderRecord(fullPath, exportName, id);
+ const dataProvider = await functionsRuntime.loadDataProvider(fullPath, exportName);
+ invariant(dataProvider.deleteRecord, 'DataProvider does not support deleteRecord');
+ return dataProvider.deleteRecord(id);
+ }
+
+ async updateDataProviderRecord(
+ fileName: string,
+ exportName: string,
+ id: GridRowId,
+ values: Record,
+ ): Promise {
+ const fullPath = await this.getBuiltOutputFilePath(fileName);
+ const dataProvider = await functionsRuntime.loadDataProvider(fullPath, exportName);
+ invariant(dataProvider.updateRecord, 'DataProvider does not support updateRecord');
+ return dataProvider.updateRecord(id, values);
+ }
+
+ async createDataProviderRecord(
+ fileName: string,
+ exportName: string,
+ values: Record,
+ ): Promise {
+ const fullPath = await this.getBuiltOutputFilePath(fileName);
+ const dataProvider = await functionsRuntime.loadDataProvider(fullPath, exportName);
+ invariant(dataProvider.createRecord, 'DataProvider does not support createRecord');
+ return dataProvider.createRecord(values);
}
}
diff --git a/packages/toolpad-app/src/server/appBuilderWorker.ts b/packages/toolpad-app/src/server/appBuilderWorker.ts
index e425645ccf5..1dc992ca9f0 100644
--- a/packages/toolpad-app/src/server/appBuilderWorker.ts
+++ b/packages/toolpad-app/src/server/appBuilderWorker.ts
@@ -23,7 +23,8 @@ async function main() {
await buildApp({
root: project.getRoot(),
base,
- getComponents: () => project.getComponents(),
+ getComponents: () => project.getComponentsManifest(),
+ getPagesManifest: () => project.getPagesManifest(),
outDir: project.getAppOutputFolder(),
loadDom: () => project.loadDom(),
});
diff --git a/packages/toolpad-app/src/server/appServerWorker.ts b/packages/toolpad-app/src/server/appServerWorker.ts
index 0b6f5b9c185..fbee164ae46 100644
--- a/packages/toolpad-app/src/server/appServerWorker.ts
+++ b/packages/toolpad-app/src/server/appServerWorker.ts
@@ -5,7 +5,7 @@ import { createRpcClient } from '@mui/toolpad-utils/workerRpc';
import { getHtmlContent, createViteConfig } from './toolpadAppBuilder';
import type { RuntimeConfig } from '../types';
import type * as appDom from '../appDom';
-import type { ComponentEntry } from './localMode';
+import type { ComponentEntry, PagesManifest } from './localMode';
import createRuntimeState from '../runtime/createRuntimeState';
import { postProcessHtml } from './toolpadAppServer';
@@ -15,9 +15,10 @@ export type WorkerRpc = {
notifyReady: () => Promise;
loadDom: () => Promise;
getComponents: () => Promise;
+ getPagesManifest: () => Promise;
};
-const { notifyReady, loadDom, getComponents } = createRpcClient(
+const { notifyReady, loadDom, getComponents, getPagesManifest } = createRpcClient(
workerData.mainThreadRpcPort,
);
@@ -75,6 +76,7 @@ export async function main({ port, ...config }: AppViteServerConfig) {
dev: true,
plugins: [devServerPlugin(config)],
getComponents,
+ getPagesManifest,
loadDom,
});
diff --git a/packages/toolpad-app/src/server/functionsDevWorker.ts b/packages/toolpad-app/src/server/functionsDevWorker.ts
deleted file mode 100644
index 120fd447500..00000000000
--- a/packages/toolpad-app/src/server/functionsDevWorker.ts
+++ /dev/null
@@ -1,264 +0,0 @@
-import { Worker, MessageChannel, isMainThread, parentPort } from 'worker_threads';
-import * as path from 'path';
-import { createRequire } from 'node:module';
-import * as fs from 'fs/promises';
-import * as vm from 'vm';
-import * as url from 'node:url';
-import {
- ServerContext,
- getServerContext,
- initialContextStore,
- withContext,
-} from '@mui/toolpad-core/serverRuntime';
-import { isWebContainer } from '@webcontainer/env';
-import * as superjson from 'superjson';
-import { createRpcClient, serveRpc } from '@mui/toolpad-utils/workerRpc';
-import { workerData } from 'node:worker_threads';
-import { ToolpadDataProviderIntrospection } from '@mui/toolpad-core/runtime';
-import { TOOLPAD_DATA_PROVIDER_MARKER, ToolpadDataProvider } from '@mui/toolpad-core/server';
-import * as z from 'zod';
-import { fromZodError } from 'zod-validation-error';
-import { GetRecordsParams, GetRecordsResult, PaginationMode } from '@mui/toolpad-core';
-import invariant from 'invariant';
-import type { GridRowId } from '@mui/x-data-grid';
-
-import.meta.url ??= url.pathToFileURL(__filename).toString();
-const currentDirectory = url.fileURLToPath(new URL('.', import.meta.url));
-
-interface ModuleObject {
- exports: Record;
-}
-
-const fileContents = new Map();
-const moduleCache = new Map();
-
-function loadModule(fullPath: string, content: string) {
- const moduleRequire = createRequire(url.pathToFileURL(fullPath));
- const moduleObject: ModuleObject = { exports: {} };
-
- const serverRuntime = moduleRequire('@mui/toolpad-core/serverRuntime');
- serverRuntime.initStore(initialContextStore);
-
- vm.runInThisContext(`((require, exports, module) => {\n${content}\n})`)(
- moduleRequire,
- moduleObject.exports,
- moduleObject,
- );
-
- return moduleObject;
-}
-
-async function resolveExports(filePath: string): Promise> {
- const fullPath = path.resolve(filePath);
- const content = await fs.readFile(fullPath, 'utf-8');
-
- if (content !== fileContents.get(fullPath)) {
- moduleCache.delete(fullPath);
- fileContents.set(fullPath, content);
- }
-
- let cachedModule = moduleCache.get(fullPath);
-
- if (!cachedModule) {
- cachedModule = loadModule(fullPath, content);
- moduleCache.set(fullPath, cachedModule);
- }
-
- return new Map(Object.entries(cachedModule.exports));
-}
-
-interface ExecuteParams {
- filePath: string;
- name: string;
- parameters: unknown[];
- cookies?: Record;
-}
-
-interface ExecuteResult {
- result: string;
- newCookies: [string, string][];
-}
-
-async function execute(msg: ExecuteParams): Promise {
- const exports = await resolveExports(msg.filePath);
-
- const fn = exports.get(msg.name);
- if (typeof fn !== 'function') {
- throw new Error(`Function "${msg.name}" not found`);
- }
-
- let functionFinished = false;
-
- try {
- const newCookies = new Map();
-
- const ctx: ServerContext = {
- cookies: msg.cookies || {},
- setCookie(name: string, value: string) {
- if (functionFinished) {
- throw new Error(`setCookie can't be called after the function has finished executing.`);
- }
- newCookies.set(name, value);
- },
- };
-
- const shouldBypassContext = isWebContainer();
-
- if (shouldBypassContext) {
- console.warn(
- 'Bypassing server context in web containers, see https://github.com/stackblitz/core/issues/2711',
- );
- }
-
- const rawResult = shouldBypassContext
- ? await fn(...msg.parameters)
- : await withContext(ctx, async () => fn(...msg.parameters));
-
- const serializedResult = superjson.stringify(rawResult);
-
- return { result: serializedResult, newCookies: Array.from(newCookies.entries()) };
- } finally {
- functionFinished = true;
- }
-}
-
-const dataProviderSchema: z.ZodType> = z.object({
- paginationMode: z.enum(['index', 'cursor']).optional().default('index'),
- getRecords: z.function(z.tuple([z.any()]), z.any()),
- deleteRecord: z.function(z.tuple([z.any()]), z.any()).optional(),
- updateRecord: z.function(z.tuple([z.any()]), z.any()).optional(),
- createRecord: z.function(z.tuple([z.any()]), z.any()).optional(),
- [TOOLPAD_DATA_PROVIDER_MARKER]: z.literal(true),
-});
-
-async function loadDataProvider(
- filePath: string,
- name: string,
-): Promise> {
- const exports = await resolveExports(filePath);
- const dataProviderExport = exports.get(name);
-
- if (!dataProviderExport || typeof dataProviderExport !== 'object') {
- throw new Error(`DataProvider "${name}" not found`);
- }
-
- const parsed = dataProviderSchema.safeParse(dataProviderExport);
-
- if (parsed.success) {
- return parsed.data;
- }
-
- throw fromZodError(parsed.error);
-}
-
-async function introspectDataProvider(
- filePath: string,
- name: string,
-): Promise {
- const dataProvider = await loadDataProvider(filePath, name);
-
- return {
- paginationMode: dataProvider.paginationMode,
- hasDeleteRecord: !!dataProvider.deleteRecord,
- };
-}
-
-async function getDataProviderRecords(
- filePath: string,
- name: string,
- params: GetRecordsParams,
-): Promise> {
- const dataProvider = await loadDataProvider(filePath, name);
-
- return dataProvider.getRecords(params);
-}
-
-async function deleteDataProviderRecord(
- filePath: string,
- name: string,
- id: GridRowId,
-): Promise {
- const dataProvider = await loadDataProvider(filePath, name);
- invariant(dataProvider.deleteRecord, 'DataProvider does not support deleteRecord');
- return dataProvider.deleteRecord(id);
-}
-
-type WorkerRpcServer = {
- execute: typeof execute;
- introspectDataProvider: typeof introspectDataProvider;
- getDataProviderRecords: typeof getDataProviderRecords;
- deleteDataProviderRecord: typeof deleteDataProviderRecord;
-};
-
-if (!isMainThread && parentPort) {
- serveRpc(workerData.workerRpcPort, {
- execute,
- introspectDataProvider,
- getDataProviderRecords,
- deleteDataProviderRecord,
- });
-}
-
-export function createWorker(env: Record) {
- const workerRpcChannel = new MessageChannel();
- const worker = new Worker(path.resolve(currentDirectory, '../cli/functionsDevWorker.mjs'), {
- env,
- workerData: {
- workerRpcPort: workerRpcChannel.port1,
- },
- transferList: [workerRpcChannel.port1],
- });
-
- const client = createRpcClient(workerRpcChannel.port2);
-
- return {
- async terminate() {
- return worker.terminate();
- },
-
- async execute(filePath: string, name: string, parameters: unknown[]): Promise {
- const ctx = getServerContext();
-
- const { result: serializedResult, newCookies } = await client.execute({
- filePath,
- name,
- parameters,
- cookies: ctx?.cookies,
- });
-
- if (ctx) {
- for (const [cookieName, cookieValue] of newCookies) {
- ctx.setCookie(cookieName, cookieValue);
- }
- }
-
- const result = superjson.parse(serializedResult);
-
- return result;
- },
-
- async introspectDataProvider(
- filePath: string,
- name: string,
- ): Promise {
- return client.introspectDataProvider(filePath, name);
- },
-
- async getDataProviderRecords(
- filePath: string,
- name: string,
- params: GetRecordsParams,
- ): Promise> {
- return client.getDataProviderRecords(filePath, name, params);
- },
-
- async deleteDataProviderRecord(filePath: string, name: string, id: GridRowId): Promise {
- return client.deleteDataProviderRecord(filePath, name, id);
- },
- };
-}
-
-process.on('unhandledRejection', (error) => {
- console.error(error);
- process.exit(1);
-});
diff --git a/packages/toolpad-app/src/server/functionsRuntime.ts b/packages/toolpad-app/src/server/functionsRuntime.ts
new file mode 100644
index 00000000000..ddf6f8c9f73
--- /dev/null
+++ b/packages/toolpad-app/src/server/functionsRuntime.ts
@@ -0,0 +1,96 @@
+import * as path from 'path';
+import { createRequire } from 'node:module';
+import * as fs from 'fs/promises';
+import * as vm from 'vm';
+import * as url from 'node:url';
+import { initialContextStore } from '@mui/toolpad-core/serverRuntime';
+import { TOOLPAD_DATA_PROVIDER_MARKER, ToolpadDataProvider } from '@mui/toolpad-core/server';
+import * as z from 'zod';
+import { fromZodError } from 'zod-validation-error';
+
+import.meta.url ??= url.pathToFileURL(__filename).toString();
+
+interface ModuleObject {
+ exports: Record;
+}
+
+const fileContents = new Map();
+const moduleCache = new Map();
+
+function loadModule(fullPath: string, content: string) {
+ const moduleRequire = createRequire(url.pathToFileURL(fullPath));
+ const moduleObject: ModuleObject = { exports: {} };
+
+ const serverRuntime = moduleRequire('@mui/toolpad/server');
+ // eslint-disable-next-line no-underscore-dangle
+ serverRuntime.__initContextStore(initialContextStore);
+
+ vm.runInThisContext(`((require, exports, module) => {\n${content}\n})`)(
+ moduleRequire,
+ moduleObject.exports,
+ moduleObject,
+ );
+
+ return moduleObject;
+}
+
+async function loadExports(filePath: string): Promise> {
+ const fullPath = path.resolve(filePath);
+ const content = await fs.readFile(fullPath, 'utf-8');
+
+ if (content !== fileContents.get(fullPath)) {
+ moduleCache.delete(fullPath);
+ fileContents.set(fullPath, content);
+ }
+
+ let cachedModule = moduleCache.get(fullPath);
+
+ if (!cachedModule) {
+ cachedModule = loadModule(fullPath, content);
+ moduleCache.set(fullPath, cachedModule);
+ }
+
+ return new Map(Object.entries(cachedModule.exports));
+}
+
+const dataProviderSchema: z.ZodType> = z.object({
+ paginationMode: z.enum(['index', 'cursor']).optional().default('index'),
+ getRecords: z.function(z.tuple([z.any()]), z.any()),
+ deleteRecord: z.function(z.tuple([z.any()]), z.any()).optional(),
+ updateRecord: z.function(z.tuple([z.any(), z.any()]), z.any()).optional(),
+ createRecord: z.function(z.tuple([z.any()]), z.any()).optional(),
+ [TOOLPAD_DATA_PROVIDER_MARKER]: z.literal(true),
+});
+
+export async function loadDataProvider(
+ filePath: string,
+ name: string,
+): Promise> {
+ const exports = await loadExports(filePath);
+ const dataProviderExport = exports.get(name);
+
+ if (!dataProviderExport || typeof dataProviderExport !== 'object') {
+ throw new Error(`DataProvider "${name}" not found`);
+ }
+
+ const parsed = dataProviderSchema.safeParse(dataProviderExport);
+
+ if (parsed.success) {
+ return parsed.data;
+ }
+
+ throw fromZodError(parsed.error);
+}
+
+export async function execute(filePath: string, name: string, parameters: unknown[]): Promise {
+ const exports = await loadExports(filePath);
+
+ const fn = exports.get(name);
+ if (typeof fn !== 'function') {
+ throw new Error(`Function "${name}" not found`);
+ }
+
+ const result = await fn(...parameters);
+
+ return result;
+}
diff --git a/packages/toolpad-app/src/server/index.ts b/packages/toolpad-app/src/server/index.ts
index c2048b3357b..59cd181762e 100644
--- a/packages/toolpad-app/src/server/index.ts
+++ b/packages/toolpad-app/src/server/index.ts
@@ -92,7 +92,8 @@ async function createDevHandler(project: ToolpadProject) {
serveRpc(mainThreadRpcChannel.port2, {
notifyReady: async () => resolveReadyPromise?.(),
loadDom: async () => project.loadDom(),
- getComponents: async () => project.getComponents(),
+ getComponents: async () => project.getComponentsManifest(),
+ getPagesManifest: async () => project.getPagesManifest(),
});
project.events.on('componentsListChanged', () => {
diff --git a/packages/toolpad-app/src/server/localMode.ts b/packages/toolpad-app/src/server/localMode.ts
index 3e1138804b1..0f67461daf5 100644
--- a/packages/toolpad-app/src/server/localMode.ts
+++ b/packages/toolpad-app/src/server/localMode.ts
@@ -11,6 +11,7 @@ import { glob } from 'glob';
import * as chokidar from 'chokidar';
import { debounce, throttle } from 'lodash-es';
import { Emitter } from '@mui/toolpad-utils/events';
+import { guessTitle } from '@mui/toolpad-utils/strings';
import { errorFrom } from '@mui/toolpad-utils/errors';
import { filterValues, hasOwnProperty, mapValues } from '@mui/toolpad-utils/collections';
import { execa } from 'execa';
@@ -115,43 +116,16 @@ function getAppOutputFolder(root: string) {
return path.join(getOutputFolder(root), 'app');
}
-type ComponentsContent = Record;
-
export interface ComponentEntry {
name: string;
path: string;
}
-async function getComponents(root: string): Promise {
- const componentsFolder = getComponentsFolder(root);
- const entries = (await readMaybeDir(componentsFolder)) || [];
- const result = entries.map((entry) => {
- if (entry.isFile()) {
- const fileName = entry.name;
- const componentName = entry.name.replace(/\.tsx$/, '');
- const filePath = path.resolve(componentsFolder, fileName);
- return { name: componentName, path: filePath };
- }
- return null;
- });
- return result.filter(Boolean);
-}
-
-async function loadCodeComponentsFromFiles(root: string): Promise {
- const components = await getComponents(root);
- const resultEntries = await Promise.all(
- components.map(async (component): Promise<[string, { code: string }]> => {
- const content = await fs.readFile(component.path, { encoding: 'utf-8' });
- return [component.name, { code: content }];
- }),
- );
-
- return Object.fromEntries(resultEntries);
-}
+export type ComponentsManifest = ComponentEntry[];
async function loadPagesFromFiles(root: string): Promise {
const pagesFolder = getPagesFolder(root);
- const entries = (await readMaybeDir(pagesFolder)) || [];
+ const entries = await readMaybeDir(pagesFolder);
const resultEntries = await Promise.all(
entries.map(async (entry): Promise<[string, Page] | null> => {
if (entry.isDirectory()) {
@@ -197,8 +171,6 @@ async function loadPagesFromFiles(root: string): Promise {
for (const extension of extensions) {
if (pageDirEntries.has(`page${extension}`)) {
- const codeFileName = `./page${extension}`;
-
return [
pageName,
{
@@ -206,7 +178,7 @@ async function loadPagesFromFiles(root: string): Promise {
kind: 'page',
spec: {
id: pageName,
- unstable_codeFile: codeFileName,
+ unstable_codeFile: true,
},
} satisfies Page,
];
@@ -320,58 +292,6 @@ async function initGitignore(root: string) {
}
}
-async function writeCodeComponentsToFiles(
- componentsFolder: string,
- components: ComponentsContent,
-): Promise {
- await Promise.all(
- Object.entries(components).map(async ([componentName, content]) => {
- const filePath = getComponentFilePath(componentsFolder, componentName);
- await writeFileRecursive(filePath, content.code, { encoding: 'utf-8' });
- }),
- );
-}
-
-function mergeComponentsContentIntoDom(
- dom: appDom.AppDom,
- componentsContent: ComponentsContent,
-): appDom.AppDom {
- const rootNode = appDom.getApp(dom);
- const { codeComponents: codeComponentNodes = [] } = appDom.getChildNodes(dom, rootNode);
- const names = new Set([
- ...Object.keys(componentsContent),
- ...codeComponentNodes.map((node) => node.name),
- ]);
-
- for (const name of names) {
- const content: { code: string } | undefined = componentsContent[name];
- const codeComponentNode = codeComponentNodes.find((node) => node.name === name);
- if (content) {
- if (codeComponentNode) {
- dom = appDom.setNodeNamespacedProp(
- dom,
- codeComponentNode,
- 'attributes',
- 'code',
- content.code,
- );
- } else {
- const newNode = appDom.createNode(dom, 'codeComponent', {
- name,
- attributes: {
- code: content.code,
- },
- });
- dom = appDom.addNode(dom, newNode, rootNode, 'codeComponents');
- }
- } else if (codeComponentNode) {
- dom = appDom.removeNode(dom, codeComponentNode.id);
- }
- }
-
- return dom;
-}
-
function mergeThemeIntoAppDom(dom: appDom.AppDom, themeFile: Theme): appDom.AppDom {
const themeFileSpec = themeFile.spec;
const app = appDom.getApp(dom);
@@ -545,6 +465,7 @@ function expandFromDom(
apiVersion: API_VERSION,
kind: 'page',
spec: {
+ displayName: node.attributes.displayName,
alias: node.attributes.alias,
title: node.attributes.title,
parameters: undefinedWhenEmpty(
@@ -727,6 +648,7 @@ function createPageDomFromPageFile(pageName: string, pageFile: Page): appDom.App
let fragment = appDom.createFragment('page', {
name: pageName,
attributes: {
+ displayName: pageFileSpec.displayName,
// Convert deprecated id to alias
alias: pageFileSpec.id ? [pageFileSpec.id] : pageFileSpec.alias,
title: pageFileSpec.title,
@@ -947,13 +869,11 @@ export type ProjectFolderEntry = {
interface ToolpadProjectFolder {
application: Application | null;
pages: Record;
- components: Record;
theme: Theme | null;
}
async function readProjectFolder(root: string): Promise {
- const [componentsContent, pagesContent, theme, application] = await Promise.all([
- loadCodeComponentsFromFiles(root),
+ const [pagesContent, theme, application] = await Promise.all([
loadPagesFromFiles(root),
loadThemeFromFile(root),
loadApplicationFromFile(root),
@@ -962,29 +882,21 @@ async function readProjectFolder(root: string): Promise {
return {
application,
pages: pagesContent,
- components: componentsContent,
theme,
};
}
-async function writeProjectFolder(
- root: string,
- folder: ToolpadProjectFolder,
- writeComponents: boolean = false,
-): Promise {
- const componentsFolder = getComponentsFolder(root);
+async function writeProjectFolder(root: string, folder: ToolpadProjectFolder): Promise {
await Promise.all([
writePagesToFiles(root, folder.pages),
writeThemeFile(root, folder.theme),
writeApplicationFile(root, folder.application),
- writeComponents ? writeCodeComponentsToFiles(componentsFolder, folder.components) : null,
]);
}
function projectFolderToAppDom(projectFolder: ToolpadProjectFolder): appDom.AppDom {
let dom = appDom.createDom();
dom = mergePagesIntoDom(dom, projectFolder.pages);
- dom = mergeComponentsContentIntoDom(dom, projectFolder.components);
if (projectFolder.theme) {
dom = mergeThemeIntoAppDom(dom, projectFolder.theme);
}
@@ -1007,8 +919,7 @@ export async function loadDomFromDisk(root: string): Promise {
function getDomFilePatterns(root: string) {
return [
path.resolve(root, './pages/*/page.yml'),
- path.resolve(root, './components'),
- path.resolve(root, './components/*.*'),
+ path.resolve(root, './theme.yml'),
path.resolve(root, './application.yml'),
];
}
@@ -1028,11 +939,6 @@ async function calculateDomFingerprint(root: string): Promise {
return insecureHash(JSON.stringify(mtimes));
}
-function getCodeComponentsFingerprint(dom: appDom.AppDom) {
- const { codeComponents = [] } = appDom.getChildNodes(dom, appDom.getApp(dom));
- return codeComponents.map(({ name }) => name).join('|');
-}
-
class ToolpadProject {
private root: string;
@@ -1044,8 +950,6 @@ class ToolpadProject {
options: ToolpadProjectOptions;
- private codeComponentsFingerprint: null | string = null;
-
envManager: EnvManager;
functionsManager: FunctionsManager;
@@ -1060,6 +964,10 @@ class ToolpadProject {
private pendingVersionCheck: Promise | undefined;
+ private componentsManifestPromise: Promise | undefined;
+
+ private pagesManifestPromise: Promise | undefined;
+
constructor(root: string, options: ToolpadProjectOptions) {
invariant(
// eslint-disable-next-line no-underscore-dangle
@@ -1096,7 +1004,7 @@ class ToolpadProject {
const updateDomFromExternal = debounce(() => {
this.domAndFingerprintLock.use(async () => {
- const [dom, fingerprint] = await this.loadDomAndFingerprint();
+ const [, fingerprint] = await this.loadDomAndFingerprint();
const newFingerprint = await calculateDomFingerprint(this.root);
if (fingerprint !== newFingerprint) {
// eslint-disable-next-line no-console
@@ -1107,14 +1015,6 @@ class ToolpadProject {
]);
this.events.emit('change', {});
this.events.emit('externalChange', {});
-
- const newCodeComponentsFingerprint = getCodeComponentsFingerprint(dom);
- if (this.codeComponentsFingerprint !== newCodeComponentsFingerprint) {
- this.codeComponentsFingerprint = newCodeComponentsFingerprint;
- if (this.codeComponentsFingerprint !== null) {
- this.events.emit('componentsListChanged', {});
- }
- }
}
});
}, 100);
@@ -1128,6 +1028,44 @@ class ToolpadProject {
chokidar.watch(getDomFilePatterns(this.root), watchOptions).on('all', () => {
updateDomFromExternal();
});
+
+ const handleComponentFileChange = async () => {
+ const oldManifest = await this.componentsManifestPromise;
+ this.componentsManifestPromise = this.buildComponentsManifest();
+ const newManifest = await this.componentsManifestPromise;
+ if (JSON.stringify(oldManifest) !== JSON.stringify(newManifest)) {
+ this.events.emit('componentsListChanged', {});
+ }
+ };
+
+ chokidar
+ .watch(
+ [path.resolve(this.root, './components'), path.resolve(this.root, './components/*.*')],
+ watchOptions,
+ )
+ .on('add', handleComponentFileChange)
+ .on('addDir', handleComponentFileChange)
+ .on('unlink', handleComponentFileChange)
+ .on('unlinkDir', handleComponentFileChange);
+
+ const handlePageFileChange = async () => {
+ const oldManifest = await this.pagesManifestPromise;
+ this.pagesManifestPromise = buildPagesManifest(this.root);
+ const newManifest = await this.pagesManifestPromise;
+ if (JSON.stringify(oldManifest) !== JSON.stringify(newManifest)) {
+ this.events.emit('pagesManifestChanged', {});
+ }
+ };
+
+ chokidar
+ .watch(
+ [path.resolve(this.root, './pages'), path.resolve(this.root, './pages/*/page.*')],
+ watchOptions,
+ )
+ .on('add', handlePageFileChange)
+ .on('addDir', handlePageFileChange)
+ .on('unlink', handlePageFileChange)
+ .on('unlinkDir', handlePageFileChange);
}
private async loadDomAndFingerprint() {
@@ -1216,8 +1154,26 @@ class ToolpadProject {
return dom;
}
- async getComponents(): Promise {
- return getComponents(this.getRoot());
+ async buildComponentsManifest(): Promise {
+ const componentsFolder = getComponentsFolder(this.getRoot());
+ const entries = (await readMaybeDir(componentsFolder)) || [];
+ const result = entries.map((entry) => {
+ if (entry.isFile()) {
+ const fileName = entry.name;
+ const componentName = entry.name.replace(/\.tsx$/, '');
+ const filePath = path.resolve(componentsFolder, fileName);
+ return { name: componentName, path: filePath };
+ }
+ return null;
+ });
+ return result.filter(Boolean);
+ }
+
+ async getComponentsManifest(): Promise {
+ if (!this.componentsManifestPromise) {
+ this.componentsManifestPromise = this.buildComponentsManifest();
+ }
+ return this.componentsManifestPromise;
}
async writeDomToDisk(newDom: appDom.AppDom) {
@@ -1346,6 +1302,13 @@ class ToolpadProject {
return null;
}
}
+
+ async getPagesManifest(): Promise {
+ if (!this.pagesManifestPromise) {
+ this.pagesManifestPromise = buildPagesManifest(this.root);
+ }
+ return this.pagesManifestPromise;
+ }
}
export type { ToolpadProject };
@@ -1375,3 +1338,78 @@ export async function initProject({ dir: dirInput, ...config }: InitProjectOptio
return project;
}
+
+const basePagesManifestEntrySchema = z.object({
+ slug: z.string(),
+ title: z.string(),
+ legacy: z.boolean().optional(),
+});
+
+export interface PagesManifestEntry extends z.infer {
+ children: PagesManifestEntry[];
+}
+
+const pagesManifestEntrySchema: z.ZodType = basePagesManifestEntrySchema.extend(
+ {
+ children: z.array(z.lazy(() => pagesManifestEntrySchema)),
+ },
+);
+
+const pagesManifestSchema = z.object({
+ pages: z.array(pagesManifestEntrySchema),
+});
+
+export type PagesManifest = z.infer;
+
+async function buildPagesManifest(root: string): Promise {
+ const pagesFolder = getPagesFolder(root);
+ const pageDirs = await readMaybeDir(pagesFolder);
+ const pages = (
+ await Promise.all(
+ pageDirs.map(async (page) => {
+ if (page.isDirectory()) {
+ const pagePath = path.resolve(pagesFolder, page.name);
+ const title = guessTitle(page.name);
+
+ const extensions = ['.tsx', '.jsx'];
+
+ for (const extension of extensions) {
+ const pageFilePath = path.resolve(pagePath, `page${extension}`);
+
+ // eslint-disable-next-line no-await-in-loop
+ const stat = await fs.stat(pageFilePath).catch(() => null);
+ if (stat?.isFile()) {
+ return [
+ {
+ slug: page.name,
+ title,
+ children: [],
+ },
+ ];
+ }
+ }
+
+ const pageFilePath = path.resolve(pagePath, 'page.yml');
+
+ const stat = await fs.stat(pageFilePath).catch(() => null);
+ if (stat?.isFile()) {
+ return [
+ {
+ slug: page.name,
+ title,
+ legacy: true,
+ children: [],
+ },
+ ];
+ }
+ }
+
+ return [];
+ }),
+ )
+ ).flat();
+
+ pages.sort((page1, page2) => page1.title.localeCompare(page2.title));
+
+ return { pages };
+}
diff --git a/packages/toolpad-app/src/server/projectRpcServer.ts b/packages/toolpad-app/src/server/projectRpcServer.ts
index 605e5b39ad7..c3d656ecb06 100644
--- a/packages/toolpad-app/src/server/projectRpcServer.ts
+++ b/packages/toolpad-app/src/server/projectRpcServer.ts
@@ -50,6 +50,9 @@ export function createRpcServer(project: ToolpadProject) {
getRuntimeConfig: createMethod(({ params }) => {
return project.getRuntimeConfig(...params);
}),
+ getComponents: createMethod(({ params }) => {
+ return project.getComponentsManifest(...params);
+ }),
} satisfies MethodResolvers;
}
diff --git a/packages/toolpad-app/src/server/runtimeRpcServer.ts b/packages/toolpad-app/src/server/runtimeRpcServer.ts
index 08d83f6a74f..8e1cbcf5555 100644
--- a/packages/toolpad-app/src/server/runtimeRpcServer.ts
+++ b/packages/toolpad-app/src/server/runtimeRpcServer.ts
@@ -19,6 +19,16 @@ export function createRpcServer(project: ToolpadProject) {
>(({ params }) => {
return project.functionsManager.deleteDataProviderRecord(...params);
}),
+ updateDataProviderRecord: createMethod<
+ typeof project.functionsManager.updateDataProviderRecord
+ >(({ params }) => {
+ return project.functionsManager.updateDataProviderRecord(...params);
+ }),
+ createDataProviderRecord: createMethod<
+ typeof project.functionsManager.createDataProviderRecord
+ >(({ params }) => {
+ return project.functionsManager.createDataProviderRecord(...params);
+ }),
execQuery: createMethod(({ params }) => {
return project.dataManager.execQuery(...params);
}),
diff --git a/packages/toolpad-app/src/server/schema.ts b/packages/toolpad-app/src/server/schema.ts
index a70b2abd52f..df488f6ff59 100644
--- a/packages/toolpad-app/src/server/schema.ts
+++ b/packages/toolpad-app/src/server/schema.ts
@@ -299,6 +299,7 @@ export type Application = z.infer;
export const pageSchema = toolpadObjectSchema(
'page',
z.object({
+ displayName: z.string().optional().describe('Page name to display in the UI.'),
id: z
.string()
.optional()
@@ -327,8 +328,8 @@ export const pageSchema = toolpadObjectSchema(
})
.optional()
.describe('Authorization configuration for this page.'),
- unstable_codeFile: z
- .string()
+ unstable_codeFile: z.coerce
+ .boolean()
.optional()
.describe('The content of the page as JSX. Experimental, do not use!.'),
display: z
diff --git a/packages/toolpad-app/src/server/toolpadAppBuilder.ts b/packages/toolpad-app/src/server/toolpadAppBuilder.ts
index bfbafabb439..799516a951a 100644
--- a/packages/toolpad-app/src/server/toolpadAppBuilder.ts
+++ b/packages/toolpad-app/src/server/toolpadAppBuilder.ts
@@ -3,7 +3,7 @@ import * as url from 'node:url';
import type { InlineConfig, Plugin } from 'vite';
import react from '@vitejs/plugin-react';
import { indent } from '@mui/toolpad-utils/strings';
-import type { ComponentEntry } from './localMode';
+import type { ComponentEntry, PagesManifest } from './localMode';
import { INITIAL_STATE_WINDOW_PROPERTY } from '../constants';
import * as appDom from '../appDom';
import { pathToNodeImportSpecifier } from '../utils/paths';
@@ -143,6 +143,7 @@ export interface CreateViteConfigParams {
plugins?: Plugin[];
getComponents: () => Promise;
loadDom: () => Promise;
+ getPagesManifest: () => Promise;
}
export async function createViteConfig({
@@ -154,6 +155,7 @@ export async function createViteConfig({
plugins = [],
getComponents,
loadDom,
+ getPagesManifest,
}: CreateViteConfigParams) {
const mode = dev ? 'development' : 'production';
@@ -229,7 +231,7 @@ if (import.meta.hot) {
for (const page of pages) {
const codeFile = page.attributes.codeFile;
if (codeFile) {
- const importPath = path.resolve(root, `./pages/${page.name}`, codeFile);
+ const importPath = path.resolve(root, `./pages/${page.name}/page`);
const relativeImportPath = path.relative(root, importPath);
const importSpec = `toolpad-user-project:${pathToNodeImportSpecifier(relativeImportPath)}`;
imports.set(page.name, importSpec);
@@ -260,6 +262,7 @@ if (import.meta.hot) {
['canvas.tsx', getEntryPoint(true)],
['components.tsx', await createComponentsFile()],
['page-components.tsx', await createPageComponentsFile()],
+ ['pages-manifest.json', JSON.stringify(await getPagesManifest(), null, 2)],
]);
const virtualToolpadFiles = viteVirtualPlugin(virtualFiles, 'toolpad-files');
@@ -364,6 +367,7 @@ if (import.meta.hot) {
'react/jsx-runtime',
'recharts',
'superjson',
+ 'title',
'zod',
],
exclude: [
@@ -391,6 +395,7 @@ export interface ToolpadBuilderParams {
outDir: string;
getComponents: () => Promise;
loadDom: () => Promise;
+ getPagesManifest: () => Promise;
root: string;
base: string;
}
@@ -399,6 +404,7 @@ export async function buildApp({
root,
base,
getComponents,
+ getPagesManifest,
loadDom,
outDir,
}: ToolpadBuilderParams) {
@@ -408,6 +414,7 @@ export async function buildApp({
base,
outDir,
getComponents,
+ getPagesManifest,
loadDom,
});
const vite = await import('vite');
diff --git a/packages/toolpad-app/src/toolpad/AppEditor/AppEditorShell.tsx b/packages/toolpad-app/src/toolpad/AppEditor/AppEditorShell.tsx
index db2be0f467f..dec86b39445 100644
--- a/packages/toolpad-app/src/toolpad/AppEditor/AppEditorShell.tsx
+++ b/packages/toolpad-app/src/toolpad/AppEditor/AppEditorShell.tsx
@@ -3,36 +3,77 @@ import { Box } from '@mui/material';
import * as React from 'react';
import PagePanel from './PagePanel';
+import { PropControlsContextProvider, PropTypeControls } from '../propertyControls';
+
+import string from '../propertyControls/string';
+import boolean from '../propertyControls/boolean';
+import number from '../propertyControls/number';
+import select from '../propertyControls/select';
+import json from '../propertyControls/json';
+import event from '../propertyControls/event';
+import markdown from '../propertyControls/Markdown';
+import GridColumns from '../propertyControls/GridColumns';
+import ToggleButtons from '../propertyControls/ToggleButtons';
+import SelectOptions from '../propertyControls/SelectOptions';
+import ChartData from '../propertyControls/ChartData';
+import RowIdFieldSelect from '../propertyControls/RowIdFieldSelect';
+import HorizontalAlign from '../propertyControls/HorizontalAlign';
+import VerticalAlign from '../propertyControls/VerticalAlign';
+import NumberFormat from '../propertyControls/NumberFormat';
+import ColorScale from '../propertyControls/ColorScale';
+import DataProviderSelector from '../propertyControls/DataProviderSelector';
+
+export const PROP_TYPE_CONTROLS: PropTypeControls = {
+ string,
+ boolean,
+ number,
+ select,
+ json,
+ markdown,
+ event,
+ GridColumns,
+ ToggleButtons,
+ SelectOptions,
+ ChartData,
+ RowIdFieldSelect,
+ HorizontalAlign,
+ VerticalAlign,
+ NumberFormat,
+ ColorScale,
+ DataProviderSelector,
+};
export interface ToolpadShellProps {
children: React.ReactNode;
}
export default function AppEditorShell({ children }: ToolpadShellProps) {
return (
-
-
+
- {children}
+
+
+ {children}
+
-
+
);
}
diff --git a/packages/toolpad-app/src/toolpad/AppEditor/BindingEditor.tsx b/packages/toolpad-app/src/toolpad/AppEditor/BindingEditor.tsx
index 5e4d3078194..035d2511462 100644
--- a/packages/toolpad-app/src/toolpad/AppEditor/BindingEditor.tsx
+++ b/packages/toolpad-app/src/toolpad/AppEditor/BindingEditor.tsx
@@ -655,8 +655,8 @@ export function BindingEditor({
aria-label={`Bind property "${label}"`}
checked={hasBinding}
disabled={disabled}
- icon={ }
- checkedIcon={ }
+ icon={ }
+ checkedIcon={ }
onClick={handleOpen}
color={error ? 'error' : undefined}
sx={{ visibility: hidden ? 'hidden' : 'visible' }}
diff --git a/packages/toolpad-app/src/toolpad/AppEditor/ExplorerHeader.tsx b/packages/toolpad-app/src/toolpad/AppEditor/ExplorerHeader.tsx
index 996a6962332..3db583e1291 100644
--- a/packages/toolpad-app/src/toolpad/AppEditor/ExplorerHeader.tsx
+++ b/packages/toolpad-app/src/toolpad/AppEditor/ExplorerHeader.tsx
@@ -4,6 +4,7 @@ import AddIcon from '@mui/icons-material/Add';
interface ExplorerHeaderProps {
headerText: string;
+ headerIcon?: React.ReactNode;
createLabelText?: string;
onCreate?: React.MouseEventHandler;
}
@@ -22,6 +23,7 @@ const ExplorerHeaderTitle = styled(Typography)(({ theme }) => ({
export default function ExplorerHeader({
headerText,
+ headerIcon,
onCreate,
createLabelText,
}: ExplorerHeaderProps) {
@@ -32,6 +34,7 @@ export default function ExplorerHeader({
justifyContent="space-between"
sx={{ pl: 2.5 }}
>
+ {headerIcon}
, meta: ScopeMeta): Explor
displayName: 'Queries',
items: [],
},
+ action: {
+ displayName: 'Actions',
+ items: [],
+ },
other: {
displayName: 'Other',
items: [],
diff --git a/packages/toolpad-app/src/toolpad/AppEditor/NodeMenu.tsx b/packages/toolpad-app/src/toolpad/AppEditor/NodeMenu.tsx
index 733664167ac..128624c4517 100644
--- a/packages/toolpad-app/src/toolpad/AppEditor/NodeMenu.tsx
+++ b/packages/toolpad-app/src/toolpad/AppEditor/NodeMenu.tsx
@@ -47,6 +47,13 @@ export default function NodeMenu({
const deletedNode = deletedNodeId && appDom.getMaybeNode(dom, deletedNodeId);
const latestDeletedNode = useLatest(deletedNode);
+ const isAction = React.useMemo(() => {
+ if (latestDeletedNode?.type === 'query' && latestDeletedNode?.attributes?.mode === 'mutation') {
+ return true;
+ }
+ return false;
+ }, [latestDeletedNode]);
+
const handleDeleteNodeDialogClose = React.useCallback(
(confirmed: boolean, event: React.MouseEvent) => {
event.stopPropagation();
@@ -118,7 +125,8 @@ export default function NodeMenu({
onClose={handleDeleteNodeDialogClose}
okButton="Delete"
>
- Delete {latestDeletedNode?.type} "{latestDeletedNode?.name}"?
+ Delete {isAction ? 'action' : 'query'} "{latestDeletedNode?.name}
+ "?
);
diff --git a/packages/toolpad-app/src/toolpad/AppEditor/PageDisplayNameEditor.tsx b/packages/toolpad-app/src/toolpad/AppEditor/PageDisplayNameEditor.tsx
new file mode 100644
index 00000000000..ecf5c596811
--- /dev/null
+++ b/packages/toolpad-app/src/toolpad/AppEditor/PageDisplayNameEditor.tsx
@@ -0,0 +1,76 @@
+import { IconButton, InputAdornment, TextField, Tooltip } from '@mui/material';
+import * as React from 'react';
+import ResetIcon from '@mui/icons-material/RestartAlt';
+import * as appDom from '../../appDom';
+import { useDomApi } from '../AppState';
+
+interface PageDisplayNameEditorProps {
+ node: appDom.PageNode;
+}
+
+function validateInput(input: string) {
+ if (!input) {
+ return 'Input required';
+ }
+ return null;
+}
+
+export default function PageDisplayNameEditor({ node }: PageDisplayNameEditorProps) {
+ const domApi = useDomApi();
+
+ const pageDisplayName = React.useMemo(() => appDom.getPageDisplayName(node), [node]);
+
+ const [pageDisplayNameInput, setPageDisplayNameInput] = React.useState(pageDisplayName);
+ React.useEffect(() => setPageDisplayNameInput(pageDisplayName), [pageDisplayName]);
+
+ const handlePageDisplayNameChange = React.useCallback(
+ (event: React.ChangeEvent) => setPageDisplayNameInput(event.target.value),
+ [],
+ );
+
+ const handleCommit = React.useCallback(() => {
+ domApi.update((dom: appDom.AppDom) =>
+ appDom.setNodeNamespacedProp(dom, node, 'attributes', 'displayName', pageDisplayNameInput),
+ );
+ }, [node, pageDisplayNameInput, domApi]);
+
+ const handleReset = React.useCallback(() => {
+ domApi.update((dom: appDom.AppDom) =>
+ appDom.setNodeNamespacedProp(dom, node, 'attributes', 'displayName', undefined),
+ );
+ }, [node, domApi]);
+
+ const handleKeyPress = React.useCallback(
+ (event: React.KeyboardEvent) => {
+ if (event.code === 'Enter') {
+ handleCommit();
+ }
+ },
+ [handleCommit],
+ );
+
+ return (
+
+
+
+
+
+
+
+ ) : null,
+ }}
+ />
+ );
+}
diff --git a/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/BindableEditor.tsx b/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/BindableEditor.tsx
index ec4c7ae8459..882e878b8ee 100644
--- a/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/BindableEditor.tsx
+++ b/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/BindableEditor.tsx
@@ -1,4 +1,10 @@
-import { Stack, SxProps } from '@mui/material';
+import {
+ Stack,
+ SxProps,
+ inputBaseClasses,
+ formLabelClasses,
+ typographyClasses,
+} from '@mui/material';
import * as React from 'react';
import {
BindableAttrValue,
@@ -83,7 +89,17 @@ export default function BindableEditor({
const hasBinding = value && valueBindingType !== 'const';
return (
-
+
{renderControl({
label,
diff --git a/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/ComponentCatalog/ComponentCatalog.tsx b/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/ComponentCatalog/ComponentCatalog.tsx
index 35a57ed1606..7b25e0926c5 100644
--- a/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/ComponentCatalog/ComponentCatalog.tsx
+++ b/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/ComponentCatalog/ComponentCatalog.tsx
@@ -40,11 +40,11 @@ const FUTURE_COMPONENTS = new Map([
['Radio', { url: 'https://github.com/mui/mui-toolpad/issues/744', displayName: 'Radio' }],
]);
-const WIDTH_COLLAPSED = 40;
+const COMPONENT_CATALOG_WIDTH_COLLAPSED = 40;
const ComponentCatalogRoot = styled('div')({
position: 'relative',
- width: WIDTH_COLLAPSED + 1,
+ width: COMPONENT_CATALOG_WIDTH_COLLAPSED + 1,
height: '100%',
zIndex: 1,
overflow: 'visible',
@@ -89,7 +89,7 @@ export default function ComponentCatalog({ className }: ComponentCatalogProps) {
[openStart, setOpenStart],
);
- const toolpadComponents = useToolpadComponents(dom);
+ const toolpadComponents = useToolpadComponents();
const handleDragStart = (componentType: string) => (event: React.DragEvent) => {
const def = toolpadComponents[componentType];
@@ -354,7 +354,7 @@ export default function ComponentCatalog({ className }: ComponentCatalogProps) {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
- width: WIDTH_COLLAPSED,
+ width: COMPONENT_CATALOG_WIDTH_COLLAPSED,
}}
>
{openStart ? : }
diff --git a/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/ComponentEditor.tsx b/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/ComponentEditor.tsx
index 3ae8b92c02d..51bf95c18c5 100644
--- a/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/ComponentEditor.tsx
+++ b/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/ComponentEditor.tsx
@@ -12,10 +12,7 @@ import {
import { ExactEntriesOf } from '../../../utils/types';
import * as appDom from '../../../appDom';
import NodeAttributeEditor from './NodeAttributeEditor';
-import { useAppState } from '../../AppState';
import { usePageEditorState } from './PageEditorProvider';
-import ErrorAlert from './ErrorAlert';
-import NodeNameEditor from '../NodeNameEditor';
import { useToolpadComponent } from '../toolpadComponents';
import { getElementNodeComponentId } from '../../../runtime/toolpadComponents';
import {
@@ -167,24 +164,20 @@ interface SelectedNodeEditorProps {
}
function SelectedNodeEditor({ node }: SelectedNodeEditorProps) {
- const { dom } = useAppState();
const { bindings, viewState } = usePageEditorState();
- const nodeError = viewState.nodes[node.id]?.error;
const componentConfig = viewState.nodes[node.id]?.componentConfig || { argTypes: {} };
- const component = useToolpadComponent(dom, getElementNodeComponentId(node));
+ const component = useToolpadComponent(getElementNodeComponentId(node));
const displayName = component?.displayName || '';
return (
-
+
- Component: {displayName}
+ {node.name}
-
- {nodeError ? : null}
{node ? (
diff --git a/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/ComponentPanel.tsx b/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/ComponentPanel.tsx
index 4a91f64f18e..d7259c2c189 100644
--- a/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/ComponentPanel.tsx
+++ b/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/ComponentPanel.tsx
@@ -7,44 +7,6 @@ import ThemeEditor from './ThemeEditor';
import { useAppState, useAppStateApi } from '../../AppState';
import { PageViewTab } from '../../../utils/domView';
import * as appDom from '../../../appDom';
-import { PropControlsContextProvider, PropTypeControls } from '../../propertyControls';
-import string from '../../propertyControls/string';
-import boolean from '../../propertyControls/boolean';
-import number from '../../propertyControls/number';
-import select from '../../propertyControls/select';
-import json from '../../propertyControls/json';
-import event from '../../propertyControls/event';
-import markdown from '../../propertyControls/Markdown';
-import GridColumns from '../../propertyControls/GridColumns';
-import ToggleButtons from '../../propertyControls/ToggleButtons';
-import SelectOptions from '../../propertyControls/SelectOptions';
-import ChartData from '../../propertyControls/ChartData';
-import RowIdFieldSelect from '../../propertyControls/RowIdFieldSelect';
-import HorizontalAlign from '../../propertyControls/HorizontalAlign';
-import VerticalAlign from '../../propertyControls/VerticalAlign';
-import NumberFormat from '../../propertyControls/NumberFormat';
-import ColorScale from '../../propertyControls/ColorScale';
-import DataProviderSelector from '../../propertyControls/DataProviderSelector';
-
-export const PROP_TYPE_CONTROLS: PropTypeControls = {
- string,
- boolean,
- number,
- select,
- json,
- markdown,
- event,
- GridColumns,
- ToggleButtons,
- SelectOptions,
- ChartData,
- RowIdFieldSelect,
- HorizontalAlign,
- VerticalAlign,
- NumberFormat,
- ColorScale,
- DataProviderSelector,
-};
const classes = {
panel: 'Toolpad_Panel',
@@ -73,48 +35,46 @@ export default function ComponentPanel({ className }: ComponentPanelProps) {
const { dom, currentView } = useAppState();
const appStateApi = useAppStateApi();
- const currentTab = currentView.kind === 'page' ? currentView.tab : null;
+ const currentTab = currentView.kind === 'page' ? currentView.pageViewTab : null;
const selectedNodeId = currentView.kind === 'page' ? currentView.selectedNodeId : null;
const selectedNode = selectedNodeId ? appDom.getMaybeNode(dom, selectedNodeId) : null;
const handleChange = (_: React.SyntheticEvent, newValue: PageViewTab) => {
- appStateApi.setTab(newValue);
+ appStateApi.setPageViewTab(newValue);
};
return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {selectedNode && appDom.isElement(selectedNode) ? (
-
- ) : (
- No component selected.
- )}
-
-
-
- Customize the app with a Material UI theme. Read more about theming in the{' '}
-
- docs
-
- .
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {selectedNode && appDom.isElement(selectedNode) ? (
+
+ ) : (
+ No component selected.
+ )}
+
+
+
+ Customize the app with a Material UI theme. Read more about theming in the{' '}
+
+ docs
+
+ .
+
+
+
+
+
);
}
diff --git a/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/ConnectionSelect.tsx b/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/ConnectionSelect.tsx
index 499797ffc6b..612adf88525 100644
--- a/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/ConnectionSelect.tsx
+++ b/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/ConnectionSelect.tsx
@@ -80,27 +80,16 @@ export default function ConnectionSelect({
}, [options, value]);
return (
-
+
{options.map((option, index) => {
const config = dataSources[option.dataSourceId];
const dataSourceLabel = config
? config.displayName
: ``;
- const connectionLabel = option.connectionId
- ? appDom.getMaybeNode(dom, option.connectionId)?.name
- : '';
return (
{dataSourceLabel}
- {config?.ConnectionParamsInput ? ` | ${connectionLabel}` : ''}
);
})}
diff --git a/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/PageOptionsPanel.tsx b/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/PageOptionsPanel.tsx
index 515086c114b..6dd1548d081 100644
--- a/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/PageOptionsPanel.tsx
+++ b/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/PageOptionsPanel.tsx
@@ -14,11 +14,12 @@ import {
import * as React from 'react';
import { useAppState, useDomApi } from '../../AppState';
import { usePageEditorState } from './PageEditorProvider';
-import QueryEditor from './QueryEditor';
+
import UrlQueryEditor from './UrlQueryEditor';
import NodeNameEditor from '../NodeNameEditor';
import * as appDom from '../../../appDom';
import PageTitleEditor from '../PageTitleEditor';
+import PageDisplayNameEditor from '../PageDisplayNameEditor';
import { FEATURE_FLAG_AUTHORIZATION } from '../../../constants';
const PAGE_DISPLAY_OPTIONS: { value: appDom.PageDisplayMode; label: string }[] = [
@@ -34,7 +35,6 @@ export default function PageOptionsPanel() {
const appNode = appDom.getApp(dom);
const page = appDom.getNode(dom, pageNodeId, 'page');
-
const handleDisplayModeChange = React.useCallback(
(event: React.MouseEvent, newValue: appDom.PageDisplayMode) => {
domApi.update((draft) =>
@@ -80,6 +80,7 @@ export default function PageOptionsPanel() {
Page:
@@ -146,7 +147,6 @@ export default function PageOptionsPanel() {
Page State:
-
)}
diff --git a/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/ParametersEditor.tsx b/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/ParametersEditor.tsx
index 1f03f33dc12..fd3ce40bd8b 100644
--- a/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/ParametersEditor.tsx
+++ b/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/ParametersEditor.tsx
@@ -1,4 +1,4 @@
-import { Box, TextField, IconButton, SxProps } from '@mui/material';
+import { Box, TextField, IconButton, SxProps, inputLabelClasses } from '@mui/material';
import * as React from 'react';
import DeleteIcon from '@mui/icons-material/Delete';
import { BindableAttrValue, ScopeMeta, JsRuntime, LiveBinding } from '@mui/toolpad-core';
@@ -53,7 +53,14 @@ export default function ParametersEditor({
}, [value]);
return (
-
+
{label ? {label}: : null}
{value.map(([field, fieldValue], index) => {
const liveBinding: LiveBinding | undefined = liveValue[index]?.[1];
@@ -69,6 +76,8 @@ export default function ParametersEditor({
value.map((entry, i) => (i === index ? [event.target.value, entry[1]] : entry)),
)
}
+ sx={{ [`& .${inputLabelClasses.root}`]: { fontSize: 12 } }}
+ inputProps={{ sx: { fontSize: 12 } }}
error={!isValidFieldName[index]}
disabled={disabled}
/>
@@ -87,8 +96,12 @@ export default function ParametersEditor({
env={env}
/>
-
-
+
+
);
@@ -102,6 +115,8 @@ export default function ParametersEditor({
onChange={(event) => {
onChange([...value, [event.target.value, null]]);
}}
+ sx={{ [`& .${inputLabelClasses.root}`]: { fontSize: 12 } }}
+ inputProps={{ sx: { fontSize: 12 } }}
autoFocus={autoFocus}
disabled={disabled}
/>
diff --git a/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/QueriesExplorer/index.tsx b/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/QueriesExplorer/index.tsx
new file mode 100644
index 00000000000..b48bee1bd1d
--- /dev/null
+++ b/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/QueriesExplorer/index.tsx
@@ -0,0 +1,505 @@
+import * as React from 'react';
+import clsx from 'clsx';
+import { NodeId } from '@mui/toolpad-core';
+import invariant from 'invariant';
+import {
+ styled,
+ Box,
+ Button,
+ IconButton,
+ Typography,
+ Popover,
+ Stack,
+ Paper,
+ SxProps,
+} from '@mui/material';
+import { TreeView, treeItemClasses } from '@mui/x-tree-view';
+import AddIcon from '@mui/icons-material/Add';
+import MoreVertIcon from '@mui/icons-material/MoreVert';
+import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
+import ChevronRightIcon from '@mui/icons-material/ChevronRight';
+import * as appDom from '../../../../appDom';
+import dataSources from '../../../../toolpadDataSources/client';
+import QueryIcon from '../../QueryIcon';
+import { useAppState, useAppStateApi } from '../../../AppState';
+import useBoolean from '../../../../utils/useBoolean';
+import EditableTreeItem, { EditableTreeItemProps } from '../../../../components/EditableTreeItem';
+import NodeMenu from '../../NodeMenu';
+import ExplorerHeader from '../../ExplorerHeader';
+
+const classes = {
+ treeItemMenuButton: 'Toolpad__QueryListItem',
+ treeItemMenuOpen: 'Toolpad__QueryListItemMenuOpen',
+};
+
+const StyledTreeItem = styled(EditableTreeItem)({
+ [`& .${classes.treeItemMenuButton}`]: {
+ visibility: 'hidden',
+ },
+ [`
+ & .${treeItemClasses.content}:hover .${classes.treeItemMenuButton},
+ & .${classes.treeItemMenuOpen}
+ `]: {
+ visibility: 'visible',
+ },
+});
+
+interface StyledTreeItemProps extends EditableTreeItemProps {
+ onDeleteNode?: (nodeId: NodeId) => void;
+ onDuplicateNode?: (nodeId: NodeId) => void;
+ onRenameNode?: (nodeId: NodeId, updatedName: string) => void;
+ onSelectNode?: (nodeId: NodeId) => void;
+ onCreate?: (event: React.MouseEvent, mode?: appDom.FetchMode) => void;
+ labelTextSx?: SxProps;
+ labelIconId?: string;
+ labelIconSx?: SxProps;
+ createLabelText?: string;
+ deleteLabelText?: string;
+ renameLabelText?: string;
+ duplicateLabelText?: string;
+ toolpadNodeId?: NodeId;
+}
+
+function DataTreeItem(props: StyledTreeItemProps) {
+ const {
+ nodeId,
+ labelText,
+ labelTextSx,
+ labelIconSx,
+ labelIconId,
+ onCreate,
+ onSelectNode,
+ onDeleteNode,
+ onDuplicateNode,
+ onRenameNode,
+ createLabelText,
+ deleteLabelText = 'Delete',
+ duplicateLabelText = 'Duplicate',
+ renameLabelText = 'Rename',
+ toolpadNodeId,
+ validateItemName,
+ ...other
+ } = props;
+
+ const { value: isEditing, setTrue: startEditing, setFalse: stopEditing } = useBoolean(false);
+
+ const handleRenameConfirm = React.useCallback(
+ (updatedName: string) => {
+ if (onRenameNode) {
+ onRenameNode(nodeId as NodeId, updatedName);
+ stopEditing();
+ }
+ },
+ [nodeId, onRenameNode, stopEditing],
+ );
+
+ const validateEditableQueryName = React.useCallback(
+ (newName: string) => {
+ if (newName !== labelText && validateItemName) {
+ return validateItemName(newName);
+ }
+ return { isValid: true };
+ },
+ [labelText, validateItemName],
+ );
+
+ const handleClick = React.useCallback(() => {
+ invariant(toolpadNodeId, 'DataTreeItem should only be used for nodes with a toolpadNodeId');
+ onSelectNode?.(toolpadNodeId);
+ }, [onSelectNode, toolpadNodeId]);
+
+ const queryCreationMode = React.useMemo(() => {
+ if (props.nodeId === ':query') {
+ return 'query';
+ }
+ if (props.nodeId === ':mutation') {
+ return 'mutation';
+ }
+ return undefined;
+ }, [props.nodeId]);
+
+ return (
+ (
+
+
+ {children}
+ {onCreate ? (
+ {
+ onCreate(event, queryCreationMode);
+ }}
+ size="small"
+ >
+
+
+ ) : null}
+ {toolpadNodeId ? (
+ (
+
+
+
+ )}
+ nodeId={toolpadNodeId}
+ deleteLabelText={deleteLabelText}
+ duplicateLabelText={duplicateLabelText}
+ renameLabelText={renameLabelText}
+ onRenameNode={startEditing}
+ onDeleteNode={onDeleteNode}
+ onDuplicateNode={onDuplicateNode}
+ />
+ ) : null}
+
+ )}
+ suggestedNewItemName={labelText}
+ onCancel={stopEditing}
+ isEditing={isEditing}
+ {...(onRenameNode ? { onEdit: handleRenameConfirm } : {})}
+ validateItemName={validateEditableQueryName}
+ {...other}
+ />
+ );
+}
+
+interface CreatePopoverProps {
+ anchorEl: Element | null;
+ createPopoverOpen: boolean;
+ handleCreateNode: (dataSourceId: string) => () => void;
+ handleCreateClose: () => void;
+ createMode: appDom.FetchMode | undefined;
+}
+
+function CreatePopover({
+ anchorEl,
+ createPopoverOpen,
+ handleCreateNode,
+ handleCreateClose,
+ createMode,
+}: CreatePopoverProps) {
+ return (
+
+
+
+ {createMode === 'query'
+ ? 'Make backend data available as state on the page'
+ : 'Run an action on the page'}
+
+
+ {Object.keys(dataSources).map((dataSourceId) => {
+ const dataSource = dataSources[dataSourceId];
+ return (
+
+ {' '}
+ {dataSource?.displayName || dataSourceId}
+
+ );
+ })}
+
+
+
+ );
+}
+
+interface ExplorerProps {
+ nodes: appDom.QueryNode[];
+ setAnchorEl: (anchorEl: Element | null) => void;
+ headerText: string;
+ nodeName: string;
+}
+
+function Explorer({ nodes, setAnchorEl, nodeName, headerText }: ExplorerProps) {
+ const { dom, currentView } = useAppState();
+ const appStateApi = useAppStateApi();
+ const currentPageName = currentView.name;
+
+ const handleQuerySelect = React.useCallback(
+ (selectedQueryId: NodeId) => {
+ appStateApi.openQueryTab(selectedQueryId);
+ },
+ [appStateApi],
+ );
+
+ const handleCreateClick = React.useCallback(
+ (event: React.MouseEvent) => {
+ event.stopPropagation();
+ setAnchorEl(event.currentTarget);
+ },
+ [setAnchorEl],
+ );
+
+ const handleDeleteNode = React.useCallback(
+ (selectedQueryId: NodeId) => {
+ const selectedQueryTabIndex = currentView.queryPanel?.queryTabs?.findIndex(
+ (tab) => tab.meta?.id === selectedQueryId,
+ );
+
+ appStateApi.closeQueryTab(selectedQueryId, selectedQueryTabIndex, true);
+ },
+ [appStateApi, currentView],
+ );
+
+ const existingNames = React.useMemo(() => {
+ if (!currentPageName) {
+ return undefined;
+ }
+ const currentPageNode = appDom.getPageByName(dom, currentPageName);
+ if (!currentPageNode) {
+ return undefined;
+ }
+ return appDom.getExistingNamesForChildren(dom, currentPageNode);
+ }, [currentPageName, dom]);
+
+ const handleDuplicateNode = React.useCallback(
+ (nodeId: NodeId) => {
+ const node = appDom.getNode(dom, nodeId, 'query');
+ invariant(
+ currentPageName,
+ 'handleDuplicateNode should only be used for queries, which should always belong to a page',
+ );
+ const currentPageNode = appDom.getPageByName(dom, currentPageName);
+
+ const newName = appDom.proposeName(node.name, existingNames);
+ const copy = appDom.createNode(dom, 'query', { ...node, name: newName });
+ if (!currentPageNode) {
+ return;
+ }
+ appStateApi.update((draft) => appDom.addNode(draft, copy, currentPageNode, 'queries'), {
+ kind: 'page',
+ name: currentPageName,
+ view: { kind: 'query', nodeId: copy.id },
+ });
+ },
+ [dom, currentPageName, existingNames, appStateApi],
+ );
+
+ const validateName = React.useCallback(
+ (queryName: string) => {
+ if (!existingNames) {
+ return {
+ isValid: true,
+ };
+ }
+
+ const validationErrorMessage = appDom.validateNodeName(queryName, existingNames, 'query');
+ return {
+ isValid: !validationErrorMessage,
+ ...(validationErrorMessage ? { errorMessage: validationErrorMessage } : {}),
+ };
+ },
+ [existingNames],
+ );
+
+ const handleRenameNode = React.useCallback(
+ (nodeId: NodeId, updatedName: string) => {
+ const node = appDom.getNode(dom, nodeId, 'query');
+ appStateApi.update((draft) => appDom.setNodeName(draft, node, updatedName), {
+ ...currentView,
+ queryPanel: {
+ ...currentView.queryPanel,
+ queryTabs: currentView.queryPanel?.queryTabs?.map((tab) => {
+ if (tab?.meta?.id === nodeId && tab.draft && tab.saved) {
+ const updatedNode = { ...tab.draft, name: updatedName };
+ return {
+ ...tab,
+ meta: {
+ ...tab.meta,
+ name: updatedName,
+ },
+ draft: updatedNode,
+ saved: updatedNode,
+ };
+ }
+ return tab;
+ }),
+ },
+ });
+ },
+ [dom, appStateApi, currentView],
+ );
+
+ return (
+
+ }
+ headerText={headerText}
+ onCreate={handleCreateClick}
+ createLabelText={`Create new ${nodeName}`}
+ />
+ }
+ defaultExpandIcon={ }
+ sx={{
+ flexGrow: 1,
+ maxWidth: 400,
+ overflowY: 'auto',
+ scrollbarGutter: 'stable',
+ }}
+ >
+ {nodes.map((node) => (
+
+ ))}
+
+
+ );
+}
+
+export function QueriesExplorer() {
+ const { dom, currentView } = useAppState();
+ const appStateApi = useAppStateApi();
+ const currentPageName = currentView.name;
+ const queryNodes = React.useMemo(() => {
+ if (!currentPageName) {
+ return [];
+ }
+ if (currentPageName) {
+ const currentPageNode = appDom.getPageByName(dom, currentPageName);
+ if (currentPageNode) {
+ return appDom.getChildNodes(dom, currentPageNode).queries ?? [];
+ }
+ }
+ return [];
+ }, [currentPageName, dom]);
+
+ const queries = React.useMemo(() => {
+ return queryNodes.filter(
+ (query) => query.attributes?.mode === 'query' || !query.attributes?.mode,
+ );
+ }, [queryNodes]);
+
+ const [anchorEl, setAnchorEl] = React.useState(null);
+ const createPopoverOpen = Boolean(anchorEl);
+ const handleCreateClose = () => {
+ setAnchorEl(null);
+ };
+
+ const handleCreateNode = React.useCallback(
+ (dataSourceId: string) => () => {
+ const dataSource = dataSources[dataSourceId];
+ invariant(dataSource, `Selected non-existing dataSource "${dataSourceId}"`);
+ invariant(
+ currentPageName,
+ 'handleCreateNode should only be used for queries, which should always belong to a page',
+ );
+
+ appStateApi.createQueryTab(dataSource, dataSourceId, 'query');
+ setAnchorEl(null);
+ },
+ [currentPageName, appStateApi],
+ );
+
+ return (
+
+
+
+ ;
+
+ );
+}
+
+export function ActionsExplorer() {
+ const { dom, currentView } = useAppState();
+ const appStateApi = useAppStateApi();
+ const currentPageName = currentView.name;
+ const queryNodes = React.useMemo(() => {
+ if (!currentPageName) {
+ return [];
+ }
+ if (currentPageName) {
+ const currentPageNode = appDom.getPageByName(dom, currentPageName);
+ if (currentPageNode) {
+ return appDom.getChildNodes(dom, currentPageNode).queries ?? [];
+ }
+ }
+ return [];
+ }, [currentPageName, dom]);
+
+ const actions = React.useMemo(() => {
+ return queryNodes.filter((query) => query.attributes?.mode === 'mutation');
+ }, [queryNodes]);
+
+ const [anchorEl, setAnchorEl] = React.useState(null);
+ const createPopoverOpen = Boolean(anchorEl);
+ const handleCreateClose = () => {
+ setAnchorEl(null);
+ };
+
+ const handleCreateNode = React.useCallback(
+ (dataSourceId: string) => () => {
+ const dataSource = dataSources[dataSourceId];
+ invariant(dataSource, `Selected non-existing dataSource "${dataSourceId}"`);
+ invariant(
+ currentPageName,
+ 'handleCreateNode should only be used for queries, which should always belong to a page',
+ );
+
+ appStateApi.createQueryTab(dataSource, dataSourceId, 'mutation');
+ setAnchorEl(null);
+ },
+ [currentPageName, appStateApi],
+ );
+
+ return (
+
+
+
+ ;
+
+ );
+}
diff --git a/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/QueryEditor/QueryEditorDialog.tsx b/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/QueryEditor/QueryEditorDialog.tsx
deleted file mode 100644
index fa3587e7418..00000000000
--- a/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/QueryEditor/QueryEditorDialog.tsx
+++ /dev/null
@@ -1,374 +0,0 @@
-import {
- Stack,
- Button,
- Dialog,
- DialogTitle,
- DialogContent,
- DialogActions,
- TextField,
- InputAdornment,
- Divider,
- Alert,
- Box,
- MenuItem,
-} from '@mui/material';
-import * as React from 'react';
-import { BindableAttrValue } from '@mui/toolpad-core';
-import { useBrowserJsRuntime } from '@mui/toolpad-core/jsBrowserRuntime';
-import invariant from 'invariant';
-import useEventCallback from '@mui/utils/useEventCallback';
-import useLatest from '@mui/toolpad-utils/hooks/useLatest';
-import { usePageEditorState } from '../PageEditorProvider';
-import * as appDom from '../../../../appDom';
-import dataSources from '../../../../toolpadDataSources/client';
-import { omit, update } from '../../../../utils/immutability';
-import { useEvaluateLiveBinding } from '../../useEvaluateLiveBinding';
-import { useAppState } from '../../../AppState';
-import { ConnectionContextProvider } from '../../../../toolpadDataSources/context';
-import ConnectionSelect, { ConnectionOption } from '../ConnectionSelect';
-import BindableEditor from '../BindableEditor';
-import { ConfirmDialog } from '../../../../components/SystemDialogs';
-import useBoolean from '../../../../utils/useBoolean';
-import { useNodeNameValidation } from '../../PagesExplorer/validation';
-import useUnsavedChangesConfirm from '../../../hooks/useUnsavedChangesConfirm';
-import { useProjectApi } from '../../../../projectApi';
-
-interface QueryEditorDialogActionsProps {
- saveDisabled?: boolean;
- onSave?: () => void;
- onRemove?: () => void;
- isDraft?: boolean;
- onClose?: () => void;
-}
-
-function QueryEditorDialogActions({
- saveDisabled,
- onSave,
- onRemove,
- onClose,
- isDraft,
-}: QueryEditorDialogActionsProps) {
- const {
- value: removeConfirmOpen,
- setTrue: handleRemoveConfirmOpen,
- setFalse: handleRemoveConfirmclose,
- } = useBoolean(false);
-
- const handleRemoveConfirm = React.useCallback(
- (confirmed: boolean) => {
- handleRemoveConfirmclose();
- if (confirmed) {
- onRemove?.();
- }
- },
- [handleRemoveConfirmclose, onRemove],
- );
-
- return (
-
-
- Cancel
-
-
- Remove
-
-
- Are you sure your want to remove this query?
-
-
- Save
-
-
- );
-}
-
-function refetchIntervalInSeconds(maybeInterval?: number) {
- if (typeof maybeInterval !== 'number') {
- return undefined;
- }
- const seconds = Math.floor(maybeInterval / 1000);
- return seconds > 0 ? seconds : undefined;
-}
-
-interface QueryNodeEditorProps {
- open: boolean;
- onClose: () => void;
- onSave: (newNode: appDom.QueryNode) => void;
- onRemove: (newNode: appDom.QueryNode) => void;
- node: appDom.QueryNode;
- isDraft: boolean;
-}
-
-export default function QueryNodeEditorDialog({
- open,
- node: nodeProp,
- onClose,
- onRemove,
- onSave,
- isDraft,
-}: QueryNodeEditorProps) {
- const projectApi = useProjectApi();
- const { dom } = useAppState();
- const { data: runtimeConfig } = projectApi.useQuery('getRuntimeConfig', []);
-
- // To keep it around during closing animation
- const node = useLatest(nodeProp);
-
- const [input, setInput] = React.useState>(node);
- React.useEffect(() => {
- setInput(node);
- }, [node]);
-
- const reset = useEventCallback(() => setInput(node));
-
- React.useEffect(() => {
- if (open) {
- reset();
- }
- }, [open, reset]);
-
- const connectionId = input.attributes.connectionId
- ? appDom.deref(input.attributes.connectionId)
- : null;
-
- const connection = connectionId ? appDom.getMaybeNode(dom, connectionId, 'connection') : null;
- const dataSourceId = input.attributes.dataSource || null;
- const dataSource = (dataSourceId && dataSources[dataSourceId]) || null;
-
- const connectionParams = connection?.attributes.params;
-
- const handleCommit = React.useCallback(() => {
- let toCommit: appDom.QueryNode = input;
- if (dataSource?.transformQueryBeforeCommit) {
- toCommit = {
- ...input,
- attributes: {
- ...input.attributes,
- query: dataSource.transformQueryBeforeCommit(input.attributes.query),
- },
- };
- }
- onSave(toCommit);
- }, [dataSource, input, onSave]);
-
- const { pageState, globalScopeMeta } = usePageEditorState();
-
- const handleConnectionChange = React.useCallback(
- (newConnectionOption: ConnectionOption | null) => {
- if (newConnectionOption) {
- setInput((existing) =>
- update(existing, {
- attributes: update(existing.attributes, {
- connectionId: appDom.ref(newConnectionOption.connectionId),
- dataSource: newConnectionOption.dataSourceId,
- }),
- }),
- );
- } else {
- setInput((existing) =>
- update(existing, {
- attributes: update(existing.attributes, {
- connectionId: undefined,
- dataSource: undefined,
- }),
- }),
- );
- }
- },
- [],
- );
-
- const handleModeChange = React.useCallback((event: React.ChangeEvent) => {
- setInput((existing) =>
- update(existing, {
- attributes: update(existing.attributes, {
- mode: event.target.value as appDom.FetchMode,
- }),
- }),
- );
- }, []);
-
- const handleEnabledChange = React.useCallback((newValue: BindableAttrValue | null) => {
- setInput((existing) =>
- update(existing, {
- attributes: update(existing.attributes, {
- enabled: newValue ?? undefined,
- }),
- }),
- );
- }, []);
-
- const handleRefetchIntervalChange = React.useCallback(
- (event: React.ChangeEvent) => {
- const interval = Number(event.target.value);
-
- setInput((existing) =>
- update(existing, {
- attributes:
- Number.isNaN(interval) || interval <= 0
- ? omit(existing.attributes, 'refetchInterval')
- : update(existing.attributes, {
- refetchInterval: interval * 1000,
- }),
- }),
- );
- },
- [],
- );
-
- const handleRemove = React.useCallback(() => {
- if (!isDraft) {
- onRemove(node);
- }
- onClose();
- }, [isDraft, onClose, onRemove, node]);
-
- const isInputSaved = !isDraft && node === input;
-
- const { handleCloseWithUnsavedChanges } = useUnsavedChangesConfirm({
- hasUnsavedChanges: !isInputSaved,
- onClose,
- });
-
- const handleSave = React.useCallback(() => {
- handleCommit();
- onClose();
- }, [handleCommit, onClose]);
-
- const queryEditorContext = React.useMemo(
- () => (dataSourceId ? { dataSourceId, connectionId } : null),
- [dataSourceId, connectionId],
- );
-
- const jsBrowserRuntime = useBrowserJsRuntime();
-
- const liveEnabled = useEvaluateLiveBinding({
- jsRuntime: jsBrowserRuntime,
- input: input.attributes.enabled || null,
- globalScope: pageState,
- });
-
- const mode = input.attributes.mode || 'query';
-
- const existingNames = React.useMemo(
- () => appDom.getExistingNamesForNode(dom, input),
- [dom, input],
- );
-
- const nodeNameError = useNodeNameValidation(input.name, existingNames, 'query');
- const isNameValid = !nodeNameError;
-
- const execPrivate = React.useCallback(
- (method: string, args: any[]) => {
- invariant(dataSourceId, 'dataSourceId must be set');
- return projectApi.methods.dataSourceExecPrivate(dataSourceId, method, args);
- },
- [projectApi, dataSourceId],
- );
-
- return (
-
- {dataSourceId && dataSource && queryEditorContext && runtimeConfig ? (
-
-
-
-
- setInput((existing) => ({ ...existing, name: event.target.value }))
- }
- error={!isNameValid}
- helperText={nodeNameError}
- />
-
-
-
-
-
-
-
-
-
-
-
- Fetch at any time to always be available on the page
-
- Only fetch on manual action
-
-
- liveBinding={liveEnabled}
- globalScope={pageState}
- globalScopeMeta={globalScopeMeta}
- jsRuntime={jsBrowserRuntime}
- label="Enabled"
- propType={{ type: 'boolean' }}
- value={input.attributes.enabled ?? true}
- onChange={handleEnabledChange}
- disabled={mode !== 'query'}
- />
- s,
- }}
- sx={{ maxWidth: 300 }}
- type="number"
- label="Refetch interval"
- value={refetchIntervalInSeconds(input.attributes.refetchInterval) ?? ''}
- onChange={handleRefetchIntervalChange}
- disabled={mode !== 'query'}
- />
-
-
-
-
- ) : (
- Datasource "{dataSourceId}" not found
- )}
-
- );
-}
diff --git a/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/QueryEditor/QueryEditorPanel.tsx b/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/QueryEditor/QueryEditorPanel.tsx
new file mode 100644
index 00000000000..baeae4d6aac
--- /dev/null
+++ b/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/QueryEditor/QueryEditorPanel.tsx
@@ -0,0 +1,242 @@
+import {
+ Box,
+ Stack,
+ TextField,
+ InputAdornment,
+ Alert,
+ MenuItem,
+ Typography,
+ inputLabelClasses,
+ inputBaseClasses,
+} from '@mui/material';
+import * as React from 'react';
+import { BindableAttrValue, LiveBinding } from '@mui/toolpad-core';
+import { useBrowserJsRuntime } from '@mui/toolpad-core/jsBrowserRuntime';
+import invariant from 'invariant';
+import { usePageEditorState } from '../PageEditorProvider';
+import * as appDom from '../../../../appDom';
+import dataSources from '../../../../toolpadDataSources/client';
+import { useEvaluateLiveBinding } from '../../useEvaluateLiveBinding';
+import { useAppState, useAppStateApi } from '../../../AppState';
+import { ConnectionContextProvider } from '../../../../toolpadDataSources/context';
+import BindableEditor from '../BindableEditor';
+import { useProjectApi } from '../../../../projectApi';
+
+interface QueryEditorProps {
+ draft: appDom.QueryNode;
+ saved?: appDom.QueryNode;
+}
+
+function refetchIntervalInSeconds(maybeInterval?: number) {
+ if (typeof maybeInterval !== 'number') {
+ return undefined;
+ }
+ const seconds = Math.floor(maybeInterval / 1000);
+ return seconds > 0 ? seconds : undefined;
+}
+
+interface QuerySettingsTabProps {
+ draft: appDom.QueryNode;
+ liveEnabled: LiveBinding;
+ pageState: any;
+ globalScopeMeta: any;
+ jsBrowserRuntime: any;
+}
+
+function QuerySettingsTab({
+ draft,
+ liveEnabled,
+ pageState,
+ globalScopeMeta,
+ jsBrowserRuntime,
+}: QuerySettingsTabProps) {
+ const appStateApi = useAppStateApi();
+
+ const updateAttribute = React.useCallback(
+ function updateAttribute(
+ attrName: K,
+ attrValue: appDom.QueryNode['attributes'][K],
+ ) {
+ appStateApi.updateQueryDraft((node) => ({
+ ...node,
+ attributes: {
+ ...node.attributes,
+ [attrName]: attrValue,
+ },
+ }));
+ },
+ [appStateApi],
+ );
+
+ const handleModeChange = React.useCallback(
+ (event: React.ChangeEvent) => {
+ if (event.target.value === 'mutation' || event.target.value === 'query') {
+ updateAttribute('mode', event.target.value);
+ }
+ },
+ [updateAttribute],
+ );
+
+ const handleEnabledChange = React.useCallback(
+ (newValue: BindableAttrValue | null) => {
+ if (newValue !== null) {
+ updateAttribute('enabled', newValue);
+ }
+ },
+ [updateAttribute],
+ );
+
+ const handleRefetchIntervalChange = React.useCallback(
+ (event: React.ChangeEvent) => {
+ const interval = Number(event.target.value);
+
+ if (!Number.isNaN(interval) && interval > 0) {
+ updateAttribute('refetchInterval', interval * 1000);
+ }
+ },
+ [updateAttribute],
+ );
+ return (
+
+
+
+ Set query mode:
+
+
+ Fetch at any time to always be available on the page
+ Only fetch on manual action
+
+ {draft?.attributes?.mode !== 'mutation' ? (
+
+
+ Set refetch interval:
+
+ s,
+ }}
+ sx={{
+ [`& .${inputLabelClasses.root}`]: { fontSize: 12 },
+ [`& .${inputBaseClasses.root}`]: { fontSize: 12 },
+ maxWidth: 200,
+ }}
+ type="number"
+ label="Refetch interval"
+ value={refetchIntervalInSeconds(draft?.attributes?.refetchInterval) ?? ''}
+ onChange={handleRefetchIntervalChange}
+ />
+
+ Set query enabled/disabled:
+
+
+ liveBinding={liveEnabled}
+ globalScope={pageState}
+ globalScopeMeta={globalScopeMeta}
+ jsRuntime={jsBrowserRuntime}
+ label="Enabled"
+ propType={{ type: 'boolean' }}
+ value={draft?.attributes?.enabled ?? true}
+ onChange={handleEnabledChange}
+ sx={{ maxWidth: 100 }}
+ />
+
+ ) : null}
+
+
+ );
+}
+
+export default function QueryEditorPanel({ draft, saved }: QueryEditorProps) {
+ const { dom } = useAppState();
+ const projectApi = useProjectApi();
+
+ const { data: runtimeConfig, status: runtimeConfigFetchStatus } = projectApi.useQuery(
+ 'getRuntimeConfig',
+ [],
+ );
+
+ const connectionId =
+ appDom.deref(saved ? saved?.attributes?.connectionId : draft?.attributes?.connectionId) ?? null;
+
+ const connection = connectionId ? appDom.getMaybeNode(dom, connectionId, 'connection') : null;
+ const dataSourceId = saved ? saved?.attributes?.dataSource : draft?.attributes?.dataSource;
+ const dataSource = (dataSourceId && dataSources[dataSourceId]) || null;
+
+ const connectionParams = connection?.attributes?.params;
+
+ const { pageState, globalScopeMeta } = usePageEditorState();
+
+ const queryEditorContext = React.useMemo(
+ () => (dataSourceId ? { dataSourceId, connectionId } : null),
+ [dataSourceId, connectionId],
+ );
+
+ const jsBrowserRuntime = useBrowserJsRuntime();
+
+ const liveEnabled = useEvaluateLiveBinding({
+ jsRuntime: jsBrowserRuntime,
+ input: draft?.attributes?.enabled || null,
+ globalScope: pageState,
+ });
+
+ const execPrivate = React.useCallback(
+ (method: string, args: any[]) => {
+ invariant(dataSourceId, 'dataSourceId must be set');
+ return projectApi.methods.dataSourceExecPrivate(dataSourceId, method, args);
+ },
+ [projectApi, dataSourceId],
+ );
+
+ return dataSourceId && dataSource && queryEditorContext ? (
+
+
+ {draft && runtimeConfigFetchStatus === 'success' ? (
+
+ }
+ />
+ ) : null}
+
+
+ ) : (
+ Datasource "{dataSourceId}" not found
+ );
+}
diff --git a/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/QueryEditor/index.tsx b/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/QueryEditor/index.tsx
index 79dd33c7fb1..74a00b1d977 100644
--- a/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/QueryEditor/index.tsx
+++ b/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/QueryEditor/index.tsx
@@ -1,317 +1,309 @@
-import {
- Stack,
- Button,
- Dialog,
- DialogTitle,
- DialogContent,
- List,
- ListItem,
- DialogActions,
- ListItemText,
- IconButton,
- styled,
- ListItemButton,
- ButtonBase,
- Popover,
- Paper,
- Typography,
-} from '@mui/material';
import * as React from 'react';
-import AddIcon from '@mui/icons-material/Add';
import { NodeId } from '@mui/toolpad-core';
-import invariant from 'invariant';
-import MoreVertIcon from '@mui/icons-material/MoreVert';
-import clsx from 'clsx';
+import { Stack, Chip, Tab, IconButton } from '@mui/material';
+import { LoadingButton, TabList, TabContext, TabPanel } from '@mui/lab';
+import ClearOutlinedIcon from '@mui/icons-material/ClearOutlined';
+import CircleIcon from '@mui/icons-material/Circle';
+import CancelPresentationIcon from '@mui/icons-material/CancelPresentation';
+import { useAppState, useAppStateApi } from '../../../AppState';
import { usePageEditorState } from '../PageEditorProvider';
import * as appDom from '../../../../appDom';
-import dataSources from '../../../../toolpadDataSources/client';
-import { useAppStateApi, useAppState, useDomApi } from '../../../AppState';
-import NodeMenu from '../../NodeMenu';
-import QueryNodeEditorDialog from './QueryEditorDialog';
-
-const DataSourceButton = styled(ButtonBase)(({ theme }) => ({
- position: 'relative',
- width: 150,
- height: 70,
- border: 1,
- borderColor: 'divider',
- borderStyle: 'solid',
- color: 'text.secondary',
- padding: theme.spacing(1),
- borderRadius: 8,
- '&:hover': {
- backgroundColor: theme.palette.action.hover,
- },
-}));
-
-interface DataSourceSelectorProps {
- open: boolean;
- onClose: () => void;
- onCreated: (newNode: appDom.QueryNode) => void;
-}
-
-function ConnectionSelectorDialog({ open, onCreated, onClose }: DataSourceSelectorProps) {
- const { dom } = useAppState();
-
- const handleCreateClick = React.useCallback(
- (dataSourceId: string) => () => {
- const dataSource = dataSources[dataSourceId];
- invariant(dataSource, `Selected non-existing dataSource "${dataSourceId}"`);
-
- const queryNode = appDom.createNode(dom, 'query', {
- attributes: {
- query: dataSource.getInitialQueryValue(),
- connectionId: null,
- dataSource: dataSourceId,
- },
- });
-
- onCreated(queryNode);
- },
- [dom, onCreated],
- );
+import QueryIcon from '../../QueryIcon';
+import QueryEditorPanel from './QueryEditorPanel';
+import useShortcut from '../../../../utils/useShortcut';
+import { getModifierKey } from '../../../../utils/platform';
+import useUnsavedChangesConfirm from '../../../hooks/useUnsavedChangesConfirm';
+function SaveShortcutIndicator() {
return (
-
- Create Query
-
-
- Local function
- Fetch
-
-
-
-
- Cancel
-
-
-
+
+ {getModifierKey()}+S
+
);
}
-const classes = {
- listItemMenuButton: 'Toolpad__QueryListItem',
- listItemMenuOpen: 'Toolpad__QueryListItemMenuOpen',
-};
+function TabCloseIcon({
+ queryIndex,
+ unsaved,
+ queryId,
+}: {
+ queryIndex: number;
+ unsaved?: boolean;
+ queryId?: NodeId;
+}) {
+ const appStateApi = useAppStateApi();
-const QueryListItem = styled(ListItem)({
- [`& .${classes.listItemMenuButton}`]: {
- visibility: 'hidden',
- },
- [`
- &:hover .${classes.listItemMenuButton},
- & .${classes.listItemMenuOpen}
- `]: {
- visibility: 'visible',
- },
-});
+ const [notHovered, setNotHovered] = React.useState(true);
-type DialogState =
- | {
- node?: undefined;
- isDraft?: undefined;
+ const onClose = React.useCallback(() => {
+ if (queryId === undefined) {
+ return;
}
- | {
- node: appDom.QueryNode;
- isDraft: boolean;
- };
+ appStateApi.closeQueryTab(queryId, queryIndex);
+ }, [appStateApi, queryIndex, queryId]);
+
+ const { handleCloseWithUnsavedChanges: handleCloseTab } = useUnsavedChangesConfirm({
+ hasUnsavedChanges: unsaved ?? false,
+ onClose,
+ });
+ return unsaved && notHovered ? (
+
+ theme.palette.mode === 'dark'
+ ? theme.palette.primaryDark[300]
+ : theme.palette.primary.main,
+ fontSize: 12,
+ }}
+ onMouseEnter={() => {
+ setNotHovered(false);
+ }}
+ />
+ ) : (
+ {
+ setNotHovered(true);
+ }}
+ onClick={(event) => {
+ // Prevent the tab from being selected.
+ event.stopPropagation();
+ handleCloseTab();
+ }}
+ role="button"
+ aria-label={`Close query tab ${queryIndex + 1}`}
+ sx={{
+ color: (theme) =>
+ theme.palette.mode === 'dark' ? theme.palette.primaryDark[400] : theme.palette.grey[500],
+ fontSize: 12,
+ padding: '1px',
+ '&:hover': {
+ color: (theme) =>
+ theme.palette.mode === 'dark'
+ ? theme.palette.primaryDark[300]
+ : theme.palette.grey[700],
+ backgroundColor: (theme) =>
+ theme.palette.mode === 'dark'
+ ? theme.palette.primaryDark[700]
+ : theme.palette.grey[300],
+ borderRadius: '4px',
+ },
+ }}
+ />
+ );
+}
export default function QueryEditor() {
- const { dom } = useAppState();
- const { currentView } = useAppState();
- const state = usePageEditorState();
+ const { currentView, dom } = useAppState();
const appStateApi = useAppStateApi();
- const domApi = useDomApi();
-
- const [dialogState, setDialogState] = React.useState(null);
- const isDraft = dialogState?.isDraft || false;
+ const state = usePageEditorState();
const page = appDom.getNode(dom, state.nodeId, 'page');
- const { queries = [] } = appDom.getChildNodes(dom, page) ?? [];
- const handleEditStateDialogClose = React.useCallback(() => {
- if (isDraft) {
- setDialogState(null);
- } else {
- appStateApi.setView({ kind: 'page', name: page.name });
+ const currentQueryId = React.useMemo(() => {
+ if (currentView.kind === 'page' && currentView.view?.kind === 'query') {
+ return currentView.view.nodeId;
}
- }, [appStateApi, isDraft, page.name]);
+ return '';
+ }, [currentView]);
- const handleCreated = React.useCallback((node: appDom.QueryNode) => {
- setDialogState({ node, isDraft: true });
- }, []);
-
- const handleSave = React.useCallback(
- (node: appDom.QueryNode) => {
- if (appDom.nodeExists(dom, node.id)) {
- domApi.saveNode(node);
- } else {
- appStateApi.update((draft) => appDom.addNode(draft, node, page, 'queries'));
+ const currentTabIndex = React.useMemo(() => {
+ if (currentView.kind === 'page' && currentView.view?.kind === 'query') {
+ return currentView.queryPanel?.currentTabIndex?.toString() || '';
+ }
+ return '';
+ }, [currentView]);
+
+ const handleTabChange = React.useCallback(
+ (event: React.SyntheticEvent, newValue: string) => {
+ if (currentView.kind === 'page') {
+ const tabIndex = parseInt(newValue, 10);
+ const queryId = currentView.queryPanel?.queryTabs?.[tabIndex]?.meta?.id;
+ if (queryId) {
+ appStateApi.setView({
+ kind: 'page',
+ name: page.name,
+ view: { kind: 'query', nodeId: queryId },
+ queryPanel: {
+ ...currentView.queryPanel,
+ currentTabIndex: tabIndex,
+ },
+ });
+ }
}
},
- [dom, domApi, appStateApi, page],
- );
-
- const handleDeleteNode = React.useCallback(
- (nodeId: NodeId) => {
- appStateApi.update((draft) => appDom.removeNode(draft, nodeId), {
- kind: 'page',
- name: page.name,
- });
- },
- [appStateApi, page.name],
+ [appStateApi, currentView, page.name],
);
- const handleRemove = React.useCallback(
- (node: appDom.QueryNode) => handleDeleteNode(node.id),
- [handleDeleteNode],
- );
-
- const handleDuplicateNode = React.useCallback(
- (nodeId: NodeId) => {
- const node = appDom.getNode(dom, nodeId, 'query');
- invariant(
- page,
- 'handleDuplicateNode should only be used for queries, which should always belong to a page',
- );
- const existingNames = appDom.getExistingNamesForChildren(dom, page);
- const newName = appDom.proposeName(node.name, existingNames);
- const copy = appDom.createNode(dom, 'query', { ...node, name: newName });
-
- setDialogState({ node: copy, isDraft: true });
- },
- [dom, page],
- );
-
- React.useEffect(() => {
- setDialogState((previousState) => {
- if (currentView.kind === 'page' && currentView.view?.kind === 'query') {
- const node = appDom.getNode(dom, currentView.view?.nodeId, 'query');
- return { node, isDraft: false };
+ const hasUnsavedChanges = React.useCallback(
+ (queryIndex: number) => {
+ if (
+ currentView.kind !== 'page' ||
+ !currentView.name ||
+ !currentView.queryPanel?.queryTabs ||
+ queryIndex === undefined
+ ) {
+ return false;
}
-
- if (isDraft) {
- return previousState;
+ const tab = currentView.queryPanel?.queryTabs[queryIndex];
+ const draft = tab?.draft;
+ if (!tab || !tab.meta?.id || !draft) {
+ return false;
}
+ return draft !== tab.saved;
+ },
+ [currentView],
+ );
- return null;
- });
- }, [currentView, dom, isDraft]);
-
- const [anchorEl, setAnchorEl] = React.useState(null);
-
- const handleCreate = (event: React.MouseEvent) => {
- setAnchorEl(event.currentTarget);
- };
-
- const handleClose = () => {
- setAnchorEl(null);
- };
-
- const open = Boolean(anchorEl);
-
- const handleCreateClick = React.useCallback(
- (dataSourceId: string) => () => {
- const dataSource = dataSources[dataSourceId];
- invariant(dataSource, `Selected non-existing dataSource "${dataSourceId}"`);
+ const handleSave = React.useCallback(() => {
+ if (
+ currentView.kind !== 'page' ||
+ !currentView.name ||
+ !currentView.queryPanel?.queryTabs ||
+ currentView.queryPanel?.currentTabIndex === undefined
+ ) {
+ return;
+ }
+ const currentTab = currentView.queryPanel?.queryTabs[currentView.queryPanel?.currentTabIndex];
+ const currentQueryDraft = currentTab?.draft;
+ if (!currentTab || !currentTab.meta?.id || !currentQueryDraft) {
+ return;
+ }
+ appStateApi.saveQueryDraft(currentQueryDraft);
+ }, [currentView, appStateApi]);
- const node = appDom.createNode(dom, 'query', {
- attributes: {
- query: dataSource.getInitialQueryValue(),
- connectionId: null,
- dataSource: dataSourceId,
- },
- });
+ const onClosePanel = React.useCallback(() => {
+ appStateApi.closeQueryPanel();
+ }, [appStateApi]);
- setAnchorEl(null);
- setDialogState({ node, isDraft: true });
- },
- [dom],
+ const saveDisabled = React.useMemo(
+ () => !hasUnsavedChanges(parseInt(currentTabIndex, 10)),
+ [hasUnsavedChanges, currentTabIndex],
);
- return (
-
- } onClick={handleCreate}>
- Add query
-
-
-
- Make backend data available as state on the page.
-
-
- Custom function
-
- HTTP request
-
-
-
-
- {queries.map((queryNode) => {
- return (
- {
- appStateApi.setView({
- kind: 'page',
- name: page.name,
- view: { kind: 'query', nodeId: queryNode.id },
- });
- }}
- secondaryAction={
- (
-
-
-
- )}
- nodeId={queryNode.id}
- deleteLabelText="Delete"
- duplicateLabelText="Duplicate"
- onDeleteNode={handleDeleteNode}
- onDuplicateNode={handleDuplicateNode}
- />
- }
+ const hasUnsavedChangesInPanel = React.useMemo(() => {
+ if (currentView.kind !== 'page' || !currentView.queryPanel?.queryTabs) {
+ return false;
+ }
+ return currentView.queryPanel?.queryTabs.some((tab) => tab.draft !== tab.saved);
+ }, [currentView]);
+
+ const { handleCloseWithUnsavedChanges: handleClosePanel } = useUnsavedChangesConfirm({
+ hasUnsavedChanges: hasUnsavedChangesInPanel,
+ onClose: onClosePanel,
+ });
+
+ useShortcut({ key: 's', metaKey: true, disabled: saveDisabled }, handleSave);
+
+ return currentView.kind === 'page' &&
+ currentView.view?.kind === 'query' &&
+ currentQueryId &&
+ currentView?.queryPanel?.queryTabs ? (
+
+
+
+
+ {currentView.queryPanel?.queryTabs?.map((query, index) => (
+
+ }
+ // Need to pass onDelete to allow the delete icon to be rendered
+ onDelete={() => {}}
+ />
+ }
+ value={index.toString()}
+ icon={
+
+ }
+ iconPosition="start"
+ />
+ ))}
+
+
+
-
-
-
-
- );
+ Save
+
+
+
+ theme.palette.grey[500],
+ transition: (theme) =>
+ theme.transitions.create('color', {
+ duration: theme.transitions.duration.shortest,
+ }),
+ '&:hover, &:focus': {
+ color: (theme) =>
+ theme.palette.mode === 'dark'
+ ? theme.palette.primaryDark[300]
+ : theme.palette.primary.main,
+ },
+ fontSize: 16,
+ }}
+ />
+
+
+
+
+ {currentView.queryPanel?.queryTabs?.map((query, index) => {
+ if (query && query.draft) {
+ return (
+
+
+
+ );
+ }
+ return null;
})}
-
- {dialogState?.node ? (
-
- ) : (
-
- )}
+
- );
+ ) : null;
}
diff --git a/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/RenderPanel/NodeDropArea.tsx b/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/RenderPanel/NodeDropArea.tsx
index 1d710582b17..1c0d3757c57 100644
--- a/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/RenderPanel/NodeDropArea.tsx
+++ b/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/RenderPanel/NodeDropArea.tsx
@@ -49,7 +49,7 @@ const StyledNodeDropArea = styled('div', {
pointerEvents: 'none',
position: 'absolute',
[`&.${dropAreaHighlightClasses.highlightedTop}`]: {
- '&:after': {
+ '&::after': {
backgroundColor: theme.palette.primary[500],
content: "''",
position: 'absolute',
@@ -60,7 +60,7 @@ const StyledNodeDropArea = styled('div', {
},
},
[`&.${dropAreaHighlightClasses.highlightedRight}`]: {
- '&:after': {
+ '&::after': {
backgroundColor: theme.palette.primary[500],
content: "''",
position: 'absolute',
@@ -71,7 +71,7 @@ const StyledNodeDropArea = styled('div', {
},
},
[`&.${dropAreaHighlightClasses.highlightedBottom}`]: {
- '&:after': {
+ '&::after': {
backgroundColor: theme.palette.primary[500],
content: "''",
position: 'absolute',
@@ -82,7 +82,7 @@ const StyledNodeDropArea = styled('div', {
},
},
[`&.${dropAreaHighlightClasses.highlightedLeft}`]: {
- '&:after': {
+ '&::after': {
backgroundColor: theme.palette.primary[500],
content: "''",
position: 'absolute',
diff --git a/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/RenderPanel/RenderOverlay.tsx b/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/RenderPanel/RenderOverlay.tsx
index af6bd3d44b6..85157a43c29 100644
--- a/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/RenderPanel/RenderOverlay.tsx
+++ b/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/RenderPanel/RenderOverlay.tsx
@@ -1104,7 +1104,7 @@ export default function RenderOverlay({ bridge }: RenderOverlayProps) {
return normalizePageRowColumnSizes(draft, pageNode);
},
currentView.kind === 'page'
- ? { ...omit(currentView, 'tab'), selectedNodeId: newNode?.id || draggedNodeId }
+ ? { ...omit(currentView, 'pageViewTab'), selectedNodeId: newNode?.id || draggedNodeId }
: currentView,
);
diff --git a/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/UrlQueryEditor.tsx b/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/UrlQueryEditor.tsx
index 1f89df20020..9c11e07e5a9 100644
--- a/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/UrlQueryEditor.tsx
+++ b/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/UrlQueryEditor.tsx
@@ -67,15 +67,21 @@ export default function UrlQueryEditor({ pageNodeId }: UrlQueryEditorProps) {
const handleButtonClick = React.useCallback(() => {
appStateApi.setView({
+ ...currentView,
kind: 'page',
name: page.name,
- view: { kind: 'pageParameters' },
+ pageParametersDialogOpen: true,
});
- }, [appStateApi, page.name]);
+ }, [appStateApi, page.name, currentView]);
const handleDialogClose = React.useCallback(() => {
- appStateApi.setView({ kind: 'page', name: page.name });
- }, [appStateApi, page.name]);
+ appStateApi.setView({
+ ...currentView,
+ kind: 'page',
+ name: page.name,
+ pageParametersDialogOpen: false,
+ });
+ }, [appStateApi, page.name, currentView]);
const { handleCloseWithUnsavedChanges } = useUnsavedChangesConfirm({
hasUnsavedChanges,
@@ -90,7 +96,7 @@ export default function UrlQueryEditor({ pageNodeId }: UrlQueryEditorProps) {
}, [domApi, handleDialogClose, input, page]);
React.useEffect(() => {
- if (currentView.kind === 'page' && currentView.view?.kind === 'pageParameters') {
+ if (currentView.kind === 'page' && currentView.pageParametersDialogOpen) {
openDialog();
} else {
closeDialog();
diff --git a/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/index.tsx b/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/index.tsx
index dc2558ed562..bb4d6ce1016 100644
--- a/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/index.tsx
+++ b/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/index.tsx
@@ -3,13 +3,14 @@ import { styled } from '@mui/material';
import usePageTitle from '@mui/toolpad-utils/hooks/usePageTitle';
import { Panel, PanelGroup, PanelResizeHandle } from '../../../components/resizablePanels';
import RenderPanel from './RenderPanel';
-import ComponentPanel from './ComponentPanel';
import { PageEditorProvider } from './PageEditorProvider';
+import ComponentPanel from './ComponentPanel';
import { useAppState } from '../../AppState';
import * as appDom from '../../../appDom';
import ComponentCatalog from './ComponentCatalog';
import NotFoundEditor from '../NotFoundEditor';
import useUndoRedo from '../../hooks/useUndoRedo';
+import QueryEditor from './QueryEditor';
const classes = {
renderPanel: 'Toolpad_RenderPanel',
@@ -32,20 +33,36 @@ interface PageEditorContentProps {
function PageEditorContent({ node }: PageEditorContentProps) {
usePageTitle(`${appDom.getPageTitle(node)} | Toolpad editor`);
+ const { currentView } = useAppState();
+ const showQuery =
+ currentView.kind === 'page' &&
+ currentView.view?.kind === 'query' &&
+ currentView.queryPanel?.queryTabs;
return (
-
-
-
- {appDom.isCodePage(node) ? null : }
-
-
+
+
+
+
+
+ {appDom.isCodePage(node) ? null : }
+
+
+
+
+
+
+
+
-
-
-
+
+ {showQuery ? (
+
+
+
+ ) : null}
);
diff --git a/packages/toolpad-app/src/toolpad/AppEditor/PagePanel.tsx b/packages/toolpad-app/src/toolpad/AppEditor/PagePanel.tsx
index dbf5e70c1dc..ce535b541dd 100644
--- a/packages/toolpad-app/src/toolpad/AppEditor/PagePanel.tsx
+++ b/packages/toolpad-app/src/toolpad/AppEditor/PagePanel.tsx
@@ -5,12 +5,16 @@ import PagesExplorer from './PagesExplorer';
import PageHierarchyExplorer from './HierarchyExplorer';
import { useAppState } from '../AppState';
import AppOptions from '../AppOptions';
+import { QueriesExplorer, ActionsExplorer } from './PageEditor/QueriesExplorer';
import { useProject } from '../../project';
import * as appDom from '../../appDom';
+const PAGE_PANEL_WIDTH = 250;
+
const PagePanelRoot = styled('div')({
display: 'flex',
flexDirection: 'column',
+ width: PAGE_PANEL_WIDTH,
});
export interface ComponentPanelProps {
@@ -44,15 +48,23 @@ export default function PagePanel({ className, sx }: ComponentPanelProps) {
-
+
{currentPageNode && !appDom.isCodePage(currentPageNode) ? (
-
+
+
+
+
+
+
+
+
+
) : null}
diff --git a/packages/toolpad-app/src/toolpad/AppEditor/PagesExplorer/CreateCodeComponentNodeDialog.tsx b/packages/toolpad-app/src/toolpad/AppEditor/PagesExplorer/CreateCodeComponentNodeDialog.tsx
index c258bca11a9..56bcafd6844 100644
--- a/packages/toolpad-app/src/toolpad/AppEditor/PagesExplorer/CreateCodeComponentNodeDialog.tsx
+++ b/packages/toolpad-app/src/toolpad/AppEditor/PagesExplorer/CreateCodeComponentNodeDialog.tsx
@@ -15,11 +15,11 @@ import CloseIcon from '@mui/icons-material/Close';
import useEventCallback from '@mui/utils/useEventCallback';
import useLatest from '@mui/toolpad-utils/hooks/useLatest';
import * as appDom from '../../../appDom';
-import { useAppState } from '../../AppState';
import DialogForm from '../../../components/DialogForm';
import { useNodeNameValidation } from './validation';
import { useProjectApi } from '../../../projectApi';
import OpenCodeEditorButton from '../../OpenCodeEditor';
+import { useToolpadComponents } from '../toolpadComponents';
function handleInputFocus(event: React.FocusEvent) {
event.target.select();
@@ -37,12 +37,18 @@ export default function CreateCodeComponentDialog({
onClose,
...props
}: CreateCodeComponentDialogProps) {
- const { dom } = useAppState();
const projectApi = useProjectApi();
+ const codeComponents = useToolpadComponents();
+
const existingNames = React.useMemo(
- () => appDom.getExistingNamesForChildren(dom, appDom.getApp(dom), 'codeComponents'),
- [dom],
+ () =>
+ new Set(
+ Object.values(codeComponents)
+ .map((component) => component?.displayName)
+ .filter(Boolean),
+ ),
+ [codeComponents],
);
const [name, setName] = React.useState(appDom.proposeName(DEFAULT_NAME, existingNames));
diff --git a/packages/toolpad-app/src/toolpad/AppEditor/PagesExplorer/index.tsx b/packages/toolpad-app/src/toolpad/AppEditor/PagesExplorer/index.tsx
index e2e651a64dd..ff42fa79b70 100644
--- a/packages/toolpad-app/src/toolpad/AppEditor/PagesExplorer/index.tsx
+++ b/packages/toolpad-app/src/toolpad/AppEditor/PagesExplorer/index.tsx
@@ -365,7 +365,8 @@ export default function PagesExplorer({ className }: PagesExplorerProps) {
key={page.id}
nodeId={page.id}
toolpadNodeId={page.id}
- labelText={page.name}
+ labelText={appDom.getPageDisplayName(page)}
+ title={page.name}
onRenameNode={handleRenameNode}
onDuplicateNode={handleDuplicateNode}
onDeleteNode={handleDeletePage}
diff --git a/packages/toolpad-app/src/toolpad/AppEditor/QueryIcon.tsx b/packages/toolpad-app/src/toolpad/AppEditor/QueryIcon.tsx
new file mode 100644
index 00000000000..7772cf7ba68
--- /dev/null
+++ b/packages/toolpad-app/src/toolpad/AppEditor/QueryIcon.tsx
@@ -0,0 +1,56 @@
+import * as React from 'react';
+import HttpIcon from '@mui/icons-material/Http';
+import JavascriptIcon from '@mui/icons-material/Javascript';
+import AdsClickIcon from '@mui/icons-material/AdsClick';
+import AutoModeIcon from '@mui/icons-material/AutoMode';
+import { SvgIconProps } from '@mui/material/SvgIcon';
+import { SxProps } from '@mui/system';
+import { styled } from '@mui/material/styles';
+
+const dataSourceIconMap = new Map>([
+ [
+ 'rest',
+ styled(HttpIcon)(({ theme }) => ({
+ marginRight: theme.spacing(0.5),
+ marginLeft: theme.spacing(0.5),
+ })),
+ ],
+ [
+ 'local',
+ styled(JavascriptIcon)(({ theme }) => ({
+ marginRight: theme.spacing(0.25),
+ marginLeft: theme.spacing(0),
+ })),
+ ],
+]);
+
+const modeIconMap = new Map>([
+ ['query', AutoModeIcon],
+ ['action', AdsClickIcon],
+ ['mutation', AdsClickIcon],
+]);
+
+interface QueryIconProps {
+ id?: string;
+ mode?: string;
+ sx?: SxProps;
+}
+
+export default function QueryIcon({ id: iconId, mode, sx }: QueryIconProps) {
+ const DataSourceIcon = dataSourceIconMap.get(iconId ?? '');
+ const ModeIcon = modeIconMap.get(mode ?? '');
+
+ return (
+
+ {ModeIcon ? (
+
+ ) : null}
+ {DataSourceIcon ? : null}
+
+ );
+}
diff --git a/packages/toolpad-app/src/toolpad/AppEditor/toolpadComponents.tsx b/packages/toolpad-app/src/toolpad/AppEditor/toolpadComponents.tsx
index df8579c29e3..05e4743b616 100644
--- a/packages/toolpad-app/src/toolpad/AppEditor/toolpadComponents.tsx
+++ b/packages/toolpad-app/src/toolpad/AppEditor/toolpadComponents.tsx
@@ -1,20 +1,166 @@
import * as React from 'react';
-import * as appDom from '../../appDom';
+import { ToolpadComponent } from '@mui/toolpad-core';
+import { useSuspenseQuery } from '@tanstack/react-query';
import {
- getToolpadComponent,
- getToolpadComponents,
- ToolpadComponentDefinition,
- ToolpadComponentDefinitions,
+ FORM_COMPONENT_ID,
+ PAGE_COLUMN_COMPONENT_ID,
+ PAGE_ROW_COMPONENT_ID,
+ STACK_COMPONENT_ID,
} from '../../runtime/toolpadComponents';
+import { useProject } from '../../project';
-export function useToolpadComponents(dom: appDom.AppDom): ToolpadComponentDefinitions {
- return React.useMemo(() => getToolpadComponents(dom), [dom]);
+export interface ToolpadComponentDefinition {
+ displayName: string;
+ builtIn?: string;
+ system?: boolean;
+ synonyms: string[];
+ initialProps?: Record;
}
-export function useToolpadComponent(
- dom: appDom.AppDom,
- id: string,
-): ToolpadComponentDefinition | null {
- const components = useToolpadComponents(dom);
- return React.useMemo(() => getToolpadComponent(components, id), [components, id]);
+export type ToolpadComponentDefinitions = Record;
+export interface InstantiatedComponent extends ToolpadComponentDefinition {
+ Component: ToolpadComponent;
+}
+export type InstantiatedComponents = Record;
+
+export const INTERNAL_COMPONENTS = new Map([
+ [PAGE_ROW_COMPONENT_ID, { displayName: 'Row', builtIn: 'PageRow', system: true, synonyms: [] }],
+ [
+ PAGE_COLUMN_COMPONENT_ID,
+ { displayName: 'Column', builtIn: 'PageColumn', system: true, synonyms: [] },
+ ],
+ [STACK_COMPONENT_ID, { displayName: 'Stack', builtIn: 'Stack', system: true, synonyms: [] }],
+ [
+ 'Autocomplete',
+ {
+ displayName: 'Autocomplete',
+ builtIn: 'Autocomplete',
+ synonyms: ['combobox', 'select', 'dropdown'],
+ },
+ ],
+ [
+ 'Button',
+ {
+ displayName: 'Button',
+ builtIn: 'Button',
+ synonyms: ['click', 'action'],
+ },
+ ],
+ ['Image', { displayName: 'Image', builtIn: 'Image', synonyms: ['picture'] }],
+ ['DataGrid', { displayName: 'Data Grid', builtIn: 'DataGrid', synonyms: ['table'] }],
+ [
+ 'Chart',
+ {
+ displayName: 'Chart',
+ builtIn: 'Chart',
+ synonyms: ['graph', 'bar chart', 'pie chart', 'line chart', 'plot'],
+ },
+ ],
+ [
+ 'TextField',
+ { displayName: 'Text Field', builtIn: 'TextField', synonyms: ['input', 'field', 'password'] },
+ ],
+ ['DatePicker', { displayName: 'Date Picker', builtIn: 'DatePicker', synonyms: ['time'] }],
+ ['FilePicker', { displayName: 'File Picker', builtIn: 'FilePicker', synonyms: [] }],
+ ['Text', { displayName: 'Text', builtIn: 'Text', synonyms: ['markdown', 'link', 'output'] }],
+ [
+ 'Markdown',
+ {
+ displayName: 'Markdown',
+ builtIn: 'Text',
+ initialProps: {
+ mode: 'markdown',
+ },
+ synonyms: [],
+ },
+ ],
+ [
+ 'Link',
+ {
+ displayName: 'Link',
+ builtIn: 'Text',
+ initialProps: {
+ mode: 'link',
+ },
+ synonyms: [],
+ },
+ ],
+ ['Select', { displayName: 'Select', builtIn: 'Select', synonyms: ['combobox', 'dropdown'] }],
+ ['List', { displayName: 'List', builtIn: 'List', synonyms: ['repeat'] }],
+ ['Paper', { displayName: 'Paper', builtIn: 'Paper', synonyms: ['surface'] }],
+ ['Tabs', { displayName: 'Tabs', builtIn: 'Tabs', synonyms: [] }],
+ ['Container', { displayName: 'Container', builtIn: 'Container', synonyms: [] }],
+ ['Metric', { displayName: 'Metric', builtIn: 'Metric', synonyms: ['value', 'number', 'output'] }],
+ [
+ 'Checkbox',
+ {
+ displayName: 'Checkbox',
+ initialProps: {
+ mode: 'checkbox',
+ },
+ builtIn: 'Checkbox',
+ synonyms: ['switch'],
+ },
+ ],
+ [
+ 'Switch',
+ {
+ displayName: 'Switch',
+ initialProps: {
+ mode: 'switch',
+ },
+ builtIn: 'Checkbox',
+ synonyms: ['switch'],
+ },
+ ],
+ [FORM_COMPONENT_ID, { displayName: 'Form', builtIn: 'Form', synonyms: [] }],
+ [
+ 'Password',
+ {
+ displayName: 'Password',
+ builtIn: 'TextField',
+ synonyms: [],
+ initialProps: { password: true },
+ },
+ ],
+]);
+
+function useCodeComponents(): ToolpadComponentDefinitions {
+ const project = useProject();
+ const { data: codeComponents, refetch } = useSuspenseQuery({
+ queryKey: ['codeComponents'],
+ queryFn: () => project.api.methods.getComponents(),
+ });
+
+ React.useEffect(
+ () => project.events.subscribe('componentsListChanged', refetch),
+ [project.events, refetch],
+ );
+
+ return React.useMemo(
+ () =>
+ Object.fromEntries(
+ codeComponents.map((codeComponent) => [
+ `codeComponent.${codeComponent.name}`,
+ {
+ displayName: codeComponent.name,
+ synonyms: [],
+ },
+ ]),
+ ),
+ [codeComponents],
+ );
+}
+
+export function useToolpadComponents(): ToolpadComponentDefinitions {
+ const codeComponents = useCodeComponents();
+ return React.useMemo(
+ () => ({ ...Object.fromEntries(INTERNAL_COMPONENTS), ...codeComponents }),
+ [codeComponents],
+ );
+}
+
+export function useToolpadComponent(id: string): ToolpadComponentDefinition | null {
+ const components = useToolpadComponents();
+ return React.useMemo(() => components[id] || null, [components, id]);
}
diff --git a/packages/toolpad-app/src/toolpad/AppState.tsx b/packages/toolpad-app/src/toolpad/AppState.tsx
index 9c0b58b2061..05f868aa80f 100644
--- a/packages/toolpad-app/src/toolpad/AppState.tsx
+++ b/packages/toolpad-app/src/toolpad/AppState.tsx
@@ -12,8 +12,9 @@ import { omit, update } from '../utils/immutability';
import { useProjectApi } from '../projectApi';
import useShortcut from '../utils/useShortcut';
import insecureHash from '../utils/insecureHash';
+import { ClientDataSource } from '../types';
import { hasFieldFocus } from '../utils/fields';
-import { DomView, getViewFromPathname, PageViewTab } from '../utils/domView';
+import { DomView, getViewFromPathname, PageViewTab, QueryTab } from '../utils/domView';
export function getNodeHashes(dom: appDom.AppDom): NodeHashes {
return mapValues(dom.nodes, (node) => insecureHash(JSON.stringify(omit(node, 'id'))));
@@ -59,7 +60,38 @@ export type AppStateAction =
view: DomView;
}
| {
- type: 'SET_TAB';
+ type: 'OPEN_QUERY_TAB';
+ queryId: NodeId;
+ }
+ | {
+ type: 'CREATE_QUERY_TAB';
+ dataSource: ClientDataSource;
+ dataSourceId: string;
+ mode?: appDom.FetchMode;
+ }
+ | {
+ type: 'CLOSE_QUERY_TAB';
+ queryId: NodeId;
+ queryIndex?: number;
+ deleteQuery?: boolean;
+ }
+ | {
+ type: 'UPDATE_QUERY_TAB';
+ updater: (tab: QueryTab) => QueryTab;
+ }
+ | {
+ type: 'CLOSE_QUERY_PANEL';
+ }
+ | {
+ type: 'UPDATE_QUERY_DRAFT';
+ updater: (draft: appDom.QueryNode) => appDom.QueryNode;
+ }
+ | {
+ type: 'SAVE_QUERY_DRAFT';
+ draft: appDom.QueryNode;
+ }
+ | {
+ type: 'SET_PAGE_VIEW_TAB';
tab: PageViewTab;
}
| {
@@ -220,7 +252,11 @@ export function appStateReducer(state: AppState, action: AppStateAction): AppSta
case 'SELECT_NODE': {
if (state.currentView.kind === 'page') {
return update(state, {
- currentView: { ...state.currentView, selectedNodeId: action.nodeId, tab: 'component' },
+ currentView: {
+ ...state.currentView,
+ selectedNodeId: action.nodeId,
+ pageViewTab: 'component',
+ },
});
}
return state;
@@ -228,7 +264,7 @@ export function appStateReducer(state: AppState, action: AppStateAction): AppSta
case 'DESELECT_NODE': {
if (state.currentView.kind === 'page') {
return update(state, {
- currentView: { ...state.currentView, selectedNodeId: null, tab: 'page' },
+ currentView: { ...state.currentView, selectedNodeId: null, pageViewTab: 'page' },
});
}
return state;
@@ -268,10 +304,10 @@ export function appStateReducer(state: AppState, action: AppStateAction): AppSta
: null,
};
}
- if (action.view.selectedNodeId && typeof action.view.tab === 'undefined') {
+ if (action.view.selectedNodeId && typeof action.view.pageViewTab === 'undefined') {
newView = {
...action.view,
- tab: 'component',
+ pageViewTab: 'component',
};
}
}
@@ -280,10 +316,10 @@ export function appStateReducer(state: AppState, action: AppStateAction): AppSta
currentView: newView,
});
}
- case 'SET_TAB': {
+ case 'SET_PAGE_VIEW_TAB': {
if (state.currentView.kind === 'page') {
return update(state, {
- currentView: { ...state.currentView, tab: action.tab },
+ currentView: { ...state.currentView, pageViewTab: action.tab },
});
}
return state;
@@ -293,6 +329,351 @@ export function appStateReducer(state: AppState, action: AppStateAction): AppSta
hasUnsavedChanges: action.hasUnsavedChanges,
});
}
+ case 'SAVE_QUERY_DRAFT': {
+ if (state.currentView.kind === 'page' && state.currentView.view?.kind === 'query') {
+ const queryTabs = state.currentView.queryPanel?.queryTabs || [];
+ const currentTabIndex = state.currentView.queryPanel?.currentTabIndex;
+ if (currentTabIndex !== undefined && queryTabs) {
+ let newDom = state.dom;
+ let nodeName = action.draft.name;
+ // Check if the dom contains this query draft via its id
+ try {
+ appDom.getNode(state.dom, action.draft.id);
+ } catch (err) {
+ if (state.currentView?.name) {
+ // const pageNode = appDom.getNode(state.dom, state.currentView.nodeId, 'page');
+ const pageNode = appDom.getPageByName(state.dom, state.currentView.name);
+ if (pageNode) {
+ newDom = appDom.addNode(state.dom, action.draft, pageNode, 'queries');
+ const createdNode = appDom.getNode(newDom, action.draft.id);
+ nodeName = createdNode.name;
+ }
+ }
+ }
+
+ newDom = appDom.saveNode(newDom, action.draft);
+ return update(state, {
+ currentView: {
+ ...state.currentView,
+ queryPanel: {
+ ...state.currentView.queryPanel,
+ queryTabs: state.currentView?.queryPanel?.queryTabs?.map((tab, index) => {
+ if (index === currentTabIndex) {
+ return {
+ ...tab,
+ meta: {
+ ...tab.meta,
+ name: nodeName,
+ },
+ saved: action.draft,
+ };
+ }
+ return tab;
+ }),
+ },
+ },
+ dom: newDom,
+ });
+ }
+ }
+ return state;
+ }
+ case 'UPDATE_QUERY_DRAFT': {
+ if (state.currentView.kind === 'page' && state.currentView.view?.kind === 'query') {
+ const queryTabs = state.currentView.queryPanel?.queryTabs || [];
+ const currentTabIndex = state.currentView.queryPanel?.currentTabIndex;
+ if (currentTabIndex !== undefined && queryTabs) {
+ return update(state, {
+ currentView: {
+ ...state.currentView,
+ queryPanel: {
+ ...state.currentView.queryPanel,
+ queryTabs: state.currentView?.queryPanel?.queryTabs?.map((tab, index) => {
+ if (index === currentTabIndex) {
+ if (action.updater && tab.draft) {
+ return {
+ ...tab,
+ draft: action.updater(tab.draft),
+ };
+ }
+ }
+ return tab;
+ }),
+ },
+ },
+ });
+ }
+ }
+ return state;
+ }
+ case 'CREATE_QUERY_TAB': {
+ if (state.currentView.kind !== 'page' || !state.currentView.name) {
+ return state;
+ }
+ // const pageNode = appDom.getNode(state.dom, state.currentView.nodeId, 'page');
+ const draftNode = appDom.createNode(state.dom, 'query', {
+ name: action.mode === 'mutation' ? 'action' : 'query',
+ attributes: {
+ query: action.dataSource?.getInitialQueryValue(),
+ mode: action.mode ?? undefined,
+ connectionId: null,
+ dataSource: action?.dataSourceId,
+ },
+ });
+
+ // const newDom = appDom.addNode(state.dom, draftNode, pageNode, 'queries');
+ const newView = { ...state.currentView };
+ // const createdNode = newDom.nodes[draftNode.id] as appDom.QueryNode;
+
+ /**
+ * To make the app state updates atomic, we must also simultaneously
+ * update the dom and the currentView
+ */
+
+ /**
+ * If tabs are open, simply add the new tab as the latest tab
+ */
+
+ if (state.currentView.queryPanel?.queryTabs) {
+ newView.view = { kind: 'query', nodeId: draftNode.id };
+ newView.queryPanel = {
+ queryTabs: [
+ ...state.currentView.queryPanel.queryTabs,
+ {
+ meta: {
+ id: draftNode.id,
+ name: draftNode.name,
+ dataSource: action.dataSourceId,
+ mode: draftNode.attributes?.mode,
+ },
+ saved: draftNode,
+ draft: draftNode,
+ toolsTabType: 'preview',
+ isPreviewLoading: false,
+ },
+ ],
+ currentTabIndex: state.currentView.queryPanel.queryTabs.length,
+ };
+ } else {
+ /**
+ * If no tabs are open, initialise the query panel
+ */
+ newView.view = { kind: 'query', nodeId: draftNode.id };
+ newView.queryPanel = {
+ queryTabs: [
+ {
+ meta: {
+ id: draftNode.id,
+ name: draftNode.name,
+ dataSource: action.dataSourceId,
+ mode: draftNode.attributes?.mode,
+ },
+ saved: draftNode,
+ draft: draftNode,
+ isPreviewLoading: false,
+ toolsTabType: 'preview',
+ },
+ ],
+ currentTabIndex: 0,
+ };
+ }
+
+ return update(state, {
+ currentView: newView,
+ });
+ }
+ case 'OPEN_QUERY_TAB': {
+ if (state.currentView.kind !== 'page' || !state.currentView.name) {
+ return state;
+ }
+ if (state.currentView.name) {
+ /**
+ * Selected query is already open, do nothing
+ */
+ if (
+ state.currentView?.view?.kind === 'query' &&
+ action.queryId === state.currentView.view?.nodeId
+ ) {
+ return state;
+ }
+ /**
+ * Selected query is open but not the active tab, set it as active
+ * and update the view
+ */
+
+ const selectedQueryTabIndex = state?.currentView?.queryPanel?.queryTabs?.findIndex(
+ (tab) => {
+ return tab.meta.id === action.queryId;
+ },
+ );
+
+ if (selectedQueryTabIndex !== undefined && selectedQueryTabIndex > -1) {
+ return update(state, {
+ currentView: update(state.currentView, {
+ view: { kind: 'query', nodeId: action.queryId },
+ queryPanel: update(state.currentView.queryPanel, {
+ currentTabIndex: selectedQueryTabIndex,
+ }),
+ }),
+ });
+ }
+ /**
+ * Selected query is not open, add it as a tab
+ * and update the view
+ */
+
+ let newTabIndex;
+ let newTabs;
+ const pageNode = appDom.getPageByName(state.dom, state.currentView.name);
+ if (pageNode) {
+ const queries = appDom.getChildNodes(state.dom, pageNode).queries ?? [];
+ if (queries.length) {
+ const selectedQuery = queries?.find((query) => query?.id === action.queryId);
+ const newTab: QueryTab = {
+ meta: {
+ id: action.queryId,
+ name: selectedQuery?.name,
+ dataSource: selectedQuery?.attributes?.dataSource,
+ mode: selectedQuery?.attributes?.mode,
+ },
+ saved: selectedQuery,
+ draft: selectedQuery,
+ toolsTabType: 'preview',
+ isPreviewLoading: false,
+ };
+
+ /**
+ * If no tabs are open, set the currentTabIndex to 0
+ */
+ if (
+ !state.currentView?.queryPanel?.queryTabs ||
+ state?.currentView?.queryPanel?.queryTabs?.length === 0
+ ) {
+ newTabIndex = 0;
+ newTabs = [newTab];
+ } else {
+ /*
+ * If tabs are open, set the currentTabIndex to the next index
+ */
+ newTabIndex = state.currentView?.queryPanel.queryTabs.length;
+ newTabs = [...state.currentView.queryPanel.queryTabs, newTab];
+ }
+ return update(state, {
+ currentView: {
+ ...state.currentView,
+ view: { kind: 'query', nodeId: action.queryId },
+ queryPanel: {
+ currentTabIndex: newTabIndex,
+ queryTabs: newTabs,
+ },
+ },
+ });
+ }
+ }
+ }
+ return state;
+ }
+ case 'UPDATE_QUERY_TAB': {
+ if (state.currentView.kind !== 'page' || !state.currentView.name) {
+ return state;
+ }
+
+ return update(state, {
+ currentView: {
+ ...state.currentView,
+ queryPanel: {
+ ...state.currentView.queryPanel,
+ queryTabs: state.currentView.queryPanel?.queryTabs?.map((tab, index) => {
+ if (index === state.currentView.queryPanel?.currentTabIndex) {
+ return action.updater ? action.updater(tab) : tab;
+ }
+ return tab;
+ }),
+ },
+ },
+ });
+ }
+ case 'CLOSE_QUERY_TAB': {
+ if (state.currentView.kind !== 'page' || !state.currentView.name) {
+ return state;
+ }
+
+ const tabs = state.currentView.queryPanel?.queryTabs;
+ const newView = { ...state.currentView };
+ const newTabs = tabs?.filter((tab) => tab.meta.id !== action.queryId);
+ let newDom = state.dom;
+
+ if (tabs && action.queryId !== undefined) {
+ /*
+ * if this is the only tab,
+ * remove the tab and set the view to the page
+ */
+ if (tabs.length === 1) {
+ newView.view = undefined;
+ newView.queryPanel = {
+ queryTabs: undefined,
+ currentTabIndex: undefined,
+ };
+ }
+ }
+
+ const currentTabIndex = state.currentView.queryPanel?.currentTabIndex;
+
+ if (currentTabIndex !== undefined && action.queryId && action.queryIndex !== undefined) {
+ /*
+ * if the query being closed is not the one open,
+ * decrement the current tab index if it is greater than the index of the tab being closed
+ */
+ if (action.queryIndex !== currentTabIndex) {
+ const newTabIndex =
+ currentTabIndex > action.queryIndex ? currentTabIndex - 1 : currentTabIndex;
+ newView.queryPanel = {
+ queryTabs: newTabs,
+ currentTabIndex: newTabIndex,
+ };
+ }
+ // if there are multiple tabs open, and
+ // the query being closed is the one open,
+ // select the previous tab, or the next tab if there is no previous tab
+ else {
+ const queryIds = tabs?.map((tab) => tab.meta.id);
+
+ const replacementQueryId =
+ queryIds?.[action.queryIndex === 0 ? currentTabIndex + 1 : currentTabIndex - 1];
+ const replacementTabIndex =
+ action.queryIndex === 0 ? currentTabIndex : currentTabIndex - 1;
+ if (replacementQueryId) {
+ newView.view = { kind: 'query', nodeId: replacementQueryId };
+ newView.queryPanel = {
+ queryTabs: newTabs,
+ currentTabIndex: replacementTabIndex,
+ };
+ }
+ }
+ }
+
+ // If a delete action is also involved, remove the query from the dom
+ if (action.deleteQuery) {
+ newDom = appDom.removeNode(state.dom, action.queryId);
+ }
+
+ return update(state, {
+ dom: newDom,
+ currentView: newView,
+ });
+ }
+ case 'CLOSE_QUERY_PANEL': {
+ if (state.currentView.kind === 'page') {
+ return update(state, {
+ currentView: {
+ ...state.currentView,
+ view: undefined,
+ queryPanel: undefined,
+ },
+ });
+ }
+ return state;
+ }
default:
return state;
}
@@ -352,9 +733,9 @@ function createAppStateApi(
view,
});
},
- setTab(tab: PageViewTab) {
+ setPageViewTab(tab: PageViewTab) {
dispatch({
- type: 'SET_TAB',
+ type: 'SET_PAGE_VIEW_TAB',
tab,
});
},
@@ -386,6 +767,51 @@ function createAppStateApi(
hasUnsavedChanges,
});
},
+ openQueryTab(queryId: NodeId) {
+ dispatch({
+ type: 'OPEN_QUERY_TAB',
+ queryId,
+ });
+ },
+ createQueryTab(dataSource: ClientDataSource, dataSourceId: string, mode?: appDom.FetchMode) {
+ dispatch({
+ type: 'CREATE_QUERY_TAB',
+ dataSource,
+ dataSourceId,
+ mode,
+ });
+ },
+ updateQueryTab(updater: (tab: QueryTab) => QueryTab) {
+ dispatch({
+ type: 'UPDATE_QUERY_TAB',
+ updater,
+ });
+ },
+ closeQueryTab(queryId: NodeId, queryIndex?: number, deleteQuery?: boolean) {
+ dispatch({
+ type: 'CLOSE_QUERY_TAB',
+ queryId,
+ queryIndex,
+ deleteQuery,
+ });
+ },
+ closeQueryPanel() {
+ dispatch({
+ type: 'CLOSE_QUERY_PANEL',
+ });
+ },
+ updateQueryDraft(updater: (draft: appDom.QueryNode) => appDom.QueryNode) {
+ dispatch({
+ type: 'UPDATE_QUERY_DRAFT',
+ updater,
+ });
+ },
+ saveQueryDraft(draft: appDom.QueryNode) {
+ dispatch({
+ type: 'SAVE_QUERY_DRAFT',
+ draft,
+ });
+ },
};
}
@@ -428,13 +854,21 @@ type AppStateActionType = AppStateAction['type'];
const UNDOABLE_ACTIONS = new Set([
'UPDATE',
'SET_VIEW',
- 'SET_TAB',
+ 'SET_PAGE_VIEW_TAB',
'SELECT_NODE',
'DESELECT_NODE',
+ 'UPDATE_QUERY_DRAFT',
+ 'OPEN_QUERY_TAB',
+ 'CREATE_QUERY_TAB',
+ 'CLOSE_QUERY_TAB',
]);
function isCancellableAction(action: AppStateAction): boolean {
- return Boolean(action.type === 'SET_VIEW' || (action.type === 'UPDATE' && action.view));
+ return Boolean(
+ action.type === 'SET_VIEW' ||
+ (action.type === 'UPDATE' && action.view) ||
+ (action.type === 'UPDATE_QUERY_DRAFT' && action.updater),
+ );
}
export interface DomContextProps {
@@ -458,7 +892,7 @@ export default function AppProvider({ appUrl, children }: DomContextProps) {
kind: 'page',
name: firstPage?.name,
selectedNodeId: null,
- tab: 'page',
+ pageViewTab: 'page',
};
const [state, dispatch] = React.useReducer(appStateReducer, {
diff --git a/packages/toolpad-app/src/toolpad/ToolpadHomeShell.tsx b/packages/toolpad-app/src/toolpad/ToolpadHomeShell.tsx
deleted file mode 100644
index 81611ab82eb..00000000000
--- a/packages/toolpad-app/src/toolpad/ToolpadHomeShell.tsx
+++ /dev/null
@@ -1,65 +0,0 @@
-import {
- Box,
- Divider,
- List,
- ListItem,
- ListItemButton,
- ListItemText,
- Stack,
- styled,
-} from '@mui/material';
-import * as React from 'react';
-import { Link } from 'react-router-dom';
-import FlexFill from '../components/FlexFill';
-import { DOCUMENTATION_URL, REPOSITORY_URL } from '../constants';
-import ToolpadShell, { ToolpadShellProps } from './ToolpadShell';
-
-const NavigationListItemButton = styled(ListItemButton)({ height: 56 });
-
-export interface HomeShellProps extends ToolpadShellProps {}
-
-export default function HomeShell({ children, ...props }: HomeShellProps) {
- return (
-
-
-
-
-
- {/* @ts-expect-error https://github.com/mui/material-ui/issues/29875 */}
-
-
-
-
-
-
-
-
-
- {/* @ts-expect-error https://github.com/mui/material-ui/issues/29875 */}
-
-
-
-
-
-
- {/* @ts-expect-error https://github.com/mui/material-ui/issues/29875 */}
-
-
-
-
-
-
-
- {children}
-
-
- );
-}
diff --git a/packages/toolpad-app/src/toolpad/propertyControls/GridColumns.tsx b/packages/toolpad-app/src/toolpad/propertyControls/GridColumns.tsx
index 433a81ddb5d..72e4ffad39f 100644
--- a/packages/toolpad-app/src/toolpad/propertyControls/GridColumns.tsx
+++ b/packages/toolpad-app/src/toolpad/propertyControls/GridColumns.tsx
@@ -31,9 +31,7 @@ import { generateUniqueString } from '@mui/toolpad-utils/strings';
import { NumberFormatEditor } from '@mui/toolpad-core/numberFormat';
import { DateFormatEditor } from '@mui/toolpad-core/dateFormat';
import type { EditorProps } from '../../types';
-import { useToolpadComponents } from '../AppEditor/toolpadComponents';
-import { ToolpadComponentDefinition } from '../../runtime/toolpadComponents';
-import { useAppState } from '../AppState';
+import { ToolpadComponentDefinition, useToolpadComponents } from '../AppEditor/toolpadComponents';
import PropertyControl from '../../components/PropertyControl';
// TODO: this import suggests leaky abstraction
@@ -117,8 +115,7 @@ function GridColumnEditor({
value: editedColumn,
onChange: handleColumnChange,
}: GridColumnEditorProps) {
- const { dom } = useAppState();
- const toolpadComponents = useToolpadComponents(dom);
+ const toolpadComponents = useToolpadComponents();
const codeComponents: ToolpadComponentDefinition[] = React.useMemo(() => {
return Object.values(toolpadComponents)
.filter(Boolean)
@@ -234,6 +231,22 @@ function GridColumnEditor({
label="Filterable"
/>
+
+ handleColumnChange({
+ ...editedColumn,
+ editable: event.target.checked,
+ })
+ }
+ />
+ }
+ label="Editable"
+ />
+
{editedColumn.type === 'number' ? (
- setDialogOpen(true)}>
+ setDialogOpen(true)}
+ >
{label}
diff --git a/packages/toolpad-app/src/toolpadDataSources/QueryInputPanel.tsx b/packages/toolpad-app/src/toolpadDataSources/QueryInputPanel.tsx
index 3914aa8843e..fabc9f46e01 100644
--- a/packages/toolpad-app/src/toolpadDataSources/QueryInputPanel.tsx
+++ b/packages/toolpad-app/src/toolpadDataSources/QueryInputPanel.tsx
@@ -1,8 +1,7 @@
import * as React from 'react';
-import { Box, Toolbar } from '@mui/material';
+import { Box } from '@mui/material';
import { LoadingButton } from '@mui/lab';
import PlayArrowIcon from '@mui/icons-material/PlayArrow';
-import FlexFill from '../components/FlexFill';
export interface QueryInputPanelProps {
children: React.ReactNode;
@@ -18,19 +17,17 @@ export default function QueryInputPanel({
previewDisabled,
}: QueryInputPanelProps) {
return (
-
-
- }
- onClick={onRunPreview}
- disabled={previewDisabled}
- >
- Preview
-
-
- {actions}
-
+
+ {actions}
{children}
+ }
+ onClick={onRunPreview}
+ disabled={previewDisabled}
+ variant="outlined"
+ >
+ Preview
+
);
}
diff --git a/packages/toolpad-app/src/toolpadDataSources/TranformInput.tsx b/packages/toolpad-app/src/toolpadDataSources/TranformInput.tsx
index cf15dd04c5f..4e52c9857fa 100644
--- a/packages/toolpad-app/src/toolpadDataSources/TranformInput.tsx
+++ b/packages/toolpad-app/src/toolpadDataSources/TranformInput.tsx
@@ -35,9 +35,13 @@ export default function TransformInput({
diff --git a/packages/toolpad-app/src/toolpadDataSources/client.tsx b/packages/toolpad-app/src/toolpadDataSources/client.tsx
index 28703589baf..8aa1e728ef4 100644
--- a/packages/toolpad-app/src/toolpadDataSources/client.tsx
+++ b/packages/toolpad-app/src/toolpadDataSources/client.tsx
@@ -1,17 +1,11 @@
-import postgres from './postgres/client';
-import mysql from './mysql/client';
import rest from './rest/client';
import { ClientDataSource } from '../types';
-import googleSheets from './googleSheets/client';
import local from './local/client';
type ClientDataSources = { [key: string]: ClientDataSource | undefined };
const dataSources: ClientDataSources = {
rest,
- postgres,
- googleSheets,
- mysql,
local,
};
diff --git a/packages/toolpad-app/src/toolpadDataSources/googleSheets/client.tsx b/packages/toolpad-app/src/toolpadDataSources/googleSheets/client.tsx
index 751d4c2b893..e715486e382 100644
--- a/packages/toolpad-app/src/toolpadDataSources/googleSheets/client.tsx
+++ b/packages/toolpad-app/src/toolpadDataSources/googleSheets/client.tsx
@@ -81,7 +81,7 @@ function QueryEditor({
const handleSpreadsheetChange = React.useCallback(
(event: React.SyntheticEvent, newValue: GoogleDriveFile | null) => {
- setInput((existing) => {
+ setInput?.((existing) => {
existing = appDom.setQueryProp(existing, 'sheetName', null);
existing = appDom.setQueryProp(existing, 'spreadsheetId', newValue?.id ?? null);
return existing;
@@ -92,7 +92,7 @@ function QueryEditor({
const handleSheetChange = React.useCallback(
(event: React.SyntheticEvent, newValue: GoogleSheet | null) => {
- setInput((existing) =>
+ setInput?.((existing) =>
appDom.setQueryProp(existing, 'sheetName', newValue?.properties?.title ?? null),
);
},
@@ -101,14 +101,14 @@ function QueryEditor({
const handleRangeChange = React.useCallback(
(event: React.ChangeEvent) => {
- setInput((existing) => appDom.setQueryProp(existing, 'ranges', event.target.value));
+ setInput?.((existing) => appDom.setQueryProp(existing, 'ranges', event.target.value));
},
[setInput],
);
const handleTransformChange = React.useCallback(
(event: React.ChangeEvent) => {
- setInput((existing) => appDom.setQueryProp(existing, 'headerRow', event.target.checked));
+ setInput?.((existing) => appDom.setQueryProp(existing, 'headerRow', event.target.checked));
},
[setInput],
);
@@ -140,8 +140,8 @@ function QueryEditor({
const previewGridKey = React.useMemo(() => getObjectKey(columns), [columns]);
return (
-
-
+
+
-
+
({
+ [`& .${autocompleteClasses.paper}`]: {
+ boxShadow: 'none',
+ margin: 0,
+ borderRadius: 0,
+ color: 'inherit',
+ fontSize: 12,
+ },
+ [`& .${autocompleteClasses.listbox}`]: {
+ backgroundColor:
+ theme.palette.mode === 'light'
+ ? theme.palette.background.paper
+ : theme.palette.primaryDark[900],
+ padding: 0,
+ [`& .${autocompleteClasses.option}`]: {
+ minHeight: 'auto',
+ alignItems: 'flex-start',
+ padding: 8,
+ borderBottom: `1px solid ${theme.palette.divider}`,
+ [`&.${autocompleteClasses.focused}:not([aria-selected="true"])`]: {
+ backgroundColor: theme.palette.action.hover,
+ },
+ },
+ },
+ [`&.${autocompleteClasses.popperDisablePortal}`]: {
+ position: 'relative',
+ },
+}));
+
+function PopperComponent(props: PopperComponentProps) {
+ const { disablePortal, anchorEl, open, ...other } = props;
+ return ;
+}
+
+const StyledPopper = styled(Popper)(({ theme }) => ({
+ border: `1px solid ${theme.palette.divider}`,
+ boxShadow: `0 8px 24px ${
+ theme.palette.mode === 'light'
+ ? alpha(theme.palette.grey[800], 0.5)
+ : alpha(theme.palette.grey[700], 0.2)
+ }`,
+ borderRadius: 6,
+ width: 300,
+ zIndex: theme.zIndex.modal,
+ fontSize: 12,
+ color: theme.palette.mode === 'light' ? theme.palette.common.black : theme.palette.grey[500],
+ backgroundColor: theme.palette.background.paper,
+}));
+
+const StyledInput = styled(InputBase)(({ theme }) => ({
+ padding: 10,
+ width: '100%',
+ border: `1px solid ${theme.palette.divider}`,
+ '& input': {
+ borderRadius: 4,
+ backgroundColor: theme.palette.background.paper,
+ padding: 8,
+ transition: theme.transitions.create(['border-color', 'box-shadow']),
+ border: `1px solid ${theme.palette.divider}`,
+ fontSize: 12,
+ color: theme.palette.mode === 'light' ? theme.palette.common.black : theme.palette.grey[500],
+ '&:focus': {
+ boxShadow: `0px 0px 0px 3px ${
+ theme.palette.mode === 'light' ? theme.palette.primary[100] : theme.palette.primaryDark[600]
+ }`,
+ borderColor:
+ theme.palette.mode === 'light'
+ ? theme.palette.primary.main
+ : theme.palette.primaryDark.main,
+ },
+ },
+}));
+
+const FunctionButton = styled(Chip)(({ theme }) => ({
+ fontSize: 12,
+ width: '100%',
+ fontFamily: theme.typography.fontFamilyCode,
+ marginTop: theme.spacing(1),
+ fontWeight: 'normal',
+ color: theme.palette.primary.main,
+ transition: theme.transitions.create('color', { duration: theme.transitions.duration.shorter }),
+ '&:active': {
+ boxShadow: 'none',
+ },
+ '&:focus': {
+ backgroundColor:
+ theme.palette.mode === 'light' ? theme.palette.primary[100] : theme.palette.primaryDark[600],
+ },
+ '& svg': {
+ width: 12,
+ height: 12,
+ },
+}));
+
+const StyledListSubheader = styled(ListSubheader)(({ theme }) => ({
+ lineHeight: 2.5,
+ fontSize: 13,
+ fontFamily: theme.typography.fontFamilyCode,
+ backgroundColor:
+ theme.palette.mode === 'light' ? theme.palette.grey[200] : alpha(theme.palette.grey[900], 0.5),
+ borderRadius: 0,
+ borderBottom: `1px solid ${theme.palette.divider}`,
+ color: theme.palette.mode === 'light' ? theme.palette.grey[700] : theme.palette.grey[500],
+}));
+
+interface FunctionAutocompleteProps {
+ files: FileIntrospectionResult[];
+ selectedFunctionId?: string;
+ onCreateNew: () => Promise;
+ onSelect: (functionName: string) => void;
+}
+
+export default function FunctionSelector({
+ files,
+ selectedFunctionId,
+ onCreateNew,
+ onSelect,
+}: FunctionAutocompleteProps) {
+ const [anchorEl, setAnchorEl] = React.useState(null);
+ const [inputValue, setInputValue] = React.useState('');
+
+ const { selectedFileName, selectedFunctionName } = React.useMemo(() => {
+ const parsed = parseLegacyFunctionId(selectedFunctionId ?? '');
+ return {
+ selectedFileName: parsed.file,
+ selectedFunctionName: parsed.handler,
+ };
+ }, [selectedFunctionId]);
+
+ const selectedFunctionLabel = React.useMemo(() => {
+ if (selectedFunctionName) {
+ return `${selectedFileName} > ${selectedFunctionName}`;
+ }
+ return 'Select function';
+ }, [selectedFileName, selectedFunctionName]);
+
+ const options = React.useMemo(() => {
+ const functions: string[] = [];
+
+ files.forEach((file) => {
+ file.handlers.forEach((fn) => {
+ functions.push(serializeFunctionId({ file: file.name, handler: fn.name }));
+ });
+ });
+ return functions;
+ }, [files]);
+
+ const handleClick = React.useCallback((event: React.MouseEvent) => {
+ setAnchorEl(event.currentTarget);
+ }, []);
+
+ const handleClose = React.useCallback(() => {
+ setAnchorEl(null);
+ }, []);
+
+ const open = Boolean(anchorEl);
+ const id = open ? 'function-selector' : undefined;
+
+ const handleCreateNew = React.useCallback(async () => {
+ const functionId = await onCreateNew();
+ // Select the newly created function.
+ onSelect(functionId);
+ }, [onCreateNew, onSelect]);
+
+ const handleInput = React.useCallback((event: React.FormEvent) => {
+ setInputValue((event.target as HTMLInputElement).value);
+ }, []);
+
+ return (
+
+ }
+ onClick={handleClick}
+ label={selectedFunctionLabel}
+ />
+
+
+
+
+ Search for functions
+
+
, reason: AutocompleteCloseReason) => {
+ if (reason === 'escape') {
+ handleClose();
+ }
+ }}
+ value={selectedFunctionId}
+ inputValue={inputValue}
+ onInput={handleInput}
+ onChange={(event, newValue, reason) => {
+ if (
+ event.type === 'keydown' &&
+ (event as React.KeyboardEvent).key === 'Backspace' &&
+ reason === 'removeOption'
+ ) {
+ return;
+ }
+
+ if (newValue) {
+ onSelect(newValue);
+ }
+
+ handleClose();
+ }}
+ PopperComponent={PopperComponent}
+ renderTags={() => null}
+ noOptionsText="No functions"
+ groupBy={(option) => parseLegacyFunctionId(option).file ?? ''}
+ renderGroup={(params) => [
+
+
+ {params.group}
+ theme.transitions.create('color', { duration: 200 }),
+ '&:hover': {
+ color: (theme) =>
+ theme.palette.mode === 'light'
+ ? theme.palette.grey[800]
+ : theme.palette.grey[300],
+ },
+ }}
+ />
+
+ ,
+ params.children,
+ ]}
+ renderOption={(props, option, { selected }) => (
+
+
+
+ theme.typography.fontFamilyCode,
+ }}
+ >
+ {parseLegacyFunctionId(option).handler ?? ''}
+
+
+ )}
+ options={options.sort((a, b) => {
+ // Display the selected function first.
+ if (selectedFunctionId === a) {
+ return -1;
+ }
+ if (selectedFunctionId === b) {
+ return 1;
+ }
+
+ // Then display the functions in the same file.
+ const fa = parseLegacyFunctionId(a).file;
+ const fb = parseLegacyFunctionId(b).file;
+
+ // Display the file with the selected function first.
+ const sf = parseLegacyFunctionId(selectedFunctionId ?? '').file;
+
+ if (sf === fa) {
+ if (fa === fb) {
+ // Alphabetically sort functions with the same file
+ return a.localeCompare(b);
+ }
+ return -1;
+ }
+ if (sf === fb) {
+ return 1;
+ }
+ return fa?.localeCompare(fb ?? '') ?? 0;
+ })}
+ renderInput={(params) => (
+
+ )}
+ />
+ }
+ onClick={handleCreateNew}
+ >
+ New file
+
+
+
+
+
+ );
+}
diff --git a/packages/toolpad-app/src/toolpadDataSources/local/client.tsx b/packages/toolpad-app/src/toolpadDataSources/local/client.tsx
index ddd78c74b17..c20d81f0ddf 100644
--- a/packages/toolpad-app/src/toolpadDataSources/local/client.tsx
+++ b/packages/toolpad-app/src/toolpadDataSources/local/client.tsx
@@ -1,117 +1,110 @@
import * as React from 'react';
+import LoadingButton from '@mui/lab/LoadingButton';
import { BindableAttrEntries } from '@mui/toolpad-core';
-import {
- Alert,
- Box,
- Button,
- CircularProgress,
- InputBase,
- Popover,
- Skeleton,
- Stack,
- Typography,
- generateUtilityClasses,
- styled,
-} from '@mui/material';
+import { Alert, Box, Divider, Stack, Tab } from '@mui/material';
+import PlayArrowIcon from '@mui/icons-material/PlayArrow';
+import { TabContext, TabList } from '@mui/lab';
import { useBrowserJsRuntime } from '@mui/toolpad-core/jsBrowserRuntime';
import { errorFrom } from '@mui/toolpad-utils/errors';
-import { TreeView, treeItemClasses, TreeItem } from '@mui/x-tree-view';
-import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
-import ChevronRightIcon from '@mui/icons-material/ChevronRight';
-import useBoolean from '@mui/toolpad-utils/hooks/useBoolean';
+
import { useQuery } from '@tanstack/react-query';
-import { ensureSuffix } from '@mui/toolpad-utils/strings';
-import { Panel, PanelGroup, PanelResizeHandle } from '../../components/resizablePanels';
+import Grid2 from '@mui/material/Unstable_Grid2/Grid2';
+import TabPanel from '../../components/TabPanel';
import { ClientDataSource, QueryEditorProps } from '../../types';
import { LocalPrivateApi, LocalQuery, LocalConnectionParams } from './types';
import {
useEvaluateLiveBindingEntries,
useEvaluateLiveBindings,
} from '../../toolpad/AppEditor/useEvaluateLiveBinding';
-import * as appDom from '../../appDom';
+import { useAppState, useAppStateApi } from '../../toolpad/AppState';
+import { QueryEditorTabType, QueryEditorToolsTabType } from '../../utils/domView';
+import { Panel, PanelGroup, PanelResizeHandle } from '../../components/resizablePanels';
import JsonView from '../../components/JsonView';
import OpenCodeEditorButton from '../../toolpad/OpenCodeEditor';
import useQueryPreview from '../useQueryPreview';
-import QueryInputPanel from '../QueryInputPanel';
import QueryPreview from '../QueryPreview';
import BindableEditor from '../../toolpad/AppEditor/PageEditor/BindableEditor';
import { getDefaultControl, usePropControlsContext } from '../../toolpad/propertyControls';
-import { parseFunctionId, parseLegacyFunctionId, serializeFunctionId } from './shared';
-import FlexFill from '../../components/FlexFill';
-import { FileIntrospectionResult } from '../../server/functionsTypesWorker';
-
-const fileTreeItemClasses = generateUtilityClasses('FileTreeItem', ['actionButton', 'handlerItem']);
-
-const FileTreeItemRoot = styled(TreeItem)(({ theme }) => ({
- [`& .${treeItemClasses.label}`]: {
- display: 'flex',
- flexDirection: 'row',
- alignItems: 'center',
- padding: 2,
- paddingRight: 0,
-
- [`&:hover .${fileTreeItemClasses.actionButton}`]: {
- visibility: 'visible',
- },
- },
+import { parseLegacyFunctionId, serializeFunctionId, transformLegacyFunctionId } from './shared';
+import FunctionSelector from './FunctionSelector';
- [`& .${fileTreeItemClasses.actionButton}`]: {
- visibility: 'hidden',
- },
-
- [`& .${fileTreeItemClasses.handlerItem} .${treeItemClasses.label}`]: {
- fontSize: '0.8em',
- padding: 0,
- fontFamily: theme.typography.fontFamilyCode,
- },
-}));
+const EMPTY_PARAMS: BindableAttrEntries = [];
-interface HandlerFileTreeItemProps {
- file: FileIntrospectionResult;
+interface ResolvedPreviewProps {
+ preview: any;
}
-function HandlerFileTreeItem({ file }: HandlerFileTreeItemProps) {
- return (
-
- {file.name}
-
-
-
- }
- >
- {file.handlers.map((handler) => {
- return (
-
- );
- })}
-
- );
-}
+function ResolvedPreview({ preview }: ResolvedPreviewProps): React.ReactElement | null {
+ if (!preview) {
+ return (
+ ({
+ my: theme.spacing(2),
+ mx: 'auto',
+ p: theme.spacing(1),
+ fontSize: theme.typography.pxToRem(11),
+ width: 'fit-content',
+ })}
+ >
+ No request has been sent yet.
+ Click Run
+
+ to preview the response here.
+
+ );
+ }
-const EMPTY_PARAMS: BindableAttrEntries = [];
+ const { data } = preview;
+
+ return ;
+}
function QueryEditor({
globalScope,
globalScopeMeta,
value: input,
- onChange: setInput,
+ settingsTab,
execApi,
}: QueryEditorProps) {
+ const appStateApi = useAppStateApi();
+ const { currentView } = useAppState();
const introspection = useQuery({
queryKey: ['introspection'],
queryFn: () => execApi('introspection', []),
retry: false,
});
+ const updateProp = React.useCallback(
+ function updateProp(prop: K, value: LocalQuery[K]) {
+ appStateApi.updateQueryDraft((draft) => ({
+ ...draft,
+ attributes: {
+ ...draft.attributes,
+ query: {
+ ...draft.attributes.query,
+ [prop]: value,
+ },
+ },
+ }));
+ },
+ [appStateApi],
+ );
+
+ const currentTab = React.useMemo(() => {
+ if (
+ currentView.kind === 'page' &&
+ currentView.view?.kind === 'query' &&
+ currentView.queryPanel?.currentTabIndex !== undefined
+ ) {
+ return currentView.queryPanel?.queryTabs?.[currentView.queryPanel?.currentTabIndex];
+ }
+ return null;
+ }, [currentView]);
+
const propTypeControls = usePropControlsContext();
const { file: selectedFile = undefined, handler: selectedFunction = undefined } = input.attributes
@@ -119,22 +112,21 @@ function QueryEditor({
? parseLegacyFunctionId(input.attributes.query.function)
: {};
- const selectedNodeId: string | undefined = selectedFile
- ? serializeFunctionId({
- file: selectedFile,
- handler: selectedFunction,
- })
- : undefined;
-
const selectedOption = React.useMemo(() => {
return introspection.data?.files
.find((file) => file.name === selectedFile)
?.handlers.find((handler) => handler.name === selectedFunction);
}, [introspection.data?.files, selectedFile, selectedFunction]);
- const parameterDefs = Object.fromEntries(selectedOption?.parameters || []);
+ const parameterDefs = React.useMemo(
+ () => Object.fromEntries(selectedOption?.parameters || []),
+ [selectedOption?.parameters],
+ );
- const paramsEntries = input.params?.filter(([key]) => !!parameterDefs[key]) || EMPTY_PARAMS;
+ const paramsEntries = React.useMemo(
+ () => input.params?.filter(([key]) => !!parameterDefs[key]) || EMPTY_PARAMS,
+ [input.params, parameterDefs],
+ );
const paramsObject = Object.fromEntries(paramsEntries);
@@ -151,249 +143,263 @@ function QueryEditor({
[paramsEditorLiveValue],
);
+ const handleToolsTabTypeChange = React.useCallback(
+ (value: QueryEditorToolsTabType) => {
+ appStateApi.updateQueryTab((tab) => ({
+ ...tab,
+ toolsTabType: value,
+ }));
+ },
+ [appStateApi],
+ );
+
const fetchServerPreview = React.useCallback(
- async (query: LocalQuery, params: Record) =>
- execApi('debugExec', [query, params]),
+ async (query: LocalQuery, params: Record) => {
+ return execApi('debugExec', [query, params]);
+ },
[execApi],
);
- const {
- preview,
- runPreview: handleRunPreview,
- isLoading: previewIsLoading,
- } = useQueryPreview(
+ const { preview, runPreview, isLoading } = useQueryPreview(
fetchServerPreview,
input.attributes.query,
previewParams as Record,
);
+ const handleRunPreview = React.useCallback(() => {
+ runPreview();
+ }, [runPreview]);
+
+ React.useEffect(() => {
+ appStateApi.updateQueryTab((tab) => ({
+ ...tab,
+ previewHandler: handleRunPreview,
+ isPreviewLoading: isLoading,
+ }));
+ }, [handleRunPreview, appStateApi, isLoading]);
+
const liveBindings = useEvaluateLiveBindings({
jsRuntime: jsBrowserRuntime,
input: paramsObject,
globalScope,
});
- const setSelectedHandler = React.useCallback(
- (id: string) => {
- setInput((draft) => {
- return appDom.setQueryProp(draft, 'function', id);
- });
- },
- [setInput],
- );
-
const handleSelectFunction = React.useCallback(
- (_event: React.SyntheticEvent, nodeId: string) => {
- const parsed = parseFunctionId(nodeId);
- if (parsed.handler) {
- setSelectedHandler(nodeId);
- }
+ (functionId: string) => {
+ updateProp('function', functionId);
},
- [setSelectedHandler],
+ [updateProp],
);
- const handlerTreeRef = React.useRef(null);
-
- React.useEffect(() => {
- handlerTreeRef.current?.querySelector(`.${treeItemClasses.selected}`)?.scrollIntoView();
- }, []);
-
- const [newHandlerInput, setNewHandlerInput] = React.useState('');
- const [newHandlerLoading, setNewHandlerLoading] = React.useState(false);
-
- const {
- value: isCreateNewHandlerOpen,
- setTrue: handleOpenCreateNewHandler,
- setFalse: handleCloseCreateNewHandlerDialog,
- } = useBoolean(false);
+ const proposedFileName = React.useMemo(() => {
+ const existingNames = new Set(introspection.data?.files.map((file) => file.name) || []);
+ const baseName = 'functions';
+ let counter = 2;
- const handleCloseCreateNewHandler = React.useCallback(() => {
- setNewHandlerInput('');
- handleCloseCreateNewHandlerDialog();
- }, [handleCloseCreateNewHandlerDialog]);
-
- const [expanded, setExpanded] = React.useState(selectedFile ? [selectedFile] : []);
-
- const [anchorEl, setAnchorEl] = React.useState(null);
- const createNewInputRef = React.useRef(null);
- const open = !!anchorEl;
-
- const inputError: string | null = React.useMemo(() => {
- const alreadyExists = introspection.data?.files.some(
- (file) => file.name === newHandlerInput || file.name === ensureSuffix(newHandlerInput, '.ts'),
- );
-
- return alreadyExists ? 'File already exists' : null;
- }, [introspection.data?.files, newHandlerInput]);
-
- React.useEffect(() => {
- setAnchorEl(inputError ? createNewInputRef.current : null);
- }, [inputError]);
-
- const handleCreateNewCommit = React.useCallback(async () => {
- if (!newHandlerInput || inputError || newHandlerLoading) {
- handleCloseCreateNewHandler();
- return;
+ while (existingNames.has(`${baseName}${counter}.ts`)) {
+ counter += 1;
}
- const fileName = ensureSuffix(newHandlerInput, '.ts');
+ return `${baseName}${counter}.ts`;
+ }, [introspection.data?.files]);
- setNewHandlerLoading(true);
+ const handleCreateNewCommit = React.useCallback(async () => {
try {
- await execApi('createNew', [fileName]);
+ await execApi('createNew', [proposedFileName]);
await introspection.refetch();
} catch (error) {
- // eslint-disable-next-line no-alert
- window.alert(errorFrom(error).message);
- } finally {
- setNewHandlerLoading(false);
+ console.error(errorFrom(error).message);
}
+ return serializeFunctionId({ file: proposedFileName, handler: 'default' });
+ }, [execApi, introspection, proposedFileName]);
+
+ const handleTabTypeChange = React.useCallback(
+ (value: QueryEditorTabType) => {
+ appStateApi.updateQueryTab((tab) => ({
+ ...tab,
+ tabType: value,
+ }));
+ },
+ [appStateApi],
+ );
- const newNodeId = serializeFunctionId({ file: fileName, handler: 'default' });
- setSelectedHandler(newNodeId);
- setExpanded([fileName]);
- handleCloseCreateNewHandler();
- }, [
- execApi,
- handleCloseCreateNewHandler,
- inputError,
- introspection,
- newHandlerInput,
- newHandlerLoading,
- setSelectedHandler,
- ]);
-
- return (
-
-
- New handler file}
- >
-
-
- }
- defaultExpandIcon={ }
- expanded={expanded}
- onNodeToggle={(_event, nodeIds) => setExpanded(nodeIds)}
+ return currentTab ? (
+
+
+
+
+
+ handleTabTypeChange(value)}
+ aria-label="Query editor active tab type"
>
- {isCreateNewHandlerOpen ? (
-
-
- setNewHandlerInput(event.target.value.replaceAll(/[^a-zA-Z0-9]/g, ''))
- }
- autoFocus
- disabled={newHandlerLoading}
- endAdornment={newHandlerLoading ? : null}
- onBlur={handleCreateNewCommit}
- onKeyDown={(event) => {
- if (event.key === 'Enter') {
- handleCreateNewCommit();
- } else if (event.key === 'Escape') {
- handleCloseCreateNewHandler();
- event.stopPropagation();
- }
- }}
- />
- setAnchorEl(null)}
- disableAutoFocus
- anchorOrigin={{
- vertical: 'bottom',
- horizontal: 'left',
- }}
- >
-
- {inputError}
-
-
-
- }
- />
- ) : null}
-
- {introspection.data?.files?.map((file) => (
-
- ))}
+
+
+
+
- {introspection.isLoading ? (
-
- } />
- } />
- } />
-
+
+
+
+
+ ({
+ marginTop: theme.spacing(1),
+ marginLeft: theme.spacing(1),
+ border: '1px solid',
+ borderColor: theme.palette.divider,
+ })}
+ />
+ {introspection.error ? (
+
+ {errorFrom(introspection.error).message}
+
) : null}
-
- {introspection.error ? (
-
+
+
+ {settingsTab}
+
+
+
+
+
+
+
+
+
+
+
- {errorFrom(introspection.error).message}
-
- ) : null}
+
+
+
+
+
+
+ {Object.entries(parameterDefs).map(([name, definiton]) => {
+ const Control = getDefaultControl(propTypeControls, definiton, liveBindings);
+ return Control ? (
+ (
+
+ )}
+ value={paramsObject[name]}
+ onChange={(newValue) => {
+ const paramKeys = Object.keys(parameterDefs);
+ const newParams: BindableAttrEntries = paramKeys.flatMap((key) => {
+ const paramValue = key === name ? newValue : paramsObject[key];
+ return paramValue ? [[key, paramValue]] : [];
+ });
+ appStateApi.updateQueryDraft((draft) => ({
+ ...draft,
+ params: newParams,
+ }));
+ }}
+ />
+ ) : null;
+ })}
+
+
+
-
-
- Parameters:
- {Object.entries(parameterDefs).map(([name, definiton]) => {
- const Control = getDefaultControl(propTypeControls, definiton, liveBindings);
- return Control ? (
- (
-
- )}
- value={paramsObject[name]}
- onChange={(newValue) => {
- const paramKeys = Object.keys(parameterDefs);
- const newParams: BindableAttrEntries = paramKeys.flatMap((key) => {
- const paramValue = key === name ? newValue : paramsObject[key];
- return paramValue ? [[key, paramValue]] : [];
- });
- setInput((existing) => ({
- ...existing,
- params: newParams,
- }));
- }}
- />
- ) : null;
- })}
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+ handleToolsTabTypeChange(value)}
+ aria-label="Query tools active tab"
+ >
+
+
+ }
+ >
+ Run
+
+
+
+
+
+
+
+
+
+
+ ) : (
+
+ An error occurred while rendering this tab. Please refresh and try again.
+
);
}
@@ -402,7 +408,7 @@ function getInitialQueryValue(): LocalQuery {
}
const dataSource: ClientDataSource = {
- displayName: 'Local',
+ displayName: 'Custom',
QueryEditor,
getInitialQueryValue,
hasDefault: true,
diff --git a/packages/toolpad-app/src/toolpadDataSources/local/shared.tsx b/packages/toolpad-app/src/toolpadDataSources/local/shared.tsx
index 7227c7f2a01..dfa2ab9cc2d 100644
--- a/packages/toolpad-app/src/toolpadDataSources/local/shared.tsx
+++ b/packages/toolpad-app/src/toolpadDataSources/local/shared.tsx
@@ -9,6 +9,9 @@ export type ParsedFunctionId =
};
export function parseLegacyFunctionId(id: string): ParsedFunctionId {
+ if (!id) {
+ return { file: 'functions.ts' };
+ }
const [file, handler] = id.split('#');
return handler ? { file, handler } : { file: 'functions.ts', handler: file };
}
@@ -21,3 +24,11 @@ export function parseFunctionId(id: string): ParsedFunctionId {
export function serializeFunctionId({ file, handler }: ParsedFunctionId): string {
return handler ? `${file}#${handler}` : file;
}
+
+export function transformLegacyFunctionId(id: string): string {
+ if (!id) {
+ return '';
+ }
+ const [file, handler] = id.split('#');
+ return handler ? id : `functions.ts#${file}`;
+}
diff --git a/packages/toolpad-app/src/toolpadDataSources/local/types.ts b/packages/toolpad-app/src/toolpadDataSources/local/types.ts
index 02f8e99e5b8..e84cef557f3 100644
--- a/packages/toolpad-app/src/toolpadDataSources/local/types.ts
+++ b/packages/toolpad-app/src/toolpadDataSources/local/types.ts
@@ -2,7 +2,6 @@ import { BindableAttrValue, ExecFetchResult, PrimitiveValueType } from '@mui/too
import type { IntrospectionResult } from '../../server/functionsTypesWorker';
export interface LocalConnectionParams {}
-
export interface LocalQuery {
/**
* name of the handler to execute.
diff --git a/packages/toolpad-app/src/toolpadDataSources/rest/BodyEditor.tsx b/packages/toolpad-app/src/toolpadDataSources/rest/BodyEditor.tsx
index c8cadd4729f..4181b7d9cc2 100644
--- a/packages/toolpad-app/src/toolpadDataSources/rest/BodyEditor.tsx
+++ b/packages/toolpad-app/src/toolpadDataSources/rest/BodyEditor.tsx
@@ -10,6 +10,8 @@ import {
Toolbar,
ToolbarProps,
Typography,
+ inputLabelClasses,
+ inputBaseClasses,
} from '@mui/material';
import { TabContext } from '@mui/lab';
import { BindableAttrValue, LiveBinding, ScopeMeta } from '@mui/toolpad-core';
@@ -122,7 +124,11 @@ function RawBodyEditor({
raw
x-www-form-urlencoded
diff --git a/packages/toolpad-app/src/toolpadDataSources/rest/client.tsx b/packages/toolpad-app/src/toolpadDataSources/rest/client.tsx
index a09df3f369a..cb5503b5e78 100644
--- a/packages/toolpad-app/src/toolpadDataSources/rest/client.tsx
+++ b/packages/toolpad-app/src/toolpadDataSources/rest/client.tsx
@@ -12,7 +12,12 @@ import {
Typography,
Alert,
styled,
+ Divider,
+ inputLabelClasses,
+ inputBaseClasses,
} from '@mui/material';
+import LoadingButton from '@mui/lab/LoadingButton';
+import PlayArrowIcon from '@mui/icons-material/PlayArrow';
import { Controller, useForm } from 'react-hook-form';
import { TabContext, TabList } from '@mui/lab';
import { createServerJsRuntime } from '@mui/toolpad-core/jsServerRuntime';
@@ -39,7 +44,8 @@ import MapEntriesEditor from '../../components/MapEntriesEditor';
import { Maybe } from '../../utils/types';
import AuthenticationEditor from './AuthenticationEditor';
import { isSaveDisabled, validation } from '../../utils/forms';
-import * as appDom from '../../appDom';
+import { useAppState, useAppStateApi } from '../../toolpad/AppState';
+import { QueryEditorTabType, QueryEditorToolsTabType } from '../../utils/domView';
import ParametersEditor from '../../toolpad/AppEditor/PageEditor/ParametersEditor';
import BodyEditor from './BodyEditor';
import TabPanel from '../../components/TabPanel';
@@ -48,7 +54,6 @@ import useQueryPreview from '../useQueryPreview';
import TransformInput from '../TranformInput';
import Devtools from '../../components/Devtools';
import { createHarLog, mergeHar } from '../../utils/har';
-import QueryInputPanel from '../QueryInputPanel';
import useFetchPrivate from '../useFetchPrivate';
import QueryPreview from '../QueryPreview';
import { usePrivateQuery } from '../context';
@@ -204,7 +209,26 @@ function ResolvedPreview({
onShowTransform,
}: ResolvedPreviewProps): React.ReactElement | null {
if (!preview) {
- return null;
+ return (
+ ({
+ my: theme.spacing(2),
+ mx: 'auto',
+ p: theme.spacing(1),
+ fontSize: theme.typography.pxToRem(11),
+ width: 'fit-content',
+ })}
+ >
+ No request has been sent yet.
+ Click Run
+
+ to preview the response here.
+
+ );
}
const { data, untransformedData } = preview;
@@ -248,9 +272,11 @@ function QueryEditor({
globalScopeMeta,
connectionParams: rawConnectionParams,
value: input,
- onChange: setInput,
+ settingsTab,
runtimeConfig,
}: QueryEditorProps) {
+ const appStateApi = useAppStateApi();
+ const { currentView } = useAppState();
const isBrowserSide = input.attributes.query.browser;
const connectionParams = isBrowserSide ? null : rawConnectionParams;
@@ -266,70 +292,89 @@ function QueryEditor({
{ retry: false },
);
+ const updateProp = React.useCallback(
+ function updateProp(prop: K, value: FetchQuery[K]) {
+ appStateApi.updateQueryDraft((draft) => ({
+ ...draft,
+ attributes: {
+ ...draft.attributes,
+ query: {
+ ...draft.attributes.query,
+ [prop]: value,
+ },
+ },
+ }));
+ },
+ [appStateApi],
+ );
+
const env = React.useMemo(() => introspection?.data?.env, [introspection]);
const handleParamsChange = React.useCallback(
(newParams: [string, BindableAttrValue][]) => {
- setInput((existing) => ({ ...existing, params: newParams }));
+ appStateApi.updateQueryDraft((draft) => ({
+ ...draft,
+ params: newParams,
+ }));
},
- [setInput],
+ [appStateApi],
);
const handleUrlChange = React.useCallback(
(newUrl: BindableAttrValue | null) => {
- setInput((existing) => appDom.setQueryProp(existing, 'url', newUrl || ''));
+ updateProp('url', newUrl ?? '');
},
- [setInput],
+ [updateProp],
);
const handleMethodChange = React.useCallback(
(event: React.ChangeEvent) => {
- setInput((existing) => appDom.setQueryProp(existing, 'method', event.target.value));
+ updateProp('method', event.target.value);
},
- [setInput],
+ [updateProp],
);
const handleTransformEnabledChange = React.useCallback(
(transformEnabled: boolean) => {
- setInput((existing) => appDom.setQueryProp(existing, 'transformEnabled', transformEnabled));
+ updateProp('transformEnabled', transformEnabled);
},
- [setInput],
+ [updateProp],
);
const handleTransformChange = React.useCallback(
(transform: string) => {
- setInput((existing) => appDom.setQueryProp(existing, 'transform', transform));
+ updateProp('transform', transform);
},
- [setInput],
+ [updateProp],
);
const handleBodyChange = React.useCallback(
(newBody: Maybe) => {
- setInput((existing) => appDom.setQueryProp(existing, 'body', newBody || undefined));
+ updateProp('body', newBody || undefined);
},
- [setInput],
+ [updateProp],
);
const handleSearchParamsChange = React.useCallback(
(newSearchParams: BindableAttrEntries) => {
- setInput((existing) => appDom.setQueryProp(existing, 'searchParams', newSearchParams));
+ updateProp('searchParams', newSearchParams);
},
- [setInput],
+ [updateProp],
);
const handleHeadersChange = React.useCallback(
(newHeaders: BindableAttrEntries) => {
- setInput((existing) => appDom.setQueryProp(existing, 'headers', newHeaders));
+ updateProp('headers', newHeaders);
},
- [setInput],
+ [updateProp],
);
const handleResponseTypeChange = React.useCallback(
(event: React.ChangeEvent) => {
- setInput((existing) =>
- appDom.setQueryProp(existing, 'response', { kind: event.target.value } as ResponseType),
- );
+ updateProp('response', {
+ kind: event.target.value,
+ } as ResponseType);
},
- [setInput],
+ [updateProp],
);
const paramsEntries = input.params || EMPTY_PARAMS;
@@ -371,7 +416,28 @@ function QueryEditor({
globalScope: queryScope,
});
- const [activeTab, setActiveTab] = React.useState('urlQuery');
+ const [configTab, setConfigTab] = React.useState('urlQuery');
+
+ const currentTab = React.useMemo(() => {
+ if (
+ currentView.kind === 'page' &&
+ currentView.view?.kind === 'query' &&
+ currentView.queryPanel?.currentTabIndex !== undefined
+ ) {
+ return currentView.queryPanel?.queryTabs?.[currentView.queryPanel?.currentTabIndex];
+ }
+ return null;
+ }, [currentView]);
+
+ const handleToolsTabTypeChange = React.useCallback(
+ (value: QueryEditorToolsTabType) => {
+ appStateApi.updateQueryTab((tab) => ({
+ ...tab,
+ toolsTabType: value,
+ }));
+ },
+ [appStateApi],
+ );
const fetchPrivate = useFetchPrivate();
const fetchPreview = React.useCallback(
@@ -381,42 +447,74 @@ function QueryEditor({
);
const [previewHar, setPreviewHar] = React.useState(() => createHarLog());
- const {
- preview,
- runPreview: handleRunPreview,
- isLoading: previewIsLoading,
- } = useQueryPreview(
+ const { preview, runPreview, isLoading } = useQueryPreview(
fetchPreview,
input.attributes.query,
previewParams as Record,
{
- onPreview(result) {
+ onPreview: React.useCallback((result: FetchResult) => {
setPreviewHar((existing) =>
result.har ? mergeHar(createHarLog(), existing, result.har) : existing,
);
- },
+ }, []),
},
);
const handleHarClear = React.useCallback(() => setPreviewHar(createHarLog()), []);
- const handleActiveTabChange = React.useCallback(
- (event: React.SyntheticEvent, newValue: string) => setActiveTab(newValue),
+ const handleConfigTabChange = React.useCallback(
+ (event: React.SyntheticEvent, newValue: string) => setConfigTab(newValue),
[],
);
- return (
-
-
-
-
-
-
- Query
-
+ const handleTabTypeChange = React.useCallback(
+ (event: React.SyntheticEvent, value: QueryEditorTabType) => {
+ appStateApi.updateQueryTab((tab) => ({
+ ...tab,
+ tabType: value,
+ }));
+ },
+ [appStateApi],
+ );
+
+ return currentTab ? (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
theme.typography.pxToRem(20),
+ },
+ }}
onChange={handleMethodChange}
>
{HTTP_METHODS.map((method) => (
@@ -438,11 +536,12 @@ function QueryEditor({
onChange={handleUrlChange}
/>
-
-
-
+
+
+
@@ -452,7 +551,7 @@ function QueryEditor({
-
+
-
+
-
+
-
+
@@ -500,7 +603,7 @@ function QueryEditor({
-
+
-
-
-
-
-
-
-
-
- Parameters
-
-
-
-
+
+
+
+ {settingsTab}
+
+
+
-
-
-
-
-
-
- setActiveTab('transform')}
- />
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+ handleToolsTabTypeChange(value)}
+ aria-label="Query tools active tab"
+ >
+
+
+
+ }
+ >
+ Run
+
+
+
+
+ setConfigTab('transform')}
+ />
+
+
+
+
+
+
+ ) : (
+
+ An error occurred while rendering this tab. Please refresh and try again.
+
);
}
@@ -570,7 +715,7 @@ function getInitialQueryValue(): FetchQuery {
}
const dataSource: ClientDataSource = {
- displayName: 'Fetch',
+ displayName: 'REST API',
ConnectionParamsInput,
QueryEditor,
getInitialQueryValue,
diff --git a/packages/toolpad-app/src/toolpadDataSources/rest/types.ts b/packages/toolpad-app/src/toolpadDataSources/rest/types.ts
index f7ea42e80e4..b9a3651977d 100644
--- a/packages/toolpad-app/src/toolpadDataSources/rest/types.ts
+++ b/packages/toolpad-app/src/toolpadDataSources/rest/types.ts
@@ -1,5 +1,5 @@
import { BindableAttrValue, ExecFetchResult } from '@mui/toolpad-core';
-import { Har } from 'har-format';
+import type { Har } from 'har-format';
import { Maybe } from '../../utils/types';
interface AuthenticationBase {
diff --git a/packages/toolpad-app/src/toolpadDataSources/sql/client.tsx b/packages/toolpad-app/src/toolpadDataSources/sql/client.tsx
index f2954051070..06880d8acfc 100644
--- a/packages/toolpad-app/src/toolpadDataSources/sql/client.tsx
+++ b/packages/toolpad-app/src/toolpadDataSources/sql/client.tsx
@@ -200,7 +200,7 @@ export function QueryEditor({
const handleParamsChange = React.useCallback(
(newParams: [string, BindableAttrValue][]) => {
- setInput((existing) => ({ ...existing, params: newParams }));
+ setInput?.((existing) => ({ ...existing, params: newParams }));
},
[setInput],
);
@@ -233,16 +233,16 @@ export function QueryEditor({
const previewGridKey = React.useMemo(() => getObjectKey(columns), [columns]);
return (
-
-
-
-
+
+
+
+
- setInput((existing) => appDom.setQueryProp(existing, 'sql', newValue))
+ setInput?.((existing) => appDom.setQueryProp(existing, 'sql', newValue))
}
language="sql"
/>
@@ -257,7 +257,7 @@ export function QueryEditor({
}}
/>
-
+
Parameters
-
+
dofetch: (query: Q, params: P) => Promise,
query: Q,
params: P,
- { onPreview = () => {} }: UseQueryPreviewOptions = {},
+ { onPreview }: UseQueryPreviewOptions = {},
) {
const [preview, setPreview] = React.useState(null);
- const [isLoading, setIsloading] = React.useState(false);
+ const [isLoading, setIsLoading] = React.useState(false);
const cancelRunPreview = React.useRef<(() => void) | null>(null);
const runPreview = React.useCallback(() => {
@@ -28,7 +28,7 @@ export default function useQueryPreview
canceled = true;
};
- setIsloading(true);
+ setIsLoading(true);
dofetch(query, params)
.then(
(result) => {
@@ -42,7 +42,7 @@ export default function useQueryPreview
},
)
.finally(() => {
- setIsloading(false);
+ setIsLoading(false);
cancelRunPreview.current = null;
});
}, [dofetch, query, params, onPreview]);
diff --git a/packages/toolpad-app/src/types.ts b/packages/toolpad-app/src/types.ts
index 04335e286fd..4e2189a637d 100644
--- a/packages/toolpad-app/src/types.ts
+++ b/packages/toolpad-app/src/types.ts
@@ -91,8 +91,7 @@ export type ConnectionParamsEditor = React.FC>;
export type Methods = Record Awaitable>;
-export interface QueryEditorProps
- extends WithControlledProp> {
+export interface QueryEditorProps {
connectionParams: Maybe;
execApi: (
query: K,
@@ -100,7 +99,10 @@ export interface QueryEditorProps
) => Promise>>;
globalScope: Record;
globalScopeMeta: ScopeMeta;
- onChange: React.Dispatch>>;
+ value: appDom.QueryNode;
+ onSave?: (newNode: appDom.QueryNode) => void;
+ settingsTab?: React.ReactNode;
+ onChange?: React.Dispatch>>;
onCommit?: () => void;
runtimeConfig: RuntimeConfig;
}
@@ -198,6 +200,8 @@ export type ProjectEvents = {
envChanged: {};
// Functions or datasources have been updated
functionsChanged: {};
+ // Pagesmanifest has changed
+ pagesManifestChanged: {};
};
export interface ToolpadProjectOptions {
diff --git a/packages/toolpad-app/src/utils/domView.ts b/packages/toolpad-app/src/utils/domView.ts
index 50a1384d401..347112df032 100644
--- a/packages/toolpad-app/src/utils/domView.ts
+++ b/packages/toolpad-app/src/utils/domView.ts
@@ -1,9 +1,36 @@
import { NodeId } from '@mui/toolpad-core';
import { matchPath } from 'react-router-dom';
+import { QueryNode, FetchMode } from '../appDom';
+
+export type QueryMeta = {
+ name?: string;
+ id?: NodeId;
+ dataSource?: string;
+ mode?: FetchMode;
+};
+
+export type QueryEditorTabType = 'config' | 'settings';
+
+export type QueryEditorToolsTabType = 'preview' | 'devTools';
+
+export type QueryTab = {
+ meta: QueryMeta;
+ saved?: QueryNode;
+ draft?: QueryNode;
+ tabType?: QueryEditorTabType;
+ toolsTabType: QueryEditorToolsTabType;
+ isPreviewLoading: boolean;
+ previewHandler?: () => void;
+};
+
+export type QueryPanel = {
+ queryTabs?: QueryTab[];
+ currentTabIndex?: number;
+};
const APP_PAGE_ROUTE = '/app/pages/:pageName';
-export type PageView = { kind: 'query'; nodeId: NodeId } | { kind: 'pageParameters' };
+export type PageView = { kind: 'query'; nodeId: NodeId };
export type PageViewTab = 'page' | 'component' | 'theme';
@@ -13,7 +40,9 @@ export type DomView = {
view?: PageView;
selectedNodeId?: NodeId | null;
hoveredNodeId?: NodeId | null;
- tab?: PageViewTab;
+ pageViewTab?: PageViewTab;
+ queryPanel?: QueryPanel;
+ pageParametersDialogOpen?: boolean;
};
export function getPathnameFromView(view: DomView): string {
@@ -32,7 +61,7 @@ export function getViewFromPathname(pathname: string): DomView | null {
kind: 'page',
name: pageRouteMatch.params.pageName,
selectedNodeId: null,
- tab: 'page',
+ pageViewTab: 'page',
};
}
diff --git a/packages/toolpad-app/src/utils/har.ts b/packages/toolpad-app/src/utils/har.ts
index 34a9344f93c..7e143dbeb11 100644
--- a/packages/toolpad-app/src/utils/har.ts
+++ b/packages/toolpad-app/src/utils/har.ts
@@ -1,4 +1,4 @@
-import { Har } from 'har-format';
+import type { Har } from 'har-format';
/**
* Initializes an empty HAR object.
diff --git a/packages/toolpad-app/src/utils/platform.tsx b/packages/toolpad-app/src/utils/platform.tsx
new file mode 100644
index 00000000000..7a78d7a8516
--- /dev/null
+++ b/packages/toolpad-app/src/utils/platform.tsx
@@ -0,0 +1,10 @@
+import * as React from 'react';
+
+function isMac(): boolean {
+ const userAgent = navigator.userAgent;
+ return /Mac|iPod|iPhone|iPad/.test(userAgent);
+}
+
+export function getModifierKey(): string | JSX.Element {
+ return isMac() ? '⌘' : Ctrl ;
+}
diff --git a/packages/toolpad-app/tsup.config.ts b/packages/toolpad-app/tsup.config.ts
index bb2e54dad2c..9ed6659cc31 100644
--- a/packages/toolpad-app/tsup.config.ts
+++ b/packages/toolpad-app/tsup.config.ts
@@ -25,7 +25,6 @@ export default defineConfig((options) => [
// Worker entry points
appServerWorker: './src/server/appServerWorker.ts',
appBuilderWorker: './src/server/appBuilderWorker.ts',
- functionsDevWorker: './src/server/functionsDevWorker.ts',
functionsTypesWorker: './src/server/functionsTypesWorker.ts',
},
format: ['esm'],
diff --git a/packages/toolpad-app/typings/node-fetch-har.d.ts b/packages/toolpad-app/typings/node-fetch-har.d.ts
index c607735be06..8dbc2620c80 100644
--- a/packages/toolpad-app/typings/node-fetch-har.d.ts
+++ b/packages/toolpad-app/typings/node-fetch-har.d.ts
@@ -1,5 +1,5 @@
declare module 'node-fetch-har' {
- import { Har } from 'har-format';
+ import type { Har } from 'har-format';
import fetch from 'node-fetch';
export interface WithHarOptions {
diff --git a/packages/toolpad-components/package.json b/packages/toolpad-components/package.json
index 73e8418cbbb..e7e8ad82bac 100644
--- a/packages/toolpad-components/package.json
+++ b/packages/toolpad-components/package.json
@@ -1,6 +1,6 @@
{
"name": "@mui/toolpad-components",
- "version": "0.1.41",
+ "version": "0.1.42",
"description": "Build MUI apps quickly",
"author": "MUI Toolpad team",
"homepage": "https://github.com/mui/mui-toolpad#readme",
@@ -38,24 +38,25 @@
"url": "https://github.com/mui/mui-toolpad/issues"
},
"dependencies": {
- "@mui/icons-material": "5.15.0",
- "@mui/lab": "5.0.0-alpha.156",
- "@mui/material": "5.15.0",
- "@mui/toolpad-core": "0.1.41",
- "@mui/toolpad-utils": "0.1.41",
- "@mui/x-charts": "6.18.3",
- "@mui/x-data-grid-pro": "6.18.4",
- "@mui/x-date-pickers": "6.18.4",
+ "@mui/icons-material": "5.15.1",
+ "@mui/lab": "5.0.0-alpha.157",
+ "@mui/material": "5.15.1",
+ "@mui/toolpad-core": "0.1.42",
+ "@mui/toolpad-utils": "0.1.42",
+ "@mui/x-charts": "6.18.4",
+ "@mui/x-data-grid-pro": "6.18.6",
+ "@mui/x-date-pickers": "6.18.6",
"@mui/x-license-pro": "6.10.2",
- "@tanstack/react-query": "5.13.4",
+ "@tanstack/react-query": "5.14.6",
"dayjs": "1.11.10",
"invariant": "2.2.4",
"markdown-to-jsx": "7.3.2",
- "react-error-boundary": "4.0.11",
- "react-hook-form": "7.49.0"
+ "react-error-boundary": "4.0.12",
+ "react-hook-form": "7.49.2"
},
"devDependencies": {
- "@types/react": "18.2.43",
+ "@types/invariant": "2.2.35",
+ "@types/react": "18.2.45",
"react": "18.2.0"
},
"peerDependencies": {
diff --git a/packages/toolpad-components/src/Autocomplete.tsx b/packages/toolpad-components/src/Autocomplete.tsx
index ff684d691e8..e21d996fb7c 100644
--- a/packages/toolpad-components/src/Autocomplete.tsx
+++ b/packages/toolpad-components/src/Autocomplete.tsx
@@ -8,7 +8,6 @@ import createBuiltin from './createBuiltin';
import { SX_PROP_HELPER_TEXT } from './constants';
import {
FORM_INPUT_ARG_TYPES,
- FORM_TEXT_INPUT_ARG_TYPES,
FormInputComponentProps,
useFormInput,
withComponentForm,
@@ -163,7 +162,6 @@ export default createBuiltin(FormWrappedAutocomplete, {
type: 'boolean',
},
...FORM_INPUT_ARG_TYPES,
- ...FORM_TEXT_INPUT_ARG_TYPES,
sx: {
helperText: SX_PROP_HELPER_TEXT,
type: 'object',
diff --git a/packages/toolpad-components/src/DataGrid.tsx b/packages/toolpad-components/src/DataGrid.tsx
index 41596090d6d..2819697c97e 100644
--- a/packages/toolpad-components/src/DataGrid.tsx
+++ b/packages/toolpad-components/src/DataGrid.tsx
@@ -25,6 +25,10 @@ import {
GridFilterModel,
GridSortModel,
GridNoRowsOverlay,
+ GridRowModes,
+ GridApiPro,
+ GridRowModesModel,
+ GridRowModel,
} from '@mui/x-data-grid-pro';
import {
Unstable_LicenseInfoProvider as LicenseInfoProvider,
@@ -56,8 +60,10 @@ import {
Alert,
Collapse,
} from '@mui/material';
-import DeleteIcon from '@mui/icons-material/Delete';
+import DeleteIcon from '@mui/icons-material/DeleteOutline';
import CloseIcon from '@mui/icons-material/Close';
+import SaveIcon from '@mui/icons-material/Save';
+import EditIcon from '@mui/icons-material/Edit';
import { getObjectKey } from '@mui/toolpad-utils/objectKey';
import { errorFrom } from '@mui/toolpad-utils/errors';
import { hasImageExtension } from '@mui/toolpad-utils/path';
@@ -404,7 +410,7 @@ export const CUSTOM_COLUMN_TYPES: Record = {
export interface SerializableGridColumn
extends Pick<
GridColDef,
- 'field' | 'type' | 'align' | 'width' | 'headerName' | 'sortable' | 'filterable'
+ 'field' | 'type' | 'align' | 'width' | 'headerName' | 'sortable' | 'filterable' | 'editable'
> {
numberFormat?: NumberFormat;
dateFormat?: DateFormat;
@@ -430,12 +436,16 @@ export function inferColumns(rows: GridRowsProp): SerializableGridColumns {
export function parseColumns(columns: SerializableGridColumns): GridColDef[] {
return columns.map((column) => {
- const customType = column.type ? CUSTOM_COLUMN_TYPES[column.type] : {};
+ let baseColumn: Omit = { editable: true };
+
+ if (column.type) {
+ baseColumn = { ...baseColumn, ...CUSTOM_COLUMN_TYPES[column.type] };
+ }
if (column.type === 'number' && column.numberFormat) {
const format = createNumberFormat(column.numberFormat);
return {
- ...customType,
+ ...baseColumn,
...column,
valueFormatter: ({ value }) => format.format(value),
};
@@ -444,7 +454,7 @@ export function parseColumns(columns: SerializableGridColumns): GridColDef[] {
if (column.type === 'date') {
const format = createDateFormat(column.dateFormat);
return {
- ...customType,
+ ...baseColumn,
...column,
valueFormatter: ({ value }) => {
try {
@@ -459,7 +469,7 @@ export function parseColumns(columns: SerializableGridColumns): GridColDef[] {
if (column.type === 'dateTime') {
const format = createDateFormat(column.dateTimeFormat);
return {
- ...customType,
+ ...baseColumn,
...column,
valueFormatter: ({ value }) => {
try {
@@ -473,7 +483,7 @@ export function parseColumns(columns: SerializableGridColumns): GridColDef[] {
const type = column.type && column.type in DEFAULT_COLUMN_TYPES ? column.type : undefined;
- return { ...customType, ...column, type };
+ return { ...baseColumn, ...column, type };
});
}
@@ -498,15 +508,14 @@ interface ToolpadDataGridProps extends Omit;
+ dataProvider: ToolpadDataProviderBase, PaginationMode>;
refetch: () => unknown;
}
function DeleteAction({ id, dataProvider, refetch }: DeleteActionProps) {
const [loading, setLoading] = React.useState(false);
- const setActionError = React.useContext(SetActionErrorContext);
- invariant(setActionError, 'setActionError must be defined');
+ const setActionError = useNonNullableContext(SetActionErrorContext);
const handleDeleteClick = React.useCallback(async () => {
invariant(dataProvider.deleteRecord, 'dataProvider must be defined');
@@ -535,6 +544,8 @@ interface DataProviderDataGridProps extends Partial {
function useDataProviderDataGridProps(
dataProviderId: string | null | undefined,
+ api: GridApiPro,
+ setActionError: (error: Error) => void,
): DataProviderDataGridProps {
const useDataProvider = useNonNullableContext(UseDataProviderContext);
const { dataProvider } = useDataProvider(dataProviderId || null);
@@ -594,6 +605,8 @@ function useDataProviderDataGridProps(
[rawSortModel],
);
+ const [rowModesModel, setRowModesModel] = React.useState({});
+
const {
data,
isFetching,
@@ -637,22 +650,99 @@ function useDataProviderDataGridProps(
: undefined) ??
0;
+ const [rowUpdating, setRowUpdating] = React.useState>>({});
+
+ const handleProcessRowUpdate = React.useCallback(
+ async (newRow: GridRowModel, oldRow: GridRowModel) => {
+ invariant(
+ dataProvider?.updateRecord,
+ 'Edit action should be unavailable when dataProvider.updateRecord is not defined',
+ );
+
+ // TODO: handle when idField is not 'id'
+ const idField = 'id';
+ const id = oldRow[idField];
+ const values = Object.fromEntries(
+ Object.entries(newRow).filter(([key, value]) => value !== oldRow[key]),
+ );
+
+ setRowUpdating((oldState) => ({ ...oldState, [id]: true }));
+ try {
+ await dataProvider.updateRecord(id, values);
+ return newRow;
+ } finally {
+ setRowUpdating((oldState) => {
+ const { [id]: discard, ...newState } = oldState;
+ return newState;
+ });
+ await refetch();
+ }
+ },
+ [dataProvider, refetch],
+ );
+
const getActions = React.useMemo(() => {
- if (!dataProvider?.deleteRecord) {
+ if (!dataProvider?.deleteRecord && !dataProvider?.updateRecord) {
return undefined;
}
return ({ id }) => {
const result = [];
- if (dataProvider?.deleteRecord) {
+ if (dataProvider.updateRecord) {
+ const rowIsInEditMode = rowModesModel[id]?.mode === GridRowModes.Edit;
+ const rowIsUpdating = rowUpdating[id];
+
+ if (rowIsInEditMode || rowIsUpdating) {
+ return [
+ {
+ api.stopRowEditMode({ id });
+ }}
+ >
+ {rowIsUpdating ? : }
+ ,
+ {
+ api.stopRowEditMode({ id, ignoreModifications: true });
+ }}
+ >
+
+ ,
+ ];
+ }
+
+ result.push(
+ {
+ api.startRowEditMode({ id });
+ }}
+ size="small"
+ aria-label={`Edit row with id "${id}"`}
+ >
+
+ ,
+ );
+ }
+
+ if (dataProvider.deleteRecord) {
result.push(
,
);
}
+
return result;
};
- }, [dataProvider, refetch]);
+ }, [api, dataProvider, refetch, rowModesModel, rowUpdating]);
if (!dataProvider) {
return {};
@@ -681,6 +771,11 @@ function useDataProviderDataGridProps(
rows: data?.records ?? [],
rowLoadingError,
getActions,
+ editMode: 'row',
+ rowModesModel,
+ onRowModesModelChange: (model) => setRowModesModel(model),
+ processRowUpdate: handleProcessRowUpdate,
+ onProcessRowUpdateError: (err) => setActionError(errorFrom(err)),
};
}
@@ -716,11 +811,18 @@ const DataGridComponent = React.forwardRef(function DataGridComponent(
}: ToolpadDataGridProps,
ref: React.ForwardedRef,
) {
+ const apiRef = useGridApiRef();
+ const [actionError, setActionError] = React.useState();
+
const {
rows: dataProviderRowsInput,
getActions: getProviderActions,
...dataProviderProps
- } = useDataProviderDataGridProps(rowsSource === 'dataProvider' ? dataProviderId : null);
+ } = useDataProviderDataGridProps(
+ rowsSource === 'dataProvider' ? dataProviderId : null,
+ apiRef.current,
+ setActionError,
+ );
const nodeRuntime = useNode();
@@ -777,8 +879,7 @@ const DataGridComponent = React.forwardRef(function DataGridComponent(
const hasExplicitRowId: boolean = React.useMemo(() => {
const hasRowIdField: boolean = !!(rowIdFieldProp && rowIdFieldProp !== 'id');
- const parsedRows = rowsInput;
- return parsedRows.length === 0 || hasRowIdField || !!parsedRows[0].id;
+ return hasRowIdField || rowsInput.length === 0 || rowsInput[0].id !== undefined;
}, [rowIdFieldProp, rowsInput]);
const rows: GridRowsProp = React.useMemo(
@@ -829,7 +930,6 @@ const DataGridComponent = React.forwardRef(function DataGridComponent(
[columnsProp],
);
- const apiRef = useGridApiRef();
React.useEffect(() => {
apiRef.current.updateColumns(columns);
}, [apiRef, columns]);
@@ -869,8 +969,6 @@ const DataGridComponent = React.forwardRef(function DataGridComponent(
return columns;
}, [columns, getProviderActions]);
- const [actionError, setActionError] = React.useState();
-
const open = !!actionError;
const lastActionError = useLatest(actionError);
diff --git a/packages/toolpad-components/src/DatePicker.tsx b/packages/toolpad-components/src/DatePicker.tsx
index cbb74654da4..1e43719716c 100644
--- a/packages/toolpad-components/src/DatePicker.tsx
+++ b/packages/toolpad-components/src/DatePicker.tsx
@@ -68,7 +68,7 @@ function getSnapshot() {
}
export interface DatePickerProps
- extends Omit, 'value' | 'onChange' | 'defaultValue'>,
+ extends Omit, 'value' | 'onChange' | 'defaultValue' | 'name'>,
Pick {
value?: string;
onChange: (newValue: string | null) => void;
diff --git a/packages/toolpad-components/src/Form.tsx b/packages/toolpad-components/src/Form.tsx
index acd105c91b9..50e4c830e1c 100644
--- a/packages/toolpad-components/src/Form.tsx
+++ b/packages/toolpad-components/src/Form.tsx
@@ -352,12 +352,14 @@ export const FORM_INPUT_ARG_TYPES: BuiltinArgTypeDefinitions<
type: 'string',
},
isRequired: {
+ label: 'Required',
helperText: 'Whether the input is required to have a value.',
type: 'boolean',
default: false,
category: 'validation',
},
isInvalid: {
+ label: 'Invalid',
helperText: 'Whether the input value is invalid.',
type: 'boolean',
default: false,
diff --git a/packages/toolpad-components/src/components/ErrorOverlay.tsx b/packages/toolpad-components/src/components/ErrorOverlay.tsx
index 160b387ce8b..fa67d6f9b45 100644
--- a/packages/toolpad-components/src/components/ErrorOverlay.tsx
+++ b/packages/toolpad-components/src/components/ErrorOverlay.tsx
@@ -29,7 +29,7 @@ export function ErrorContent({ sx, error }: ErrorContentProps) {
);
}
-const ErrorOverlay = styled(ErrorContent)(({ theme }) => ({
+const ErrorOverlay: React.ComponentType = styled(ErrorContent)(({ theme }) => ({
position: 'absolute',
inset: '0 0 0 0',
borderWidth: 1,
diff --git a/packages/toolpad-core/package.json b/packages/toolpad-core/package.json
index 59c70d837da..1c5871e7837 100644
--- a/packages/toolpad-core/package.json
+++ b/packages/toolpad-core/package.json
@@ -1,6 +1,6 @@
{
"name": "@mui/toolpad-core",
- "version": "0.1.41",
+ "version": "0.1.42",
"description": "Build MUI apps quickly",
"author": "MUI Toolpad team",
"homepage": "https://github.com/mui/mui-toolpad#readme",
@@ -40,19 +40,20 @@
"url": "https://github.com/mui/mui-toolpad/issues"
},
"dependencies": {
- "@mui/material": "5.15.0",
- "@mui/toolpad-utils": "0.1.41",
- "@tanstack/react-query": "5.13.4",
+ "@mui/material": "5.15.1",
+ "@mui/toolpad-utils": "0.1.42",
+ "@tanstack/react-query": "5.14.6",
"@types/json-schema": "7.0.15",
+ "@webcontainer/env": "1.1.0",
"cookie": "0.6.0",
"invariant": "2.2.4",
"quickjs-emscripten": "0.24.0",
- "react-error-boundary": "4.0.11",
+ "react-error-boundary": "4.0.12",
"react-is": "18.2.0"
},
"devDependencies": {
"@types/cookie": "0.6.0",
- "@types/react": "18.2.43",
+ "@types/react": "18.2.45",
"@types/react-is": "18.2.4",
"concurrently": "8.2.2"
},
diff --git a/packages/toolpad-core/src/runtime.tsx b/packages/toolpad-core/src/runtime.tsx
index a4604d85f4a..e0c89d07561 100644
--- a/packages/toolpad-core/src/runtime.tsx
+++ b/packages/toolpad-core/src/runtime.tsx
@@ -296,16 +296,23 @@ export function useComponent(id: string) {
export interface ToolpadDataProviderIntrospection {
paginationMode: PaginationMode;
hasDeleteRecord: boolean;
+ hasUpdateRecord: boolean;
+ hasCreateRecord: boolean;
}
-export interface UseDataProviderHookResult {
+export interface UseDataProviderHookResult<
+ R extends Record,
+ P extends PaginationMode,
+> {
isLoading: boolean;
error?: unknown;
dataProvider: ToolpadDataProviderBase | null;
}
export interface UseDataProviderHook {
- (id: string | null): UseDataProviderHookResult;
+ , P extends PaginationMode>(
+ id: string | null,
+ ): UseDataProviderHookResult;
}
export const UseDataProviderContext = React.createContext(null);
diff --git a/packages/toolpad-core/src/server.ts b/packages/toolpad-core/src/server.ts
index 330a3ea7fd7..ad781515cc1 100644
--- a/packages/toolpad-core/src/server.ts
+++ b/packages/toolpad-core/src/server.ts
@@ -8,7 +8,7 @@ import {
PropValueType,
ToolpadDataProviderBase,
} from './types';
-import { ServerContext, getServerContext } from './serverRuntime';
+import { ServerContext, __initContextStore, getServerContext } from './serverRuntime';
/**
* The runtime configuration for a Toolpad function. Describes the parameters it accepts and their
@@ -118,8 +118,10 @@ export function getContext(): ServerContext {
export const TOOLPAD_DATA_PROVIDER_MARKER = Symbol.for('TOOLPAD_DATA_PROVIDER_MARKER');
-export interface ToolpadDataProvider
- extends ToolpadDataProviderBase {
+export interface ToolpadDataProvider<
+ R extends Record,
+ P extends PaginationMode = 'index',
+> extends ToolpadDataProviderBase {
[TOOLPAD_DATA_PROVIDER_MARKER]: true;
}
@@ -135,8 +137,11 @@ export interface ToolpadDataProvider
* - [`createDataProvider` API](https://mui.com/toolpad/reference/api/create-data-provider/)
*
*/
-export function createDataProvider(
- input: ToolpadDataProviderBase,
-): ToolpadDataProvider {
+export function createDataProvider<
+ R extends Record,
+ P extends PaginationMode = 'index',
+>(input: ToolpadDataProviderBase): ToolpadDataProvider {
return Object.assign(input, { [TOOLPAD_DATA_PROVIDER_MARKER]: true as const });
}
+
+export { __initContextStore };
diff --git a/packages/toolpad-core/src/serverRuntime.ts b/packages/toolpad-core/src/serverRuntime.ts
index 63c29cd5ad3..9b1cdaef94a 100644
--- a/packages/toolpad-core/src/serverRuntime.ts
+++ b/packages/toolpad-core/src/serverRuntime.ts
@@ -1,6 +1,7 @@
import { AsyncLocalStorage } from 'node:async_hooks';
import { IncomingMessage, ServerResponse } from 'node:http';
import * as cookie from 'cookie';
+import { isWebContainer } from '@webcontainer/env';
export interface ServerContext {
/**
@@ -17,7 +18,11 @@ let contextStore = new AsyncLocalStorage();
export const initialContextStore = contextStore;
-export function initStore(store: AsyncLocalStorage) {
+/**
+ * INTERNAL: Do not use
+ */
+// eslint-disable-next-line no-underscore-dangle, @typescript-eslint/naming-convention
+export function __initContextStore(store: AsyncLocalStorage) {
contextStore = store;
}
@@ -36,5 +41,14 @@ export function createServerContext(req: IncomingMessage, res: ServerResponse):
}
export function withContext(ctx: ServerContext, doWork: () => Promise): Promise {
+ const shouldBypassContext = isWebContainer();
+
+ if (shouldBypassContext) {
+ console.warn(
+ 'Bypassing server context in web containers, see https://github.com/stackblitz/core/issues/2711',
+ );
+ return doWork();
+ }
+
return contextStore.run(ctx, doWork);
}
diff --git a/packages/toolpad-core/src/types.ts b/packages/toolpad-core/src/types.ts
index 09fe514fcca..06ed3f00cf5 100644
--- a/packages/toolpad-core/src/types.ts
+++ b/packages/toolpad-core/src/types.ts
@@ -363,7 +363,7 @@ export type ScopeMetaField = {
props?: Record;
}
| {
- kind: 'query' | 'local';
+ kind: 'query' | 'action' | 'local';
}
);
@@ -541,12 +541,15 @@ export interface GetRecordsResult {
cursor?: P extends 'cursor' ? string | null : undefined;
}
-export interface ToolpadDataProviderBase {
+export interface ToolpadDataProviderBase<
+ R extends Record = {},
+ P extends PaginationMode = 'index',
+> {
paginationMode?: P;
getRecords: (params: GetRecordsParams) => Promise>;
deleteRecord?: (id: string | number) => Promise;
- // updateRecord?: (id: string | number, record: R) => Promise;
- // createRecord?: (record: R) => Promise;
+ updateRecord?: (id: string | number, record: Partial) => Promise;
+ createRecord?: (record: R) => Promise;
}
export type NodeHashes = Record;
diff --git a/packages/toolpad-utils/package.json b/packages/toolpad-utils/package.json
index bed9d5da2b4..7cb28b96022 100644
--- a/packages/toolpad-utils/package.json
+++ b/packages/toolpad-utils/package.json
@@ -1,6 +1,6 @@
{
"name": "@mui/toolpad-utils",
- "version": "0.1.41",
+ "version": "0.1.42",
"description": "Build MUI apps quickly",
"author": "MUI Toolpad team",
"homepage": "https://github.com/mui/mui-toolpad#readme",
@@ -55,13 +55,15 @@
"invariant": "2.2.4",
"prettier": "2.8.8",
"react-is": "18.2.0",
+ "title": "3.5.3",
"yaml": "2.3.4",
"yaml-diff-patch": "2.0.0"
},
"devDependencies": {
"@types/invariant": "2.2.37",
"@types/prettier": "2.7.3",
- "@types/react": "18.2.43",
- "@types/react-is": "18.2.4"
+ "@types/react": "18.2.45",
+ "@types/react-is": "18.2.4",
+ "@types/title": "3.4.3"
}
}
diff --git a/packages/toolpad-utils/src/fs.ts b/packages/toolpad-utils/src/fs.ts
index 6b9efe5e1e7..840bbc5c35c 100644
--- a/packages/toolpad-utils/src/fs.ts
+++ b/packages/toolpad-utils/src/fs.ts
@@ -32,20 +32,20 @@ export async function readMaybeFile(filePath: string): Promise {
return await fs.readFile(filePath, { encoding: 'utf-8' });
} catch (rawError) {
const error = errorFrom(rawError);
- if (error.code === 'ENOENT') {
+ if (error.code === 'ENOENT' || error.code === 'EISDIR') {
return null;
}
throw error;
}
}
-export async function readMaybeDir(dirPath: string): Promise {
+export async function readMaybeDir(dirPath: string): Promise {
try {
return await fs.readdir(dirPath, { withFileTypes: true });
} catch (rawError: unknown) {
const error = errorFrom(rawError);
- if (errorFrom(error).code === 'ENOENT') {
- return null;
+ if (error.code === 'ENOENT' || error.code === 'ENOTDIR') {
+ return [];
}
throw error;
}
diff --git a/packages/toolpad-utils/src/hooks/index.ts b/packages/toolpad-utils/src/hooks/index.ts
index e343dec392b..e847138d45f 100644
--- a/packages/toolpad-utils/src/hooks/index.ts
+++ b/packages/toolpad-utils/src/hooks/index.ts
@@ -1,2 +1,2 @@
-export { default as useBoolean } from './useBoolean.js';
-export { default as usePageTitle } from './usePageTitle.js';
+export { default as useBoolean } from './useBoolean';
+export { default as usePageTitle } from './usePageTitle';
diff --git a/packages/toolpad-utils/src/strings.spec.ts b/packages/toolpad-utils/src/strings.spec.ts
index b5d0d5fbe83..d5dde09d606 100644
--- a/packages/toolpad-utils/src/strings.spec.ts
+++ b/packages/toolpad-utils/src/strings.spec.ts
@@ -1,5 +1,12 @@
import { describe, test, expect } from 'vitest';
-import { findImports, capitalize, uncapitalize, pascalCase, camelCase } from './strings';
+import {
+ findImports,
+ capitalize,
+ uncapitalize,
+ pascalCase,
+ camelCase,
+ guessTitle,
+} from './strings';
describe('findImports', () => {
test('finds all imports', () => {
@@ -87,3 +94,19 @@ describe('camelCase', () => {
expect(camelCase(...got)).toEqual(expected);
});
});
+
+describe('guessTitle', () => {
+ test.each([
+ ['camelCaseExample', 'Camel Case Example'],
+ ['snake_case_example', 'Snake Case Example'],
+ ['kebab-case-example', 'Kebab Case Example'],
+ ['ACRONYMExample', 'Acronym Example'],
+ ['helloACRONYMExample', 'Hello Acronym Example'],
+ ['HelloACRONYMExample', 'Hello Acronym Example'],
+ ['example123', 'Example 123'],
+ ['example123Wat', 'Example 123 Wat'],
+ ['example123more456', 'Example 123 More 456'],
+ ])('should split %p into %p', (got, expected) => {
+ expect(guessTitle(got)).toEqual(expected);
+ });
+});
diff --git a/packages/toolpad-utils/src/strings.ts b/packages/toolpad-utils/src/strings.ts
index 1b5e02e439e..7b90460600d 100644
--- a/packages/toolpad-utils/src/strings.ts
+++ b/packages/toolpad-utils/src/strings.ts
@@ -1,3 +1,5 @@
+import title from 'title';
+
/**
* Makes the first letter of [str] uppercase.
* Not locale aware.
@@ -171,3 +173,17 @@ export function indent(text: string, length = 2): string {
export function isValidJsIdentifier(base: string): boolean {
return /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(base);
}
+
+export function guessTitle(str: string): string {
+ // Replace snake_case with space
+ str = str.replace(/[_-]/g, ' ');
+ // Split camelCase
+ str = str.replace(/([a-z0-9])([A-Z])/g, '$1 $2');
+ // Split acronyms
+ str = str.replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2');
+ // Split numbers
+ str = str.replace(/([a-zA-Z])(\d+)/g, '$1 $2');
+ str = str.replace(/(\d+)([a-zA-Z])/g, '$1 $2');
+
+ return title(str);
+}
diff --git a/test/integration/backend-basic/fixture/toolpad/pages/basic/page.yml b/test/integration/backend-basic/fixture/toolpad/pages/basic/page.yml
index 61bda8e54c0..610fbc72da2 100644
--- a/test/integration/backend-basic/fixture/toolpad/pages/basic/page.yml
+++ b/test/integration/backend-basic/fixture/toolpad/pages/basic/page.yml
@@ -240,3 +240,9 @@ spec:
query:
function: functions.ts#setCustomCookie
kind: local
+ - name: action
+ mode: mutation
+ query:
+ kind: rest
+ headers: []
+ method: GET
diff --git a/test/integration/backend-basic/fixture/toolpad/resources/myCrudData.ts b/test/integration/backend-basic/fixture/toolpad/resources/myCrudData.ts
index a032a8b1165..538335faf26 100644
--- a/test/integration/backend-basic/fixture/toolpad/resources/myCrudData.ts
+++ b/test/integration/backend-basic/fixture/toolpad/resources/myCrudData.ts
@@ -11,4 +11,8 @@ export default createDataProvider({
async deleteRecord(id) {
DATA = DATA.filter((item) => item.id !== id);
},
+
+ async updateRecord(id, updates) {
+ DATA = DATA.map((item) => (item.id === id ? { ...item, ...updates } : item));
+ },
});
diff --git a/test/integration/backend-basic/index.spec.ts b/test/integration/backend-basic/index.spec.ts
index a0a77e80e2a..50afd0818c7 100644
--- a/test/integration/backend-basic/index.spec.ts
+++ b/test/integration/backend-basic/index.spec.ts
@@ -10,6 +10,7 @@ import { expectBasicRuntimeTests } from './shared';
import { setPageHidden } from '../../utils/page';
import { withTemporaryEdits } from '../../utils/fs';
import clickCenter from '../../utils/clickCenter';
+import { cellLocator } from '../../utils/locators';
const currentDirectory = url.fileURLToPath(new URL('.', import.meta.url));
@@ -80,15 +81,15 @@ test('function editor parameters update', async ({ page, localApp, argosScreensh
const editorModel = new ToolpadEditor(page);
await editorModel.goToPage('basic');
- await editorModel.pageEditor.getByRole('button', { name: 'withParams' }).click();
+ await editorModel.queriesExplorer.getByText('withParams').click();
- const queryEditor = page.getByRole('dialog', { name: 'withParams' });
- await expect(queryEditor).toBeVisible();
- await expect(queryEditor.getByLabel('foo', { exact: true })).toBeVisible();
- await expect(queryEditor.getByLabel('bar', { exact: true })).not.toBeVisible();
+ const queryEditorTab = page.getByRole('tabpanel', { name: 'withParams' });
+ await expect(queryEditorTab).toBeVisible();
+ await expect(queryEditorTab.getByLabel('foo', { exact: true })).toBeVisible();
+ await expect(queryEditorTab.getByLabel('bar', { exact: true })).not.toBeVisible();
await argosScreenshot('function-editor', {
- clip: (await queryEditor.boundingBox()) || undefined,
+ clip: (await queryEditorTab.boundingBox()) || undefined,
});
await setPageHidden(page, true); // simulate page hidden
@@ -101,7 +102,7 @@ test('function editor parameters update', async ({ page, localApp, argosScreensh
await setPageHidden(page, false); // simulate page restored
- await expect(queryEditor.getByLabel('bar', { exact: true })).toBeVisible();
+ await expect(queryEditorTab.getByLabel('bar', { exact: true })).toBeVisible();
});
test('bound parameters are preserved on manual call', async ({ page }) => {
@@ -178,24 +179,33 @@ test('function editor extracted parameters', async ({ page, localApp }) => {
const editorModel = new ToolpadEditor(page);
await editorModel.goToPage('extractedTypes');
- await editorModel.pageEditor.getByRole('button', { name: 'bareWithParams' }).click();
- const queryEditor = page.getByRole('dialog', { name: 'bareWithParams' });
+ await editorModel.queriesExplorer.getByText('bareWithParams').click();
- await queryEditor.getByRole('button', { name: 'Preview', exact: true }).click();
- await queryEditor
+ await editorModel.queryEditorPanel.getByRole('button', { name: 'Run' }).click();
+ await editorModel.queryEditorPanel
.getByTestId('query-preview')
.getByText(
'bare function with parameters: foo: bar; typeof bar: number; quux: true; baz.hello: 5',
);
- await expect(queryEditor).toBeVisible();
- await expect(queryEditor.getByRole('checkbox', { name: 'quux', exact: true })).toBeVisible();
- await expect(queryEditor.getByRole('textbox', { name: 'foo', exact: true })).toBeVisible();
- await expect(queryEditor.getByRole('textbox', { name: 'foo', exact: true })).toBeVisible();
- await expect(queryEditor.getByRole('button', { name: 'baz', exact: true })).toBeVisible();
- await expect(queryEditor.getByRole('spinbutton', { name: 'bar', exact: true })).toBeVisible();
+ await expect(editorModel.queryEditorPanel).toBeVisible();
+ await expect(
+ editorModel.queryEditorPanel.getByRole('checkbox', { name: 'quux', exact: true }),
+ ).toBeVisible();
+ await expect(
+ editorModel.queryEditorPanel.getByRole('textbox', { name: 'foo', exact: true }),
+ ).toBeVisible();
+ await expect(
+ editorModel.queryEditorPanel.getByRole('button', { name: 'baz', exact: true }),
+ ).toBeVisible();
+ await expect(
+ editorModel.queryEditorPanel.getByRole('spinbutton', { name: 'bar', exact: true }),
+ ).toBeVisible();
- const fizzCombobox = queryEditor.getByRole('combobox', { name: 'fizz', exact: true });
+ const fizzCombobox = editorModel.queryEditorPanel.getByRole('combobox', {
+ name: 'fizz',
+ exact: true,
+ });
await expect(fizzCombobox).toBeVisible();
await fizzCombobox.click();
@@ -203,7 +213,9 @@ test('function editor extracted parameters', async ({ page, localApp }) => {
await expect(page.getByRole('option', { name: 'world', exact: true })).toBeVisible();
await page.keyboard.press('Escape');
- await expect(queryEditor.getByRole('textbox', { name: 'buzz', exact: true })).not.toBeVisible();
+ await expect(
+ editorModel.queryEditorPanel.getByRole('textbox', { name: 'buzz', exact: true }),
+ ).not.toBeVisible();
await setPageHidden(page, true); // simulate page hidden
@@ -215,7 +227,9 @@ test('function editor extracted parameters', async ({ page, localApp }) => {
await setPageHidden(page, false); // simulate page restored
- await expect(queryEditor.getByRole('textbox', { name: 'buzz', exact: true })).toBeVisible();
+ await expect(
+ editorModel.queryEditorPanel.getByRole('textbox', { name: 'buzz', exact: true }),
+ ).toBeVisible();
});
test('data providers', async ({ page }) => {
@@ -262,4 +276,25 @@ test('data providers crud', async ({ page }) => {
await grid.getByRole('button', { name: 'Delete row with id "5"', exact: true }).click();
await expect(grid.getByText('Index item 5')).not.toBeVisible();
+
+ await grid.getByRole('button', { name: 'Edit row with id "7"', exact: true }).click();
+
+ await cellLocator(grid, 8, 1).getByRole('textbox').fill('edited');
+
+ await grid.getByRole('button', { name: 'Cancel updates', exact: true }).click();
+
+ await expect(cellLocator(grid, 8, 1)).toHaveText('Index item 7');
+
+ await grid.getByRole('button', { name: 'Edit row with id "7"', exact: true }).click();
+
+ await cellLocator(grid, 8, 1).getByRole('textbox').fill('edited');
+
+ await grid.getByRole('button', { name: 'Save updates to row with id "7"', exact: true }).click();
+
+ await expect(cellLocator(grid, 8, 1)).toHaveText('edited');
+
+ await expect(grid.getByRole('button', { name: 'Cancel updates', exact: true })).not.toBeVisible();
+ await expect(
+ grid.getByRole('button', { name: 'Save updates to row with id "7"', exact: true }),
+ ).not.toBeVisible();
});
diff --git a/test/integration/data-grid/basic.spec.ts b/test/integration/data-grid/basic.spec.ts
index d86d3eec6e0..1dc91091892 100644
--- a/test/integration/data-grid/basic.spec.ts
+++ b/test/integration/data-grid/basic.spec.ts
@@ -1,8 +1,9 @@
import * as path from 'path';
import * as url from 'url';
import { ToolpadEditor } from '../../models/ToolpadEditor';
-import { test, expect, Locator } from '../../playwright/localTest';
+import { test, expect } from '../../playwright/localTest';
import clickCenter from '../../utils/clickCenter';
+import { cellLocator } from '../../utils/locators';
const currentDirectory = url.fileURLToPath(new URL('.', import.meta.url));
@@ -56,12 +57,6 @@ test('Column prop updates are not lost on drag interactions', async ({ page }) =
).toBeVisible();
});
-function cellLocator(gridLocator: Locator, rowIndex: number, collIndex: number) {
- return gridLocator
- .locator(`[aria-rowindex="${rowIndex}"]`)
- .locator(`[aria-colindex="${collIndex}"]`);
-}
-
test('Date columns', async ({ page }) => {
const editorModel = new ToolpadEditor(page);
editorModel.goToPage('dateColumns');
diff --git a/test/integration/duplication/index.spec.ts b/test/integration/duplication/index.spec.ts
index ebb581600c3..c4a68d7ffea 100644
--- a/test/integration/duplication/index.spec.ts
+++ b/test/integration/duplication/index.spec.ts
@@ -19,7 +19,7 @@ test('duplication', async ({ page }) => {
await editorModel.goto();
{
- await editorModel.openPageExplorerMenu('page1');
+ await editorModel.openPageExplorerMenu('Page 1');
const duplicateMenuItem = page.getByRole('menuitem', { name: 'Duplicate' });
await duplicateMenuItem.click();
@@ -28,12 +28,12 @@ test('duplication', async ({ page }) => {
const button = editorModel.appCanvas.getByRole('button', { name: 'hello world' });
await expect(button).toBeVisible();
- await editorModel.openPageExplorerMenu('page2');
+ await editorModel.openPageExplorerMenu('Page 2');
const deleteMenuItem = page.getByRole('menuitem', { name: 'Delete' });
await deleteMenuItem.click();
const deleteButton = editorModel.confirmationDialog.getByRole('button', { name: 'Delete' });
await deleteButton.click();
- await expect(editorModel.getExplorerItem('page2')).toBeHidden();
+ await expect(editorModel.getExplorerItem('Page 2')).toBeHidden();
}
});
diff --git a/test/integration/editor/new.spec.ts b/test/integration/editor/new.spec.ts
index d4c48c0b183..95fadfda6c3 100644
--- a/test/integration/editor/new.spec.ts
+++ b/test/integration/editor/new.spec.ts
@@ -29,7 +29,8 @@ test('can place new components from catalog', async ({ page }) => {
await expect(canvasInputLocator).toHaveCount(1);
await expect(canvasInputLocator).toBeVisible();
- expect(await page.getByLabel('Node name').inputValue()).toBe('textField');
+
+ await expect(editorModel.componentEditor.getByText('textField')).toBeVisible();
// Drag in a second component
@@ -63,7 +64,7 @@ test('can create/delete page', async ({ page, localApp }) => {
await editorModel.createPage('someOtherPage');
- const pageMenuItem = editorModel.getExplorerItem('someOtherPage');
+ const pageMenuItem = editorModel.getExplorerItem('Some Other Page');
const pageFolder = path.resolve(localApp.dir, './toolpad/pages/someOtherPage');
const pageFile = path.resolve(pageFolder, './page.yml');
diff --git a/test/integration/pages/index.spec.ts b/test/integration/pages/index.spec.ts
index 699d83fbc26..87bbcda482c 100644
--- a/test/integration/pages/index.spec.ts
+++ b/test/integration/pages/index.spec.ts
@@ -56,7 +56,7 @@ test('can rename page', async ({ page, localApp }) => {
const oldPageFolder = path.resolve(localApp.dir, './toolpad/pages/page2');
await expect.poll(async () => folderExists(oldPageFolder)).toBe(true);
- await editorModel.explorer.getByText('page2').dblclick();
+ await editorModel.explorer.getByText('Page 2').dblclick();
await page.keyboard.type('renamedpage');
await page.keyboard.press('Enter');
diff --git a/test/integration/propControls/basic.spec.ts b/test/integration/propControls/basic.spec.ts
index f3e394667e2..dda7f851275 100644
--- a/test/integration/propControls/basic.spec.ts
+++ b/test/integration/propControls/basic.spec.ts
@@ -29,9 +29,7 @@ test('can control component prop values in properties control panel', async ({ p
const firstInputLocator = canvasInputLocator.first();
await clickCenter(page, firstInputLocator);
- await editorModel.componentEditor
- .locator('h6:has-text("Text Field")')
- .waitFor({ state: 'visible' });
+ await editorModel.componentEditor.getByText('textField1').waitFor({ state: 'visible' });
const labelControlInput = editorModel.componentEditor.getByLabel('label', { exact: true });
@@ -70,9 +68,7 @@ test('can toggle boolean prop that is true by default', async ({ page }) => {
await clickCenter(page, autocomplete);
- await editorModel.componentEditor
- .locator('h6:has-text("Autocomplete")')
- .waitFor({ state: 'visible' });
+ await editorModel.componentEditor.getByText('autocomplete').waitFor({ state: 'visible' });
const fullWidthControlInput = editorModel.componentEditor.getByLabel('fullWidth', {
exact: true,
diff --git a/test/integration/rest-basic/index.spec.ts b/test/integration/rest-basic/index.spec.ts
index 8fd1409aa80..f3a2b03377d 100644
--- a/test/integration/rest-basic/index.spec.ts
+++ b/test/integration/rest-basic/index.spec.ts
@@ -71,19 +71,19 @@ test('rest editor basics', async ({ page, context, localApp, argosScreenshot })
await editorModel.goto();
await editorModel.waitForOverlay();
- await editorModel.pageEditor.getByRole('button', { name: 'Add query' }).click();
- await page.getByRole('button', { name: 'HTTP request' }).click();
+ await editorModel.queriesExplorer.getByLabel('Create new query').click();
+ await page.getByRole('button', { name: 'REST API' }).click();
- const newQueryEditor = page.getByRole('dialog', { name: 'query' });
+ const queryEditor = editorModel.queryEditorPanel;
- await expect(newQueryEditor).toBeVisible();
+ await expect(queryEditor).toBeVisible();
- const urlInput = newQueryEditor.getByLabel('url', { exact: true });
+ const urlInput = queryEditor.getByLabel('url', { exact: true });
await urlInput.click();
await urlInput.fill('http://foo.bar');
await argosScreenshot('rest-editor', {
- clip: (await newQueryEditor.boundingBox()) || undefined,
+ clip: (await queryEditor.boundingBox()) || undefined,
});
const envFilePath = path.resolve(localApp.dir, './.env');
@@ -93,33 +93,33 @@ test('rest editor basics', async ({ page, context, localApp, argosScreenshot })
await expect(editorModel.appCanvas.getByText('query4 authorization: bar')).toBeVisible();
});
- // Make sure switching tabs does not close query editor
+ // Make sure switching tabs does not close query editor`
const newTab = await context.newPage();
await newTab.bringToFront();
await page.bringToFront();
await newTab.close();
- await expect(newQueryEditor).toBeVisible();
+ await expect(queryEditor).toBeVisible();
- await newQueryEditor.getByRole('button', { name: 'Save' }).click();
- await expect(newQueryEditor).not.toBeVisible();
+ await page.getByLabel('Unsaved changes 1').hover();
+ page.on('dialog', (dialog) => dialog.accept());
+ await page.getByLabel('Close query tab 1').click();
+ await expect(queryEditor).not.toBeVisible();
- await editorModel.pageEditor.getByRole('button', { name: 'query1' }).click();
+ await editorModel.queriesExplorer.getByText('query1').click();
- const existingQueryEditor = page.getByRole('dialog', { name: 'query1' });
+ await expect(queryEditor).toBeVisible();
- await expect(existingQueryEditor).toBeVisible();
-
- await existingQueryEditor.getByRole('button', { name: 'Preview' }).click();
- const networkTab = existingQueryEditor.getByRole('tabpanel', { name: 'Network' });
+ await queryEditor.getByRole('button', { name: 'Run' }).click();
+ await queryEditor.getByRole('tab', { name: 'Dev Tools' }).click();
+ const networkTab = queryEditor.getByRole('tabpanel', { name: 'Dev Tools' });
await expect(networkTab.getByText('/get?query1_param1=query1_value')).not.toBeEmpty();
- await newQueryEditor.getByRole('tab', { name: 'Headers' }).click();
+ await queryEditor.getByRole('tab', { name: 'Headers' }).click();
- await existingQueryEditor.getByRole('button', { name: 'Cancel' }).click();
- await expect(existingQueryEditor).not.toBeVisible();
+ await page.getByLabel('Close query tab 1').click();
+ await expect(queryEditor).not.toBeVisible();
- await editorModel.pageEditor.getByRole('button', { name: 'queryWithEnv' }).click();
+ await editorModel.queriesExplorer.getByText('queryWithEnv').click();
- const queryWithEnvQueryEditor = page.getByRole('dialog', { name: 'queryWithEnv' });
- await queryWithEnvQueryEditor.getByRole('tab', { name: 'Headers' }).click();
+ await queryEditor.getByRole('tab', { name: 'Headers' }).click();
});
diff --git a/test/integration/undo-redo/multiple-pages.spec.ts b/test/integration/undo-redo/multiple-pages.spec.ts
index 2061ea6f382..038c0958461 100644
--- a/test/integration/undo-redo/multiple-pages.spec.ts
+++ b/test/integration/undo-redo/multiple-pages.spec.ts
@@ -25,7 +25,7 @@ test('test undo and redo through different pages', async ({ page }) => {
});
await expect(pageButton1).toBeVisible();
- await editorModel.explorer.getByText('page2').click();
+ await editorModel.explorer.getByText('Page 2').click();
const pageButton2 = editorModel.appCanvas.getByRole('button', {
name: 'page2Button',
diff --git a/test/models/ToolpadEditor.ts b/test/models/ToolpadEditor.ts
index 2a0da4d9343..3dbb53fe344 100644
--- a/test/models/ToolpadEditor.ts
+++ b/test/models/ToolpadEditor.ts
@@ -47,8 +47,12 @@ export class ToolpadEditor {
readonly explorer: Locator;
+ readonly queriesExplorer: Locator;
+
readonly confirmationDialog: Locator;
+ readonly queryEditorPanel: Locator;
+
constructor(page: Page) {
this.page = page;
@@ -68,7 +72,9 @@ export class ToolpadEditor {
this.pageOverlay = this.appCanvas.getByTestId('page-overlay');
this.explorer = page.getByTestId('pages-explorer');
+ this.queriesExplorer = page.getByTestId('query-explorer');
this.confirmationDialog = page.getByRole('dialog').filter({ hasText: 'Confirm' });
+ this.queryEditorPanel = page.getByRole('tabpanel', { name: 'Query editor panel', exact: true });
}
async goto() {
diff --git a/test/package.json b/test/package.json
index 61ca8221eae..ac4ab1caf2d 100644
--- a/test/package.json
+++ b/test/package.json
@@ -2,15 +2,14 @@
"name": "@mui/toolpad-tests",
"private": true,
"devDependencies": {
+ "@mui/material": "5.15.1",
"@mui/toolpad": "workspace:*",
+ "@mui/toolpad-utils": "workspace:*",
+ "express": "4.18.2",
"get-port": "7.0.0",
"invariant": "2.2.4",
"react": "18.2.0",
"react-dom": "18.2.0"
},
- "type": "module",
- "dependencies": {
- "@mui/material": "5.15.0",
- "@mui/toolpad": "0.1.37"
- }
+ "type": "module"
}
diff --git a/test/utils/locators.ts b/test/utils/locators.ts
new file mode 100644
index 00000000000..d3b4b55b5de
--- /dev/null
+++ b/test/utils/locators.ts
@@ -0,0 +1,7 @@
+import { Locator } from '../playwright/test';
+
+export function cellLocator(gridLocator: Locator, rowIndex: number, collIndex: number) {
+ return gridLocator
+ .locator(`[aria-rowindex="${rowIndex}"]`)
+ .locator(`[aria-colindex="${collIndex}"]`);
+}
diff --git a/yarn.lock b/yarn.lock
index 1fe0d5e904a..72eefc6bf7e 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -190,38 +190,38 @@
"@babel/highlight" "^7.23.4"
chalk "^2.4.2"
-"@babel/compat-data@^7.22.9":
+"@babel/compat-data@^7.23.5":
version "7.23.5"
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.23.5.tgz#ffb878728bb6bdcb6f4510aa51b1be9afb8cfd98"
integrity sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==
-"@babel/core@7.23.5", "@babel/core@^7.11.1", "@babel/core@^7.18.9", "@babel/core@^7.23.5":
- version "7.23.5"
- resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.23.5.tgz#6e23f2acbcb77ad283c5ed141f824fd9f70101c7"
- integrity sha512-Cwc2XjUrG4ilcfOw4wBAK+enbdgwAcAJCfGUItPBKR7Mjw4aEfAFYrLxeRp4jWgtNIKn3n2AlBOfwwafl+42/g==
+"@babel/core@7.23.6", "@babel/core@^7.11.1", "@babel/core@^7.18.9", "@babel/core@^7.23.5":
+ version "7.23.6"
+ resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.23.6.tgz#8be77cd77c55baadcc1eae1c33df90ab6d2151d4"
+ integrity sha512-FxpRyGjrMJXh7X3wGLGhNDCRiwpWEF74sKjTLDJSG5Kyvow3QZaG0Adbqzi9ZrVjTWpsX+2cxWXD71NMg93kdw==
dependencies:
"@ampproject/remapping" "^2.2.0"
"@babel/code-frame" "^7.23.5"
- "@babel/generator" "^7.23.5"
- "@babel/helper-compilation-targets" "^7.22.15"
+ "@babel/generator" "^7.23.6"
+ "@babel/helper-compilation-targets" "^7.23.6"
"@babel/helper-module-transforms" "^7.23.3"
- "@babel/helpers" "^7.23.5"
- "@babel/parser" "^7.23.5"
+ "@babel/helpers" "^7.23.6"
+ "@babel/parser" "^7.23.6"
"@babel/template" "^7.22.15"
- "@babel/traverse" "^7.23.5"
- "@babel/types" "^7.23.5"
+ "@babel/traverse" "^7.23.6"
+ "@babel/types" "^7.23.6"
convert-source-map "^2.0.0"
debug "^4.1.0"
gensync "^1.0.0-beta.2"
json5 "^2.2.3"
semver "^6.3.1"
-"@babel/generator@^7.23.5", "@babel/generator@^7.6.2":
- version "7.23.5"
- resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.5.tgz#17d0a1ea6b62f351d281350a5f80b87a810c4755"
- integrity sha512-BPssCHrBD+0YrxviOa3QzpqwhNIXKEtOa2jQrm4FlmkC2apYgRnQcmPWiGZDlGxiNtltnUFolMe8497Esry+jA==
+"@babel/generator@^7.23.6", "@babel/generator@^7.6.2":
+ version "7.23.6"
+ resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.6.tgz#9e1fca4811c77a10580d17d26b57b036133f3c2e"
+ integrity sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==
dependencies:
- "@babel/types" "^7.23.5"
+ "@babel/types" "^7.23.6"
"@jridgewell/gen-mapping" "^0.3.2"
"@jridgewell/trace-mapping" "^0.3.17"
jsesc "^2.5.1"
@@ -233,14 +233,14 @@
dependencies:
"@babel/types" "^7.22.5"
-"@babel/helper-compilation-targets@^7.22.15":
- version "7.22.15"
- resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz#0698fc44551a26cf29f18d4662d5bf545a6cfc52"
- integrity sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==
+"@babel/helper-compilation-targets@^7.23.6":
+ version "7.23.6"
+ resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz#4d79069b16cbcf1461289eccfbbd81501ae39991"
+ integrity sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==
dependencies:
- "@babel/compat-data" "^7.22.9"
- "@babel/helper-validator-option" "^7.22.15"
- browserslist "^4.21.9"
+ "@babel/compat-data" "^7.23.5"
+ "@babel/helper-validator-option" "^7.23.5"
+ browserslist "^4.22.2"
lru-cache "^5.1.1"
semver "^6.3.1"
@@ -356,19 +356,19 @@
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0"
integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==
-"@babel/helper-validator-option@^7.22.15":
+"@babel/helper-validator-option@^7.22.15", "@babel/helper-validator-option@^7.23.5":
version "7.23.5"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz#907a3fbd4523426285365d1206c423c4c5520307"
integrity sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==
-"@babel/helpers@^7.23.5":
- version "7.23.5"
- resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.23.5.tgz#52f522840df8f1a848d06ea6a79b79eefa72401e"
- integrity sha512-oO7us8FzTEsG3U6ag9MfdF1iA/7Z6dz+MtFhifZk8C8o453rGJFFWUP1t+ULM9TUIAzC9uxXEiXjOiVMyd7QPg==
+"@babel/helpers@^7.23.6":
+ version "7.23.6"
+ resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.23.6.tgz#d03af2ee5fb34691eec0cda90f5ecbb4d4da145a"
+ integrity sha512-wCfsbN4nBidDRhpDhvcKlzHWCTlgJYUUdSJfzXb2NuBssDSIjc3xcb+znA7l+zYsFljAcGM0aFkN40cR3lXiGA==
dependencies:
"@babel/template" "^7.22.15"
- "@babel/traverse" "^7.23.5"
- "@babel/types" "^7.23.5"
+ "@babel/traverse" "^7.23.6"
+ "@babel/types" "^7.23.6"
"@babel/highlight@^7.23.4":
version "7.23.4"
@@ -379,10 +379,10 @@
chalk "^2.4.2"
js-tokens "^4.0.0"
-"@babel/parser@^7.1.0", "@babel/parser@^7.20.7", "@babel/parser@^7.22.15", "@babel/parser@^7.23.5":
- version "7.23.5"
- resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.5.tgz#37dee97c4752af148e1d38c34b856b2507660563"
- integrity sha512-hOOqoiNXrmGdFbhgCzu6GiURxUgM27Xwd/aPuu8RfHEZPBzL1Z54okAHAQjXfcQNwvrlkAmAp4SlRTZ45vlthQ==
+"@babel/parser@^7.1.0", "@babel/parser@^7.20.7", "@babel/parser@^7.22.15", "@babel/parser@^7.23.6":
+ version "7.23.6"
+ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.6.tgz#ba1c9e512bda72a47e285ae42aff9d2a635a9e3b"
+ integrity sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==
"@babel/plugin-syntax-class-properties@^7.10.4":
version "7.12.13"
@@ -463,10 +463,10 @@
"@babel/plugin-transform-modules-commonjs" "^7.23.3"
"@babel/plugin-transform-typescript" "^7.23.3"
-"@babel/runtime-corejs2@7.23.5":
- version "7.23.5"
- resolved "https://registry.yarnpkg.com/@babel/runtime-corejs2/-/runtime-corejs2-7.23.5.tgz#b828c9e412d2ae0d08f3fc0406befb645b97e97d"
- integrity sha512-htng2Ks50HN2/hvRU2P6cIzPods3CXaDt0Rf0bhsJc+hD3gaVPreL/UA24jcjqrVRUgu14KucMiCLu6hMjjryQ==
+"@babel/runtime-corejs2@7.23.6":
+ version "7.23.6"
+ resolved "https://registry.yarnpkg.com/@babel/runtime-corejs2/-/runtime-corejs2-7.23.6.tgz#00d4a77e49a33540160312ecb329ac1ba73df3f9"
+ integrity sha512-k8QKC2DmBqkwJDOLa4biAZjoCGPQIaAoA1HvHtZ+gR2E9AauudikJOB34h4ETEavN5UG21X0KPdM3IvBRxM0CA==
dependencies:
core-js "^2.6.12"
regenerator-runtime "^0.14.0"
@@ -487,26 +487,26 @@
"@babel/parser" "^7.22.15"
"@babel/types" "^7.22.15"
-"@babel/traverse@^7.18.9", "@babel/traverse@^7.23.5":
- version "7.23.5"
- resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.5.tgz#f546bf9aba9ef2b042c0e00d245990c15508e7ec"
- integrity sha512-czx7Xy5a6sapWWRx61m1Ke1Ra4vczu1mCTtJam5zRTBOonfdJ+S/B6HYmGYu3fJtr8GGET3si6IhgWVBhJ/m8w==
+"@babel/traverse@^7.18.9", "@babel/traverse@^7.23.6":
+ version "7.23.6"
+ resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.6.tgz#b53526a2367a0dd6edc423637f3d2d0f2521abc5"
+ integrity sha512-czastdK1e8YByZqezMPFiZ8ahwVMh/ESl9vPgvgdB9AmFMGP5jfpFax74AQgl5zj4XHzqeYAg2l8PuUeRS1MgQ==
dependencies:
"@babel/code-frame" "^7.23.5"
- "@babel/generator" "^7.23.5"
+ "@babel/generator" "^7.23.6"
"@babel/helper-environment-visitor" "^7.22.20"
"@babel/helper-function-name" "^7.23.0"
"@babel/helper-hoist-variables" "^7.22.5"
"@babel/helper-split-export-declaration" "^7.22.6"
- "@babel/parser" "^7.23.5"
- "@babel/types" "^7.23.5"
- debug "^4.1.0"
+ "@babel/parser" "^7.23.6"
+ "@babel/types" "^7.23.6"
+ debug "^4.3.1"
globals "^11.1.0"
-"@babel/types@^7.0.0", "@babel/types@^7.11.0", "@babel/types@^7.18.9", "@babel/types@^7.20.7", "@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.5", "@babel/types@^7.6.1":
- version "7.23.5"
- resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.5.tgz#48d730a00c95109fa4393352705954d74fb5b602"
- integrity sha512-ON5kSOJwVO6xXVRTvOI0eOnWe7VdUcIpsovGo9U/Br4Ie4UVFQTboO2cYnDhAGU6Fp+UxSiT+pMft0SMHfuq6w==
+"@babel/types@^7.0.0", "@babel/types@^7.11.0", "@babel/types@^7.18.9", "@babel/types@^7.20.7", "@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.6", "@babel/types@^7.6.1":
+ version "7.23.6"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.6.tgz#be33fdb151e1f5a56877d704492c240fc71c7ccd"
+ integrity sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==
dependencies:
"@babel/helper-string-parser" "^7.23.4"
"@babel/helper-validator-identifier" "^7.22.20"
@@ -577,7 +577,7 @@
resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.9.1.tgz#4ffb0055f7ef676ebc3a5a91fb621393294e2f43"
integrity sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==
-"@emotion/is-prop-valid@^1.2.1":
+"@emotion/is-prop-valid@1.2.1", "@emotion/is-prop-valid@^1.2.1":
version "1.2.1"
resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.2.1.tgz#23116cf1ed18bfeac910ec6436561ecb1a3885cc"
integrity sha512-61Mf7Ufx4aDxx1xlDeOm8aFFigGHE4z+0sKCa+IHCeZKiyP9RLD0Mmx7m8b9/Cf37f7NAvQOOJAbQQGVr5uERw==
@@ -589,24 +589,24 @@
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.8.1.tgz#c1ddb040429c6d21d38cc945fe75c818cfb68e17"
integrity sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==
-"@emotion/react@11.11.1":
- version "11.11.1"
- resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.11.1.tgz#b2c36afac95b184f73b08da8c214fdf861fa4157"
- integrity sha512-5mlW1DquU5HaxjLkfkGN1GA/fvVGdyHURRiX/0FHl2cfIfRxSOfmxEH5YS43edp0OldZrZ+dkBKbngxcNCdZvA==
+"@emotion/react@11.11.3":
+ version "11.11.3"
+ resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.11.3.tgz#96b855dc40a2a55f52a72f518a41db4f69c31a25"
+ integrity sha512-Cnn0kuq4DoONOMcnoVsTOR8E+AdnKFf//6kUWc4LCdnxj31pZWn7rIULd6Y7/Js1PiPHzn7SKCM9vB/jBni8eA==
dependencies:
"@babel/runtime" "^7.18.3"
"@emotion/babel-plugin" "^11.11.0"
"@emotion/cache" "^11.11.0"
- "@emotion/serialize" "^1.1.2"
+ "@emotion/serialize" "^1.1.3"
"@emotion/use-insertion-effect-with-fallbacks" "^1.0.1"
"@emotion/utils" "^1.2.1"
"@emotion/weak-memoize" "^0.3.1"
hoist-non-react-statics "^3.3.1"
-"@emotion/serialize@^1.1.2":
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.1.2.tgz#017a6e4c9b8a803bd576ff3d52a0ea6fa5a62b51"
- integrity sha512-zR6a/fkFP4EAcCMQtLOhIgpprZOwNmCldtpaISpvz348+DP4Mz8ZoKaGGCQpbzepNIUWbq4w6hNZkwDyKoS+HA==
+"@emotion/serialize@^1.1.2", "@emotion/serialize@^1.1.3":
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.1.3.tgz#84b77bfcfe3b7bb47d326602f640ccfcacd5ffb0"
+ integrity sha512-iD4D6QVZFDhcbH0RAG1uVu1CwVLMWUkCvAqqlewO/rxf8+87yIBAlt4+AxMiiKPLs5hFc0owNk/sLLAOROw3cA==
dependencies:
"@emotion/hash" "^0.9.1"
"@emotion/memoize" "^0.8.1"
@@ -641,7 +641,12 @@
"@emotion/use-insertion-effect-with-fallbacks" "^1.0.1"
"@emotion/utils" "^1.2.1"
-"@emotion/unitless@^0.8.0", "@emotion/unitless@^0.8.1":
+"@emotion/unitless@0.8.0":
+ version "0.8.0"
+ resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.8.0.tgz#a4a36e9cbdc6903737cd20d38033241e1b8833db"
+ integrity sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw==
+
+"@emotion/unitless@^0.8.1":
version "0.8.1"
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.8.1.tgz#182b5a4704ef8ad91bde93f7a860a88fd92c79a3"
integrity sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==
@@ -661,225 +666,230 @@
resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz#d0fce5d07b0620caa282b5131c297bb60f9d87e6"
integrity sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==
+"@esbuild/aix-ppc64@0.19.10":
+ version "0.19.10"
+ resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.19.10.tgz#fb3922a0183d27446de00cf60d4f7baaadf98d84"
+ integrity sha512-Q+mk96KJ+FZ30h9fsJl+67IjNJm3x2eX+GBWGmocAKgzp27cowCOOqSdscX80s0SpdFXZnIv/+1xD1EctFx96Q==
+
"@esbuild/android-arm64@0.18.20":
version "0.18.20"
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz#984b4f9c8d0377443cc2dfcef266d02244593622"
integrity sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==
-"@esbuild/android-arm64@0.19.9":
- version "0.19.9"
- resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.19.9.tgz#683794bdc3d27222d3eced7b74cad15979548031"
- integrity sha512-q4cR+6ZD0938R19MyEW3jEsMzbb/1rulLXiNAJQADD/XYp7pT+rOS5JGxvpRW8dFDEfjW4wLgC/3FXIw4zYglQ==
+"@esbuild/android-arm64@0.19.10":
+ version "0.19.10"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.19.10.tgz#ef31015416dd79398082409b77aaaa2ade4d531a"
+ integrity sha512-1X4CClKhDgC3by7k8aOWZeBXQX8dHT5QAMCAQDArCLaYfkppoARvh0fit3X2Qs+MXDngKcHv6XXyQCpY0hkK1Q==
"@esbuild/android-arm@0.18.20":
version "0.18.20"
resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.18.20.tgz#fedb265bc3a589c84cc11f810804f234947c3682"
integrity sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==
-"@esbuild/android-arm@0.19.9":
- version "0.19.9"
- resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.19.9.tgz#21a4de41f07b2af47401c601d64dfdefd056c595"
- integrity sha512-jkYjjq7SdsWuNI6b5quymW0oC83NN5FdRPuCbs9HZ02mfVdAP8B8eeqLSYU3gb6OJEaY5CQabtTFbqBf26H3GA==
+"@esbuild/android-arm@0.19.10":
+ version "0.19.10"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.19.10.tgz#1c23c7e75473aae9fb323be5d9db225142f47f52"
+ integrity sha512-7W0bK7qfkw1fc2viBfrtAEkDKHatYfHzr/jKAHNr9BvkYDXPcC6bodtm8AyLJNNuqClLNaeTLuwURt4PRT9d7w==
"@esbuild/android-x64@0.18.20":
version "0.18.20"
resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.18.20.tgz#35cf419c4cfc8babe8893d296cd990e9e9f756f2"
integrity sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==
-"@esbuild/android-x64@0.19.9":
- version "0.19.9"
- resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.19.9.tgz#e2d7674bc025ddc8699f0cc76cb97823bb63c252"
- integrity sha512-KOqoPntWAH6ZxDwx1D6mRntIgZh9KodzgNOy5Ebt9ghzffOk9X2c1sPwtM9P+0eXbefnDhqYfkh5PLP5ULtWFA==
+"@esbuild/android-x64@0.19.10":
+ version "0.19.10"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.19.10.tgz#df6a4e6d6eb8da5595cfce16d4e3f6bc24464707"
+ integrity sha512-O/nO/g+/7NlitUxETkUv/IvADKuZXyH4BHf/g/7laqKC4i/7whLpB0gvpPc2zpF0q9Q6FXS3TS75QHac9MvVWw==
"@esbuild/darwin-arm64@0.18.20":
version "0.18.20"
resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz#08172cbeccf95fbc383399a7f39cfbddaeb0d7c1"
integrity sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==
-"@esbuild/darwin-arm64@0.19.9":
- version "0.19.9"
- resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.19.9.tgz#ae7a582289cc5c0bac15d4b9020a90cb7288f1e9"
- integrity sha512-KBJ9S0AFyLVx2E5D8W0vExqRW01WqRtczUZ8NRu+Pi+87opZn5tL4Y0xT0mA4FtHctd0ZgwNoN639fUUGlNIWw==
+"@esbuild/darwin-arm64@0.19.10":
+ version "0.19.10"
+ resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.19.10.tgz#8462a55db07c1b2fad61c8244ce04469ef1043be"
+ integrity sha512-YSRRs2zOpwypck+6GL3wGXx2gNP7DXzetmo5pHXLrY/VIMsS59yKfjPizQ4lLt5vEI80M41gjm2BxrGZ5U+VMA==
"@esbuild/darwin-x64@0.18.20":
version "0.18.20"
resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz#d70d5790d8bf475556b67d0f8b7c5bdff053d85d"
integrity sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==
-"@esbuild/darwin-x64@0.19.9":
- version "0.19.9"
- resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.19.9.tgz#8a216c66dcf51addeeb843d8cfaeff712821d12b"
- integrity sha512-vE0VotmNTQaTdX0Q9dOHmMTao6ObjyPm58CHZr1UK7qpNleQyxlFlNCaHsHx6Uqv86VgPmR4o2wdNq3dP1qyDQ==
+"@esbuild/darwin-x64@0.19.10":
+ version "0.19.10"
+ resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.19.10.tgz#d1de20bfd41bb75b955ba86a6b1004539e8218c1"
+ integrity sha512-alfGtT+IEICKtNE54hbvPg13xGBe4GkVxyGWtzr+yHO7HIiRJppPDhOKq3zstTcVf8msXb/t4eavW3jCDpMSmA==
"@esbuild/freebsd-arm64@0.18.20":
version "0.18.20"
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz#98755cd12707f93f210e2494d6a4b51b96977f54"
integrity sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==
-"@esbuild/freebsd-arm64@0.19.9":
- version "0.19.9"
- resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.9.tgz#63d4f603e421252c3cd836b18d01545be7c6c440"
- integrity sha512-uFQyd/o1IjiEk3rUHSwUKkqZwqdvuD8GevWF065eqgYfexcVkxh+IJgwTaGZVu59XczZGcN/YMh9uF1fWD8j1g==
+"@esbuild/freebsd-arm64@0.19.10":
+ version "0.19.10"
+ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.10.tgz#16904879e34c53a2e039d1284695d2db3e664d57"
+ integrity sha512-dMtk1wc7FSH8CCkE854GyGuNKCewlh+7heYP/sclpOG6Cectzk14qdUIY5CrKDbkA/OczXq9WesqnPl09mj5dg==
"@esbuild/freebsd-x64@0.18.20":
version "0.18.20"
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz#c1eb2bff03915f87c29cece4c1a7fa1f423b066e"
integrity sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==
-"@esbuild/freebsd-x64@0.19.9":
- version "0.19.9"
- resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.19.9.tgz#a3db52595be65360eae4de1d1fa3c1afd942e1e4"
- integrity sha512-WMLgWAtkdTbTu1AWacY7uoj/YtHthgqrqhf1OaEWnZb7PQgpt8eaA/F3LkV0E6K/Lc0cUr/uaVP/49iE4M4asA==
+"@esbuild/freebsd-x64@0.19.10":
+ version "0.19.10"
+ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.19.10.tgz#8ad9e5ca9786ca3f1ef1411bfd10b08dcd9d4cef"
+ integrity sha512-G5UPPspryHu1T3uX8WiOEUa6q6OlQh6gNl4CO4Iw5PS+Kg5bVggVFehzXBJY6X6RSOMS8iXDv2330VzaObm4Ag==
"@esbuild/linux-arm64@0.18.20":
version "0.18.20"
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz#bad4238bd8f4fc25b5a021280c770ab5fc3a02a0"
integrity sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==
-"@esbuild/linux-arm64@0.19.9":
- version "0.19.9"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.19.9.tgz#4ae5811ce9f8d7df5eb9edd9765ea9401a534f13"
- integrity sha512-PiPblfe1BjK7WDAKR1Cr9O7VVPqVNpwFcPWgfn4xu0eMemzRp442hXyzF/fSwgrufI66FpHOEJk0yYdPInsmyQ==
+"@esbuild/linux-arm64@0.19.10":
+ version "0.19.10"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.19.10.tgz#d82cf2c590faece82d28bbf1cfbe36f22ae25bd2"
+ integrity sha512-QxaouHWZ+2KWEj7cGJmvTIHVALfhpGxo3WLmlYfJ+dA5fJB6lDEIg+oe/0//FuyVHuS3l79/wyBxbHr0NgtxJQ==
"@esbuild/linux-arm@0.18.20":
version "0.18.20"
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz#3e617c61f33508a27150ee417543c8ab5acc73b0"
integrity sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==
-"@esbuild/linux-arm@0.19.9":
- version "0.19.9"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.19.9.tgz#9807e92cfd335f46326394805ad488e646e506f2"
- integrity sha512-C/ChPohUYoyUaqn1h17m/6yt6OB14hbXvT8EgM1ZWaiiTYz7nWZR0SYmMnB5BzQA4GXl3BgBO1l8MYqL/He3qw==
+"@esbuild/linux-arm@0.19.10":
+ version "0.19.10"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.19.10.tgz#477b8e7c7bcd34369717b04dd9ee6972c84f4029"
+ integrity sha512-j6gUW5aAaPgD416Hk9FHxn27On28H4eVI9rJ4az7oCGTFW48+LcgNDBN+9f8rKZz7EEowo889CPKyeaD0iw9Kg==
"@esbuild/linux-ia32@0.18.20":
version "0.18.20"
resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz#699391cccba9aee6019b7f9892eb99219f1570a7"
integrity sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==
-"@esbuild/linux-ia32@0.19.9":
- version "0.19.9"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.19.9.tgz#18892c10f3106652b16f9da88a0362dc95ed46c7"
- integrity sha512-f37i/0zE0MjDxijkPSQw1CO/7C27Eojqb+r3BbHVxMLkj8GCa78TrBZzvPyA/FNLUMzP3eyHCVkAopkKVja+6Q==
+"@esbuild/linux-ia32@0.19.10":
+ version "0.19.10"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.19.10.tgz#d55ff822cf5b0252a57112f86857ff23be6cab0e"
+ integrity sha512-4ub1YwXxYjj9h1UIZs2hYbnTZBtenPw5NfXCRgEkGb0b6OJ2gpkMvDqRDYIDRjRdWSe/TBiZltm3Y3Q8SN1xNg==
"@esbuild/linux-loong64@0.18.20":
version "0.18.20"
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz#e6fccb7aac178dd2ffb9860465ac89d7f23b977d"
integrity sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==
-"@esbuild/linux-loong64@0.19.9":
- version "0.19.9"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.19.9.tgz#dc2ebf9a125db0a1bba18c2bbfd4fbdcbcaf61c2"
- integrity sha512-t6mN147pUIf3t6wUt3FeumoOTPfmv9Cc6DQlsVBpB7eCpLOqQDyWBP1ymXn1lDw4fNUSb/gBcKAmvTP49oIkaA==
+"@esbuild/linux-loong64@0.19.10":
+ version "0.19.10"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.19.10.tgz#a9ad057d7e48d6c9f62ff50f6f208e331c4543c7"
+ integrity sha512-lo3I9k+mbEKoxtoIbM0yC/MZ1i2wM0cIeOejlVdZ3D86LAcFXFRdeuZmh91QJvUTW51bOK5W2BznGNIl4+mDaA==
"@esbuild/linux-mips64el@0.18.20":
version "0.18.20"
resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz#eeff3a937de9c2310de30622a957ad1bd9183231"
integrity sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==
-"@esbuild/linux-mips64el@0.19.9":
- version "0.19.9"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.19.9.tgz#4c2f7c5d901015e3faf1563c4a89a50776cb07fd"
- integrity sha512-jg9fujJTNTQBuDXdmAg1eeJUL4Jds7BklOTkkH80ZgQIoCTdQrDaHYgbFZyeTq8zbY+axgptncko3v9p5hLZtw==
+"@esbuild/linux-mips64el@0.19.10":
+ version "0.19.10"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.19.10.tgz#b011a96924773d60ebab396fbd7a08de66668179"
+ integrity sha512-J4gH3zhHNbdZN0Bcr1QUGVNkHTdpijgx5VMxeetSk6ntdt+vR1DqGmHxQYHRmNb77tP6GVvD+K0NyO4xjd7y4A==
"@esbuild/linux-ppc64@0.18.20":
version "0.18.20"
resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz#2f7156bde20b01527993e6881435ad79ba9599fb"
integrity sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==
-"@esbuild/linux-ppc64@0.19.9":
- version "0.19.9"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.19.9.tgz#8385332713b4e7812869622163784a5633f76fc4"
- integrity sha512-tkV0xUX0pUUgY4ha7z5BbDS85uI7ABw3V1d0RNTii7E9lbmV8Z37Pup2tsLV46SQWzjOeyDi1Q7Wx2+QM8WaCQ==
+"@esbuild/linux-ppc64@0.19.10":
+ version "0.19.10"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.19.10.tgz#5d8b59929c029811e473f2544790ea11d588d4dd"
+ integrity sha512-tgT/7u+QhV6ge8wFMzaklOY7KqiyitgT1AUHMApau32ZlvTB/+efeCtMk4eXS+uEymYK249JsoiklZN64xt6oQ==
"@esbuild/linux-riscv64@0.18.20":
version "0.18.20"
resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz#6628389f210123d8b4743045af8caa7d4ddfc7a6"
integrity sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==
-"@esbuild/linux-riscv64@0.19.9":
- version "0.19.9"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.19.9.tgz#23f1db24fa761be311874f32036c06249aa20cba"
- integrity sha512-DfLp8dj91cufgPZDXr9p3FoR++m3ZJ6uIXsXrIvJdOjXVREtXuQCjfMfvmc3LScAVmLjcfloyVtpn43D56JFHg==
+"@esbuild/linux-riscv64@0.19.10":
+ version "0.19.10"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.19.10.tgz#292b06978375b271bd8bc0a554e0822957508d22"
+ integrity sha512-0f/spw0PfBMZBNqtKe5FLzBDGo0SKZKvMl5PHYQr3+eiSscfJ96XEknCe+JoOayybWUFQbcJTrk946i3j9uYZA==
"@esbuild/linux-s390x@0.18.20":
version "0.18.20"
resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz#255e81fb289b101026131858ab99fba63dcf0071"
integrity sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==
-"@esbuild/linux-s390x@0.19.9":
- version "0.19.9"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.19.9.tgz#2dffe497726b897c9f0109e774006e25b33b4fd0"
- integrity sha512-zHbglfEdC88KMgCWpOl/zc6dDYJvWGLiUtmPRsr1OgCViu3z5GncvNVdf+6/56O2Ca8jUU+t1BW261V6kp8qdw==
+"@esbuild/linux-s390x@0.19.10":
+ version "0.19.10"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.19.10.tgz#d30af63530f8d4fa96930374c9dd0d62bf59e069"
+ integrity sha512-pZFe0OeskMHzHa9U38g+z8Yx5FNCLFtUnJtQMpwhS+r4S566aK2ci3t4NCP4tjt6d5j5uo4h7tExZMjeKoehAA==
"@esbuild/linux-x64@0.18.20":
version "0.18.20"
resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz#c7690b3417af318a9b6f96df3031a8865176d338"
integrity sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==
-"@esbuild/linux-x64@0.19.9":
- version "0.19.9"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.19.9.tgz#ceb1d62cd830724ff5b218e5d3172a8bad59420e"
- integrity sha512-JUjpystGFFmNrEHQnIVG8hKwvA2DN5o7RqiO1CVX8EN/F/gkCjkUMgVn6hzScpwnJtl2mPR6I9XV1oW8k9O+0A==
+"@esbuild/linux-x64@0.19.10":
+ version "0.19.10"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.19.10.tgz#898c72eeb74d9f2fb43acf316125b475548b75ce"
+ integrity sha512-SpYNEqg/6pZYoc+1zLCjVOYvxfZVZj6w0KROZ3Fje/QrM3nfvT2llI+wmKSrWuX6wmZeTapbarvuNNK/qepSgA==
"@esbuild/netbsd-x64@0.18.20":
version "0.18.20"
resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz#30e8cd8a3dded63975e2df2438ca109601ebe0d1"
integrity sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==
-"@esbuild/netbsd-x64@0.19.9":
- version "0.19.9"
- resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.19.9.tgz#0cbca65e9ef4d3fc41502d3e055e6f49479a8f18"
- integrity sha512-GThgZPAwOBOsheA2RUlW5UeroRfESwMq/guy8uEe3wJlAOjpOXuSevLRd70NZ37ZrpO6RHGHgEHvPg1h3S1Jug==
+"@esbuild/netbsd-x64@0.19.10":
+ version "0.19.10"
+ resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.19.10.tgz#fd473a5ae261b43eab6dad4dbd5a3155906e6c91"
+ integrity sha512-ACbZ0vXy9zksNArWlk2c38NdKg25+L9pr/mVaj9SUq6lHZu/35nx2xnQVRGLrC1KKQqJKRIB0q8GspiHI3J80Q==
"@esbuild/openbsd-x64@0.18.20":
version "0.18.20"
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz#7812af31b205055874c8082ea9cf9ab0da6217ae"
integrity sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==
-"@esbuild/openbsd-x64@0.19.9":
- version "0.19.9"
- resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.19.9.tgz#1f57adfbee09c743292c6758a3642e875bcad1cf"
- integrity sha512-Ki6PlzppaFVbLnD8PtlVQfsYw4S9n3eQl87cqgeIw+O3sRr9IghpfSKY62mggdt1yCSZ8QWvTZ9jo9fjDSg9uw==
+"@esbuild/openbsd-x64@0.19.10":
+ version "0.19.10"
+ resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.19.10.tgz#96eb8992e526717b5272321eaad3e21f3a608e46"
+ integrity sha512-PxcgvjdSjtgPMiPQrM3pwSaG4kGphP+bLSb+cihuP0LYdZv1epbAIecHVl5sD3npkfYBZ0ZnOjR878I7MdJDFg==
"@esbuild/sunos-x64@0.18.20":
version "0.18.20"
resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz#d5c275c3b4e73c9b0ecd38d1ca62c020f887ab9d"
integrity sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==
-"@esbuild/sunos-x64@0.19.9":
- version "0.19.9"
- resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.19.9.tgz#116be6adbd2c7479edeeb5f6ea0441002ab4cb9c"
- integrity sha512-MLHj7k9hWh4y1ddkBpvRj2b9NCBhfgBt3VpWbHQnXRedVun/hC7sIyTGDGTfsGuXo4ebik2+3ShjcPbhtFwWDw==
+"@esbuild/sunos-x64@0.19.10":
+ version "0.19.10"
+ resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.19.10.tgz#c16ee1c167f903eaaa6acf7372bee42d5a89c9bc"
+ integrity sha512-ZkIOtrRL8SEJjr+VHjmW0znkPs+oJXhlJbNwfI37rvgeMtk3sxOQevXPXjmAPZPigVTncvFqLMd+uV0IBSEzqA==
"@esbuild/win32-arm64@0.18.20":
version "0.18.20"
resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz#73bc7f5a9f8a77805f357fab97f290d0e4820ac9"
integrity sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==
-"@esbuild/win32-arm64@0.19.9":
- version "0.19.9"
- resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.19.9.tgz#2be22131ab18af4693fd737b161d1ef34de8ca9d"
- integrity sha512-GQoa6OrQ8G08guMFgeXPH7yE/8Dt0IfOGWJSfSH4uafwdC7rWwrfE6P9N8AtPGIjUzdo2+7bN8Xo3qC578olhg==
+"@esbuild/win32-arm64@0.19.10":
+ version "0.19.10"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.19.10.tgz#7e417d1971dbc7e469b4eceb6a5d1d667b5e3dcc"
+ integrity sha512-+Sa4oTDbpBfGpl3Hn3XiUe4f8TU2JF7aX8cOfqFYMMjXp6ma6NJDztl5FDG8Ezx0OjwGikIHw+iA54YLDNNVfw==
"@esbuild/win32-ia32@0.18.20":
version "0.18.20"
resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz#ec93cbf0ef1085cc12e71e0d661d20569ff42102"
integrity sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==
-"@esbuild/win32-ia32@0.19.9":
- version "0.19.9"
- resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.19.9.tgz#e10ead5a55789b167b4225d2469324538768af7c"
- integrity sha512-UOozV7Ntykvr5tSOlGCrqU3NBr3d8JqPes0QWN2WOXfvkWVGRajC+Ym0/Wj88fUgecUCLDdJPDF0Nna2UK3Qtg==
+"@esbuild/win32-ia32@0.19.10":
+ version "0.19.10"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.19.10.tgz#2b52dfec6cd061ecb36171c13bae554888b439e5"
+ integrity sha512-EOGVLK1oWMBXgfttJdPHDTiivYSjX6jDNaATeNOaCOFEVcfMjtbx7WVQwPSE1eIfCp/CaSF2nSrDtzc4I9f8TQ==
"@esbuild/win32-x64@0.18.20":
version "0.18.20"
resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz#786c5f41f043b07afb1af37683d7c33668858f6d"
integrity sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==
-"@esbuild/win32-x64@0.19.9":
- version "0.19.9"
- resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.19.9.tgz#b2da6219b603e3fa371a78f53f5361260d0c5585"
- integrity sha512-oxoQgglOP7RH6iasDrhY+R/3cHrfwIDvRlT4CGChflq6twk8iENeVvMJjmvBb94Ik1Z+93iGO27err7w6l54GQ==
+"@esbuild/win32-x64@0.19.10":
+ version "0.19.10"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.19.10.tgz#bd123a74f243d2f3a1f046447bb9b363ee25d072"
+ integrity sha512-whqLG6Sc70AbU73fFYvuYzaE4MNMBIlR1Y/IrUeOXFrWHxBEjjbZaQ3IXIQS8wJdAzue2GwYZCjOrgrU1oUHoA==
"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0":
version "4.4.0"
@@ -908,10 +918,10 @@
minimatch "^3.1.2"
strip-json-comments "^3.1.1"
-"@eslint/js@8.55.0":
- version "8.55.0"
- resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.55.0.tgz#b721d52060f369aa259cf97392403cb9ce892ec6"
- integrity sha512-qQfo2mxH5yVom1kacMtZZJFVdW+E70mqHMJvVg6WTLo+VBuQJ4TojZlfWBjK0ve5BdEeNAVxOsl/nvNMpJOaJA==
+"@eslint/js@8.56.0":
+ version "8.56.0"
+ resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.56.0.tgz#ef20350fec605a7f7035a01764731b2de0f3782b"
+ integrity sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==
"@fast-csv/format@4.3.5":
version "4.3.5"
@@ -965,11 +975,6 @@
resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.1.6.tgz#22958c042e10b67463997bd6ea7115fe28cbcaf9"
integrity sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==
-"@gar/promisify@^1.1.3":
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6"
- integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==
-
"@googleapis/drive@8.4.0":
version "8.4.0"
resolved "https://registry.yarnpkg.com/@googleapis/drive/-/drive-8.4.0.tgz#65b3335d3d39f7fd755bb339896baba60c4b3f4d"
@@ -1067,12 +1072,12 @@
"@jridgewell/resolve-uri" "^3.1.0"
"@jridgewell/sourcemap-codec" "^1.4.14"
-"@lerna/create@8.0.0":
- version "8.0.0"
- resolved "https://registry.yarnpkg.com/@lerna/create/-/create-8.0.0.tgz#fc12ac308d27b6b16304e0b2d11b8efaa93d524f"
- integrity sha512-mCeEhjFDRwPY7J4uxCjqdzPwPFBUGlkdlQjBidaX5XaoQcxR2hAAvgHZKfVGkUUEZKfyPcWwKzen4KydNB2G7A==
+"@lerna/create@8.0.1":
+ version "8.0.1"
+ resolved "https://registry.yarnpkg.com/@lerna/create/-/create-8.0.1.tgz#cc0ab19163c67269552292d95f23568468fa9921"
+ integrity sha512-PDYNUF8Nv5j7DbGvVbizEuYuQbNFZ0+wVOtRPvBQOkC2dMNryi3dJjktEd1QeDX6Wa/JkJWvZ5SMHyr+7H3Rtg==
dependencies:
- "@npmcli/run-script" "6.0.2"
+ "@npmcli/run-script" "7.0.2"
"@nx/devkit" ">=17.1.2 < 18"
"@octokit/plugin-enterprise-rest" "6.0.1"
"@octokit/rest" "19.0.11"
@@ -1115,7 +1120,7 @@
p-map-series "2.1.0"
p-queue "6.6.2"
p-reduce "^2.1.0"
- pacote "^15.2.0"
+ pacote "^17.0.5"
pify "5.0.0"
read-cmd-shim "4.0.0"
read-package-json "6.0.4"
@@ -1144,56 +1149,61 @@
dependencies:
call-bind "^1.0.2"
-"@mui/base@5.0.0-beta.27", "@mui/base@^5.0.0-beta.20", "@mui/base@^5.0.0-beta.22":
- version "5.0.0-beta.27"
- resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-beta.27.tgz#21a9c7d954a5f88f6706dfee630154c651ee73af"
- integrity sha512-duL37qxihT1N0pW/gyXVezP7SttLkF+cLAs/y6g6ubEFmVadjbnZ45SeF12/vAiKzqwf5M0uFH1cczIPXFZygA==
+"@mui/base@5.0.0-beta.28", "@mui/base@^5.0.0-beta.20", "@mui/base@^5.0.0-beta.22":
+ version "5.0.0-beta.28"
+ resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-beta.28.tgz#f072e55c0530f456ee5cb5cde2af788fdda3bf05"
+ integrity sha512-KIoSc5sUFceeCaZTq5MQBapFzhHqMo4kj+4azWaCAjorduhcRQtN+BCgVHmo+gvEjix74bUfxwTqGifnu2fNTg==
dependencies:
"@babel/runtime" "^7.23.5"
"@floating-ui/react-dom" "^2.0.4"
"@mui/types" "^7.2.11"
- "@mui/utils" "^5.15.0"
+ "@mui/utils" "^5.15.1"
"@popperjs/core" "^2.11.8"
clsx "^2.0.0"
prop-types "^15.8.1"
-"@mui/core-downloads-tracker@^5.15.0":
- version "5.15.0"
- resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.15.0.tgz#6b45d5bff38f305402d24d3bf86075b56c578909"
- integrity sha512-NpGtlHwuyLfJtdrlERXb8qRqd279O0VnuGaZAor1ehdNhUJOD1bSxHDeXKZkbqNpvi50hasFj7lsbTpluworTQ==
+"@mui/core-downloads-tracker@^5.15.1":
+ version "5.15.1"
+ resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.15.1.tgz#8aad47e2b198640244f05f6486a927ce362e814e"
+ integrity sha512-y/nUEsWHyBzaKYp9zLtqJKrLod/zMNEWpMj488FuQY9QTmqBiyUhI2uh7PVaLqLewXRtdmG6JV0b6T5exyuYRw==
-"@mui/icons-material@5.15.0":
- version "5.15.0"
- resolved "https://registry.yarnpkg.com/@mui/icons-material/-/icons-material-5.15.0.tgz#fdc93611ca77ce3b79128be02fb6c1ae79b972b8"
- integrity sha512-zHY6fOkaK7VfhWeyxO8MjO3IAjEYpYMXuqUhX7TkUZJ9+TSH/9dn4ClG4K2j6hdgBU5Yrq2Z/89Bo6BHHp7AdQ==
+"@mui/icons-material@5.15.1":
+ version "5.15.1"
+ resolved "https://registry.yarnpkg.com/@mui/icons-material/-/icons-material-5.15.1.tgz#38f51a88d224a107e753313b4d9815247caa5398"
+ integrity sha512-VPJdBSyap6uOxCb5BLbWbkvd6aeJCp1pQZm8DcZBITCH0NOSv8Mz9c8Zvo8xr4Od7+xyWHUAgvRSL4047pL2WQ==
dependencies:
"@babel/runtime" "^7.23.5"
-"@mui/lab@5.0.0-alpha.156":
- version "5.0.0-alpha.156"
- resolved "https://registry.yarnpkg.com/@mui/lab/-/lab-5.0.0-alpha.156.tgz#9fee3a408ded367ab4fe84275789155b65dee7e7"
- integrity sha512-OUAckFeqlAG6aIBG1Ud1fDCBqnU1wltWZYHsA7YCGzRBykNzQC/W/dYddp+RJLu0BgYpMiXwPXq2Hg0ERVtaog==
+"@mui/lab@5.0.0-alpha.157":
+ version "5.0.0-alpha.157"
+ resolved "https://registry.yarnpkg.com/@mui/lab/-/lab-5.0.0-alpha.157.tgz#cb248823ffd881153eef86c2e3786c35601d1986"
+ integrity sha512-gY7UM2kNSxiVLfsm0o6HG2G5rM2Vr47prJhDCazY+VG/NOSRc8CG7la6dpL9WDTJhotEZdWwfj1FOUxTonmuQA==
dependencies:
"@babel/runtime" "^7.23.5"
- "@mui/base" "5.0.0-beta.27"
- "@mui/system" "^5.15.0"
+ "@mui/base" "5.0.0-beta.28"
+ "@mui/system" "^5.15.1"
"@mui/types" "^7.2.11"
- "@mui/utils" "^5.15.0"
+ "@mui/utils" "^5.15.1"
clsx "^2.0.0"
prop-types "^15.8.1"
-"@mui/material@5.15.0":
+"@mui/material-nextjs@^5.15.0":
version "5.15.0"
- resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.15.0.tgz#f801cf56d505cc52dca225438360ab9c62057285"
- integrity sha512-60CDI/hQNwJv9a3vEZtFG7zz0USdQhVwpBd3fZqrzhuXSdiMdYMaZcCXeX/KMuNq0ZxQEAZd74Pv+gOb408QVA==
+ resolved "https://registry.yarnpkg.com/@mui/material-nextjs/-/material-nextjs-5.15.0.tgz#a5bceb1f9d6848640b9661852a80193519527431"
+ integrity sha512-UC3lnoRqJXoWUBeekqjxC4CpxMElz4D4bBCegOhrm80qGV1cP5TBJGjalqoSUq6HSl+COVv6u//AjjIMKCj/qA==
+
+"@mui/material@5.15.1":
+ version "5.15.1"
+ resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.15.1.tgz#5fc15c6eb9efe4b62b0c30b13bf5fa042bda71a1"
+ integrity sha512-WA5DVyvacxDakVyAhNqu/rRT28ppuuUFFw1bLpmRzrCJ4uw/zLTATcd4WB3YbB+7MdZNEGG/SJNWTDLEIyn3xQ==
dependencies:
"@babel/runtime" "^7.23.5"
- "@mui/base" "5.0.0-beta.27"
- "@mui/core-downloads-tracker" "^5.15.0"
- "@mui/system" "^5.15.0"
+ "@mui/base" "5.0.0-beta.28"
+ "@mui/core-downloads-tracker" "^5.15.1"
+ "@mui/system" "^5.15.1"
"@mui/types" "^7.2.11"
- "@mui/utils" "^5.15.0"
- "@types/react-transition-group" "^4.4.9"
+ "@mui/utils" "^5.15.1"
+ "@types/react-transition-group" "^4.4.10"
clsx "^2.0.0"
csstype "^3.1.2"
prop-types "^15.8.1"
@@ -1201,38 +1211,38 @@
react-transition-group "^4.4.5"
"@mui/monorepo@https://github.com/mui/material-ui.git":
- version "5.14.20"
- resolved "https://github.com/mui/material-ui.git#922e29ff4d94b1bf78fc65c1c096a39eb36c7ea4"
-
-"@mui/private-theming@^5.15.0":
version "5.15.0"
- resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-5.15.0.tgz#96de66ce097ba417e1b6b769cd67cbf516bd8876"
- integrity sha512-7WxtIhXxNek0JjtsYy+ut2LtFSLpsUW5JSDehQO+jF7itJ8ehy7Bd9bSt2yIllbwGjCFowLfYpPk2Ykgvqm1tA==
+ resolved "https://github.com/mui/material-ui.git#b5a8ddfe8304be625dcea127dd00486487e3ccad"
+
+"@mui/private-theming@^5.15.1":
+ version "5.15.1"
+ resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-5.15.1.tgz#58fd8da48295e105067fa7361734ee0b166d9cca"
+ integrity sha512-wTbzuy5KjSvCPE9UVJktWHJ0b/tD5biavY9wvF+OpYDLPpdXK52vc1hTDxSbdkHIFMkJExzrwO9GvpVAHZBnFQ==
dependencies:
"@babel/runtime" "^7.23.5"
- "@mui/utils" "^5.15.0"
+ "@mui/utils" "^5.15.1"
prop-types "^15.8.1"
-"@mui/styled-engine@^5.15.0":
- version "5.15.0"
- resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-5.15.0.tgz#44e068dbb855699053b9e6e4e6d3ed5efe98b7d9"
- integrity sha512-6NysIsHkuUS2lF+Lzv1jiK3UjBJk854/vKVcJQVGKlPiqNEVZJNlwaSpsaU5xYXxWEZYfbVFSAomLOS/LV/ovQ==
+"@mui/styled-engine@^5.15.1":
+ version "5.15.1"
+ resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-5.15.1.tgz#00f179e51afe252022bf356f72354968f9c5bf25"
+ integrity sha512-7WDZTJLqGexWDjqE9oAgjU8ak6hEtUw2yQU7SIYID5kLVO2Nj/Wi/KicbLsXnTsJNvSqePIlUIWTBSXwWJCPZw==
dependencies:
"@babel/runtime" "^7.23.5"
"@emotion/cache" "^11.11.0"
csstype "^3.1.2"
prop-types "^15.8.1"
-"@mui/styles@5.15.0":
- version "5.15.0"
- resolved "https://registry.yarnpkg.com/@mui/styles/-/styles-5.15.0.tgz#8cf728ffa3ef33eb20f7533438c3ff36b98863c6"
- integrity sha512-YAtXHlANm7wPo2IbYcWhya2c4KI9lxJm3d6UiFhObVg9WdkXZlF+hAIspmXLXo+Z9I/3AH44se+dJfY+B+duVQ==
+"@mui/styles@5.15.1":
+ version "5.15.1"
+ resolved "https://registry.yarnpkg.com/@mui/styles/-/styles-5.15.1.tgz#4493b603ed0d0721edf3da05633d4aafaed84f7e"
+ integrity sha512-ZuUImqLIZUzoGklmQIjtczK49L+gtWwRNrgXXgAbmPKWOCjkrn/a6XZvqvD91VwlPYQUFhzyR+OcSi+k4cxFaQ==
dependencies:
"@babel/runtime" "^7.23.5"
"@emotion/hash" "^0.9.1"
- "@mui/private-theming" "^5.15.0"
+ "@mui/private-theming" "^5.15.1"
"@mui/types" "^7.2.11"
- "@mui/utils" "^5.15.0"
+ "@mui/utils" "^5.15.1"
clsx "^2.0.0"
csstype "^3.1.2"
hoist-non-react-statics "^3.3.2"
@@ -1246,16 +1256,16 @@
jss-plugin-vendor-prefixer "^10.10.0"
prop-types "^15.8.1"
-"@mui/system@5.15.0", "@mui/system@^5.15.0":
- version "5.15.0"
- resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.15.0.tgz#d4f6fd65ad8e404d4d7c7b56d755d2a63b0edddb"
- integrity sha512-8TPjfTlYBNB7/zBJRL4QOD9kImwdZObbiYNh0+hxvhXr2koezGx8USwPXj8y/JynbzGCkIybkUztCdWlMZe6OQ==
+"@mui/system@5.15.1", "@mui/system@^5.15.1":
+ version "5.15.1"
+ resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.15.1.tgz#e2a79b5e188ca89a3e58aa4d27e3484edf9e24b0"
+ integrity sha512-LAnP0ls69rqW9eBgI29phIx/lppv+WDGI7b3EJN7VZIqw0RezA0GD7NRpV12BgEYJABEii6z5Q9B5tg7dsX0Iw==
dependencies:
"@babel/runtime" "^7.23.5"
- "@mui/private-theming" "^5.15.0"
- "@mui/styled-engine" "^5.15.0"
+ "@mui/private-theming" "^5.15.1"
+ "@mui/styled-engine" "^5.15.1"
"@mui/types" "^7.2.11"
- "@mui/utils" "^5.15.0"
+ "@mui/utils" "^5.15.1"
clsx "^2.0.0"
csstype "^3.1.2"
prop-types "^15.8.1"
@@ -1265,20 +1275,20 @@
resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.2.11.tgz#36b99a88f8010dc716128e568dc05681a69dc7ae"
integrity sha512-KWe/QTEsFFlFSH+qRYf3zoFEj3z67s+qAuSnMMg+gFwbxG7P96Hm6g300inQL1Wy///gSRb8juX7Wafvp93m3w==
-"@mui/utils@5.15.0", "@mui/utils@^5.13.7", "@mui/utils@^5.14.14", "@mui/utils@^5.14.16", "@mui/utils@^5.15.0":
- version "5.15.0"
- resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.15.0.tgz#87b4db92dd2ddf3e2676377427f50662124013b4"
- integrity sha512-XSmTKStpKYamewxyJ256+srwEnsT3/6eNo6G7+WC1tj2Iq9GfUJ/6yUoB7YXjOD2jTZ3XobToZm4pVz1LBt6GA==
+"@mui/utils@5.15.1", "@mui/utils@^5.13.7", "@mui/utils@^5.14.14", "@mui/utils@^5.14.16", "@mui/utils@^5.15.1":
+ version "5.15.1"
+ resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.15.1.tgz#71d69dc8c0f13a1fd6aca20b53ec496636e6b854"
+ integrity sha512-V1/d0E3Bju5YdB59HJf2G0tnHrFEvWLN+f8hAXp9+JSNy/LC2zKyqUfPPahflR6qsI681P8G9r4mEZte/SrrYA==
dependencies:
"@babel/runtime" "^7.23.5"
"@types/prop-types" "^15.7.11"
prop-types "^15.8.1"
react-is "^18.2.0"
-"@mui/x-charts@6.18.3":
- version "6.18.3"
- resolved "https://registry.yarnpkg.com/@mui/x-charts/-/x-charts-6.18.3.tgz#d99504b59d55a4e45ed13b7f55b21fe98e4c6714"
- integrity sha512-RpYaXGdFKxFW5xH+Lahkte9ew1Pawd/fQQmvgQPB7ufUH9PibOpaqxIV3gZvOMexMSmPXWCTHRucQkce9goNTA==
+"@mui/x-charts@6.18.4":
+ version "6.18.4"
+ resolved "https://registry.yarnpkg.com/@mui/x-charts/-/x-charts-6.18.4.tgz#db3fc4008c0d9b86c6bc0ebe8b75e2a9838429d3"
+ integrity sha512-KqZla5yyXK0T+tZSTuAGYZZpajKKCwG2rhWrt2DKxqirG9PWxa9Iy7RIx6NupKeNGUqUkWQJkAh0IHYylfxvbQ==
dependencies:
"@babel/runtime" "^7.23.2"
"@mui/base" "^5.0.0-beta.22"
@@ -1290,24 +1300,24 @@
d3-shape "^3.2.0"
prop-types "^15.8.1"
-"@mui/x-data-grid-pro@6.18.4":
- version "6.18.4"
- resolved "https://registry.yarnpkg.com/@mui/x-data-grid-pro/-/x-data-grid-pro-6.18.4.tgz#c13e2c7e9bb089db69ad2484fc588fb8c9a8bc3f"
- integrity sha512-xcQFNvf8p8EU6K05uDd9k83nfRm4UkffxXvXH9RRvV2B4rfcfsGlRZRpmt0+LeGh8jSdMNnAfSGLMgzbCXJ08A==
+"@mui/x-data-grid-pro@6.18.6":
+ version "6.18.6"
+ resolved "https://registry.yarnpkg.com/@mui/x-data-grid-pro/-/x-data-grid-pro-6.18.6.tgz#2a21dd92c76c410581215d37259759e8592a2d08"
+ integrity sha512-fyex5IcRrtT7K6JoY/FoWFjlIaXmJ3tQgWh4ew8YG46jVvCtZlumQgGw5bSjs2/QVp0NVeXlp9nZ5O8dSN8xLg==
dependencies:
"@babel/runtime" "^7.23.2"
"@mui/utils" "^5.14.16"
- "@mui/x-data-grid" "6.18.4"
+ "@mui/x-data-grid" "6.18.6"
"@mui/x-license-pro" "6.10.2"
"@types/format-util" "^1.0.3"
clsx "^2.0.0"
prop-types "^15.8.1"
reselect "^4.1.8"
-"@mui/x-data-grid@6.18.4":
- version "6.18.4"
- resolved "https://registry.yarnpkg.com/@mui/x-data-grid/-/x-data-grid-6.18.4.tgz#5066d3b6f017ea6fe524ed57059365f684f2cc43"
- integrity sha512-uiinfqioCRoesUlJF3gvh67Ja3TrJJvPRTu4Gkf/RQBjr0BDNQ8BJrnuffqD8D/0SVUiqRZvcrjtgG1BIyjKRw==
+"@mui/x-data-grid@6.18.6":
+ version "6.18.6"
+ resolved "https://registry.yarnpkg.com/@mui/x-data-grid/-/x-data-grid-6.18.6.tgz#59e16a850b28229c294d440617fb6d5b0070d4c2"
+ integrity sha512-BRI2ilDrWq5pSBH1Rx/har57CIQPF0CebvPZNRVE4EV9RqTt3pwNyWaRQDjmHN9kij0YUlbZe0v9UrRT9I8KLw==
dependencies:
"@babel/runtime" "^7.23.2"
"@mui/utils" "^5.14.16"
@@ -1315,24 +1325,24 @@
prop-types "^15.8.1"
reselect "^4.1.8"
-"@mui/x-date-pickers-pro@6.18.4":
- version "6.18.4"
- resolved "https://registry.yarnpkg.com/@mui/x-date-pickers-pro/-/x-date-pickers-pro-6.18.4.tgz#ac6b1366e71253134f253282a281aa1ec33383b0"
- integrity sha512-0znZmEXn95TFfpyz5q9tcjUoJLXPcS1XFj7VaA12NJJotkYtW13Bg7idEOQqlNNhuLD/nDtEI3grYtdoQB+n5Q==
+"@mui/x-date-pickers-pro@6.18.6":
+ version "6.18.6"
+ resolved "https://registry.yarnpkg.com/@mui/x-date-pickers-pro/-/x-date-pickers-pro-6.18.6.tgz#45688a157ca426c2f05122542d74fe567c5e878b"
+ integrity sha512-rFG0fnTVcnDG0NTJ0yEA98eKZdVbouhq83gtpIwJdtyCKhHdA74fE2OQsMoeXjt5yDx7alylWm73oCIYeVN8dg==
dependencies:
"@babel/runtime" "^7.23.2"
"@mui/base" "^5.0.0-beta.22"
"@mui/utils" "^5.14.16"
- "@mui/x-date-pickers" "6.18.4"
+ "@mui/x-date-pickers" "6.18.6"
"@mui/x-license-pro" "6.10.2"
clsx "^2.0.0"
prop-types "^15.8.1"
react-transition-group "^4.4.5"
-"@mui/x-date-pickers@6.18.4":
- version "6.18.4"
- resolved "https://registry.yarnpkg.com/@mui/x-date-pickers/-/x-date-pickers-6.18.4.tgz#0b54634d182b5fdf6337c0915f39b606c094b64f"
- integrity sha512-YqJ6lxZHBIt344B3bvRAVbdYSQz4dcmJQXGcfvJTn26VdKjpgzjAqwhlbQhbAt55audJOWzGB99ImuQuljDROA==
+"@mui/x-date-pickers@6.18.6":
+ version "6.18.6"
+ resolved "https://registry.yarnpkg.com/@mui/x-date-pickers/-/x-date-pickers-6.18.6.tgz#416e0b83dd2774547e3c864c89bedf2f4ca3e05a"
+ integrity sha512-pqOrGPUDVY/1xXrM1hofqwgquno/SB9aG9CVS1m2Rs8hKF1VWRC+jYlEa1Qk08xKmvkia5g7NsdV/BBb+tHUZw==
dependencies:
"@babel/runtime" "^7.23.2"
"@mui/base" "^5.0.0-beta.22"
@@ -1441,13 +1451,16 @@
"@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0"
-"@npmcli/fs@^2.1.0":
- version "2.1.2"
- resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-2.1.2.tgz#a9e2541a4a2fec2e69c29b35e6060973da79b865"
- integrity sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==
+"@npmcli/agent@^2.0.0":
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/@npmcli/agent/-/agent-2.2.0.tgz#e81f00fdb2a670750ff7731bbefb47ecbf0ccf44"
+ integrity sha512-2yThA1Es98orMkpSLVqlDZAMPK3jHJhifP2gnNUdk1754uZ8yI5c+ulCoVG+WlntQA6MzhrURMXjSd9Z7dJ2/Q==
dependencies:
- "@gar/promisify" "^1.1.3"
- semver "^7.3.5"
+ agent-base "^7.1.0"
+ http-proxy-agent "^7.0.0"
+ https-proxy-agent "^7.0.1"
+ lru-cache "^10.0.1"
+ socks-proxy-agent "^8.0.1"
"@npmcli/fs@^3.1.0":
version "3.1.0"
@@ -1456,19 +1469,19 @@
dependencies:
semver "^7.3.5"
-"@npmcli/git@^4.0.0":
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/@npmcli/git/-/git-4.1.0.tgz#ab0ad3fd82bc4d8c1351b6c62f0fa56e8fe6afa6"
- integrity sha512-9hwoB3gStVfa0N31ymBmrX+GuDGdVA/QWShZVqE0HK2Af+7QGGrCTbZia/SW0ImUTjTne7SP91qxDmtXvDHRPQ==
+"@npmcli/git@^5.0.0":
+ version "5.0.3"
+ resolved "https://registry.yarnpkg.com/@npmcli/git/-/git-5.0.3.tgz#ad3ede0994bcf716ddb63d361f3ea16cb72d878c"
+ integrity sha512-UZp9NwK+AynTrKvHn5k3KviW/hA5eENmFsu3iAPe7sWRt0lFUdsY/wXIYjpDFe7cdSNwOIzbObfwgt6eL5/2zw==
dependencies:
- "@npmcli/promise-spawn" "^6.0.0"
- lru-cache "^7.4.4"
- npm-pick-manifest "^8.0.0"
+ "@npmcli/promise-spawn" "^7.0.0"
+ lru-cache "^10.0.1"
+ npm-pick-manifest "^9.0.0"
proc-log "^3.0.0"
promise-inflight "^1.0.1"
promise-retry "^2.0.1"
semver "^7.3.5"
- which "^3.0.0"
+ which "^4.0.0"
"@npmcli/installed-package-contents@^2.0.1":
version "2.0.2"
@@ -1478,36 +1491,28 @@
npm-bundled "^3.0.0"
npm-normalize-package-bin "^3.0.0"
-"@npmcli/move-file@^2.0.0":
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-2.0.1.tgz#26f6bdc379d87f75e55739bab89db525b06100e4"
- integrity sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==
- dependencies:
- mkdirp "^1.0.4"
- rimraf "^3.0.2"
-
"@npmcli/node-gyp@^3.0.0":
version "3.0.0"
resolved "https://registry.yarnpkg.com/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz#101b2d0490ef1aa20ed460e4c0813f0db560545a"
integrity sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==
-"@npmcli/promise-spawn@^6.0.0", "@npmcli/promise-spawn@^6.0.1":
- version "6.0.2"
- resolved "https://registry.yarnpkg.com/@npmcli/promise-spawn/-/promise-spawn-6.0.2.tgz#c8bc4fa2bd0f01cb979d8798ba038f314cfa70f2"
- integrity sha512-gGq0NJkIGSwdbUt4yhdF8ZrmkGKVz9vAdVzpOfnom+V8PLSmSOVhZwbNvZZS1EYcJN5hzzKBxmmVVAInM6HQLg==
+"@npmcli/promise-spawn@^7.0.0":
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/@npmcli/promise-spawn/-/promise-spawn-7.0.0.tgz#fd1c64ed4ff2341e503e1f390c62640a6540df09"
+ integrity sha512-wBqcGsMELZna0jDblGd7UXgOby45TQaMWmbFwWX+SEotk4HV6zG2t6rT9siyLhPk4P6YYqgfL1UO8nMWDBVJXQ==
dependencies:
- which "^3.0.0"
+ which "^4.0.0"
-"@npmcli/run-script@6.0.2", "@npmcli/run-script@^6.0.0":
- version "6.0.2"
- resolved "https://registry.yarnpkg.com/@npmcli/run-script/-/run-script-6.0.2.tgz#a25452d45ee7f7fb8c16dfaf9624423c0c0eb885"
- integrity sha512-NCcr1uQo1k5U+SYlnIrbAh3cxy+OQT1VtqiAbxdymSlptbzBb62AjH2xXgjNCoP073hoa1CfCAcwoZ8k96C4nA==
+"@npmcli/run-script@7.0.2", "@npmcli/run-script@^7.0.0":
+ version "7.0.2"
+ resolved "https://registry.yarnpkg.com/@npmcli/run-script/-/run-script-7.0.2.tgz#497e7f058799497889df65900c711312252276d3"
+ integrity sha512-Omu0rpA8WXvcGeY6DDzyRoY1i5DkCBkzyJ+m2u7PD6quzb0TvSqdIPOkTn8ZBOj7LbbcbMfZ3c5skwSu6m8y2w==
dependencies:
"@npmcli/node-gyp" "^3.0.0"
- "@npmcli/promise-spawn" "^6.0.0"
- node-gyp "^9.0.0"
+ "@npmcli/promise-spawn" "^7.0.0"
+ node-gyp "^10.0.0"
read-package-json-fast "^3.0.0"
- which "^3.0.0"
+ which "^4.0.0"
"@nrwl/devkit@17.1.3":
version "17.1.3"
@@ -1795,10 +1800,10 @@
"@react-spring/shared" "~9.7.3"
"@react-spring/types" "~9.7.3"
-"@remix-run/router@1.13.1":
- version "1.13.1"
- resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.13.1.tgz#07e2a8006f23a3bc898b3f317e0a58cc8076b86e"
- integrity sha512-so+DHzZKsoOcoXrILB4rqDkMDy7NLMErRdOxvzvOKb507YINKUP4Di+shbTZDhSE/pBZ+vr7XGIpcOO0VLSA+Q==
+"@remix-run/router@1.14.1":
+ version "1.14.1"
+ resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.14.1.tgz#6d2dd03d52e604279c38911afc1079d58c50a755"
+ integrity sha512-Qg4DMQsfPNAs88rb2xkdk03N3bjK4jgX5fR24eHCTR9q6PrhZQZ4UJBPzCHJkIpTRN1UKxx2DzjZmnC+7Lj0Ow==
"@rollup/rollup-android-arm-eabi@4.6.1":
version "4.6.1"
@@ -1867,7 +1872,14 @@
dependencies:
"@sigstore/protobuf-specs" "^0.2.0"
-"@sigstore/protobuf-specs@^0.2.0":
+"@sigstore/bundle@^2.1.0":
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/@sigstore/bundle/-/bundle-2.1.0.tgz#c6140ca97b68815edf7c4fb7bdbf58d656525c39"
+ integrity sha512-89uOo6yh/oxaU8AeOUnVrTdVMcGk9Q1hJa7Hkvalc6G3Z3CupWk4Xe9djSgJm9fMkH69s0P0cVHUoKSOemLdng==
+ dependencies:
+ "@sigstore/protobuf-specs" "^0.2.1"
+
+"@sigstore/protobuf-specs@^0.2.0", "@sigstore/protobuf-specs@^0.2.1":
version "0.2.1"
resolved "https://registry.yarnpkg.com/@sigstore/protobuf-specs/-/protobuf-specs-0.2.1.tgz#be9ef4f3c38052c43bd399d3f792c97ff9e2277b"
integrity sha512-XTWVxnWJu+c1oCshMLwnKvz8ZQJJDVOlciMfgpJBQbThVjKTCG8dwyhgLngBD2KN0ap9F/gOV8rFDEx8uh7R2A==
@@ -1881,6 +1893,15 @@
"@sigstore/protobuf-specs" "^0.2.0"
make-fetch-happen "^11.0.1"
+"@sigstore/sign@^2.1.0":
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/@sigstore/sign/-/sign-2.2.0.tgz#4918207d8356877ab42d85d360d5729e9b3ec65a"
+ integrity sha512-AAbmnEHDQv6CSfrWA5wXslGtzLPtAtHZleKOgxdQYvx/s76Fk6T6ZVt7w2IGV9j1UrFeBocTTQxaXG2oRrDhYA==
+ dependencies:
+ "@sigstore/bundle" "^2.1.0"
+ "@sigstore/protobuf-specs" "^0.2.1"
+ make-fetch-happen "^13.0.0"
+
"@sigstore/tuf@^1.0.3":
version "1.0.3"
resolved "https://registry.yarnpkg.com/@sigstore/tuf/-/tuf-1.0.3.tgz#2a65986772ede996485728f027b0514c0b70b160"
@@ -1889,6 +1910,14 @@
"@sigstore/protobuf-specs" "^0.2.0"
tuf-js "^1.1.7"
+"@sigstore/tuf@^2.1.0":
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/@sigstore/tuf/-/tuf-2.2.0.tgz#ef636239687e41af3f2ce10667ab88f5ca6165b3"
+ integrity sha512-KKATZ5orWfqd9ZG6MN8PtCIx4eevWSuGRKQvofnWXRpyMyUEpmrzg5M5BrCpjM+NfZ0RbNGOh5tCz/P2uoRqOA==
+ dependencies:
+ "@sigstore/protobuf-specs" "^0.2.1"
+ tuf-js "^2.1.0"
+
"@sinclair/typebox@^0.27.8":
version "0.27.8"
resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e"
@@ -1918,29 +1947,29 @@
dependencies:
defer-to-connect "^2.0.1"
-"@tanstack/query-core@5.13.4":
- version "5.13.4"
- resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.13.4.tgz#50ecd3f721dfb0859528fbb8863268bee24145f0"
- integrity sha512-8+rJucXvC/xlr4OrxHhEIob/cTlbT4fgmz1VsvB0D12FRStKaXeLORNGcOhSAynRd2NL74SV/Qq0IIb4DedLcA==
+"@tanstack/query-core@5.14.2":
+ version "5.14.2"
+ resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.14.2.tgz#ef0c1a93e142d5cce90b0ac2d0333a88fc0fbb95"
+ integrity sha512-QmoJvC72sSWs3hgGis8JdmlDvqLfYGWUK4UG6OR9Q6t28JMN9m2FDwKPqoSJ9YVocELCSjMt/FGjEiLfk8000Q==
-"@tanstack/query-devtools@5.13.3":
- version "5.13.3"
- resolved "https://registry.yarnpkg.com/@tanstack/query-devtools/-/query-devtools-5.13.3.tgz#aeaa0c78cb25094172152a8d9551bf9896bcac29"
- integrity sha512-1acztPKZexvM9Ns2T0aq4rMVSDA3VGdB73KF7zT/KNVl6VfnBvs24wuIRVSPZKqyZznZTzT3/DzcpntYqg9hmw==
+"@tanstack/query-devtools@5.14.6":
+ version "5.14.6"
+ resolved "https://registry.yarnpkg.com/@tanstack/query-devtools/-/query-devtools-5.14.6.tgz#a95dffc6635659a092a0f36a48d6891f62c92b2b"
+ integrity sha512-Kj820qMnyrTodqznWGnYQzef4SSsGrTnz6kW2ViFesA/ikJ79Rz+GB327Tx+xr8rSEsF4MTKEB8oH8+PKpXL4g==
-"@tanstack/react-query-devtools@5.13.4":
- version "5.13.4"
- resolved "https://registry.yarnpkg.com/@tanstack/react-query-devtools/-/react-query-devtools-5.13.4.tgz#146f730cbd2929d408c1a20a3bc4312122817f4f"
- integrity sha512-htYzfOrE6vucBCRrVLxW8qEg8mfC5UaMJMiFPgbv5yH3zoHtJSjVZP7fcvgTp3RwFKBr1IOQ9yHLTjSSXemS7A==
+"@tanstack/react-query-devtools@5.14.6":
+ version "5.14.6"
+ resolved "https://registry.yarnpkg.com/@tanstack/react-query-devtools/-/react-query-devtools-5.14.6.tgz#e68923e6d5b0417fdb5848382fa3f725a321086f"
+ integrity sha512-RR+y3hrv8BzFCa0tPA6Vi2lvlMDORBzNGwjDRHTTowUcx84xElbJbgB0O82HO4gYWaXMFJC4Lr2w4QfvMRVVeg==
dependencies:
- "@tanstack/query-devtools" "5.13.3"
+ "@tanstack/query-devtools" "5.14.6"
-"@tanstack/react-query@5.13.4":
- version "5.13.4"
- resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-5.13.4.tgz#1a2b93a7319f3abd13461b5c5c7cf4eac369f567"
- integrity sha512-3HjvkFFriEQwffUXtKHPiwkfFXUGbs46YATTzzyK1+Pw6Ekd3kwzS50e45qdamWuEXmXxyo5S1zp534LdFG0Rw==
+"@tanstack/react-query@5.14.6":
+ version "5.14.6"
+ resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-5.14.6.tgz#40d51832d1ca6c9e28d3e48fd44c116d9ce28296"
+ integrity sha512-+INnJdq/904d+K2XQjqdIC58glpNGfQ8Xz93M6WBeJs5FPGFV8SEuFVzPtW/bKZ/Hu7hAiJpbFLDg5Lysvwmuw==
dependencies:
- "@tanstack/query-core" "5.13.4"
+ "@tanstack/query-core" "5.14.2"
"@testing-library/dom@^9.0.0":
version "9.3.3"
@@ -1983,6 +2012,11 @@
resolved "https://registry.yarnpkg.com/@tufjs/canonical-json/-/canonical-json-1.0.0.tgz#eade9fd1f537993bc1f0949f3aea276ecc4fab31"
integrity sha512-QTnf++uxunWvG2z3UFNzAoQPHxnSXOwtaI3iJ+AohhV+5vONuArPjJE7aPXPVXfXJsqrVbZBu9b81AJoSd09IQ==
+"@tufjs/canonical-json@2.0.0":
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz#a52f61a3d7374833fca945b2549bc30a2dd40d0a"
+ integrity sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==
+
"@tufjs/models@1.0.4":
version "1.0.4"
resolved "https://registry.yarnpkg.com/@tufjs/models/-/models-1.0.4.tgz#5a689630f6b9dbda338d4b208019336562f176ef"
@@ -1991,6 +2025,14 @@
"@tufjs/canonical-json" "1.0.0"
minimatch "^9.0.0"
+"@tufjs/models@2.0.0":
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/@tufjs/models/-/models-2.0.0.tgz#c7ab241cf11dd29deb213d6817dabb8c99ce0863"
+ integrity sha512-c8nj8BaOExmZKO2DXhDfegyhSGcG9E/mPN3U13L+/PsoWm1uaGiHHjxqSHQiasDBQwDA3aHuw9+9spYAP1qvvg==
+ dependencies:
+ "@tufjs/canonical-json" "2.0.0"
+ minimatch "^9.0.3"
+
"@types/archiver@6.0.2":
version "6.0.2"
resolved "https://registry.yarnpkg.com/@types/archiver/-/archiver-6.0.2.tgz#0daf8c83359cbde69de1e4b33dcade6a48a929e2"
@@ -2160,10 +2202,10 @@
"@types/eslint" "*"
"@types/estree" "*"
-"@types/eslint@*", "@types/eslint@8.44.8":
- version "8.44.8"
- resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.44.8.tgz#f4fe1dab9b3d3dd98082d4b9f80e59ab40f1261c"
- integrity sha512-4K8GavROwhrYl2QXDXm0Rv9epkA8GBFu0EI+XrrnnuCl7u8CWBRusX7fXJfanhZTDWSAL24gDI/UqXyUM0Injw==
+"@types/eslint@*", "@types/eslint@8.44.9":
+ version "8.44.9"
+ resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.44.9.tgz#5799663009645637bd1c45b2e1a7c8f4caf89534"
+ integrity sha512-6yBxcvwnnYoYT1Uk2d+jvIfsuP4mb2EdIxFnrPABj5a/838qe5bGkNLFOiipX4ULQ7XVQvTxOh7jO+BTAiqsEw==
dependencies:
"@types/estree" "*"
"@types/json-schema" "*"
@@ -2271,6 +2313,11 @@
"@types/through" "*"
rxjs "^7.2.0"
+"@types/invariant@2.2.35":
+ version "2.2.35"
+ resolved "https://registry.yarnpkg.com/@types/invariant/-/invariant-2.2.35.tgz#cd3ebf581a6557452735688d8daba6cf0bd5a3be"
+ integrity sha512-DxX1V9P8zdJPYQat1gHyY0xj3efl8gnMVjiM9iCY6y27lj+PoQWkgjt8jDqmovPqULkKVpKRg8J36iQiA+EtEg==
+
"@types/invariant@2.2.37":
version "2.2.37"
resolved "https://registry.yarnpkg.com/@types/invariant/-/invariant-2.2.37.tgz#1709741e534364d653c87dff22fc76fa94aa7bc0"
@@ -2331,10 +2378,10 @@
"@types/node" "*"
form-data "^4.0.0"
-"@types/node@*", "@types/node@20.10.4":
- version "20.10.4"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-20.10.4.tgz#b246fd84d55d5b1b71bf51f964bd514409347198"
- integrity sha512-D08YG6rr8X90YB56tSIuBaddy/UXAA9RKJoFvrsnogAum/0pmjkgi4+2nx96A330FmioegBWmEYQ+syqCFaveg==
+"@types/node@*", "@types/node@20.10.5":
+ version "20.10.5"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-20.10.5.tgz#47ad460b514096b7ed63a1dae26fad0914ed3ab2"
+ integrity sha512-nNPsNE65wjMxEKI93yOP+NPGGBJz/PoN3kZsVLee0XMiJolxSekEVD8wRwBUBqkwc7UWop0edW50yrCQW4CyRw==
dependencies:
undici-types "~5.26.4"
@@ -2394,10 +2441,10 @@
"@types/webpack" "^4"
"@types/webpack-dev-server" "3"
-"@types/react-dom@18.2.17", "@types/react-dom@^18.0.0":
- version "18.2.17"
- resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.17.tgz#375c55fab4ae671bd98448dcfa153268d01d6f64"
- integrity sha512-rvrT/M7Df5eykWFxn6MYt5Pem/Dbyc1N8Y0S9Mrkw2WFCRiqUgw9P7ul2NpwsXCSM1DVdENzdG9J5SreqfAIWg==
+"@types/react-dom@18.2.18", "@types/react-dom@^18.0.0":
+ version "18.2.18"
+ resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.18.tgz#16946e6cd43971256d874bc3d0a72074bb8571dd"
+ integrity sha512-TJxDm6OfAX2KJWJdMEVTwWke5Sc/E/RlnPGvGfS0W7+6ocy2xhDVQVh/KvC2Uf7kACs+gDytdusDSdWfWkaNzw==
dependencies:
"@types/react" "*"
@@ -2425,17 +2472,17 @@
"@types/history" "^4.7.11"
"@types/react" "*"
-"@types/react-transition-group@^4.4.8", "@types/react-transition-group@^4.4.9":
- version "4.4.9"
- resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.9.tgz#12a1a1b5b8791067198149867b0823fbace31579"
- integrity sha512-ZVNmWumUIh5NhH8aMD9CR2hdW0fNuYInlocZHaZ+dgk/1K49j1w/HoAuK1ki+pgscQrOFRTlXeoURtuzEkV3dg==
+"@types/react-transition-group@^4.4.10", "@types/react-transition-group@^4.4.8":
+ version "4.4.10"
+ resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.10.tgz#6ee71127bdab1f18f11ad8fb3322c6da27c327ac"
+ integrity sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==
dependencies:
"@types/react" "*"
-"@types/react@*", "@types/react@18.2.43":
- version "18.2.43"
- resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.43.tgz#c58e5abe241e6f71f60ce30e2a9aceb9d3a2a374"
- integrity sha512-nvOV01ZdBdd/KW6FahSbcNplt2jCJfyWdTos61RYHV+FVv5L/g9AOX1bmbVcWcLFL8+KHQfh1zVIQrud6ihyQA==
+"@types/react@*", "@types/react@18.2.45":
+ version "18.2.45"
+ resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.45.tgz#253f4fac288e7e751ab3dc542000fb687422c15c"
+ integrity sha512-TtAxCNrlrBp8GoeEp1npd5g+d/OejJHFxS3OWmrPBMFaVQMSN0OFySozJio5BHxTuTeug00AVXVAjfDSfk+lUg==
dependencies:
"@types/prop-types" "*"
"@types/scheduler" "*"
@@ -2503,10 +2550,10 @@
resolved "https://registry.yarnpkg.com/@types/source-list-map/-/source-list-map-0.1.6.tgz#164e169dd061795b50b83c19e4d3be09f8d3a454"
integrity sha512-5JcVt1u5HDmlXkwOD2nslZVllBBc7HDuOICfiZah2Z0is8M8g+ddAEawbmd3VjedfDHBzxCaXLs07QEmb7y54g==
-"@types/stylis@^4.0.2":
- version "4.2.4"
- resolved "https://registry.yarnpkg.com/@types/stylis/-/stylis-4.2.4.tgz#14b61f022e832d87d442ae1795e0f0f0b7daa879"
- integrity sha512-36ZrGJ8fgtBr6nwNnuJ9jXIj+bn/pF6UoqmrQT7+Y99+tFFeHHsoR54+194dHdyhPjgbeoNz3Qru0oRt0l6ASQ==
+"@types/stylis@4.2.0":
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/@types/stylis/-/stylis-4.2.0.tgz#199a3f473f0c3a6f6e4e1b17cdbc967f274bdc6b"
+ integrity sha512-n4sx2bqL0mW1tvDf/loQ+aMX7GQD3lc3fkCMC55VFNDu/vBOabO+LTIeXKM14xK0ppk5TUGcWRjiSpIlUpghKw==
"@types/tapable@^1":
version "1.0.12"
@@ -2528,6 +2575,11 @@
dependencies:
"@types/node" "*"
+"@types/title@3.4.3":
+ version "3.4.3"
+ resolved "https://registry.yarnpkg.com/@types/title/-/title-3.4.3.tgz#685f2f18f19d746e70a817ca4dac26c1dd217668"
+ integrity sha512-mjupLOb4kwUuoUFokkacy/VMRVBH2qtqZ5AX7K7iha6+iKIkX80n/Y4EoNVEVRmer8dYJU/ry+fppUaDFVQh7Q==
+
"@types/uglify-js@*":
version "3.17.4"
resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.17.4.tgz#3c70021f08023e5a760ce133d22966f200e1d31c"
@@ -2598,16 +2650,16 @@
dependencies:
"@types/yargs-parser" "*"
-"@typescript-eslint/eslint-plugin@6.13.2":
- version "6.13.2"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.13.2.tgz#2e03506c5362a65e43cb132c37c9ce2d3cb51470"
- integrity sha512-3+9OGAWHhk4O1LlcwLBONbdXsAhLjyCFogJY/cWy2lxdVJ2JrcTF2pTGMaLl2AE7U1l31n8Py4a8bx5DLf/0dQ==
+"@typescript-eslint/eslint-plugin@6.14.0":
+ version "6.14.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.14.0.tgz#fc1ab5f23618ba590c87e8226ff07a760be3dd7b"
+ integrity sha512-1ZJBykBCXaSHG94vMMKmiHoL0MhNHKSVlcHVYZNw+BKxufhqQVTOawNpwwI1P5nIFZ/4jLVop0mcY6mJJDFNaw==
dependencies:
"@eslint-community/regexpp" "^4.5.1"
- "@typescript-eslint/scope-manager" "6.13.2"
- "@typescript-eslint/type-utils" "6.13.2"
- "@typescript-eslint/utils" "6.13.2"
- "@typescript-eslint/visitor-keys" "6.13.2"
+ "@typescript-eslint/scope-manager" "6.14.0"
+ "@typescript-eslint/type-utils" "6.14.0"
+ "@typescript-eslint/utils" "6.14.0"
+ "@typescript-eslint/visitor-keys" "6.14.0"
debug "^4.3.4"
graphemer "^1.4.0"
ignore "^5.2.4"
@@ -2622,15 +2674,15 @@
dependencies:
"@typescript-eslint/utils" "5.62.0"
-"@typescript-eslint/parser@6.13.2":
- version "6.13.2"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.13.2.tgz#390b79cc9a57a5f904d197a201cc4b6bc4f9afb9"
- integrity sha512-MUkcC+7Wt/QOGeVlM8aGGJZy1XV5YKjTpq9jK6r6/iLsGXhBVaGP5N0UYvFsu9BFlSpwY9kMretzdBH01rkRXg==
+"@typescript-eslint/parser@6.14.0":
+ version "6.14.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.14.0.tgz#a2d6a732e0d2b95c73f6a26ae7362877cc1b4212"
+ integrity sha512-QjToC14CKacd4Pa7JK4GeB/vHmWFJckec49FR4hmIRf97+KXole0T97xxu9IFiPxVQ1DBWrQ5wreLwAGwWAVQA==
dependencies:
- "@typescript-eslint/scope-manager" "6.13.2"
- "@typescript-eslint/types" "6.13.2"
- "@typescript-eslint/typescript-estree" "6.13.2"
- "@typescript-eslint/visitor-keys" "6.13.2"
+ "@typescript-eslint/scope-manager" "6.14.0"
+ "@typescript-eslint/types" "6.14.0"
+ "@typescript-eslint/typescript-estree" "6.14.0"
+ "@typescript-eslint/visitor-keys" "6.14.0"
debug "^4.3.4"
"@typescript-eslint/scope-manager@5.62.0":
@@ -2641,21 +2693,21 @@
"@typescript-eslint/types" "5.62.0"
"@typescript-eslint/visitor-keys" "5.62.0"
-"@typescript-eslint/scope-manager@6.13.2":
- version "6.13.2"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.13.2.tgz#5fa4e4adace028dafac212c770640b94e7b61052"
- integrity sha512-CXQA0xo7z6x13FeDYCgBkjWzNqzBn8RXaE3QVQVIUm74fWJLkJkaHmHdKStrxQllGh6Q4eUGyNpMe0b1hMkXFA==
+"@typescript-eslint/scope-manager@6.14.0":
+ version "6.14.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.14.0.tgz#53d24363fdb5ee0d1d8cda4ed5e5321272ab3d48"
+ integrity sha512-VT7CFWHbZipPncAZtuALr9y3EuzY1b1t1AEkIq2bTXUPKw+pHoXflGNG5L+Gv6nKul1cz1VH8fz16IThIU0tdg==
dependencies:
- "@typescript-eslint/types" "6.13.2"
- "@typescript-eslint/visitor-keys" "6.13.2"
+ "@typescript-eslint/types" "6.14.0"
+ "@typescript-eslint/visitor-keys" "6.14.0"
-"@typescript-eslint/type-utils@6.13.2":
- version "6.13.2"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.13.2.tgz#ebec2da14a6bb7122e0fd31eea72a382c39c6102"
- integrity sha512-Qr6ssS1GFongzH2qfnWKkAQmMUyZSyOr0W54nZNU1MDfo+U4Mv3XveeLZzadc/yq8iYhQZHYT+eoXJqnACM1tw==
+"@typescript-eslint/type-utils@6.14.0":
+ version "6.14.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.14.0.tgz#ac9cb5ba0615c837f1a6b172feeb273d36e4f8af"
+ integrity sha512-x6OC9Q7HfYKqjnuNu5a7kffIYs3No30isapRBJl1iCHLitD8O0lFbRcVGiOcuyN837fqXzPZ1NS10maQzZMKqw==
dependencies:
- "@typescript-eslint/typescript-estree" "6.13.2"
- "@typescript-eslint/utils" "6.13.2"
+ "@typescript-eslint/typescript-estree" "6.14.0"
+ "@typescript-eslint/utils" "6.14.0"
debug "^4.3.4"
ts-api-utils "^1.0.1"
@@ -2664,10 +2716,10 @@
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.62.0.tgz#258607e60effa309f067608931c3df6fed41fd2f"
integrity sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==
-"@typescript-eslint/types@6.13.2":
- version "6.13.2"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.13.2.tgz#c044aac24c2f6cefb8e921e397acad5417dd0ae6"
- integrity sha512-7sxbQ+EMRubQc3wTfTsycgYpSujyVbI1xw+3UMRUcrhSy+pN09y/lWzeKDbvhoqcRbHdc+APLs/PWYi/cisLPg==
+"@typescript-eslint/types@6.14.0":
+ version "6.14.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.14.0.tgz#935307f7a931016b7a5eb25d494ea3e1f613e929"
+ integrity sha512-uty9H2K4Xs8E47z3SnXEPRNDfsis8JO27amp2GNCnzGETEW3yTqEIVg5+AI7U276oGF/tw6ZA+UesxeQ104ceA==
"@typescript-eslint/typescript-estree@5.62.0":
version "5.62.0"
@@ -2682,13 +2734,13 @@
semver "^7.3.7"
tsutils "^3.21.0"
-"@typescript-eslint/typescript-estree@6.13.2":
- version "6.13.2"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.13.2.tgz#ae556ee154c1acf025b48d37c3ef95a1d55da258"
- integrity sha512-SuD8YLQv6WHnOEtKv8D6HZUzOub855cfPnPMKvdM/Bh1plv1f7Q/0iFUDLKKlxHcEstQnaUU4QZskgQq74t+3w==
+"@typescript-eslint/typescript-estree@6.14.0":
+ version "6.14.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.14.0.tgz#90c7ddd45cd22139adf3d4577580d04c9189ac13"
+ integrity sha512-yPkaLwK0yH2mZKFE/bXkPAkkFgOv15GJAUzgUVonAbv0Hr4PK/N2yaA/4XQbTZQdygiDkpt5DkxPELqHguNvyw==
dependencies:
- "@typescript-eslint/types" "6.13.2"
- "@typescript-eslint/visitor-keys" "6.13.2"
+ "@typescript-eslint/types" "6.14.0"
+ "@typescript-eslint/visitor-keys" "6.14.0"
debug "^4.3.4"
globby "^11.1.0"
is-glob "^4.0.3"
@@ -2709,17 +2761,17 @@
eslint-scope "^5.1.1"
semver "^7.3.7"
-"@typescript-eslint/utils@6.13.2":
- version "6.13.2"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.13.2.tgz#8eb89e53adc6d703a879b131e528807245486f89"
- integrity sha512-b9Ptq4eAZUym4idijCRzl61oPCwwREcfDI8xGk751Vhzig5fFZR9CyzDz4Sp/nxSLBYxUPyh4QdIDqWykFhNmQ==
+"@typescript-eslint/utils@6.14.0":
+ version "6.14.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.14.0.tgz#856a9e274367d99ffbd39c48128b93a86c4261e3"
+ integrity sha512-XwRTnbvRr7Ey9a1NT6jqdKX8y/atWG+8fAIu3z73HSP8h06i3r/ClMhmaF/RGWGW1tHJEwij1uEg2GbEmPYvYg==
dependencies:
"@eslint-community/eslint-utils" "^4.4.0"
"@types/json-schema" "^7.0.12"
"@types/semver" "^7.5.0"
- "@typescript-eslint/scope-manager" "6.13.2"
- "@typescript-eslint/types" "6.13.2"
- "@typescript-eslint/typescript-estree" "6.13.2"
+ "@typescript-eslint/scope-manager" "6.14.0"
+ "@typescript-eslint/types" "6.14.0"
+ "@typescript-eslint/typescript-estree" "6.14.0"
semver "^7.5.4"
"@typescript-eslint/visitor-keys@5.62.0":
@@ -2730,12 +2782,12 @@
"@typescript-eslint/types" "5.62.0"
eslint-visitor-keys "^3.3.0"
-"@typescript-eslint/visitor-keys@6.13.2":
- version "6.13.2"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.13.2.tgz#e0a4a80cf842bb08e6127b903284166ac4a5594c"
- integrity sha512-OGznFs0eAQXJsp+xSd6k/O1UbFi/K/L7WjqeRoFE7vadjAF9y0uppXhYNQNEqygjou782maGClOoZwPqF0Drlw==
+"@typescript-eslint/visitor-keys@6.14.0":
+ version "6.14.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.14.0.tgz#1d1d486581819287de824a56c22f32543561138e"
+ integrity sha512-fB5cw6GRhJUz03MrROVuj5Zm/Q+XWlVdIsFj+Zb1Hvqouc8t+XP2H5y53QYU/MGtd2dPg6/vJJlhoX3xc2ehfw==
dependencies:
- "@typescript-eslint/types" "6.13.2"
+ "@typescript-eslint/types" "6.14.0"
eslint-visitor-keys "^3.4.1"
"@ungap/structured-clone@^1.2.0":
@@ -2754,44 +2806,44 @@
"@types/babel__core" "^7.20.5"
react-refresh "^0.14.0"
-"@vitest/expect@1.0.4":
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-1.0.4.tgz#2751018b6e527841043e046ff424304453a0a024"
- integrity sha512-/NRN9N88qjg3dkhmFcCBwhn/Ie4h064pY3iv7WLRsDJW7dXnEgeoa8W9zy7gIPluhz6CkgqiB3HmpIXgmEY5dQ==
+"@vitest/expect@1.1.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-1.1.0.tgz#f58eef7de090ad65f30bb93ec54fa9f94c9d1d5d"
+ integrity sha512-9IE2WWkcJo2BR9eqtY5MIo3TPmS50Pnwpm66A6neb2hvk/QSLfPXBz2qdiwUOQkwyFuuXEUj5380CbwfzW4+/w==
dependencies:
- "@vitest/spy" "1.0.4"
- "@vitest/utils" "1.0.4"
+ "@vitest/spy" "1.1.0"
+ "@vitest/utils" "1.1.0"
chai "^4.3.10"
-"@vitest/runner@1.0.4":
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-1.0.4.tgz#c4dcb88c07f40b91293ff1331747ee58fad6d5e4"
- integrity sha512-rhOQ9FZTEkV41JWXozFM8YgOqaG9zA7QXbhg5gy6mFOVqh4PcupirIJ+wN7QjeJt8S8nJRYuZH1OjJjsbxAXTQ==
+"@vitest/runner@1.1.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-1.1.0.tgz#b3bf60f4a78f4324ca09811dd0f87b721a96b534"
+ integrity sha512-zdNLJ00pm5z/uhbWF6aeIJCGMSyTyWImy3Fcp9piRGvueERFlQFbUwCpzVce79OLm2UHk9iwaMSOaU9jVHgNVw==
dependencies:
- "@vitest/utils" "1.0.4"
+ "@vitest/utils" "1.1.0"
p-limit "^5.0.0"
pathe "^1.1.1"
-"@vitest/snapshot@1.0.4":
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-1.0.4.tgz#7020983b3963b473237fea08d347ea83b266b9bb"
- integrity sha512-vkfXUrNyNRA/Gzsp2lpyJxh94vU2OHT1amoD6WuvUAA12n32xeVZQ0KjjQIf8F6u7bcq2A2k969fMVxEsxeKYA==
+"@vitest/snapshot@1.1.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-1.1.0.tgz#b9924e4303382b43bb2c31061b173e69a6fb3437"
+ integrity sha512-5O/wyZg09V5qmNmAlUgCBqflvn2ylgsWJRRuPrnHEfDNT6tQpQ8O1isNGgo+VxofISHqz961SG3iVvt3SPK/QQ==
dependencies:
magic-string "^0.30.5"
pathe "^1.1.1"
pretty-format "^29.7.0"
-"@vitest/spy@1.0.4":
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-1.0.4.tgz#e182c78fb9b1178ff789ad7eb4560ba6750e6e9b"
- integrity sha512-9ojTFRL1AJVh0hvfzAQpm0QS6xIS+1HFIw94kl/1ucTfGCaj1LV/iuJU4Y6cdR03EzPDygxTHwE1JOm+5RCcvA==
+"@vitest/spy@1.1.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-1.1.0.tgz#7f40697e4fc217ac8c3cc89a865d1751b263f561"
+ integrity sha512-sNOVSU/GE+7+P76qYo+VXdXhXffzWZcYIPQfmkiRxaNCSPiLANvQx5Mx6ZURJ/ndtEkUJEpvKLXqAYTKEY+lTg==
dependencies:
tinyspy "^2.2.0"
-"@vitest/utils@1.0.4":
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-1.0.4.tgz#6e673eaf87a2ff28a12688d17bdbb62cc22bf773"
- integrity sha512-gsswWDXxtt0QvtK/y/LWukN7sGMYmnCcv1qv05CsY6cU/Y1zpGX1QuvLs+GO1inczpE6Owixeel3ShkjhYtGfA==
+"@vitest/utils@1.1.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-1.1.0.tgz#d177a5f41bdb484bbb43c8d73a77ca782df068b5"
+ integrity sha512-z+s510fKmYz4Y41XhNs3vcuFTFhcij2YF7F8VQfMEYAAUfqQh0Zfg7+w9xdgFGhPf3tX3TicAe+8BDITk6ampQ==
dependencies:
diff-sequences "^29.6.3"
loupe "^2.3.7"
@@ -2961,10 +3013,10 @@ JSONStream@^1.3.5:
jsonparse "^1.2.0"
through ">=2.2.7 <3"
-abbrev@^1.0.0:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
- integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
+abbrev@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-2.0.0.tgz#cf59829b8b4f03f89dda2771cb7f3653828c89bf"
+ integrity sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==
abort-controller@3.0.0:
version "3.0.0"
@@ -3123,7 +3175,7 @@ ansi-regex@^6.0.1:
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a"
integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==
-ansi-styles@^3.2.1:
+ansi-styles@^3.1.0, ansi-styles@^3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
@@ -3165,6 +3217,11 @@ anymatch@^3.0.0, anymatch@~3.1.2:
resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc"
integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==
+arch@^2.1.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/arch/-/arch-2.2.0.tgz#1bc47818f305764f23ab3306b0bfc086c5a29d11"
+ integrity sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==
+
archiver-utils@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-2.1.0.tgz#e8a460e94b693c3e3da182a098ca6285ba9249e2"
@@ -3243,6 +3300,11 @@ are-we-there-yet@^3.0.0:
delegates "^1.0.0"
readable-stream "^3.6.0"
+arg@1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/arg/-/arg-1.0.0.tgz#444d885a4e25b121640b55155ef7cd03975d6050"
+ integrity sha512-Wk7TEzl1KqvTGs/uyhmHO/3XLd3t1UeU4IstvPXVzGPM522cTjqjNZ99esCkcL52sjqjo8e8CTBcWhkxvGzoAw==
+
arg@5.0.2:
version "5.0.2"
resolved "https://registry.yarnpkg.com/arg/-/arg-5.0.2.tgz#c81433cc427c92c4dcf4865142dbca6f15acd59c"
@@ -3773,14 +3835,14 @@ browserify-zlib@^0.2.0:
dependencies:
pako "~1.0.5"
-browserslist@^4.14.5, browserslist@^4.18.1, browserslist@^4.21.10, browserslist@^4.21.9:
- version "4.22.1"
- resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.22.1.tgz#ba91958d1a59b87dab6fed8dfbcb3da5e2e9c619"
- integrity sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==
+browserslist@^4.14.5, browserslist@^4.18.1, browserslist@^4.21.10, browserslist@^4.22.2:
+ version "4.22.2"
+ resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.22.2.tgz#704c4943072bd81ea18997f3bd2180e89c77874b"
+ integrity sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==
dependencies:
- caniuse-lite "^1.0.30001541"
- electron-to-chromium "^1.4.535"
- node-releases "^2.0.13"
+ caniuse-lite "^1.0.30001565"
+ electron-to-chromium "^1.4.601"
+ node-releases "^2.0.14"
update-browserslist-db "^1.0.13"
buffer-crc32@^0.2.1, buffer-crc32@^0.2.13:
@@ -3877,41 +3939,35 @@ cac@^6.7.12, cac@^6.7.14:
resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959"
integrity sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==
-cacache@^16.1.0:
- version "16.1.3"
- resolved "https://registry.yarnpkg.com/cacache/-/cacache-16.1.3.tgz#a02b9f34ecfaf9a78c9f4bc16fceb94d5d67a38e"
- integrity sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==
+cacache@^17.0.0:
+ version "17.1.4"
+ resolved "https://registry.yarnpkg.com/cacache/-/cacache-17.1.4.tgz#b3ff381580b47e85c6e64f801101508e26604b35"
+ integrity sha512-/aJwG2l3ZMJ1xNAnqbMpA40of9dj/pIH3QfiuQSqjfPJF747VR0J/bHn+/KdNnHKc6XQcWt/AfRSBft82W1d2A==
dependencies:
- "@npmcli/fs" "^2.1.0"
- "@npmcli/move-file" "^2.0.0"
- chownr "^2.0.0"
- fs-minipass "^2.1.0"
- glob "^8.0.1"
- infer-owner "^1.0.4"
+ "@npmcli/fs" "^3.1.0"
+ fs-minipass "^3.0.0"
+ glob "^10.2.2"
lru-cache "^7.7.1"
- minipass "^3.1.6"
+ minipass "^7.0.3"
minipass-collect "^1.0.2"
minipass-flush "^1.0.5"
minipass-pipeline "^1.2.4"
- mkdirp "^1.0.4"
p-map "^4.0.0"
- promise-inflight "^1.0.1"
- rimraf "^3.0.2"
- ssri "^9.0.0"
+ ssri "^10.0.0"
tar "^6.1.11"
- unique-filename "^2.0.0"
+ unique-filename "^3.0.0"
-cacache@^17.0.0:
- version "17.1.4"
- resolved "https://registry.yarnpkg.com/cacache/-/cacache-17.1.4.tgz#b3ff381580b47e85c6e64f801101508e26604b35"
- integrity sha512-/aJwG2l3ZMJ1xNAnqbMpA40of9dj/pIH3QfiuQSqjfPJF747VR0J/bHn+/KdNnHKc6XQcWt/AfRSBft82W1d2A==
+cacache@^18.0.0:
+ version "18.0.1"
+ resolved "https://registry.yarnpkg.com/cacache/-/cacache-18.0.1.tgz#b026d56ad569e4f73cc07c813b3c66707d0fb142"
+ integrity sha512-g4Uf2CFZPaxtJKre6qr4zqLDOOPU7bNVhWjlNhvzc51xaTOx2noMOLhfFkTAqwtrAZAKQUuDfyjitzilpA8WsQ==
dependencies:
"@npmcli/fs" "^3.1.0"
fs-minipass "^3.0.0"
glob "^10.2.2"
- lru-cache "^7.7.1"
+ lru-cache "^10.0.1"
minipass "^7.0.3"
- minipass-collect "^1.0.2"
+ minipass-collect "^2.0.1"
minipass-flush "^1.0.5"
minipass-pipeline "^1.2.4"
p-map "^4.0.0"
@@ -3970,10 +4026,10 @@ camelize@^1.0.0:
resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.1.tgz#89b7e16884056331a35d6b5ad064332c91daa6c3"
integrity sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==
-caniuse-lite@^1.0.30001406, caniuse-lite@^1.0.30001538, caniuse-lite@^1.0.30001541:
- version "1.0.30001565"
- resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001565.tgz#a528b253c8a2d95d2b415e11d8b9942acc100c4f"
- integrity sha512-xrE//a3O7TP0vaJ8ikzkD2c2NgcVUvsEe2IvFTntV4Yd1Z9FVzh+gW+enX96L0psrbaFMcVcH2l90xNuGDWc8w==
+caniuse-lite@^1.0.30001406, caniuse-lite@^1.0.30001538, caniuse-lite@^1.0.30001565:
+ version "1.0.30001570"
+ resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001570.tgz#b4e5c1fa786f733ab78fc70f592df6b3f23244ca"
+ integrity sha512-+3e0ASu4sw1SWaoCtvPeyXp+5PsjigkSt8OXZbF9StH5pQWbxEjLAZE3n8Aup5udop1uRiKA7a4utUk/uoSpUw==
chai@^4.3.10, chai@^4.3.7:
version "4.3.10"
@@ -3995,6 +4051,15 @@ chainsaw@~0.1.0:
dependencies:
traverse ">=0.3.0 <0.4"
+chalk@2.3.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.0.tgz#b5ea48efc9c1793dccc9b4767c93914d3f2d52ba"
+ integrity sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==
+ dependencies:
+ ansi-styles "^3.1.0"
+ escape-string-regexp "^1.0.5"
+ supports-color "^4.0.0"
+
chalk@4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a"
@@ -4144,6 +4209,14 @@ clipboard-copy@4.0.1:
resolved "https://registry.yarnpkg.com/clipboard-copy/-/clipboard-copy-4.0.1.tgz#326ef9726d4ffe72d9a82a7bbe19379de692017d"
integrity sha512-wOlqdqziE/NNTUJsfSgXmBMIrYmfd5V0HCGsR8uAKHcg+h9NENWINcfRjtWGU77wDHC8B8ijV4hMTGYbrKovng==
+clipboardy@1.2.2:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/clipboardy/-/clipboardy-1.2.2.tgz#2ce320b9ed9be1514f79878b53ff9765420903e2"
+ integrity sha512-16KrBOV7bHmHdxcQiCvfUFYVFyEah4FI8vYT1Fr7CGSA4G+xBWMEfUEQJS1hxeHGtI9ju1Bzs9uXSbj5HZKArw==
+ dependencies:
+ arch "^2.1.0"
+ execa "^0.8.0"
+
cliui@^7.0.2:
version "7.0.4"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f"
@@ -4647,6 +4720,15 @@ cross-spawn@^4.0.0:
lru-cache "^4.0.1"
which "^1.2.9"
+cross-spawn@^5.0.1:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
+ integrity sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==
+ dependencies:
+ lru-cache "^4.0.1"
+ shebang-command "^1.2.0"
+ which "^1.2.9"
+
cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3:
version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
@@ -4678,7 +4760,7 @@ css-color-keywords@^1.0.0:
resolved "https://registry.yarnpkg.com/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05"
integrity sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==
-css-to-react-native@^3.2.0:
+css-to-react-native@3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-3.2.0.tgz#cdd8099f71024e149e4f6fe17a7d46ecd55f1e32"
integrity sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==
@@ -4712,6 +4794,11 @@ cssstyle@^3.0.0:
dependencies:
rrweb-cssom "^0.6.0"
+csstype@3.1.2:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b"
+ integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==
+
csstype@3.1.3, csstype@^3.0.2, csstype@^3.1.2:
version "3.1.3"
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81"
@@ -5167,10 +5254,10 @@ ejs@^3.1.7:
dependencies:
jake "^10.8.5"
-electron-to-chromium@^1.4.535:
- version "1.4.600"
- resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.600.tgz#10ad8a5edc3f92a9a70b4453157ec2261c6db088"
- integrity sha512-KD6CWjf1BnQG+NsXuyiTDDT1eV13sKuYsOUioXkQweYTQIbgHkXPry9K7M+7cKtYHnSUPitVaLrXYB1jTkkYrw==
+electron-to-chromium@^1.4.601:
+ version "1.4.614"
+ resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.614.tgz#2fe789d61fa09cb875569f37c309d0c2701f91c0"
+ integrity sha512-X4ze/9Sc3QWs6h92yerwqv7aB/uU8vCjZcrMjA8N9R1pjMFRe44dLsck5FzLilOYvcXuDn93B+bpGYyufc70gQ==
elliptic@^6.5.3, elliptic@^6.5.4:
version "6.5.4"
@@ -5415,35 +5502,36 @@ es7-shim@^6.0.0:
string.prototype.trimleft "^2.0.0"
string.prototype.trimright "^2.0.0"
-esbuild@0.19.9, esbuild@^0.19.2, esbuild@^0.19.3:
- version "0.19.9"
- resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.19.9.tgz#423a8f35153beb22c0b695da1cd1e6c0c8cdd490"
- integrity sha512-U9CHtKSy+EpPsEBa+/A2gMs/h3ylBC0H0KSqIg7tpztHerLi6nrrcoUJAkNCEPumx8yJ+Byic4BVwHgRbN0TBg==
+esbuild@0.19.10, esbuild@^0.19.2, esbuild@^0.19.3, esbuild@~0.19.10:
+ version "0.19.10"
+ resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.19.10.tgz#55e83e4a6b702e3498b9f872d84bfb4ebcb6d16e"
+ integrity sha512-S1Y27QGt/snkNYrRcswgRFqZjaTG5a5xM3EQo97uNBnH505pdzSNe/HLBq1v0RO7iK/ngdbhJB6mDAp0OK+iUA==
optionalDependencies:
- "@esbuild/android-arm" "0.19.9"
- "@esbuild/android-arm64" "0.19.9"
- "@esbuild/android-x64" "0.19.9"
- "@esbuild/darwin-arm64" "0.19.9"
- "@esbuild/darwin-x64" "0.19.9"
- "@esbuild/freebsd-arm64" "0.19.9"
- "@esbuild/freebsd-x64" "0.19.9"
- "@esbuild/linux-arm" "0.19.9"
- "@esbuild/linux-arm64" "0.19.9"
- "@esbuild/linux-ia32" "0.19.9"
- "@esbuild/linux-loong64" "0.19.9"
- "@esbuild/linux-mips64el" "0.19.9"
- "@esbuild/linux-ppc64" "0.19.9"
- "@esbuild/linux-riscv64" "0.19.9"
- "@esbuild/linux-s390x" "0.19.9"
- "@esbuild/linux-x64" "0.19.9"
- "@esbuild/netbsd-x64" "0.19.9"
- "@esbuild/openbsd-x64" "0.19.9"
- "@esbuild/sunos-x64" "0.19.9"
- "@esbuild/win32-arm64" "0.19.9"
- "@esbuild/win32-ia32" "0.19.9"
- "@esbuild/win32-x64" "0.19.9"
-
-esbuild@^0.18.10, esbuild@~0.18.20:
+ "@esbuild/aix-ppc64" "0.19.10"
+ "@esbuild/android-arm" "0.19.10"
+ "@esbuild/android-arm64" "0.19.10"
+ "@esbuild/android-x64" "0.19.10"
+ "@esbuild/darwin-arm64" "0.19.10"
+ "@esbuild/darwin-x64" "0.19.10"
+ "@esbuild/freebsd-arm64" "0.19.10"
+ "@esbuild/freebsd-x64" "0.19.10"
+ "@esbuild/linux-arm" "0.19.10"
+ "@esbuild/linux-arm64" "0.19.10"
+ "@esbuild/linux-ia32" "0.19.10"
+ "@esbuild/linux-loong64" "0.19.10"
+ "@esbuild/linux-mips64el" "0.19.10"
+ "@esbuild/linux-ppc64" "0.19.10"
+ "@esbuild/linux-riscv64" "0.19.10"
+ "@esbuild/linux-s390x" "0.19.10"
+ "@esbuild/linux-x64" "0.19.10"
+ "@esbuild/netbsd-x64" "0.19.10"
+ "@esbuild/openbsd-x64" "0.19.10"
+ "@esbuild/sunos-x64" "0.19.10"
+ "@esbuild/win32-arm64" "0.19.10"
+ "@esbuild/win32-ia32" "0.19.10"
+ "@esbuild/win32-x64" "0.19.10"
+
+esbuild@^0.18.10:
version "0.18.20"
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.18.20.tgz#4709f5a34801b43b799ab7d6d82f7284a9b7a7a6"
integrity sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==
@@ -5570,10 +5658,10 @@ eslint-plugin-filenames@1.3.2:
lodash.snakecase "4.1.1"
lodash.upperfirst "4.3.1"
-eslint-plugin-import@2.29.0:
- version "2.29.0"
- resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.29.0.tgz#8133232e4329ee344f2f612885ac3073b0b7e155"
- integrity sha512-QPOO5NO6Odv5lpoTkddtutccQjysJuFxoPS7fAHO+9m9udNHvTCPSAMW9zGAYj8lAIdr40I8yPCdUYrncXtrwg==
+eslint-plugin-import@2.29.1:
+ version "2.29.1"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz#d45b37b5ef5901d639c15270d74d46d161150643"
+ integrity sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==
dependencies:
array-includes "^3.1.7"
array.prototype.findlastindex "^1.2.3"
@@ -5591,7 +5679,7 @@ eslint-plugin-import@2.29.0:
object.groupby "^1.0.1"
object.values "^1.1.7"
semver "^6.3.1"
- tsconfig-paths "^3.14.2"
+ tsconfig-paths "^3.15.0"
eslint-plugin-jsx-a11y@6.8.0:
version "6.8.0"
@@ -5690,15 +5778,15 @@ eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800"
integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
-eslint@8.55.0:
- version "8.55.0"
- resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.55.0.tgz#078cb7b847d66f2c254ea1794fa395bf8e7e03f8"
- integrity sha512-iyUUAM0PCKj5QpwGfmCAG9XXbZCWsqP/eWAWrG/W0umvjuLRBECwSFdt+rCntju0xEH7teIABPwXpahftIaTdA==
+eslint@8.56.0:
+ version "8.56.0"
+ resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.56.0.tgz#4957ce8da409dc0809f99ab07a1b94832ab74b15"
+ integrity sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==
dependencies:
"@eslint-community/eslint-utils" "^4.2.0"
"@eslint-community/regexpp" "^4.6.1"
"@eslint/eslintrc" "^2.1.4"
- "@eslint/js" "8.55.0"
+ "@eslint/js" "8.56.0"
"@humanwhocodes/config-array" "^0.11.13"
"@humanwhocodes/module-importer" "^1.0.1"
"@nodelib/fs.walk" "^1.2.8"
@@ -5850,6 +5938,19 @@ execa@8.0.1, execa@^8.0.1:
signal-exit "^4.1.0"
strip-final-newline "^3.0.0"
+execa@^0.8.0:
+ version "0.8.0"
+ resolved "https://registry.yarnpkg.com/execa/-/execa-0.8.0.tgz#d8d76bbc1b55217ed190fd6dd49d3c774ecfc8da"
+ integrity sha512-zDWS+Rb1E8BlqqhALSt9kUhss8Qq4nN3iof3gsOdyINksElaPyNBtKUMTR62qhvgVWR0CqCX7sdnKe4MnUbFEA==
+ dependencies:
+ cross-spawn "^5.0.1"
+ get-stream "^3.0.0"
+ is-stream "^1.1.0"
+ npm-run-path "^2.0.0"
+ p-finally "^1.0.0"
+ signal-exit "^3.0.0"
+ strip-eof "^1.0.0"
+
execa@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a"
@@ -6247,7 +6348,7 @@ fs-extra@^9.0.0:
jsonfile "^6.0.1"
universalify "^2.0.0"
-fs-minipass@^2.0.0, fs-minipass@^2.1.0:
+fs-minipass@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb"
integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==
@@ -6400,6 +6501,11 @@ get-stream@6.0.0:
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.0.tgz#3e0012cb6827319da2706e601a1583e8629a6718"
integrity sha512-A1B3Bh1UmL0bidM/YX2NsCOTnGJePL9rO/M+Mw3m9f2gUpfokS0hi5Eah0WSUEWZdZhIZtMjkIYS7mDfOqNHbg==
+get-stream@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
+ integrity sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==
+
get-stream@^5.0.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3"
@@ -6503,7 +6609,7 @@ glob-to-regexp@^0.4.1:
resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e"
integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==
-glob@10.3.10, glob@^10.2.2, glob@^10.3.7:
+glob@10.3.10, glob@^10.2.2, glob@^10.3.10, glob@^10.3.7:
version "10.3.10"
resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.10.tgz#0351ebb809fd187fe421ab96af83d3a70715df4b"
integrity sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==
@@ -6763,6 +6869,11 @@ has-bigints@^1.0.1, has-bigints@^1.0.2:
resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa"
integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==
+has-flag@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51"
+ integrity sha512-P+1n3MnwjR/Epg9BBo1KT8qbye2g2Ou4sFumihwt6I4tsUX7jnLcX4BTOSKg/B1ZrIYMN9FcEnG4x5a7NB8Eng==
+
has-flag@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
@@ -6887,6 +6998,13 @@ hosted-git-info@^6.0.0:
dependencies:
lru-cache "^7.5.1"
+hosted-git-info@^7.0.0:
+ version "7.0.1"
+ resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-7.0.1.tgz#9985fcb2700467fecf7f33a4d4874e30680b5322"
+ integrity sha512-+K84LB1DYwMHoHSgaOY/Jfhw3ucPmSET5v98Ke/HdNSw4a0UktWzyW1mjhjpuxxTqOOsfWT/7iVshHmVZ4IpOA==
+ dependencies:
+ lru-cache "^10.0.1"
+
html-encoding-sniffer@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz#696df529a7cfd82446369dc5193e590a3735b448"
@@ -6910,7 +7028,7 @@ html-tokenize@^2.0.0:
readable-stream "~1.0.27-1"
through2 "~0.4.1"
-http-cache-semantics@^4.1.0, http-cache-semantics@^4.1.1:
+http-cache-semantics@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a"
integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==
@@ -7056,7 +7174,7 @@ ignore-walk@^5.0.1:
dependencies:
minimatch "^5.0.1"
-ignore-walk@^6.0.0:
+ignore-walk@^6.0.4:
version "6.0.4"
resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-6.0.4.tgz#89950be94b4f522225eb63a13c56badb639190e9"
integrity sha512-t7sv42WkwFkyKbivUCglsQW5YWMskWtbEf4MNKX5u/CCWHKSPzN4FtBQGsQZgCLbxOzpVlcbWVK5KB3auIOjSw==
@@ -7109,11 +7227,6 @@ indent-string@^5.0.0:
resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-5.0.0.tgz#4fd2980fccaf8622d14c64d694f4cf33c81951a5"
integrity sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==
-infer-owner@^1.0.4:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467"
- integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==
-
inflight@^1.0.4:
version "1.0.6"
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
@@ -7465,6 +7578,11 @@ is-stream@2.0.0:
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3"
integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==
+is-stream@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
+ integrity sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==
+
is-stream@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077"
@@ -7565,6 +7683,11 @@ isexe@^2.0.0:
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
+isexe@^3.1.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/isexe/-/isexe-3.1.1.tgz#4a407e2bd78ddfb14bea0c27c6f7072dde775f0d"
+ integrity sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==
+
isobject@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
@@ -7940,13 +8063,13 @@ lazystream@^1.0.0:
dependencies:
readable-stream "^2.0.5"
-lerna@8.0.0:
- version "8.0.0"
- resolved "https://registry.yarnpkg.com/lerna/-/lerna-8.0.0.tgz#67e2fa42a0e6c10a95257a90ee70fd3c42a45f28"
- integrity sha512-Ddshct9hJrujtR7t2cAIiiiKnQCKiTvR/Ki3KhzpBNVepYtWq+dg+HxArZrezF+sYxI+OCxL00BxDHY4/H4uGg==
+lerna@8.0.1:
+ version "8.0.1"
+ resolved "https://registry.yarnpkg.com/lerna/-/lerna-8.0.1.tgz#cc705467c5507c38c76ae293fe976e5d438aa876"
+ integrity sha512-ZxFMmOqwkP4e+q6BrMzxkAhixi6n0GVD2jAAnAfDkIFnwumB4/7X5/If6fqTlXXshtB2dQtN5OAtzafqVq8cwA==
dependencies:
- "@lerna/create" "8.0.0"
- "@npmcli/run-script" "6.0.2"
+ "@lerna/create" "8.0.1"
+ "@npmcli/run-script" "7.0.2"
"@nx/devkit" ">=17.1.2 < 18"
"@octokit/plugin-enterprise-rest" "6.0.1"
"@octokit/rest" "19.0.11"
@@ -7997,7 +8120,7 @@ lerna@8.0.0:
p-queue "6.6.2"
p-reduce "2.1.0"
p-waterfall "2.1.1"
- pacote "^15.2.0"
+ pacote "^17.0.5"
pify "5.0.0"
read-cmd-shim "4.0.0"
read-package-json "6.0.4"
@@ -8337,6 +8460,11 @@ lowercase-keys@^3.0.0:
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-3.0.0.tgz#c5e7d442e37ead247ae9db117a9d0a467c89d4f2"
integrity sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==
+lru-cache@^10.0.1, "lru-cache@^9.1.1 || ^10.0.0":
+ version "10.1.0"
+ resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.1.0.tgz#2098d41c2dc56500e6c88584aa656c84de7d0484"
+ integrity sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==
+
lru-cache@^4.0.1:
version "4.1.5"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd"
@@ -8359,7 +8487,7 @@ lru-cache@^6.0.0:
dependencies:
yallist "^4.0.0"
-lru-cache@^7.14.1, lru-cache@^7.4.4, lru-cache@^7.5.1, lru-cache@^7.7.1:
+lru-cache@^7.14.1, lru-cache@^7.5.1, lru-cache@^7.7.1:
version "7.18.3"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89"
integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==
@@ -8369,11 +8497,6 @@ lru-cache@^8.0.0:
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-8.0.5.tgz#983fe337f3e176667f8e567cfcce7cb064ea214e"
integrity sha512-MhWWlVnuab1RG5/zMRRcVGXZLCXrZTgfwMikgzCegsPnG62yDQo5JnqKkrK4jO5iKqDAZGItAqN5CtKBCBWRUA==
-"lru-cache@^9.1.1 || ^10.0.0":
- version "10.1.0"
- resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.1.0.tgz#2098d41c2dc56500e6c88584aa656c84de7d0484"
- integrity sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==
-
lz-string@1.5.0, lz-string@^1.5.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.5.0.tgz#c1ab50f77887b712621201ba9fd4e3a6ed099941"
@@ -8408,47 +8531,42 @@ make-dir@^3.0.2:
dependencies:
semver "^6.0.0"
-make-fetch-happen@^10.0.3:
- version "10.2.1"
- resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz#f5e3835c5e9817b617f2770870d9492d28678164"
- integrity sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==
+make-fetch-happen@^11.0.0, make-fetch-happen@^11.0.1, make-fetch-happen@^11.1.1:
+ version "11.1.1"
+ resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-11.1.1.tgz#85ceb98079584a9523d4bf71d32996e7e208549f"
+ integrity sha512-rLWS7GCSTcEujjVBs2YqG7Y4643u8ucvCJeSRqiLYhesrDuzeuFIk37xREzAsfQaqzl8b9rNCE4m6J8tvX4Q8w==
dependencies:
agentkeepalive "^4.2.1"
- cacache "^16.1.0"
- http-cache-semantics "^4.1.0"
+ cacache "^17.0.0"
+ http-cache-semantics "^4.1.1"
http-proxy-agent "^5.0.0"
https-proxy-agent "^5.0.0"
is-lambda "^1.0.1"
lru-cache "^7.7.1"
- minipass "^3.1.6"
- minipass-collect "^1.0.2"
- minipass-fetch "^2.0.3"
+ minipass "^5.0.0"
+ minipass-fetch "^3.0.0"
minipass-flush "^1.0.5"
minipass-pipeline "^1.2.4"
negotiator "^0.6.3"
promise-retry "^2.0.1"
socks-proxy-agent "^7.0.0"
- ssri "^9.0.0"
+ ssri "^10.0.0"
-make-fetch-happen@^11.0.0, make-fetch-happen@^11.0.1, make-fetch-happen@^11.1.1:
- version "11.1.1"
- resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-11.1.1.tgz#85ceb98079584a9523d4bf71d32996e7e208549f"
- integrity sha512-rLWS7GCSTcEujjVBs2YqG7Y4643u8ucvCJeSRqiLYhesrDuzeuFIk37xREzAsfQaqzl8b9rNCE4m6J8tvX4Q8w==
+make-fetch-happen@^13.0.0:
+ version "13.0.0"
+ resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-13.0.0.tgz#705d6f6cbd7faecb8eac2432f551e49475bfedf0"
+ integrity sha512-7ThobcL8brtGo9CavByQrQi+23aIfgYU++wg4B87AIS8Rb2ZBt/MEaDqzA00Xwv/jUjAjYkLHjVolYuTLKda2A==
dependencies:
- agentkeepalive "^4.2.1"
- cacache "^17.0.0"
+ "@npmcli/agent" "^2.0.0"
+ cacache "^18.0.0"
http-cache-semantics "^4.1.1"
- http-proxy-agent "^5.0.0"
- https-proxy-agent "^5.0.0"
is-lambda "^1.0.1"
- lru-cache "^7.7.1"
- minipass "^5.0.0"
+ minipass "^7.0.2"
minipass-fetch "^3.0.0"
minipass-flush "^1.0.5"
minipass-pipeline "^1.2.4"
negotiator "^0.6.3"
promise-retry "^2.0.1"
- socks-proxy-agent "^7.0.0"
ssri "^10.0.0"
map-obj@^1.0.0:
@@ -8507,10 +8625,10 @@ markdownlint@0.32.1:
markdown-it "13.0.2"
markdownlint-micromark "0.1.7"
-marked@11.0.1:
- version "11.0.1"
- resolved "https://registry.yarnpkg.com/marked/-/marked-11.0.1.tgz#f8010ec2e358c0f4efedbac1ed3dbac2c7f46cdc"
- integrity sha512-P4kDhFEMlvLePBPRwOcMOv6+lYUbhfbSxJFs3Jb4Qx7v6K7l+k8Dxh9CEGfRvK71tL+qIFz5y7Pe4uzt4+/A3A==
+marked@11.1.0:
+ version "11.1.0"
+ resolved "https://registry.yarnpkg.com/marked/-/marked-11.1.0.tgz#f2d12323e80ba8a97cc8262fe7e94fcc007476ab"
+ integrity sha512-fvKJWAPEafVj1dwGwcPI5mBB/0pvViL6NlCbNDG1HOIRwwAU/jeMoFxfbRLuirO1wRH7m4yPvBqD/O1wyWvayw==
md5.js@^1.3.4:
version "1.3.5"
@@ -8618,10 +8736,10 @@ mime@1.6.0:
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
-mime@4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/mime/-/mime-4.0.0.tgz#ae999669db9568c31a8da18dff6c696663f65486"
- integrity sha512-pzhgdeqU5pJ9t5WK9m4RT4GgGWqYJylxUf62Yb9datXRwdcw5MjiD1BYI5evF8AgTXN9gtKX3CFLvCUL5fAhEA==
+mime@4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/mime/-/mime-4.0.1.tgz#ad7563d1bfe30253ad97dedfae2b1009d01b9470"
+ integrity sha512-5lZ5tyrIfliMXzFtkYyekWbtRXObT9OWa8IwQ5uxTBDHucNNwniRqo0yInflj+iYi5CBa6qxadGzGarDfuEOxA==
mimic-fn@^2.1.0:
version "2.1.0"
@@ -8686,7 +8804,7 @@ minimatch@^8.0.2:
dependencies:
brace-expansion "^2.0.1"
-minimatch@^9.0.0, minimatch@^9.0.1:
+minimatch@^9.0.0, minimatch@^9.0.1, minimatch@^9.0.3:
version "9.0.3"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825"
integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==
@@ -8714,16 +8832,12 @@ minipass-collect@^1.0.2:
dependencies:
minipass "^3.0.0"
-minipass-fetch@^2.0.3:
- version "2.1.2"
- resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-2.1.2.tgz#95560b50c472d81a3bc76f20ede80eaed76d8add"
- integrity sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==
+minipass-collect@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/minipass-collect/-/minipass-collect-2.0.1.tgz#1621bc77e12258a12c60d34e2276ec5c20680863"
+ integrity sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==
dependencies:
- minipass "^3.1.6"
- minipass-sized "^1.0.3"
- minizlib "^2.1.2"
- optionalDependencies:
- encoding "^0.1.13"
+ minipass "^7.0.3"
minipass-fetch@^3.0.0:
version "3.0.4"
@@ -8765,7 +8879,7 @@ minipass-sized@^1.0.3:
dependencies:
minipass "^3.0.0"
-minipass@^3.0.0, minipass@^3.1.1, minipass@^3.1.6:
+minipass@^3.0.0, minipass@^3.1.1:
version "3.3.6"
resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a"
integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==
@@ -8782,7 +8896,7 @@ minipass@^5.0.0:
resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d"
integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==
-"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.3:
+"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.2, minipass@^7.0.3:
version "7.0.4"
resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.4.tgz#dbce03740f50a4786ba994c1fb908844d27b038c"
integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==
@@ -8807,7 +8921,7 @@ mkdirp-classic@^0.5.2, mkdirp-classic@^0.5.3:
dependencies:
minimist "^1.2.6"
-mkdirp@^1.0.3, mkdirp@^1.0.4:
+mkdirp@^1.0.3:
version "1.0.4"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
@@ -8937,7 +9051,7 @@ nanoid@^2.0.3:
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-2.1.11.tgz#ec24b8a758d591561531b4176a01e3ab4f0f0280"
integrity sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA==
-nanoid@^3.3.4, nanoid@^3.3.7:
+nanoid@^3.3.4, nanoid@^3.3.6, nanoid@^3.3.7:
version "3.3.7"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8"
integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==
@@ -9044,29 +9158,28 @@ node-gyp-build@^4.2.2:
resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.7.1.tgz#cd7d2eb48e594874053150a9418ac85af83ca8f7"
integrity sha512-wTSrZ+8lsRRa3I3H8Xr65dLWSgCvY2l4AOnaeKdPA9TB/WYMPaTcrzf3rXvFoVvjKNVnu0CcWSx54qq9GKRUYg==
-node-gyp@^9.0.0:
- version "9.4.1"
- resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-9.4.1.tgz#8a1023e0d6766ecb52764cc3a734b36ff275e185"
- integrity sha512-OQkWKbjQKbGkMf/xqI1jjy3oCTgMKJac58G2+bjZb3fza6gW2YrCSdMQYaoTb70crvE//Gngr4f0AgVHmqHvBQ==
+node-gyp@^10.0.0:
+ version "10.0.1"
+ resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-10.0.1.tgz#205514fc19e5830fa991e4a689f9e81af377a966"
+ integrity sha512-gg3/bHehQfZivQVfqIyy8wTdSymF9yTyP4CJifK73imyNMU8AIGQE2pUa7dNWfmMeG9cDVF2eehiRMv0LC1iAg==
dependencies:
env-paths "^2.2.0"
exponential-backoff "^3.1.1"
- glob "^7.1.4"
+ glob "^10.3.10"
graceful-fs "^4.2.6"
- make-fetch-happen "^10.0.3"
- nopt "^6.0.0"
- npmlog "^6.0.0"
- rimraf "^3.0.2"
+ make-fetch-happen "^13.0.0"
+ nopt "^7.0.0"
+ proc-log "^3.0.0"
semver "^7.3.5"
tar "^6.1.2"
- which "^2.0.2"
+ which "^4.0.0"
node-machine-id@1.1.12:
version "1.1.12"
resolved "https://registry.yarnpkg.com/node-machine-id/-/node-machine-id-1.1.12.tgz#37904eee1e59b320bb9c5d6c0a59f3b469cb6267"
integrity sha512-QNABxbrPa3qEIfrE6GOJ7BYIuignnJw7iQ2YPbc3Nla1HzRJjXzZOiikfF8m7eAMfichLt3M4VgLOetqgDmgGQ==
-node-releases@^2.0.13:
+node-releases@^2.0.14:
version "2.0.14"
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b"
integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==
@@ -9104,12 +9217,12 @@ node-stdlib-browser@^1.2.0:
util "^0.12.4"
vm-browserify "^1.0.1"
-nopt@^6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/nopt/-/nopt-6.0.0.tgz#245801d8ebf409c6df22ab9d95b65e1309cdb16d"
- integrity sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==
+nopt@^7.0.0:
+ version "7.2.0"
+ resolved "https://registry.yarnpkg.com/nopt/-/nopt-7.2.0.tgz#067378c68116f602f552876194fd11f1292503d7"
+ integrity sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA==
dependencies:
- abbrev "^1.0.0"
+ abbrev "^2.0.0"
normalize-package-data@^2.3.2, normalize-package-data@^2.5.0:
version "2.5.0"
@@ -9141,6 +9254,16 @@ normalize-package-data@^5.0.0:
semver "^7.3.5"
validate-npm-package-license "^3.0.4"
+normalize-package-data@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-6.0.0.tgz#68a96b3c11edd462af7189c837b6b1064a484196"
+ integrity sha512-UL7ELRVxYBHBgYEtZCXjxuD5vPxnmvMGq0jp/dGPKKrN7tfsBh2IY7TlJ15WWwdjRWD3RJbnsygUurTK3xkPkg==
+ dependencies:
+ hosted-git-info "^7.0.0"
+ is-core-module "^2.8.1"
+ semver "^7.3.5"
+ validate-npm-package-license "^3.0.4"
+
normalize-path@^3.0.0, normalize-path@~3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
@@ -9206,6 +9329,16 @@ npm-package-arg@^10.0.0, npm-package-arg@^10.1.0:
semver "^7.3.5"
validate-npm-package-name "^5.0.0"
+npm-package-arg@^11.0.0:
+ version "11.0.1"
+ resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-11.0.1.tgz#f208b0022c29240a1c532a449bdde3f0a4708ebc"
+ integrity sha512-M7s1BD4NxdAvBKUPqqRW957Xwcl/4Zvo8Aj+ANrzvIPzGJZElrH7Z//rSaec2ORcND6FHHLnZeY8qgTpXDMFQQ==
+ dependencies:
+ hosted-git-info "^7.0.0"
+ proc-log "^3.0.0"
+ semver "^7.3.5"
+ validate-npm-package-name "^5.0.0"
+
npm-packlist@5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-5.1.1.tgz#79bcaf22a26b6c30aa4dd66b976d69cc286800e0"
@@ -9216,24 +9349,24 @@ npm-packlist@5.1.1:
npm-bundled "^1.1.2"
npm-normalize-package-bin "^1.0.1"
-npm-packlist@^7.0.0:
- version "7.0.4"
- resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-7.0.4.tgz#033bf74110eb74daf2910dc75144411999c5ff32"
- integrity sha512-d6RGEuRrNS5/N84iglPivjaJPxhDbZmlbTwTDX2IbcRHG5bZCdtysYMhwiPvcF4GisXHGn7xsxv+GQ7T/02M5Q==
+npm-packlist@^8.0.0:
+ version "8.0.1"
+ resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-8.0.1.tgz#97d1eb2a9a90e10ce1b028d058da3740c91b89ab"
+ integrity sha512-MQpL27ZrsJQ2kiAuQPpZb5LtJwydNRnI15QWXsf3WHERu4rzjRj6Zju/My2fov7tLuu3Gle/uoIX/DDZ3u4O4Q==
dependencies:
- ignore-walk "^6.0.0"
+ ignore-walk "^6.0.4"
-npm-pick-manifest@^8.0.0:
- version "8.0.2"
- resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-8.0.2.tgz#2159778d9c7360420c925c1a2287b5a884c713aa"
- integrity sha512-1dKY+86/AIiq1tkKVD3l0WI+Gd3vkknVGAggsFeBkTvbhMQ1OND/LKkYv4JtXPKUJ8bOTCyLiqEg2P6QNdK+Gg==
+npm-pick-manifest@^9.0.0:
+ version "9.0.0"
+ resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-9.0.0.tgz#f87a4c134504a2c7931f2bb8733126e3c3bb7e8f"
+ integrity sha512-VfvRSs/b6n9ol4Qb+bDwNGUXutpy76x6MARw/XssevE0TnctIKcmklJZM5Z7nqs5z5aW+0S63pgCNbpkUNNXBg==
dependencies:
npm-install-checks "^6.0.0"
npm-normalize-package-bin "^3.0.0"
- npm-package-arg "^10.0.0"
+ npm-package-arg "^11.0.0"
semver "^7.3.5"
-npm-registry-fetch@^14.0.0, npm-registry-fetch@^14.0.3, npm-registry-fetch@^14.0.5:
+npm-registry-fetch@^14.0.3, npm-registry-fetch@^14.0.5:
version "14.0.5"
resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-14.0.5.tgz#fe7169957ba4986a4853a650278ee02e568d115d"
integrity sha512-kIDMIo4aBm6xg7jOttupWZamsZRkAqMqwqqbVXnUqstY5+tapvv6bkH/qMR76jdgV+YljEUCyWx3hRYMrJiAgA==
@@ -9246,6 +9379,26 @@ npm-registry-fetch@^14.0.0, npm-registry-fetch@^14.0.3, npm-registry-fetch@^14.0
npm-package-arg "^10.0.0"
proc-log "^3.0.0"
+npm-registry-fetch@^16.0.0:
+ version "16.1.0"
+ resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-16.1.0.tgz#10227b7b36c97bc1cf2902a24e4f710cfe62803c"
+ integrity sha512-PQCELXKt8Azvxnt5Y85GseQDJJlglTFM9L9U9gkv2y4e9s0k3GVDdOx3YoB6gm2Do0hlkzC39iCGXby+Wve1Bw==
+ dependencies:
+ make-fetch-happen "^13.0.0"
+ minipass "^7.0.2"
+ minipass-fetch "^3.0.0"
+ minipass-json-stream "^1.0.1"
+ minizlib "^2.1.2"
+ npm-package-arg "^11.0.0"
+ proc-log "^3.0.0"
+
+npm-run-path@^2.0.0:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
+ integrity sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==
+ dependencies:
+ path-key "^2.0.0"
+
npm-run-path@^4.0.0, npm-run-path@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea"
@@ -9260,7 +9413,7 @@ npm-run-path@^5.1.0:
dependencies:
path-key "^4.0.0"
-npmlog@^6.0.0, npmlog@^6.0.2:
+npmlog@^6.0.2:
version "6.0.2"
resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-6.0.2.tgz#c8166017a42f2dea92d6453168dd865186a70830"
integrity sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==
@@ -9717,27 +9870,27 @@ packet-reader@1.0.0:
resolved "https://registry.yarnpkg.com/packet-reader/-/packet-reader-1.0.0.tgz#9238e5480dedabacfe1fe3f2771063f164157d74"
integrity sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==
-pacote@^15.2.0:
- version "15.2.0"
- resolved "https://registry.yarnpkg.com/pacote/-/pacote-15.2.0.tgz#0f0dfcc3e60c7b39121b2ac612bf8596e95344d3"
- integrity sha512-rJVZeIwHTUta23sIZgEIM62WYwbmGbThdbnkt81ravBplQv+HjyroqnLRNH2+sLJHcGZmLRmhPwACqhfTcOmnA==
+pacote@^17.0.5:
+ version "17.0.5"
+ resolved "https://registry.yarnpkg.com/pacote/-/pacote-17.0.5.tgz#e9854edee7a073635cdd36b0c07cd4f2ab1757b6"
+ integrity sha512-TAE0m20zSDMnchPja9vtQjri19X3pZIyRpm2TJVeI+yU42leJBBDTRYhOcWFsPhaMxf+3iwQkFiKz16G9AEeeA==
dependencies:
- "@npmcli/git" "^4.0.0"
+ "@npmcli/git" "^5.0.0"
"@npmcli/installed-package-contents" "^2.0.1"
- "@npmcli/promise-spawn" "^6.0.1"
- "@npmcli/run-script" "^6.0.0"
- cacache "^17.0.0"
+ "@npmcli/promise-spawn" "^7.0.0"
+ "@npmcli/run-script" "^7.0.0"
+ cacache "^18.0.0"
fs-minipass "^3.0.0"
- minipass "^5.0.0"
- npm-package-arg "^10.0.0"
- npm-packlist "^7.0.0"
- npm-pick-manifest "^8.0.0"
- npm-registry-fetch "^14.0.0"
+ minipass "^7.0.2"
+ npm-package-arg "^11.0.0"
+ npm-packlist "^8.0.0"
+ npm-pick-manifest "^9.0.0"
+ npm-registry-fetch "^16.0.0"
proc-log "^3.0.0"
promise-retry "^2.0.1"
- read-package-json "^6.0.0"
+ read-package-json "^7.0.0"
read-package-json-fast "^3.0.0"
- sigstore "^1.3.0"
+ sigstore "^2.0.0"
ssri "^10.0.0"
tar "^6.1.11"
@@ -9833,6 +9986,11 @@ path-is-absolute@^1.0.0:
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==
+path-key@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
+ integrity sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==
+
path-key@^3.0.0, path-key@^3.1.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
@@ -10027,10 +10185,10 @@ pirates@^4.0.1:
resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9"
integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==
-piscina@4.2.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/piscina/-/piscina-4.2.0.tgz#61ac6c07f45fdefdd7726b6b07fc237d9a8d1776"
- integrity sha512-/Yq6CLchvi5UQ6YGeiYHIJQV09VcZ5eYuNVS/YPkpxlxKrB4tEbIyc6j8F5b0jCP6tHdiji1Gos4fapc7q1csg==
+piscina@4.2.1:
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/piscina/-/piscina-4.2.1.tgz#efb7f009d3a961e02ae08f1909bd24b5423e77fa"
+ integrity sha512-LShp0+lrO+WIzB9LXO+ZmO4zGHxtTJNZhEO56H9SSu+JPaUQb6oLcTCzWi5IL2DS8/vIkCE88ElahuSSw4TAkA==
dependencies:
hdr-histogram-js "^2.0.1"
hdr-histogram-percentiles-obj "^3.0.0"
@@ -10108,7 +10266,16 @@ postcss@8.4.14:
picocolors "^1.0.0"
source-map-js "^1.0.2"
-postcss@8.4.32, postcss@^8.4.27, postcss@^8.4.31, postcss@^8.4.32:
+postcss@8.4.31:
+ version "8.4.31"
+ resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.31.tgz#92b451050a9f914da6755af352bdc0192508656d"
+ integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==
+ dependencies:
+ nanoid "^3.3.6"
+ picocolors "^1.0.0"
+ source-map-js "^1.0.2"
+
+postcss@8.4.32, postcss@^8.4.27, postcss@^8.4.32:
version "8.4.32"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.32.tgz#1dac6ac51ab19adb21b8b34fd2d93a86440ef6c9"
integrity sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==
@@ -10530,10 +10697,10 @@ react-dom@18.2.0:
loose-envify "^1.1.0"
scheduler "^0.23.0"
-react-error-boundary@4.0.11:
- version "4.0.11"
- resolved "https://registry.yarnpkg.com/react-error-boundary/-/react-error-boundary-4.0.11.tgz#36bf44de7746714725a814630282fee83a7c9a1c"
- integrity sha512-U13ul67aP5DOSPNSCWQ/eO0AQEYzEFkVljULQIjMV0KlffTAhxuDoBKdO0pb/JZ8mDhMKFZ9NZi0BmLGUiNphw==
+react-error-boundary@4.0.12:
+ version "4.0.12"
+ resolved "https://registry.yarnpkg.com/react-error-boundary/-/react-error-boundary-4.0.12.tgz#59f8f1dbc53bbbb34fc384c8db7cf4082cb63e2c"
+ integrity sha512-kJdxdEYlb7CPC1A0SeUY38cHpjuu6UkvzKiAmqmOFL21VRfMhOcWxTCBgLVCO0VEMh9JhFNcVaXlV4/BTpiwOA==
dependencies:
"@babel/runtime" "^7.12.5"
@@ -10542,10 +10709,10 @@ react-error-overlay@^6.0.11:
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.11.tgz#92835de5841c5cf08ba00ddd2d677b6d17ff9adb"
integrity sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==
-react-hook-form@7.49.0:
- version "7.49.0"
- resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.49.0.tgz#9a91edfba6b6983d4b443653a9b225a780a42b3e"
- integrity sha512-gf4qyY4WiqK2hP/E45UUT6wt3Khl49pleEVcIzxhLBrD6m+GMWtLRk0vMrRv45D1ZH8PnpXFwRPv0Pewske2jw==
+react-hook-form@7.49.2:
+ version "7.49.2"
+ resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.49.2.tgz#6fb2742e1308020f26cb1915c7012b6c07b11ade"
+ integrity sha512-TZcnSc17+LPPVpMRIDNVITY6w20deMdNi6iehTFLV1x8SqThXGwu93HjlUVU09pzFgZH7qZOvLMM7UYf2ShAHA==
react-inspector@6.0.2:
version "6.0.2"
@@ -10577,25 +10744,25 @@ react-refresh@^0.14.0:
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.0.tgz#4e02825378a5f227079554d4284889354e5f553e"
integrity sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==
-react-resizable-panels@0.0.63:
- version "0.0.63"
- resolved "https://registry.yarnpkg.com/react-resizable-panels/-/react-resizable-panels-0.0.63.tgz#d364d84ee5927bfb0e56c7ea75eb6504e9041a21"
- integrity sha512-AfA8b6kouhL4rBvgUGs17uzWVlYPaJIwwTCVeWRxNpUHJlCG1h9RIMlzA1849AZGsaNJO3j/SNdI5SS4GZDE3g==
+react-resizable-panels@1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/react-resizable-panels/-/react-resizable-panels-1.0.5.tgz#f6274758eb5f05a3fb85a077ac55f937a4dc8d80"
+ integrity sha512-OP0whNQCko+f4BgoptGaeIc7StBRyeMeJ+8r/7rXACBDf9W5EcMWuM32hfqPDMenS2HFy/eZVi/r8XqK+ZIEag==
-react-router-dom@6.20.1:
- version "6.20.1"
- resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.20.1.tgz#e34f8075b9304221420de3609e072bb349824984"
- integrity sha512-npzfPWcxfQN35psS7rJgi/EW0Gx6EsNjfdJSAk73U/HqMEJZ2k/8puxfwHFgDQhBGmS3+sjnGbMdMSV45axPQw==
+react-router-dom@6.21.1:
+ version "6.21.1"
+ resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.21.1.tgz#58b459d2fe1841388c95bb068f85128c45e27349"
+ integrity sha512-QCNrtjtDPwHDO+AO21MJd7yIcr41UetYt5jzaB9Y1UYaPTCnVuJq6S748g1dE11OQlCFIQg+RtAA1SEZIyiBeA==
dependencies:
- "@remix-run/router" "1.13.1"
- react-router "6.20.1"
+ "@remix-run/router" "1.14.1"
+ react-router "6.21.1"
-react-router@6.20.1:
- version "6.20.1"
- resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.20.1.tgz#e8cc326031d235aaeec405bb234af77cf0fe75ef"
- integrity sha512-ccvLrB4QeT5DlaxSFFYi/KR8UMQ4fcD8zBcR71Zp1kaYTC5oJKYAp1cbavzGrogwxca+ubjkd7XjFZKBW8CxPA==
+react-router@6.21.1:
+ version "6.21.1"
+ resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.21.1.tgz#8db7ee8d7cfc36513c9a66b44e0897208c33be34"
+ integrity sha512-W0l13YlMTm1YrpVIOpjCADJqEUpz1vm+CMo47RuFX4Ftegwm6KOYsL5G3eiE52jnJpKvzm6uB/vTKTPKM8dmkA==
dependencies:
- "@remix-run/router" "1.13.1"
+ "@remix-run/router" "1.14.1"
react-runner@1.0.3:
version "1.0.3"
@@ -10667,6 +10834,16 @@ read-package-json@6.0.4, read-package-json@^6.0.0:
normalize-package-data "^5.0.0"
npm-normalize-package-bin "^3.0.0"
+read-package-json@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-7.0.0.tgz#d605c9dcf6bc5856da24204aa4e9518ee9714be0"
+ integrity sha512-uL4Z10OKV4p6vbdvIXB+OzhInYtIozl/VxUBPgNkBuUi2DeRonnuspmaVAMcrkmfjKGNmRndyQAbE7/AmzGwFg==
+ dependencies:
+ glob "^10.2.2"
+ json-parse-even-better-errors "^3.0.0"
+ normalize-package-data "^6.0.0"
+ npm-normalize-package-bin "^3.0.0"
+
read-pkg-up@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07"
@@ -10823,10 +11000,10 @@ reflect.getprototypeof@^1.0.4:
globalthis "^1.0.3"
which-builtin-type "^1.1.3"
-regenerator-runtime@0.14.0, regenerator-runtime@^0.14.0:
- version "0.14.0"
- resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz#5e19d68eb12d486f797e15a3c6a918f7cec5eb45"
- integrity sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==
+regenerator-runtime@0.14.1, regenerator-runtime@^0.14.0:
+ version "0.14.1"
+ resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f"
+ integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==
regexp.prototype.flags@^1.5.0, regexp.prototype.flags@^1.5.1:
version "1.5.1"
@@ -11231,7 +11408,7 @@ shallow-clone@^3.0.0:
dependencies:
kind-of "^6.0.2"
-shallowequal@^1.1.0:
+shallowequal@1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8"
integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==
@@ -11250,6 +11427,13 @@ sharp@^0.32.5:
tar-fs "^3.0.4"
tunnel-agent "^0.6.0"
+shebang-command@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
+ integrity sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==
+ dependencies:
+ shebang-regex "^1.0.0"
+
shebang-command@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
@@ -11257,6 +11441,11 @@ shebang-command@^2.0.0:
dependencies:
shebang-regex "^3.0.0"
+shebang-regex@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
+ integrity sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==
+
shebang-regex@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
@@ -11281,7 +11470,7 @@ siginfo@^2.0.0:
resolved "https://registry.yarnpkg.com/siginfo/-/siginfo-2.0.0.tgz#32e76c70b79724e3bb567cb9d543eb858ccfaf30"
integrity sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==
-signal-exit@3.0.7, signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7:
+signal-exit@3.0.7, signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7:
version "3.0.7"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
@@ -11291,7 +11480,7 @@ signal-exit@^4.0.1, signal-exit@^4.1.0:
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04"
integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==
-sigstore@^1.3.0, sigstore@^1.4.0:
+sigstore@^1.4.0:
version "1.9.0"
resolved "https://registry.yarnpkg.com/sigstore/-/sigstore-1.9.0.tgz#1e7ad8933aa99b75c6898ddd0eeebc3eb0d59875"
integrity sha512-0Zjz0oe37d08VeOtBIuB6cRriqXse2e8w+7yIy2XSXjshRKxbc2KkhXjL229jXSxEm7UbcjS76wcJDGQddVI9A==
@@ -11302,6 +11491,16 @@ sigstore@^1.3.0, sigstore@^1.4.0:
"@sigstore/tuf" "^1.0.3"
make-fetch-happen "^11.0.1"
+sigstore@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/sigstore/-/sigstore-2.1.0.tgz#c577b596642b3f360dc4135d476466e6edeb2364"
+ integrity sha512-kPIj+ZLkyI3QaM0qX8V/nSsweYND3W448pwkDgS6CQ74MfhEkIR8ToK5Iyx46KJYRjseVcD3Rp9zAmUAj6ZjPw==
+ dependencies:
+ "@sigstore/bundle" "^2.1.0"
+ "@sigstore/protobuf-specs" "^0.2.1"
+ "@sigstore/sign" "^2.1.0"
+ "@sigstore/tuf" "^2.1.0"
+
simple-concat@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f"
@@ -11366,7 +11565,16 @@ socks-proxy-agent@^7.0.0:
debug "^4.3.3"
socks "^2.6.2"
-socks@^2.6.2:
+socks-proxy-agent@^8.0.1:
+ version "8.0.2"
+ resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-8.0.2.tgz#5acbd7be7baf18c46a3f293a840109a430a640ad"
+ integrity sha512-8zuqoLv1aP/66PHF5TqwJ7Czm3Yv32urJQHrVyhD7mmA6d61Zv8cIXQYPTWwmg6qlupnPvs/QKDmfa4P/qct2g==
+ dependencies:
+ agent-base "^7.0.2"
+ debug "^4.3.4"
+ socks "^2.7.1"
+
+socks@^2.6.2, socks@^2.7.1:
version "2.7.1"
resolved "https://registry.yarnpkg.com/socks/-/socks-2.7.1.tgz#d8e651247178fde79c0663043e07240196857d55"
integrity sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==
@@ -11493,7 +11701,7 @@ ssri@^10.0.0, ssri@^10.0.1:
dependencies:
minipass "^7.0.3"
-ssri@^9.0.0, ssri@^9.0.1:
+ssri@^9.0.1:
version "9.0.1"
resolved "https://registry.yarnpkg.com/ssri/-/ssri-9.0.1.tgz#544d4c357a8d7b71a19700074b6883fcb4eae057"
integrity sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==
@@ -11705,6 +11913,11 @@ strip-bom@^4.0.0:
resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878"
integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==
+strip-eof@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
+ integrity sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==
+
strip-final-newline@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad"
@@ -11760,20 +11973,20 @@ strong-log-transformer@2.1.0, strong-log-transformer@^2.1.0:
minimist "^1.2.0"
through "^2.3.4"
-styled-components@6.1.1:
- version "6.1.1"
- resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-6.1.1.tgz#a5414ada07fb1c17b96a26a05369daa4e2ad55e5"
- integrity sha512-cpZZP5RrKRIClBW5Eby4JM1wElLVP4NQrJbJ0h10TidTyJf4SIIwa3zLXOoPb4gJi8MsJ8mjq5mu2IrEhZIAcQ==
- dependencies:
- "@emotion/is-prop-valid" "^1.2.1"
- "@emotion/unitless" "^0.8.0"
- "@types/stylis" "^4.0.2"
- css-to-react-native "^3.2.0"
- csstype "^3.1.2"
- postcss "^8.4.31"
- shallowequal "^1.1.0"
- stylis "^4.3.0"
- tslib "^2.5.0"
+styled-components@6.1.3:
+ version "6.1.3"
+ resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-6.1.3.tgz#d3ffea630800f4486e79f6264826dad9426474e3"
+ integrity sha512-kLerFjTAABuEZ870O4q4dyT/VCOJC/HA08+VeIGhkiOKkwJLP17HAWHCiqZWnUMV19m3axlOKR/+/EbCbuJAZg==
+ dependencies:
+ "@emotion/is-prop-valid" "1.2.1"
+ "@emotion/unitless" "0.8.0"
+ "@types/stylis" "4.2.0"
+ css-to-react-native "3.2.0"
+ csstype "3.1.2"
+ postcss "8.4.31"
+ shallowequal "1.1.0"
+ stylis "4.3.0"
+ tslib "2.5.0"
styled-jsx@5.1.1:
version "5.1.1"
@@ -11794,7 +12007,7 @@ stylis@4.2.0:
resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.2.0.tgz#79daee0208964c8fe695a42fcffcac633a211a51"
integrity sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==
-stylis@4.3.0, stylis@^4.3.0:
+stylis@4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.3.0.tgz#abe305a669fc3d8777e10eefcfc73ad861c5588c"
integrity sha512-E87pIogpwUsUwXw7dNyU4QDjdgVMy52m+XEOPEKUn161cCzWjjhPSQhByfd1CcNvrOLnXQ6OnnZDwnJrz/Z4YQ==
@@ -11819,6 +12032,13 @@ superjson@2.0.0:
dependencies:
copy-anything "^3.0.2"
+supports-color@^4.0.0:
+ version "4.5.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.5.0.tgz#be7a0de484dec5c5cddf8b3d59125044912f635b"
+ integrity sha512-ycQR/UbvI9xIlEdQT1TQqwoXtEldExbCEAJgRo5YXlmSKjv6ThHnP9/vwGa1gr19Gfw+LkFd7KqYMhzrRC5JYw==
+ dependencies:
+ has-flag "^2.0.0"
+
supports-color@^5.3.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
@@ -12041,6 +12261,21 @@ tinyspy@^2.2.0:
resolved "https://registry.yarnpkg.com/tinyspy/-/tinyspy-2.2.0.tgz#9dc04b072746520b432f77ea2c2d17933de5d6ce"
integrity sha512-d2eda04AN/cPOR89F7Xv5bK/jrQEhmcLFe6HFldoeO9AJtps+fqEnh486vnT/8y4bw38pSyxDcTCAq+Ks2aJTg==
+title@3.5.3:
+ version "3.5.3"
+ resolved "https://registry.yarnpkg.com/title/-/title-3.5.3.tgz#b338d701a3d949db6b49b2c86f409f9c2f36cd91"
+ integrity sha512-20JyowYglSEeCvZv3EZ0nZ046vLarO37prvV0mbtQV7C8DJPGgN967r8SJkqd3XK3K3lD3/Iyfp3avjfil8Q2Q==
+ dependencies:
+ arg "1.0.0"
+ chalk "2.3.0"
+ clipboardy "1.2.2"
+ titleize "1.0.0"
+
+titleize@1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/titleize/-/titleize-1.0.0.tgz#7d350722061830ba6617631e0cfd3ea08398d95a"
+ integrity sha512-TARUb7z1pGvlLxgPk++7wJ6aycXF3GJ0sNSBTAsTuJrQG5QuZlkUQP+zl+nbjAh4gMX9yDw9ZYklMd7vAfJKEw==
+
tmp@^0.0.33:
version "0.0.33"
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
@@ -12131,10 +12366,10 @@ ts-interface-checker@^0.1.9:
resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699"
integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==
-tsconfig-paths@^3.14.2:
- version "3.14.2"
- resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz#6e32f1f79412decd261f92d633a9dc1cfa99f088"
- integrity sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==
+tsconfig-paths@^3.15.0:
+ version "3.15.0"
+ resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4"
+ integrity sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==
dependencies:
"@types/json5" "^0.0.29"
json5 "^1.0.2"
@@ -12150,6 +12385,11 @@ tsconfig-paths@^4.1.2:
minimist "^1.2.6"
strip-bom "^3.0.0"
+tslib@2.5.0:
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf"
+ integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==
+
tslib@^1.13.0, tslib@^1.8.1:
version "1.14.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
@@ -12187,12 +12427,12 @@ tsutils@^3.21.0:
dependencies:
tslib "^1.8.1"
-tsx@4.6.2:
- version "4.6.2"
- resolved "https://registry.yarnpkg.com/tsx/-/tsx-4.6.2.tgz#8e9c1456ad4f1102c5c42c5be7fd428259b7d39b"
- integrity sha512-QPpBdJo+ZDtqZgAnq86iY/PD2KYCUPSUGIunHdGwyII99GKH+f3z3FZ8XNFLSGQIA4I365ui8wnQpl8OKLqcsg==
+tsx@4.7.0:
+ version "4.7.0"
+ resolved "https://registry.yarnpkg.com/tsx/-/tsx-4.7.0.tgz#1689cfe7dda495ca1f9a66d4cad79cb57b9f6f4a"
+ integrity sha512-I+t79RYPlEYlHn9a+KzwrvEwhJg35h/1zHsLC2JXvhC2mdynMv6Zxzvhv5EMV6VF5qJlLlkSnMVvdZV3PSIGcg==
dependencies:
- esbuild "~0.18.20"
+ esbuild "~0.19.10"
get-tsconfig "^4.7.2"
optionalDependencies:
fsevents "~2.3.3"
@@ -12211,6 +12451,15 @@ tuf-js@^1.1.7:
debug "^4.3.4"
make-fetch-happen "^11.1.1"
+tuf-js@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/tuf-js/-/tuf-js-2.1.0.tgz#87aa36d5a166e7522f1e2050eb502a3a9b0bde72"
+ integrity sha512-eD7YPPjVlMzdggrOeE8zwoegUaG/rt6Bt3jwoQPunRiNVzgcCE009UDFJKJjG+Gk9wFu6W/Vi+P5d/5QpdD9jA==
+ dependencies:
+ "@tufjs/models" "2.0.0"
+ debug "^4.3.4"
+ make-fetch-happen "^13.0.0"
+
tunnel-agent@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
@@ -12377,13 +12626,6 @@ unicorn-magic@^0.1.0:
resolved "https://registry.yarnpkg.com/unicorn-magic/-/unicorn-magic-0.1.0.tgz#1bb9a51c823aaf9d73a8bfcd3d1a23dde94b0ce4"
integrity sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==
-unique-filename@^2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-2.0.1.tgz#e785f8675a9a7589e0ac77e0b5c34d2eaeac6da2"
- integrity sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==
- dependencies:
- unique-slug "^3.0.0"
-
unique-filename@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-3.0.0.tgz#48ba7a5a16849f5080d26c760c86cf5cf05770ea"
@@ -12391,13 +12633,6 @@ unique-filename@^3.0.0:
dependencies:
unique-slug "^4.0.0"
-unique-slug@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-3.0.0.tgz#6d347cf57c8a7a7a6044aabd0e2d74e4d76dc7c9"
- integrity sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==
- dependencies:
- imurmurhash "^0.1.4"
-
unique-slug@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-4.0.0.tgz#6bae6bb16be91351badd24cdce741f892a6532e3"
@@ -12577,10 +12812,10 @@ vite-node@0.26.3:
source-map-support "^0.5.21"
vite "^3.0.0 || ^4.0.0"
-vite-node@1.0.4:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-1.0.4.tgz#36d6c49e3b5015967d883845561ed67abe6553cc"
- integrity sha512-9xQQtHdsz5Qn8hqbV7UKqkm8YkJhzT/zr41Dmt5N7AlD8hJXw/Z7y0QiD5I8lnTthV9Rvcvi0QW7PI0Fq83ZPg==
+vite-node@1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-1.1.0.tgz#0ebcb7398692e378954786dfba28e905e28a76b4"
+ integrity sha512-jV48DDUxGLEBdHCQvxL1mEh7+naVy+nhUUUaPAZLd3FJgXuxQiewHcfeZebbJ6onDqNGkP4r3MhQ342PRlG81Q==
dependencies:
cac "^6.7.14"
debug "^4.3.4"
@@ -12588,10 +12823,10 @@ vite-node@1.0.4:
picocolors "^1.0.0"
vite "^5.0.0"
-vite@5.0.7, vite@^5.0.0:
- version "5.0.7"
- resolved "https://registry.yarnpkg.com/vite/-/vite-5.0.7.tgz#ad081d735f6769f76b556818500bdafb72c3fe93"
- integrity sha512-B4T4rJCDPihrQo2B+h1MbeGL/k/GMAHzhQ8S0LjQ142s6/+l3hHTT095ORvsshj4QCkoWu3Xtmob5mazvakaOw==
+vite@5.0.10, vite@^5.0.0:
+ version "5.0.10"
+ resolved "https://registry.yarnpkg.com/vite/-/vite-5.0.10.tgz#1e13ef5c3cf5aa4eed81f5df6d107b3c3f1f6356"
+ integrity sha512-2P8J7WWgmc355HUMlFrwofacvr98DAjoE52BfdbwQtyLH06XKwaL/FMnmKM2crF0iX4MpmMKoDlNCB1ok7zHCw==
dependencies:
esbuild "^0.19.3"
postcss "^8.4.32"
@@ -12631,16 +12866,16 @@ vitest-fail-on-console@0.5.1:
node-stdlib-browser "^1.2.0"
vitest "^0.26.2"
-vitest@1.0.4:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/vitest/-/vitest-1.0.4.tgz#c4b39ba4fcba674499c90e28f4d8dd16fa1d4eb3"
- integrity sha512-s1GQHp/UOeWEo4+aXDOeFBJwFzL6mjycbQwwKWX2QcYfh/7tIerS59hWQ20mxzupTJluA2SdwiBuWwQHH67ckg==
- dependencies:
- "@vitest/expect" "1.0.4"
- "@vitest/runner" "1.0.4"
- "@vitest/snapshot" "1.0.4"
- "@vitest/spy" "1.0.4"
- "@vitest/utils" "1.0.4"
+vitest@1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/vitest/-/vitest-1.1.0.tgz#47ba67c564aa137b53b0197d2a992908e7f5b04d"
+ integrity sha512-oDFiCrw7dd3Jf06HoMtSRARivvyjHJaTxikFxuqJjO76U436PqlVw1uLn7a8OSPrhSfMGVaRakKpA2lePdw79A==
+ dependencies:
+ "@vitest/expect" "1.1.0"
+ "@vitest/runner" "1.1.0"
+ "@vitest/snapshot" "1.1.0"
+ "@vitest/spy" "1.1.0"
+ "@vitest/utils" "1.1.0"
acorn-walk "^8.3.0"
cac "^6.7.14"
chai "^4.3.10"
@@ -12655,7 +12890,7 @@ vitest@1.0.4:
tinybench "^2.5.1"
tinypool "^0.8.1"
vite "^5.0.0"
- vite-node "1.0.4"
+ vite-node "1.1.0"
why-is-node-running "^2.2.2"
vitest@^0.26.2:
@@ -12869,19 +13104,19 @@ which@^1.2.9, which@^1.3.1:
dependencies:
isexe "^2.0.0"
-which@^2.0.1, which@^2.0.2:
+which@^2.0.1:
version "2.0.2"
resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
dependencies:
isexe "^2.0.0"
-which@^3.0.0:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/which/-/which-3.0.1.tgz#89f1cd0c23f629a8105ffe69b8172791c87b4be1"
- integrity sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==
+which@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/which/-/which-4.0.0.tgz#cd60b5e74503a3fbcfbf6cd6b4138a8bae644c1a"
+ integrity sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==
dependencies:
- isexe "^2.0.0"
+ isexe "^3.1.1"
why-is-node-running@^2.2.2:
version "2.2.2"
@@ -12973,10 +13208,10 @@ write-pkg@4.0.0:
type-fest "^0.4.1"
write-json-file "^3.2.0"
-ws@8.15.0, ws@^8.14.2:
- version "8.15.0"
- resolved "https://registry.yarnpkg.com/ws/-/ws-8.15.0.tgz#db080a279260c5f532fc668d461b8346efdfcf86"
- integrity sha512-H/Z3H55mrcrgjFwI+5jKavgXvwQLtfPCUEp6pi35VhoB0pfcHnSoyuTzkBEZpzq49g1193CUEwIvmsjcotenYw==
+ws@8.15.1, ws@^8.14.2:
+ version "8.15.1"
+ resolved "https://registry.yarnpkg.com/ws/-/ws-8.15.1.tgz#271ba33a45ca0cc477940f7f200cd7fba7ee1997"
+ integrity sha512-W5OZiCjXEmk0yZ66ZN82beM5Sz7l7coYxpRkzS+p9PP+ToQry8szKh+61eNktr7EA9DOwvFGhfC605jDHbP6QQ==
ws@^7.3.1:
version "7.5.9"
@@ -13118,10 +13353,10 @@ zip-stream@^5.0.1:
compress-commons "^5.0.1"
readable-stream "^3.6.0"
-zod-to-json-schema@3.22.1:
- version "3.22.1"
- resolved "https://registry.yarnpkg.com/zod-to-json-schema/-/zod-to-json-schema-3.22.1.tgz#30bec8fb92eabbc1f8caf978a0eabfa447b261b7"
- integrity sha512-bVSWQ2JF3ZglQefafkM+Kk9KQ2fqqSi4VhxWaup1NJX9FS5jDg0EkEioVCWui0PiIQvcXJUjmN71bg672+a+tA==
+zod-to-json-schema@3.22.3:
+ version "3.22.3"
+ resolved "https://registry.yarnpkg.com/zod-to-json-schema/-/zod-to-json-schema-3.22.3.tgz#1c71f9fa23f80b2f3b5eed537afa8a13a66a5200"
+ integrity sha512-9isG8SqRe07p+Aio2ruBZmLm2Q6Sq4EqmXOiNpDxp+7f0LV6Q/LX65fs5Nn+FV/CzfF3NLBoksXbS2jNYIfpKw==
zod-validation-error@2.1.0:
version "2.1.0"