Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
bac7f11
page
mtrezza Jul 29, 2025
19cdc01
Update Agent.scss
mtrezza Jul 29, 2025
c4a25de
Update Agent.scss
mtrezza Jul 29, 2025
749d9ec
menu
mtrezza Jul 29, 2025
56759cc
Update Agent.react.js
mtrezza Jul 29, 2025
4db1650
Update Agent.react.js
mtrezza Jul 29, 2025
3753c51
models config
mtrezza Jul 29, 2025
3a6c88a
Update Agent.react.js
mtrezza Jul 29, 2025
2fead43
api
mtrezza Jul 29, 2025
cd3b31c
fix routing
mtrezza Jul 29, 2025
b9a4e19
error handling
mtrezza Jul 29, 2025
56b7407
fix
mtrezza Jul 29, 2025
450a73f
Update app.js
mtrezza Jul 29, 2025
d7849b1
parse ops
mtrezza Jul 29, 2025
e3e75ec
context
mtrezza Jul 29, 2025
bc529e0
empty layout fix
mtrezza Jul 29, 2025
de116f6
example queries
mtrezza Jul 29, 2025
fefe7ab
markdown
mtrezza Jul 29, 2025
3723f49
fix confirmation
mtrezza Jul 29, 2025
80c23a6
bar
mtrezza Jul 29, 2025
6501774
chat scroll
mtrezza Jul 29, 2025
8eee424
Api issue
mtrezza Jul 29, 2025
29663dc
lint
mtrezza Jul 29, 2025
7b99cb4
debug
mtrezza Jul 29, 2025
f87dc21
Revert "debug"
mtrezza Jul 29, 2025
077b5a0
inst
mtrezza Jul 29, 2025
cdac8fb
debug
mtrezza Jul 29, 2025
94ccf76
instr
mtrezza Jul 29, 2025
335b29c
chat tracking
mtrezza Jul 29, 2025
3164fe7
sidebar icon
mtrezza Jul 29, 2025
ecf639e
Update README.md
mtrezza Jul 29, 2025
7c75969
Update README.md
mtrezza Jul 29, 2025
04b8ddd
warning
mtrezza Jul 29, 2025
39fb3aa
lint
mtrezza Jul 29, 2025
3f5e34a
delete class
mtrezza Jul 29, 2025
dc6aa00
missing master key
mtrezza Jul 29, 2025
feac640
Update app.js
mtrezza Jul 29, 2025
3fd8b50
permissions
mtrezza Jul 29, 2025
279ac17
permissions
mtrezza Jul 29, 2025
744bd87
lint
mtrezza Jul 29, 2025
df09472
optimize parse
mtrezza Jul 29, 2025
de7a95e
Update Agent.react.js
mtrezza Jul 29, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
869 changes: 865 additions & 4 deletions Parse-Dashboard/app.js

Large diffs are not rendered by default.

98 changes: 90 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,14 @@ Parse Dashboard is a standalone dashboard for managing your [Parse Server](https
- [Panel Item](#panel-item)
- [Prefetching](#prefetching)
- [Freeze Columns](#freeze-columns)
- [Browse as User](#browse-as-user)
- [Change Pointer Key](#change-pointer-key)
- [Limitations](#limitations)
- [CSV Export](#csv-export)
- [Browse as User](#browse-as-user)
- [Change Pointer Key](#change-pointer-key)
- [Limitations](#limitations)
- [CSV Export](#csv-export)
- [AI Agent](#ai-agent)
- [Configuration](#configuration)
- [Providers](#providers)
- [OpenAI](#openai)
- [Views](#views)
- [Data Sources](#data-sources)
- [Aggregation Pipeline](#aggregation-pipeline)
Expand Down Expand Up @@ -1231,35 +1235,113 @@ Prefetching is particularly useful when navigating through lists of objects. To

Right-click on a table column header to freeze columns from the left up to the clicked column in the data browser. When scrolling horizontally, the frozen columns remain visible while the other columns scroll underneath.

## Browse as User
### Browse as User

▶️ *Core > Browser > Browse*

This feature allows you to use the data browser as another user, respecting that user's data permissions. For example, you will only see records and fields the user has permission to see.

> ⚠️ Logging in as another user will trigger the same Cloud Triggers as if the user logged in themselves using any other login method. Logging in as another user requires to enter that user's password.

## Change Pointer Key
### Change Pointer Key

▶️ *Core > Browser > Edit > Change pointer key*

This feature allows you to change how a pointer is represented in the browser. By default, a pointer is represented by the `objectId` of the linked object. You can change this to any other column of the object class. For example, if class `Installation` has a field that contains a pointer to class `User`, the pointer will show the `objectId` of the user by default. You can change this to display the field `email` of the user, so that a pointer displays the user's email address instead.

### Limitations
#### Limitations

- This does not work for an array of pointers; the pointer will always display the `objectId`.
- System columns like `createdAt`, `updatedAt`, `ACL` cannot be set as pointer key.
- This feature uses browser storage; switching to a different browser resets the pointer key to `objectId`.

> ⚠️ For each custom pointer key in each row, a server request is triggered to resolve the custom pointer key. For example, if the browser shows a class with 50 rows and each row contains 3 custom pointer keys, a total of 150 separate server requests are triggered.
## CSV Export

### CSV Export

▶️ *Core > Browser > Export*

This feature will take either selected rows or all rows of an individual class and saves them to a CSV file, which is then downloaded. CSV headers are added to the top of the file matching the column names.

> ⚠️ There is currently a 10,000 row limit when exporting all data. If more than 10,000 rows are present in the class, the CSV file will only contain 10,000 rows.

## AI Agent

The Parse Dashboard includes an AI agent that can help manage your Parse Server data through natural language commands. The agent can perform operations like creating classes, adding data, querying records, and more.

> [!Caution]
> The AI agent has full access to your database using the master key. It can read, modify, and delete any data. This feature is highly recommended for development environments only. Always back up important data before using the AI agent.

### Configuration

To configure the AI agent for your dashboard, you need to add the `agent` configuration to your Parse Dashboard config:

```json
{
"apps": [
// ...
],
"agent": {
"models": [
{
"name": "ChatGPT 4.1",
"provider": "openai",
"model": "gpt-4.1",
"apiKey": "YOUR_OPENAI_API_KEY"
},
]
}
}
```

| Parameter | Type | Required | Description |
|-----------------------------|--------|----------|--------------------------------------------------------------------------------|
| `agent` | Object | Yes | The AI agent configuration object. |
| `agent.models` | Array | Yes | Array of AI model configurations available to the agent. |
| `agent.models[*].name` | String | Yes | The display name for the model (e.g., `ChatGPT 4.1`). |
| `agent.models[*].provider` | String | Yes | The AI provider identifier (e.g., "openai"). |
| `agent.models[*].model` | String | Yes | The specific model name from the provider (e.g., `gpt-4.1`). |
| `agent.models[*].apiKey` | String | Yes | The API key for authenticating with the AI provider. |

The agent will use the configured models to process natural language commands and perform database operations using the master key from your app configuration.

### Providers

> [!Note]
> Currently, only OpenAI models are supported. Support for additional providers may be added in future releases.

#### OpenAI

To get an OpenAI API key for use with the AI agent:

1. **Create an OpenAI account**: Visit [platform.openai.com](https://platform.openai.com) and sign up for an account if you don't already have one.

2. **Access the API section**: Once logged in, navigate to the API section of your OpenAI dashboard.

3. **Create a new project**:
- Go to the "Projects" section
- Click "Create project"
- Name your project "Parse-Dashboard" (or any descriptive name)
- Complete the project setup

4. **Configure model access**:
- In your project, navigate to "Limits > Model Usage"
- Select the AI models you want to use (e.g., `gpt-4`, `gpt-3.5-turbo`)
- These model names will be used as the `agent.models[*].model` parameter in your dashboard configuration

5. **Generate an API key**:
- Go to the "API Keys" page in your project settings
- Click "Create new secret key"
- Give your key a descriptive name (e.g., "Parse Dashboard Agent")
- Copy the generated API key immediately (you won't be able to see it again)

6. **Set up billing**: Make sure you have a valid payment method added to your OpenAI account, as API usage incurs charges.

7. **Configure the dashboard**: Add the API key to your Parse Dashboard configuration as shown in the example above.

> [!Important]
> Keep your API key secure and never commit it to version control. Consider using environment variables or secure configuration management for production deployments.

## Views

▶️ *Core > Views*
Expand Down
116 changes: 101 additions & 15 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
"immutable-devtools": "0.1.5",
"inquirer": "12.6.3",
"js-beautify": "1.15.4",
"node-fetch": "3.3.2",
"otpauth": "8.0.3",
"package-json": "7.0.0",
"parse": "3.5.1",
Expand Down
33 changes: 22 additions & 11 deletions src/components/EmptyState/EmptyState.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,27 @@ const EmptyState = ({
action = () => {},
secondaryCta = '',
secondaryAction = () => {},
}) => (
<div className={baseStyles.center}>
<div className={styles.icon}>
<Icon width={80} height={80} fill="#343445" name={icon} />
customContent = null,
useFlexLayout = false,
}) => {
const containerClass = useFlexLayout ? styles.flexContainer : baseStyles.center;

return (
<div className={containerClass}>
<div className={styles.content}>
<div className={styles.icon}>
<Icon width={80} height={80} fill="#343445" name={icon} />
</div>
<div className={styles.title}>{title}</div>
<div className={styles.description}>{description}</div>
{ctaButton(cta, action)}
{secondaryCta && ' '}
{ctaButton(secondaryCta, secondaryAction)}
</div>
{customContent && <div className={styles.customContent}>{customContent}</div>}
</div>
<div className={styles.title}>{title}</div>
<div className={styles.description}>{description}</div>
{ctaButton(cta, action)}
{secondaryCta && ' '}
{ctaButton(secondaryCta, secondaryAction)}
</div>
);
);
};

EmptyState.propTypes = {
icon: PropTypes.string.describe('The name of the large icon that appears in the empty state.'),
Expand All @@ -72,6 +81,8 @@ EmptyState.propTypes = {
secondaryAction: PropTypes.oneOfType([PropTypes.string, PropTypes.func]).describe(
'An href link or a click handler that is forwarded to the secondary CTA button.'
),
customContent: PropTypes.node.describe('Custom content to render below the empty state.'),
useFlexLayout: PropTypes.bool.describe('Whether to use flex layout instead of absolute positioning.'),
};

export default EmptyState;
Loading
Loading