mirror of
https://github.com/ToolJet/ToolJet
synced 2026-04-21 13:37:28 +00:00
Enhance TypeScript support in frontend configuration (#15576)
* test: verify pre-commit hook * fix: clean up code formatting and improve readability across multiple components * chore: update subproject commit reference in frontend/ee * chore: update eslint to version 9.26.0 and remove unused dependencies from package.json fix: update submodule reference in server/ee * chore: refactor ESLint configuration and add quiet linting script; update components to disable specific ESLint rules * chore: add GitHub Copilot review instructions for App Builder team Covers backward compatibility rules, styling conventions, state management, resolution system, widget definitions, and common review flags. * chore: add review instructions for App Builder, Data Migrations, Server Widget Config, Widget Components, and Widget Config * Enhance TypeScript support in frontend configuration - Added TypeScript parser and linting rules to ESLint configuration. - Updated Babel configuration to include TypeScript preset. - Modified package.json and package-lock.json to include TypeScript and related dependencies. - Introduced tsconfig.json for TypeScript compiler options. - Updated Webpack configuration to support .ts and .tsx file extensions. - Adjusted linting and formatting scripts to include TypeScript files. * chore: update TypeScript ESLint packages and subproject commits --------- Co-authored-by: kavinvenkatachalam <kavin.saratha@gmail.com> Co-authored-by: Johnson Cherian <johnsonc.dev@gmail.com>
This commit is contained in:
parent
e9d68061c2
commit
433e1bd4c4
263 changed files with 4987 additions and 5776 deletions
|
|
@ -1,2 +0,0 @@
|
|||
node_modules/**
|
||||
cypress-tests/**
|
||||
48
.github/copilot-instructions.md
vendored
Normal file
48
.github/copilot-instructions.md
vendored
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
# ToolJet — Shared Copilot Instructions
|
||||
|
||||
## Styling
|
||||
|
||||
- Tailwind classes MUST use the `tw-` prefix (e.g., `tw-flex`, `tw-text-default`). Unprefixed Tailwind is a bug.
|
||||
- NEVER hardcode hex/rgb colors. Use CSS variable tokens via Tailwind (`tw-text-default`, `tw-bg-page-default`) or `var(--text-default)`.
|
||||
- Prefer Tailwind over Bootstrap for new code. Do not extend legacy `react-bootstrap` usage.
|
||||
- Use custom typography utilities (`tw-font-title-default`, `tw-font-body-default`, etc.) instead of ad-hoc font-size/weight.
|
||||
- Design tokens: `frontend/src/_styles/designtheme.scss` + `frontend/tailwind.config.js`.
|
||||
|
||||
## Component Patterns
|
||||
|
||||
- Check `frontend/src/_ui/` (53+ components) before creating new UI components.
|
||||
- Functional components with hooks only. No class components.
|
||||
- File structure: `ComponentName/index.js` + optional `ComponentName.jsx` + `style.scss`.
|
||||
- Compose with Radix UI primitives for accessible interactive elements.
|
||||
|
||||
## Imports
|
||||
|
||||
- Use `@/` path alias (maps to `frontend/src/`): `import Button from '@/_ui/Button'`.
|
||||
- No deep relative paths (`../../..` is a smell).
|
||||
|
||||
## State Management
|
||||
|
||||
- Zustand with Immer middleware only. No Redux/MobX/Recoil.
|
||||
- Use `shallow` comparison in `useStore` when selecting objects/arrays. Flag missing `shallow`.
|
||||
|
||||
## Icons & Assets
|
||||
|
||||
- Use Tabler Icons (`@tabler/icons-react`) or Lucide React (`lucide-react`). Do NOT add new icon packages.
|
||||
- Static assets: `frontend/assets/images/`.
|
||||
|
||||
## Security
|
||||
|
||||
- No API keys/secrets in client-side code.
|
||||
- Backend: parameterized queries only, never concatenate user input into SQL.
|
||||
|
||||
## Common Review Flags
|
||||
|
||||
- Hardcoded colors (hex/rgb/hsl in JSX or SCSS)
|
||||
- Missing `tw-` prefix on Tailwind classes
|
||||
- New `react-bootstrap` imports
|
||||
- Class components
|
||||
- `console.log` / debug leftovers
|
||||
- Unused imports
|
||||
- Missing `key` props in `.map()`
|
||||
- Missing `shallow` in `useStore` selectors
|
||||
- Direct DOM manipulation (except canvas drop calculations)
|
||||
54
.github/instructions/appbuilder-review.instructions.md
vendored
Normal file
54
.github/instructions/appbuilder-review.instructions.md
vendored
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
---
|
||||
applyTo: "frontend/src/AppBuilder/**/*"
|
||||
excludeAgent: "coding-agent"
|
||||
---
|
||||
|
||||
# App Builder — Code Review Rules
|
||||
|
||||
## Backward Compatibility (CRITICAL)
|
||||
|
||||
No change should break existing saved applications. When reviewing, always ask: "Would an app saved before this PR still load and behave correctly after it?"
|
||||
|
||||
## Resolution System (`{{}}`)
|
||||
|
||||
- Flow: unresolved value → `extractAndReplaceReferencesFromString` → `resolveDynamicValues` → `resolveCode` (via `new Function()`) → resolved value stored in `resolvedSlice`.
|
||||
- `{{...}}` references MUST be registered in the dependency graph via `addReferencesForDependencyGraph`. Missing this causes stale renders.
|
||||
- After `setExposedValue`, `updateDependencyValues` MUST be called to propagate changes.
|
||||
- Inside ListView/Kanban, `customResolvables` provide row-scoped context (`listItem` / `cardData`).
|
||||
|
||||
## Rendering Pipeline
|
||||
|
||||
`AppCanvas → Container → WidgetWrapper → RenderWidget → Widget`
|
||||
|
||||
- Widgets receive resolved props from `RenderWidget`. They must NOT directly access store state.
|
||||
- `setExposedVariable` and `fireEvent` are passed as callbacks — widgets use these to communicate outward.
|
||||
|
||||
## Subcontainer Architecture
|
||||
|
||||
- `SubcontainerContext` carries `contextPath` array: `[{ containerId, index }, ...]`.
|
||||
- Row-scoped resolution uses prototype overlay (`prepareRowScope`/`updateRowScope`).
|
||||
- Child-to-parent: `setExposedValuesPerRow` → `_deriveListviewChain` (no callback chains).
|
||||
- ListView nesting limited to **2 levels**. Only row 0 is editable; others are read-only mirrors.
|
||||
- `findNearestSubcontainerAncestor` is critical for dependency resolution — verify it's used when walking the component tree.
|
||||
- Keywords: `listItem` (ListView), `cardData` (Kanban). Don't mix them up.
|
||||
|
||||
## Event & Query Systems
|
||||
|
||||
- Events: `fireEvent → handleEvent → executeActionsForEventId → executeAction`. Events support `runOnlyIf` and `debounce`.
|
||||
- Queries: `runQuery → resolve options → API call → update exposedValues.queries[name] → trigger dependency updates`.
|
||||
- Event definitions live in `eventsSlice`, not in component definitions.
|
||||
|
||||
## Bundle & Performance
|
||||
|
||||
- Viewer (`/applications/*`) and editor are separate lazy bundles via `RootRouter.jsx`. Do not import editor-only code into viewer paths.
|
||||
- Avoid `JSON.parse(JSON.stringify(...))` or `_.cloneDeep` in render/hot paths. Use Immer.
|
||||
- Flag O(N) loops inside already-O(N) resolution paths (eager resolution for ListView children).
|
||||
|
||||
## State Management
|
||||
|
||||
- Global stores (`appDataStore`, `currentStateStore`, `dataQueriesStore`, `resolverStore`) should NOT be used in AppBuilder code unless absolutely critical. Prefer the AppBuilder store. Flag any new usage.
|
||||
- AppBuilder store: `AppBuilder/_stores/store.js` (30+ slices). All slices are namespaced by `moduleId` (default: `'canvas'`).
|
||||
|
||||
## Security
|
||||
|
||||
- `resolveCode` uses `new Function()` — be cautious about evaluated expressions.
|
||||
31
.github/instructions/data-migrations.instructions.md
vendored
Normal file
31
.github/instructions/data-migrations.instructions.md
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
---
|
||||
applyTo: "server/data-migrations/**/*"
|
||||
---
|
||||
|
||||
# Data Migration — Logging Guidelines
|
||||
|
||||
New migrations MUST include progress logging to help monitor deployments.
|
||||
|
||||
## Required Logging Pattern
|
||||
|
||||
1. **Baseline** — Before processing, query and log total records:
|
||||
`[START] {Action} | Total: {Total}`
|
||||
|
||||
2. **Progress** — During execution, log using current/total format:
|
||||
`[PROGRESS] {Current}/{Total} ({Percentage}%)`
|
||||
|
||||
3. **Confirmation** — Log final success:
|
||||
`[SUCCESS] {Action} finished.`
|
||||
|
||||
## Reviewer Checklist
|
||||
|
||||
- [ ] Count query establishes a **total** before processing
|
||||
- [ ] Log statements use the **`x/total`** ratio pattern
|
||||
- [ ] Clear **success** log at the end
|
||||
- [ ] No silent bulk updates without console feedback
|
||||
|
||||
## When Generating Migration Code
|
||||
|
||||
- Include a count query for the denominator before processing.
|
||||
- Wrap iterative logic in a batch/loop that logs `current/total` progress.
|
||||
- Avoid silent bulk updates that provide no console feedback.
|
||||
18
.github/instructions/server-widget-config-review.instructions.md
vendored
Normal file
18
.github/instructions/server-widget-config-review.instructions.md
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
---
|
||||
applyTo: "server/src/modules/apps/services/widget-config/**/*"
|
||||
excludeAgent: "coding-agent"
|
||||
---
|
||||
|
||||
# Server Widget Config — Code Review Rules
|
||||
|
||||
## Frontend Sync (CRITICAL)
|
||||
|
||||
When any file here is modified, the corresponding config in `frontend/src/AppBuilder/WidgetManager/widgets/` MUST also be updated. Flag PRs that modify one without the other.
|
||||
|
||||
## Key Changes Require Migrations
|
||||
|
||||
If a config change moves, renames, or removes a key, a migration MUST be written in `server/migrations/` to transform saved app definitions. Flag any key restructuring that lacks an accompanying migration.
|
||||
|
||||
## Backward Compatibility
|
||||
|
||||
No change should break existing saved applications. Always ask: "Would an app saved before this PR still load and behave correctly after it?"
|
||||
14
.github/instructions/widget-components-review.instructions.md
vendored
Normal file
14
.github/instructions/widget-components-review.instructions.md
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
applyTo: "frontend/src/AppBuilder/Widgets/**/*"
|
||||
excludeAgent: "coding-agent"
|
||||
---
|
||||
|
||||
# Widget Components — Code Review Rules
|
||||
|
||||
## Component Rules
|
||||
|
||||
- New widgets MUST be lazy-loaded.
|
||||
- Use `useBatchedUpdateEffectArray` for batched state updates.
|
||||
- Widgets receive resolved props from `RenderWidget`. They must NOT directly access store state.
|
||||
- `setExposedVariable` and `fireEvent` are passed as callbacks — widgets use these to communicate outward.
|
||||
- Default values should use design tokens, not hardcoded hex colors.
|
||||
24
.github/instructions/widget-config-review.instructions.md
vendored
Normal file
24
.github/instructions/widget-config-review.instructions.md
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
---
|
||||
applyTo: "frontend/src/AppBuilder/WidgetManager/widgets/**/*"
|
||||
excludeAgent: "coding-agent"
|
||||
---
|
||||
|
||||
# Widget Config — Code Review Rules
|
||||
|
||||
## Server-Side Sync (CRITICAL)
|
||||
|
||||
When any file here is modified, the corresponding config in `server/src/modules/apps/services/widget-config/` MUST also be updated. Flag PRs that modify one without the other.
|
||||
|
||||
## Key Changes Require Migrations
|
||||
|
||||
If a config change moves, renames, or removes a key (e.g., moving `loadingState` from `styles` to `properties`), this WILL break existing apps. A migration MUST be written in `server/migrations/` to transform saved app definitions. Flag any key restructuring that lacks an accompanying migration.
|
||||
|
||||
## Widget Definition Rules
|
||||
|
||||
- New widgets MUST be lazy-loaded.
|
||||
- Use `useBatchedUpdateEffectArray` for batched state updates.
|
||||
- Widget components must be registered in `componentTypes.js`.
|
||||
|
||||
## Backward Compatibility
|
||||
|
||||
Always ask: "Would an app saved before this PR still load and behave correctly after it?"
|
||||
|
|
@ -1,4 +1 @@
|
|||
#!/bin/sh
|
||||
# . "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
# npx lint-staged
|
||||
npx lint-staged
|
||||
|
|
|
|||
49
.vscode/settings.json
vendored
49
.vscode/settings.json
vendored
|
|
@ -1,28 +1,27 @@
|
|||
{
|
||||
"[javascript, typescript]": {
|
||||
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
|
||||
"[javascript, typescript]": {
|
||||
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
|
||||
},
|
||||
"eslint.validate": [
|
||||
"javascript",
|
||||
"javascriptreact",
|
||||
"typescript",
|
||||
"typescriptreact"
|
||||
],
|
||||
"eslint.useFlatConfig": true,
|
||||
"editor.formatOnSave": false,
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": "explicit"
|
||||
},
|
||||
"json.schemas": [
|
||||
{
|
||||
"fileMatch": ["/*.operations.json"],
|
||||
"url": "https://raw.githubusercontent.com/ToolJet/ToolJet/develop/plugins/schemas/operations.schema.json"
|
||||
},
|
||||
"eslint.validate": [
|
||||
"javascript",
|
||||
"javascriptreact",
|
||||
"typescript",
|
||||
"typescriptreact"
|
||||
],
|
||||
"eslint.format.enable": true,
|
||||
"editor.formatOnSave": true,
|
||||
"json.schemas": [
|
||||
{
|
||||
"fileMatch": [
|
||||
"/*.operations.json"
|
||||
],
|
||||
"url": "https://raw.githubusercontent.com/ToolJet/ToolJet/develop/plugins/schemas/operations.schema.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"/*.manifest.json"
|
||||
],
|
||||
"url": "https://raw.githubusercontent.com/ToolJet/ToolJet/develop/plugins/schemas/manifest.schema.json"
|
||||
}
|
||||
],
|
||||
"CodeGPT.apiKey": "CodeGPT Plus Beta"
|
||||
{
|
||||
"fileMatch": ["/*.manifest.json"],
|
||||
"url": "https://raw.githubusercontent.com/ToolJet/ToolJet/develop/plugins/schemas/manifest.schema.json"
|
||||
}
|
||||
],
|
||||
"CodeGPT.apiKey": "CodeGPT Plus Beta"
|
||||
}
|
||||
4
eslint.config.mjs
Normal file
4
eslint.config.mjs
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
// Root ESLint flat config — delegates to frontend config.
|
||||
// Uses dynamic import so plugin resolution happens from frontend/node_modules.
|
||||
const { default: config } = await import('./frontend/eslint.config.mjs');
|
||||
export default config;
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
build
|
||||
assets
|
||||
|
|
@ -1,86 +0,0 @@
|
|||
module.exports = {
|
||||
root: true,
|
||||
overrides: [
|
||||
{
|
||||
files: ['**/*.js', '**/*.jsx'],
|
||||
env: {
|
||||
browser: true,
|
||||
amd: true,
|
||||
es2021: true,
|
||||
node: true,
|
||||
'jest/globals': true,
|
||||
},
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:react/recommended',
|
||||
'plugin:react-hooks/recommended',
|
||||
'plugin:import/errors',
|
||||
'plugin:import/warnings',
|
||||
'plugin:prettier/recommended',
|
||||
],
|
||||
parser: '@babel/eslint-parser',
|
||||
parserOptions: {
|
||||
requireConfigFile: false,
|
||||
babelOptions: {
|
||||
configFile: __dirname + '/babel.config.js',
|
||||
},
|
||||
ecmaFeatures: {
|
||||
jsx: true,
|
||||
},
|
||||
ecmaVersion: 12,
|
||||
sourceType: 'module',
|
||||
},
|
||||
plugins: ['react', 'prettier', 'jest'],
|
||||
rules: {
|
||||
'prettier/prettier': [
|
||||
'error',
|
||||
{
|
||||
semi: true,
|
||||
trailingComma: 'es5',
|
||||
printWidth: 120,
|
||||
singleQuote: true,
|
||||
arrowParens: 'always',
|
||||
proseWrap: 'preserve',
|
||||
},
|
||||
],
|
||||
'react/prop-types': 0,
|
||||
'react/display-name': 'off',
|
||||
'no-unused-vars': [
|
||||
'warn',
|
||||
{
|
||||
argsIgnorePattern: '^_',
|
||||
varsIgnorePattern: '^_',
|
||||
},
|
||||
],
|
||||
'react/no-deprecated': 0,
|
||||
'no-prototype-builtins': 0,
|
||||
'jest/no-disabled-tests': 'warn',
|
||||
'jest/no-focused-tests': 'error',
|
||||
'jest/no-identical-title': 'error',
|
||||
'jest/prefer-to-have-length': 'warn',
|
||||
'jest/valid-expect': 'error',
|
||||
'import/no-unresolved': [
|
||||
'error',
|
||||
{
|
||||
ignore: ['^@/', 'react-hot-toast', 'react-i18next', 'react-loading-skeleton', 'react-spring'],
|
||||
},
|
||||
],
|
||||
'react/no-unknown-property': 'off',
|
||||
},
|
||||
settings: {
|
||||
react: {
|
||||
version: 'detect',
|
||||
},
|
||||
'import/resolver': 'webpack',
|
||||
},
|
||||
globals: {
|
||||
path: true,
|
||||
fetch: true,
|
||||
process: true,
|
||||
module: true,
|
||||
__dirname: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
extends: ['plugin:storybook/recommended'],
|
||||
};
|
||||
|
|
@ -19,6 +19,6 @@ if (process.env.NODE_ENV === 'developement') {
|
|||
}
|
||||
|
||||
module.exports = {
|
||||
presets: ['@babel/preset-env', '@babel/preset-react'],
|
||||
presets: ['@babel/preset-env', '@babel/preset-react', '@babel/preset-typescript'],
|
||||
plugins,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 2dd264546928e348bc043d7434c893420ea4af0d
|
||||
Subproject commit 93b97db21954bb9f6223ae06b1a6cae0f76eba42
|
||||
266
frontend/eslint.config.mjs
Normal file
266
frontend/eslint.config.mjs
Normal file
|
|
@ -0,0 +1,266 @@
|
|||
import js from '@eslint/js';
|
||||
import globals from 'globals';
|
||||
import babelParser from '@babel/eslint-parser';
|
||||
import pluginReact from 'eslint-plugin-react';
|
||||
import pluginReactHooks from 'eslint-plugin-react-hooks';
|
||||
import pluginImportX from 'eslint-plugin-import-x';
|
||||
import pluginJest from 'eslint-plugin-jest';
|
||||
import pluginPrettier from 'eslint-plugin-prettier';
|
||||
import configPrettier from 'eslint-config-prettier';
|
||||
import pluginStorybook from 'eslint-plugin-storybook';
|
||||
import tsPlugin from '@typescript-eslint/eslint-plugin';
|
||||
import tsParser from '@typescript-eslint/parser';
|
||||
|
||||
import { fileURLToPath } from 'url';
|
||||
import { dirname } from 'path';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
// Remap import-x recommended rules from 'import-x/' prefix to 'import/' prefix
|
||||
// so they match the plugin namespace and existing eslint-disable directives
|
||||
function remapImportRules(rules) {
|
||||
const remapped = {};
|
||||
for (const [key, value] of Object.entries(rules)) {
|
||||
remapped[key.replace(/^import-x\//, 'import/')] = value;
|
||||
}
|
||||
return remapped;
|
||||
}
|
||||
|
||||
export default [
|
||||
// Global ignores (replaces .eslintignore)
|
||||
{
|
||||
ignores: ['build/**', 'assets/**', 'cypress-tests/**'],
|
||||
},
|
||||
|
||||
// Disable reporting unused eslint-disable directives (ESLint 9 defaults to "warn",
|
||||
// ESLint 8 defaulted to "off"). This prevents --fix from stripping existing
|
||||
// eslint-disable comments that plugins no longer flag.
|
||||
{
|
||||
linterOptions: {
|
||||
reportUnusedDisableDirectives: 'off',
|
||||
},
|
||||
},
|
||||
|
||||
// Main config for JS/JSX files
|
||||
{
|
||||
files: ['**/*.js', '**/*.jsx'],
|
||||
|
||||
languageOptions: {
|
||||
parser: babelParser,
|
||||
parserOptions: {
|
||||
requireConfigFile: false,
|
||||
babelOptions: {
|
||||
configFile: __dirname + '/babel.config.js',
|
||||
},
|
||||
ecmaFeatures: {
|
||||
jsx: true,
|
||||
},
|
||||
ecmaVersion: 12,
|
||||
sourceType: 'module',
|
||||
},
|
||||
globals: {
|
||||
...globals.browser,
|
||||
...globals.amd,
|
||||
...globals.node,
|
||||
...globals.es2021,
|
||||
...globals.jest,
|
||||
path: true,
|
||||
fetch: true,
|
||||
process: true,
|
||||
module: true,
|
||||
__dirname: true,
|
||||
},
|
||||
},
|
||||
|
||||
plugins: {
|
||||
react: pluginReact,
|
||||
'react-hooks': pluginReactHooks,
|
||||
// Register import-x under the 'import' namespace so existing
|
||||
// `eslint-disable import/...` directives continue to work
|
||||
import: pluginImportX,
|
||||
jest: pluginJest,
|
||||
prettier: pluginPrettier,
|
||||
},
|
||||
|
||||
settings: {
|
||||
react: {
|
||||
version: 'detect',
|
||||
},
|
||||
'import-x/resolver': 'webpack',
|
||||
},
|
||||
|
||||
rules: {
|
||||
// eslint:recommended
|
||||
...js.configs.recommended.rules,
|
||||
|
||||
// react recommended
|
||||
...pluginReact.configs.recommended.rules,
|
||||
|
||||
// react-hooks recommended
|
||||
...pluginReactHooks.configs.recommended.rules,
|
||||
|
||||
// import errors + warnings (remapped from import-x/ to import/ namespace)
|
||||
...remapImportRules(pluginImportX.configs.recommended.rules),
|
||||
|
||||
// prettier recommended (plugin + config)
|
||||
...pluginPrettier.configs.recommended.rules,
|
||||
|
||||
// prettier config (disables conflicting rules)
|
||||
...configPrettier.rules,
|
||||
|
||||
// Re-enable prettier/prettier as error (after configPrettier may disable it)
|
||||
'prettier/prettier': [
|
||||
'error',
|
||||
{
|
||||
semi: true,
|
||||
trailingComma: 'es5',
|
||||
printWidth: 120,
|
||||
singleQuote: true,
|
||||
arrowParens: 'always',
|
||||
proseWrap: 'preserve',
|
||||
},
|
||||
],
|
||||
|
||||
// Project rules (preserved from .eslintrc.js)
|
||||
'react/prop-types': 0,
|
||||
'react/display-name': 'off',
|
||||
'no-unused-vars': [
|
||||
'warn',
|
||||
{
|
||||
argsIgnorePattern: '^_',
|
||||
varsIgnorePattern: '^_',
|
||||
},
|
||||
],
|
||||
'react/no-deprecated': 0,
|
||||
'no-prototype-builtins': 0,
|
||||
'jest/no-disabled-tests': 'warn',
|
||||
'jest/no-focused-tests': 'error',
|
||||
'jest/no-identical-title': 'error',
|
||||
'jest/prefer-to-have-length': 'warn',
|
||||
'jest/valid-expect': 'error',
|
||||
'import/no-unresolved': [
|
||||
'error',
|
||||
{
|
||||
ignore: ['^@/', 'react-hot-toast', 'react-i18next', 'react-loading-skeleton', 'react-spring'],
|
||||
},
|
||||
],
|
||||
'react/no-unknown-property': 'off',
|
||||
},
|
||||
},
|
||||
|
||||
// TypeScript config for TS/TSX files
|
||||
{
|
||||
files: ['**/*.ts', '**/*.tsx'],
|
||||
|
||||
languageOptions: {
|
||||
parser: tsParser,
|
||||
parserOptions: {
|
||||
ecmaFeatures: { jsx: true },
|
||||
ecmaVersion: 'latest',
|
||||
sourceType: 'module',
|
||||
project: __dirname + '/tsconfig.json',
|
||||
},
|
||||
globals: {
|
||||
...globals.browser,
|
||||
...globals.amd,
|
||||
...globals.node,
|
||||
...globals.es2021,
|
||||
path: true,
|
||||
fetch: true,
|
||||
process: true,
|
||||
module: true,
|
||||
__dirname: true,
|
||||
},
|
||||
},
|
||||
|
||||
plugins: {
|
||||
'@typescript-eslint': tsPlugin,
|
||||
react: pluginReact,
|
||||
'react-hooks': pluginReactHooks,
|
||||
prettier: pluginPrettier,
|
||||
},
|
||||
|
||||
settings: {
|
||||
react: {
|
||||
version: 'detect',
|
||||
},
|
||||
},
|
||||
|
||||
rules: {
|
||||
// eslint:recommended
|
||||
...js.configs.recommended.rules,
|
||||
|
||||
// @typescript-eslint/recommended rules (from v7 plugin)
|
||||
// Disable base ESLint rules that conflict with TS equivalents
|
||||
'no-unused-vars': 'off',
|
||||
'no-undef': 'off', // TypeScript handles this
|
||||
'no-redeclare': 'off',
|
||||
'no-dupe-class-members': 'off',
|
||||
|
||||
// @typescript-eslint recommended
|
||||
'@typescript-eslint/adjacent-overload-signatures': 'error',
|
||||
'@typescript-eslint/ban-ts-comment': 'error',
|
||||
'@typescript-eslint/ban-types': 'error',
|
||||
'@typescript-eslint/no-array-constructor': 'error',
|
||||
'@typescript-eslint/no-empty-interface': 'error',
|
||||
'@typescript-eslint/no-extra-non-null-assertion': 'error',
|
||||
'@typescript-eslint/no-inferrable-types': 'error',
|
||||
'@typescript-eslint/no-loss-of-precision': 'error',
|
||||
'@typescript-eslint/no-misused-new': 'error',
|
||||
'@typescript-eslint/no-namespace': 'error',
|
||||
'@typescript-eslint/no-non-null-asserted-optional-chain': 'error',
|
||||
'@typescript-eslint/no-non-null-assertion': 'warn',
|
||||
'@typescript-eslint/no-this-alias': 'error',
|
||||
'@typescript-eslint/no-unnecessary-type-constraint': 'error',
|
||||
'@typescript-eslint/no-var-requires': 'error',
|
||||
'@typescript-eslint/prefer-as-const': 'error',
|
||||
'@typescript-eslint/triple-slash-reference': 'error',
|
||||
|
||||
// react recommended
|
||||
...pluginReact.configs.recommended.rules,
|
||||
|
||||
// react-hooks recommended
|
||||
...pluginReactHooks.configs.recommended.rules,
|
||||
|
||||
// prettier recommended (plugin + config)
|
||||
...pluginPrettier.configs.recommended.rules,
|
||||
|
||||
// prettier config (disables conflicting rules)
|
||||
...configPrettier.rules,
|
||||
|
||||
// Re-enable prettier/prettier as error
|
||||
'prettier/prettier': [
|
||||
'error',
|
||||
{
|
||||
semi: true,
|
||||
trailingComma: 'es5',
|
||||
printWidth: 120,
|
||||
singleQuote: true,
|
||||
arrowParens: 'always',
|
||||
proseWrap: 'preserve',
|
||||
},
|
||||
],
|
||||
|
||||
// Project rules
|
||||
'react/prop-types': 'off',
|
||||
'react/display-name': 'off',
|
||||
|
||||
// Override @typescript-eslint defaults with project preferences
|
||||
'@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }],
|
||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'warn',
|
||||
|
||||
'import/no-unresolved': [
|
||||
'error',
|
||||
{
|
||||
ignore: ['^@/', 'react-hot-toast', 'react-i18next', 'react-loading-skeleton', 'react-spring'],
|
||||
},
|
||||
],
|
||||
|
||||
'react/no-unknown-property': 'off',
|
||||
},
|
||||
},
|
||||
|
||||
// Storybook config
|
||||
...pluginStorybook.configs['flat/recommended'],
|
||||
];
|
||||
2858
frontend/package-lock.json
generated
2858
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -168,10 +168,11 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.20.12",
|
||||
"@babel/eslint-parser": "^7.19.1",
|
||||
"@babel/eslint-parser": "^7.28.6",
|
||||
"@babel/plugin-transform-runtime": "^7.19.6",
|
||||
"@babel/preset-env": "^7.20.2",
|
||||
"@babel/preset-react": "^7.18.6",
|
||||
"@babel/preset-typescript": "^7.28.5",
|
||||
"@pmmmwh/react-refresh-webpack-plugin": "^0.6.0",
|
||||
"@storybook/addon-docs": "^9.1.5",
|
||||
"@storybook/addon-links": "^9.1.5",
|
||||
|
|
@ -182,6 +183,8 @@
|
|||
"@testing-library/jest-dom": "^5.16.5",
|
||||
"@testing-library/react": "^13.4.0",
|
||||
"@testing-library/user-event": "^14.4.3",
|
||||
"@typescript-eslint/eslint-plugin": "^8.39.0",
|
||||
"@typescript-eslint/parser": "^8.39.0",
|
||||
"autoprefixer": "^10.4.17",
|
||||
"babel-loader": "^9.1.2",
|
||||
"babel-plugin-console-source": "^2.0.5",
|
||||
|
|
@ -191,19 +194,20 @@
|
|||
"css-loader": "^6.7.3",
|
||||
"css-minimizer-webpack-plugin": "^7.0.2",
|
||||
"esbuild": "0.25.9",
|
||||
"eslint": "^8.37.0",
|
||||
"eslint-config-prettier": "^8.6.0",
|
||||
"eslint-import-resolver-webpack": "^0.13.2",
|
||||
"eslint-plugin-import": "^2.27.5",
|
||||
"eslint-plugin-jest": "^27.2.1",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"eslint-plugin-react": "^7.32.2",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-storybook": "^9.1.5",
|
||||
"@eslint/js": "^9.26.0",
|
||||
"eslint": "^9.26.0",
|
||||
"eslint-config-prettier": "^8.10.2",
|
||||
"eslint-import-resolver-webpack": "^0.13.10",
|
||||
"eslint-plugin-import-x": "^4.15.0",
|
||||
"eslint-plugin-jest": "^28.14.0",
|
||||
"eslint-plugin-prettier": "^4.2.5",
|
||||
"eslint-plugin-react": "^7.37.5",
|
||||
"eslint-plugin-react-hooks": "^5.2.0",
|
||||
"eslint-plugin-storybook": "^0.12.0",
|
||||
"globals": "^15.15.0",
|
||||
"html-loader": "^4.2.0",
|
||||
"html-webpack-plugin": "^5.5.0",
|
||||
"jest": "^29.4.2",
|
||||
"madge": "^8.0.0",
|
||||
"mini-css-extract-plugin": "^2.9.4",
|
||||
"path": "^0.12.7",
|
||||
"postcss": "^8.4.35",
|
||||
|
|
@ -216,6 +220,7 @@
|
|||
"style-loader": "^3.3.1",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"terser-webpack-plugin": "^5.3.6",
|
||||
"typescript": "^5.9.3",
|
||||
"webpack": "^5.75.0",
|
||||
"webpack-bundle-analyzer": "^4.10.2",
|
||||
"webpack-cli": "^5.0.1",
|
||||
|
|
@ -266,7 +271,9 @@
|
|||
"esbuild": "0.25.9",
|
||||
"on-headers": "1.1.0",
|
||||
"tar-fs": "^3.1.0",
|
||||
"brace-expansion": ">=2.0.2"
|
||||
"minimatch@3": {
|
||||
"brace-expansion": "^1.1.11"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"start": "webpack serve --hot --port 8082 --host 0.0.0.0",
|
||||
|
|
@ -276,22 +283,19 @@
|
|||
"analyze:dev": "ANALYZE=true webpack --mode=development",
|
||||
"analyze:stats": "webpack --mode=production --json > bundle-stats.json && webpack-bundle-analyzer bundle-stats.json",
|
||||
"build:analyze": "ANALYZE=true NODE_ENV=production webpack --mode=production",
|
||||
"lint": "eslint . '**/*.{js,jsx}'",
|
||||
"format": "eslint . --fix '**/*.{js,jsx}'",
|
||||
"lint": "eslint 'src/**/*.{js,jsx,ts,tsx}'",
|
||||
"lint-quiet": "eslint --quiet 'src/**/*.{js,jsx,ts,tsx}'",
|
||||
"format": "eslint --fix 'src/**/*.{js,jsx,ts,tsx}'",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"test": "jest",
|
||||
"storybook": "storybook dev -p 6006",
|
||||
"build-storybook": "npx storybook build",
|
||||
"check:circular": "bash scripts/check-circular-deps.sh",
|
||||
"check:bundle": "node scripts/check-bundle-size.js",
|
||||
"check:all": "npm run check:circular && npm run check:bundle"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": "react-app"
|
||||
"build-storybook": "npx storybook build"
|
||||
},
|
||||
"jest": {
|
||||
"transform": {
|
||||
"^.+\\.js?$": "babel-jest",
|
||||
"^.+\\.jsx?$": "babel-jest",
|
||||
"^.+\\.tsx?$": "babel-jest",
|
||||
"^.+\\.svg$": "<rootDir>/__mocks__/svg.js"
|
||||
},
|
||||
"transformIgnorePatterns": [
|
||||
|
|
@ -306,6 +310,8 @@
|
|||
"src"
|
||||
],
|
||||
"moduleFileExtensions": [
|
||||
"ts",
|
||||
"tsx",
|
||||
"js",
|
||||
"json",
|
||||
"jsx"
|
||||
|
|
|
|||
|
|
@ -1,37 +0,0 @@
|
|||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const distPath = path.join(__dirname, '../build');
|
||||
|
||||
if (!fs.existsSync(distPath)) {
|
||||
console.log('⚠️ No build folder found, skipping bundle check');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const files = fs.readdirSync(distPath).filter(f => f.endsWith('.js'));
|
||||
const VIEWER_MAX = 1.5 * 1024 * 1024; // 1.5 MB
|
||||
|
||||
let failed = false;
|
||||
|
||||
console.log('\n📦 Bundle Size Report:\n');
|
||||
|
||||
files.forEach(file => {
|
||||
const size = fs.statSync(path.join(distPath, file)).size;
|
||||
const sizeMB = (size / 1024 / 1024).toFixed(2);
|
||||
|
||||
if (file.includes('viewer') && size > VIEWER_MAX) {
|
||||
console.error(`❌ ${file}: ${sizeMB}MB (exceeds 1.5MB limit)`);
|
||||
failed = true;
|
||||
} else if (file.includes('viewer')) {
|
||||
console.log(`✅ ${file}: ${sizeMB}MB (viewer bundle)`);
|
||||
} else {
|
||||
console.log(`ℹ️ ${file}: ${sizeMB}MB`);
|
||||
}
|
||||
});
|
||||
|
||||
if (failed) {
|
||||
console.log('\n❌ Bundle size check failed!\n');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log('\n✅ All bundles within size limits\n');
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
#!/bin/bash
|
||||
echo "🔍 Checking for circular dependencies..."
|
||||
|
||||
# Run madge to check for circular dependencies
|
||||
npx madge --circular --extensions js,jsx src/
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "❌ Circular dependencies found!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ No circular dependencies found"
|
||||
exit 0
|
||||
|
|
@ -118,24 +118,24 @@ export const ConfigHandle = ({
|
|||
const isHiddenOrModalOpen = visibility === false || (componentType === 'Modal' && isModalOpen);
|
||||
const getConfigHandleButtonStyle = isHiddenOrModalOpen
|
||||
? {
|
||||
background: 'var(--interactive-selected)',
|
||||
color: 'var(--text-default)',
|
||||
padding: '2px 6px',
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: '6px',
|
||||
height: '24px',
|
||||
}
|
||||
background: 'var(--interactive-selected)',
|
||||
color: 'var(--text-default)',
|
||||
padding: '2px 6px',
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: '6px',
|
||||
height: '24px',
|
||||
}
|
||||
: {
|
||||
color: 'var(--text-on-solid)',
|
||||
padding: '2px 6px',
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: '6px',
|
||||
height: '24px',
|
||||
};
|
||||
color: 'var(--text-on-solid)',
|
||||
padding: '2px 6px',
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: '6px',
|
||||
height: '24px',
|
||||
};
|
||||
if (isDynamicHeightEnabled && !isHiddenOrModalOpen) {
|
||||
getConfigHandleButtonStyle.background = '#9747FF';
|
||||
}
|
||||
|
|
@ -195,7 +195,6 @@ export const ConfigHandle = ({
|
|||
return null;
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`config-handle ${customClassName}`}
|
||||
|
|
@ -205,8 +204,8 @@ export const ConfigHandle = ({
|
|||
componentType === 'Modal' && isModalOpen
|
||||
? '0px'
|
||||
: position === 'top'
|
||||
? '-26px'
|
||||
: `${height - (CONFIG_HANDLE_HEIGHT + BUFFER_HEIGHT)}px`,
|
||||
? '-26px'
|
||||
: `${height - (CONFIG_HANDLE_HEIGHT + BUFFER_HEIGHT)}px`,
|
||||
visibility: _showHandle || visibility === false ? 'visible' : 'hidden',
|
||||
left: '-1px',
|
||||
display: 'flex',
|
||||
|
|
@ -288,24 +287,21 @@ export const ConfigHandle = ({
|
|||
<PencilRuler size={14} color="var(--icon-strong)" />
|
||||
</ConfigHandleButton>
|
||||
|
||||
{
|
||||
licenseValid && isRestricted && (
|
||||
<ConfigHandleButton
|
||||
customStyles={iconOnlyButtonStyle}
|
||||
message={getTooltip()}
|
||||
show={licenseValid && isRestricted && !draggingComponentId}
|
||||
dataCy={`${componentName.toLowerCase()}-permissions-button`}
|
||||
>
|
||||
<Lock size={14} color="var(--icon-strong)" />
|
||||
</ConfigHandleButton>
|
||||
)
|
||||
}
|
||||
{
|
||||
!isMultipleComponentsSelected && !shouldFreeze && (
|
||||
<Suspense fallback={null}>
|
||||
<MentionComponentInChat componentName={componentName} />
|
||||
</Suspense >
|
||||
)}
|
||||
{licenseValid && isRestricted && (
|
||||
<ConfigHandleButton
|
||||
customStyles={iconOnlyButtonStyle}
|
||||
message={getTooltip()}
|
||||
show={licenseValid && isRestricted && !draggingComponentId}
|
||||
dataCy={`${componentName.toLowerCase()}-permissions-button`}
|
||||
>
|
||||
<Lock size={14} color="var(--icon-strong)" />
|
||||
</ConfigHandleButton>
|
||||
)}
|
||||
{!isMultipleComponentsSelected && !shouldFreeze && (
|
||||
<Suspense fallback={null}>
|
||||
<MentionComponentInChat componentName={componentName} />
|
||||
</Suspense>
|
||||
)}
|
||||
<ConfigHandleButton
|
||||
customStyles={iconOnlyButtonStyle}
|
||||
onClick={() => {
|
||||
|
|
@ -319,17 +315,15 @@ export const ConfigHandle = ({
|
|||
<Trash size={14} color="var(--icon-strong)" />
|
||||
</ConfigHandleButton>
|
||||
{/* Tooltip for invalid license on ModuleViewer */}
|
||||
{
|
||||
(componentType === 'ModuleViewer' || componentType === 'ModuleContainer') && !isModulesEnabled && (
|
||||
<Tooltip
|
||||
delay={{ show: 500, hide: 50 }}
|
||||
id={`invalid-license-modules-${componentName?.toLowerCase()}`}
|
||||
className="tooltip"
|
||||
isOpen={_showHandle && (componentType === 'ModuleViewer' || componentType === 'ModuleContainer')}
|
||||
style={{ textAlign: 'center' }}
|
||||
/>
|
||||
)
|
||||
}
|
||||
</div >
|
||||
{(componentType === 'ModuleViewer' || componentType === 'ModuleContainer') && !isModulesEnabled && (
|
||||
<Tooltip
|
||||
delay={{ show: 500, hide: 50 }}
|
||||
id={`invalid-license-modules-${componentName?.toLowerCase()}`}
|
||||
className="tooltip"
|
||||
isOpen={_showHandle && (componentType === 'ModuleViewer' || componentType === 'ModuleContainer')}
|
||||
style={{ textAlign: 'center' }}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -52,8 +52,12 @@ const NoComponentCanvasContainer = () => {
|
|||
<div className="box-icon" data-cy="create-a-query-icon">
|
||||
<SolidIcon name="datasource" fill="#3E63DD" width="25" />
|
||||
</div>
|
||||
<div className={`title-text`} data-cy="create-a-query-label">Create a Query</div>
|
||||
<div className="title-desc" data-cy="create-a-query-description">{queryBoxText}</div>
|
||||
<div className={`title-text`} data-cy="create-a-query-label">
|
||||
Create a Query
|
||||
</div>
|
||||
<div className="title-desc" data-cy="create-a-query-description">
|
||||
{queryBoxText}
|
||||
</div>
|
||||
{!!sampleDataSource && !shouldFreeze && (
|
||||
<div className="box-link" data-cy="connect-to-sample-data-source-link">
|
||||
<div className="child">
|
||||
|
|
@ -73,7 +77,9 @@ const NoComponentCanvasContainer = () => {
|
|||
<div className="box-icon" data-cy="share-your-application-icon">
|
||||
<BulkIcon name="invitecollab" width="25" viewBox="0 0 28 28" />
|
||||
</div>
|
||||
<div className={`title-text `} data-cy="share-your-application-label">Share your application!</div>
|
||||
<div className={`title-text `} data-cy="share-your-application-label">
|
||||
Share your application!
|
||||
</div>
|
||||
<div className="title-desc" data-cy="share-your-application-description">
|
||||
Invite users to collaborate in real-time with multiplayer editing and comments for seamless development.
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -82,14 +82,9 @@ export const TrackedSuspense = ({ fallback = null, children }) => {
|
|||
return <Suspense fallback={fallback}>{children}</Suspense>;
|
||||
}
|
||||
|
||||
return (
|
||||
<Suspense fallback={<SuspenseFallbackTracker fallback={fallback} />}>
|
||||
{children}
|
||||
</Suspense>
|
||||
);
|
||||
return <Suspense fallback={<SuspenseFallbackTracker fallback={fallback} />}>{children}</Suspense>;
|
||||
};
|
||||
|
||||
|
||||
// Loading overlay shown while lazy components are resolving
|
||||
export const SuspenseLoadingOverlay = ({ darkMode }) => {
|
||||
const isLoading = useSuspenseLoading();
|
||||
|
|
@ -98,13 +93,15 @@ export const SuspenseLoadingOverlay = ({ darkMode }) => {
|
|||
|
||||
return (
|
||||
<div
|
||||
className={cx('suspense-loading-overlay tw-absolute tw-inset-0 tw-overflow-hidden', { 'theme-dark dark-theme': darkMode })}
|
||||
className={cx('suspense-loading-overlay tw-absolute tw-inset-0 tw-overflow-hidden', {
|
||||
'theme-dark dark-theme': darkMode,
|
||||
})}
|
||||
>
|
||||
<div className='tw-sticky tw-top-0 tw-h-screen tw-flex tw-items-center tw-justify-center'>
|
||||
<div className="tw-sticky tw-top-0 tw-h-screen tw-flex tw-items-center tw-justify-center">
|
||||
<div className="suspense-loader-wrapper">
|
||||
<TJLoader />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import React from 'react';
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import CodeMirror from '@uiw/react-codemirror';
|
||||
// import 'codemirror/theme/duotone-light.css';
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import React, { useEffect } from 'react';
|
|||
import useRouter from '@/_hooks/use-router';
|
||||
import config from 'config';
|
||||
import toast from 'react-hot-toast';
|
||||
import './embed-loader.scss'
|
||||
import './embed-loader.scss';
|
||||
import Loader from '@/ToolJetUI/Loader/Loader';
|
||||
|
||||
// In-memory PAT token store
|
||||
|
|
@ -78,13 +78,11 @@ export default function EmbedAppRedirect() {
|
|||
}, [appId]);
|
||||
|
||||
return (
|
||||
<div className="embed-loader">
|
||||
<div className="embed-loader__content">
|
||||
<Loader width={30} absolute={false} />
|
||||
<div className="embed-loader__text">
|
||||
Loading embedded app
|
||||
<div className="embed-loader">
|
||||
<div className="embed-loader__content">
|
||||
<Loader width={30} absolute={false} />
|
||||
<div className="embed-loader__text">Loading embedded app</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
export { AppVersionsManager } from './AppVersionsManager';
|
||||
export { AppVersionsManager } from './AppVersionsManager';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useEffect, useState ,useRef} from 'react';
|
||||
import React, { useEffect, useState, useRef } from 'react';
|
||||
import AlertDialog from '@/_ui/AlertDialog';
|
||||
import { Alert } from '@/_ui/Alert';
|
||||
import { toast } from 'react-hot-toast';
|
||||
|
|
@ -17,7 +17,7 @@ const CreateDraftVersionModal = ({
|
|||
canCommit,
|
||||
orgGit,
|
||||
fetchingOrgGit,
|
||||
handleCommitOnVersionCreation = () => { },
|
||||
handleCommitOnVersionCreation = () => {},
|
||||
}) => {
|
||||
const { moduleId } = useModuleContext();
|
||||
const [isCreatingVersion, setIsCreatingVersion] = useState(false);
|
||||
|
|
@ -49,10 +49,7 @@ const CreateDraftVersionModal = ({
|
|||
// Filter out draft versions - show all saved versions (PUBLISHED + any released)
|
||||
const savedVersions = developmentVersions.filter((version) => version.status !== 'DRAFT');
|
||||
useEffect(() => {
|
||||
const gitSyncEnabled =
|
||||
orgGit?.git_ssh?.is_enabled ||
|
||||
orgGit?.git_https?.is_enabled ||
|
||||
orgGit?.git_lab?.is_enabled;
|
||||
const gitSyncEnabled = orgGit?.git_ssh?.is_enabled || orgGit?.git_https?.is_enabled || orgGit?.git_lab?.is_enabled;
|
||||
setIsGitSyncEnabled(gitSyncEnabled);
|
||||
}, [orgGit]);
|
||||
|
||||
|
|
@ -112,8 +109,8 @@ const CreateDraftVersionModal = ({
|
|||
savedVersions.length > 0
|
||||
? savedVersions.map((version) => ({ label: version.name, value: version.id }))
|
||||
: selectedVersion && selectedVersion.status !== 'DRAFT'
|
||||
? [{ label: selectedVersion.name, value: selectedVersion.id }]
|
||||
: [];
|
||||
? [{ label: selectedVersion.name, value: selectedVersion.id }]
|
||||
: [];
|
||||
|
||||
const createVersion = () => {
|
||||
if (versionName.trim().length > 25) {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ const CreateVersionModal = ({
|
|||
canCommit,
|
||||
orgGit,
|
||||
fetchingOrgGit,
|
||||
handleCommitOnVersionCreation = () => { },
|
||||
handleCommitOnVersionCreation = () => {},
|
||||
versionId,
|
||||
onVersionCreated,
|
||||
}) => {
|
||||
|
|
@ -229,8 +229,7 @@ const CreateVersionModal = ({
|
|||
toast.error('Version name already exists.');
|
||||
} else if (error?.error) {
|
||||
toast.error(error?.error);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
toast.error('Error while creating version. Please try again.');
|
||||
}
|
||||
} finally {
|
||||
|
|
|
|||
|
|
@ -1,2 +1,3 @@
|
|||
// eslint-disable-next-line import/no-unresolved
|
||||
import EnvironmentManager from './EnvironmentsManager';
|
||||
export default EnvironmentManager;
|
||||
|
|
|
|||
|
|
@ -4,14 +4,13 @@ import { Tooltip } from 'react-tooltip';
|
|||
import { shallow } from 'zustand/shallow';
|
||||
import SolidIcon from '@/_ui/Icon/SolidIcons';
|
||||
import useStore from '@/AppBuilder/_stores/store';
|
||||
import { Button } from '@/components/ui/Button/Button';
|
||||
import { Button, Button as ButtonComponent } from '@/components/ui/Button/Button';
|
||||
import { Monitor, Smartphone, Play } from 'lucide-react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { useAppPreviewLink } from '@/_hooks/useAppPreviewLink';
|
||||
import { ToggleLayoutButtons } from './ToggleLayoutButtons';
|
||||
import { Button as ButtonComponent } from '@/components/ui/Button/Button';
|
||||
|
||||
const HeaderActions = function HeaderActions ({ darkMode, showFullWidth, showPreviewBtn = true }) {
|
||||
const HeaderActions = function HeaderActions({ darkMode, showFullWidth, showPreviewBtn = true }) {
|
||||
const {
|
||||
currentLayout,
|
||||
canUndo,
|
||||
|
|
@ -60,8 +59,6 @@ const HeaderActions = function HeaderActions ({ darkMode, showFullWidth, showPre
|
|||
/>
|
||||
)}
|
||||
{showPreviewBtn && (
|
||||
|
||||
|
||||
<Link
|
||||
title="Preview"
|
||||
to={appPreviewLink}
|
||||
|
|
@ -77,9 +74,8 @@ const HeaderActions = function HeaderActions ({ darkMode, showFullWidth, showPre
|
|||
variant="outline"
|
||||
leadingIcon="play"
|
||||
data-cy="editor-preview-button"
|
||||
style={{ padding: "7px 12px" }}
|
||||
style={{ padding: '7px 12px' }}
|
||||
>
|
||||
|
||||
Preview
|
||||
</ButtonComponent>
|
||||
</Link>
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import { retrieveWhiteLabelText } from '@white-label/whiteLabelling';
|
|||
import useStore from '@/AppBuilder/_stores/store';
|
||||
|
||||
class ManageAppUsersComponent extends React.Component {
|
||||
constructor (props) {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.isUserAdmin = authenticationService.currentSessionValue?.admin;
|
||||
this.whiteLabelText = retrieveWhiteLabelText();
|
||||
|
|
@ -50,7 +50,7 @@ class ManageAppUsersComponent extends React.Component {
|
|||
});
|
||||
};
|
||||
|
||||
componentDidMount () {
|
||||
componentDidMount() {
|
||||
const appId = this.props.appId;
|
||||
this.setState({ appId });
|
||||
}
|
||||
|
|
@ -171,7 +171,7 @@ class ManageAppUsersComponent extends React.Component {
|
|||
}
|
||||
};
|
||||
|
||||
render () {
|
||||
render() {
|
||||
const { appId, isSlugVerificationInProgress, newSlug, isSlugUpdated } = this.state;
|
||||
|
||||
const appLink = `${getHostURL()}/applications/`;
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import { Button } from '@/components/ui/Button/Button';
|
|||
import { Share2 } from 'lucide-react';
|
||||
|
||||
class ManageAppUsersComponent extends React.Component {
|
||||
constructor (props) {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.isUserAdmin = authenticationService.currentSessionValue?.admin;
|
||||
this.whiteLabelText = retrieveWhiteLabelText();
|
||||
|
|
@ -54,7 +54,7 @@ class ManageAppUsersComponent extends React.Component {
|
|||
});
|
||||
};
|
||||
|
||||
componentDidMount () {
|
||||
componentDidMount() {
|
||||
const appId = this.props.appId;
|
||||
this.setState({ appId });
|
||||
}
|
||||
|
|
@ -180,7 +180,7 @@ class ManageAppUsersComponent extends React.Component {
|
|||
handleMouseLeave = () => {
|
||||
this.setState({ isHovered: false });
|
||||
};
|
||||
render () {
|
||||
render() {
|
||||
const { appId, isSlugVerificationInProgress, newSlug, isSlugUpdated } = this.state;
|
||||
|
||||
const appLink = `${getHostURL()}/applications/`;
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ const VersionDropdownItem = ({
|
|||
// This ensures we can find the parent even if it's in a different environment
|
||||
const parentVersion = version.parentVersionId
|
||||
? versions.find((v) => v.id === version.parentVersionId) ||
|
||||
developmentVersions.find((v) => v.id === version.parentVersionId)
|
||||
developmentVersions.find((v) => v.id === version.parentVersionId)
|
||||
: null;
|
||||
const createdFromVersionName = parentVersion?.name || version.createdFromVersion;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,10 +4,7 @@ import useStore from '@/AppBuilder/_stores/store';
|
|||
import { shallow } from 'zustand/shallow';
|
||||
|
||||
function Debugger({ onClose, darkMode }) {
|
||||
const [logs, clearLogs] = useStore(
|
||||
(state) => [state.debugger.logs, state.debugger.clear],
|
||||
shallow
|
||||
);
|
||||
const [logs, clearLogs] = useStore((state) => [state.debugger.logs, state.debugger.clear], shallow);
|
||||
|
||||
const currentPageId = useStore((state) => state.modules.canvas.currentPageId);
|
||||
|
||||
|
|
|
|||
|
|
@ -46,16 +46,8 @@ export const SidebarDebuggerHeader = ({ darkMode, onClear, onClose, activeTab, o
|
|||
</div>
|
||||
</div>
|
||||
<div className="debugger-tabs-container" role="tablist">
|
||||
<DebuggerTab
|
||||
label="All logs"
|
||||
isActive={activeTab === 'allLog'}
|
||||
onClick={() => onTabChange('allLog')}
|
||||
/>
|
||||
<DebuggerTab
|
||||
label="Errors"
|
||||
isActive={activeTab === 'errors'}
|
||||
onClick={() => onTabChange('errors')}
|
||||
/>
|
||||
<DebuggerTab label="All logs" isActive={activeTab === 'allLog'} onClick={() => onTabChange('allLog')} />
|
||||
<DebuggerTab label="Errors" isActive={activeTab === 'errors'} onClick={() => onTabChange('errors')} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -31,12 +31,8 @@ const DebuggerTabContent = ({ logs, darkMode, tabName }) => {
|
|||
const SidebarDebuggerTabs = ({ darkMode, errors, allLog, activeTab }) => {
|
||||
return (
|
||||
<div className="">
|
||||
{activeTab === 'allLog' && (
|
||||
<DebuggerTabContent logs={allLog} darkMode={darkMode} tabName="allLogs" />
|
||||
)}
|
||||
{activeTab === 'errors' && (
|
||||
<DebuggerTabContent logs={errors} darkMode={darkMode} tabName="errors" />
|
||||
)}
|
||||
{activeTab === 'allLog' && <DebuggerTabContent logs={allLog} darkMode={darkMode} tabName="allLogs" />}
|
||||
{activeTab === 'errors' && <DebuggerTabContent logs={errors} darkMode={darkMode} tabName="errors" />}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,108 +0,0 @@
|
|||
import { useState, useEffect } from 'react';
|
||||
import { useCurrentStateStore } from '@/_stores/currentStateStore';
|
||||
import { shallow } from 'zustand/shallow';
|
||||
import { debuggerActions } from '@/_helpers/appUtils';
|
||||
import { flow, cloneDeepWith } from 'lodash';
|
||||
import moment from 'moment';
|
||||
import { reservedKeywordReplacer } from '@/_lib/reserved-keyword-replacer';
|
||||
|
||||
const useDebugger = ({ currentPageId, isDebuggerOpen }) => {
|
||||
const [errorLogs, setErrorLogs] = useState([]);
|
||||
const [errorHistory, setErrorHistory] = useState({ appLevel: [], pageLevel: [] });
|
||||
const [unReadErrorCount, setUnReadErrorCount] = useState({ read: 0, unread: 0 });
|
||||
const [allLog, setAllLog] = useState([]);
|
||||
|
||||
const { errors, succededQuery } = useCurrentStateStore(
|
||||
(state) => ({
|
||||
errors: state.errors,
|
||||
succededQuery: state.succededQuery,
|
||||
}),
|
||||
shallow
|
||||
);
|
||||
|
||||
const clearErrorLogs = () => {
|
||||
setUnReadErrorCount({ read: 0, unread: 0 });
|
||||
setErrorLogs([]);
|
||||
setAllLog([]);
|
||||
setErrorHistory({ appLevel: [], pageLevel: [] });
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (currentPageId) {
|
||||
const olderPageErrorFromHistory = errorHistory.pageLevel[currentPageId] ?? [];
|
||||
const olderAppErrorFromHistory = errorHistory.appLevel ?? [];
|
||||
setErrorLogs(() => [...olderPageErrorFromHistory, ...olderAppErrorFromHistory]);
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [currentPageId]);
|
||||
|
||||
useEffect(() => {
|
||||
const newError = flow([
|
||||
Object.entries,
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
(arr) => arr.filter(([key, value]) => value.data?.status),
|
||||
Object.fromEntries,
|
||||
])(errors);
|
||||
const newErrorLogs = debuggerActions.generateErrorLogs(newError);
|
||||
const newPageLevelErrorLogs = newErrorLogs.filter((error) => error.strace === 'page_level');
|
||||
const newAppLevelErrorLogs = newErrorLogs.filter((error) => error.strace === 'app_level');
|
||||
if (newErrorLogs) {
|
||||
setErrorLogs((prevErrors) => {
|
||||
const copy = cloneDeepWith(prevErrors, (val, key) => reservedKeywordReplacer(key, val));
|
||||
return [...newAppLevelErrorLogs, ...newPageLevelErrorLogs, ...copy];
|
||||
});
|
||||
|
||||
setAllLog((prevLog) => [...newErrorLogs, ...prevLog]);
|
||||
|
||||
setErrorHistory((prevErrors) => {
|
||||
const copy = cloneDeepWith(prevErrors, (val, key) => reservedKeywordReplacer(key, val));
|
||||
return {
|
||||
appLevel: [...newAppLevelErrorLogs, ...copy.appLevel],
|
||||
pageLevel: {
|
||||
[currentPageId]: [...newPageLevelErrorLogs, ...(copy.pageLevel[currentPageId] ?? [])],
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
debuggerActions.flush();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [JSON.stringify({ errors }, reservedKeywordReplacer)]);
|
||||
|
||||
useEffect(() => {
|
||||
const successQueryLogs = debuggerActions.generateQuerySuccessLogs(succededQuery);
|
||||
if (successQueryLogs?.length) {
|
||||
setAllLog((prevLogs) => {
|
||||
const temp = [...successQueryLogs, ...prevLogs];
|
||||
const sortedDatesDesc = temp.sort((a, b) => moment(b.timestamp).diff(moment(a.timestamp)));
|
||||
return sortedDatesDesc;
|
||||
});
|
||||
debuggerActions.flushAllLog();
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [JSON.stringify({ succededQuery })]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isDebuggerOpen) {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
setUnReadErrorCount((prev) => ({ read: errorLogs.length, unread: 0 }));
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [isDebuggerOpen]);
|
||||
|
||||
useEffect(() => {
|
||||
const unReadErrors = errorLogs.length - unReadErrorCount.read;
|
||||
setUnReadErrorCount((prev) => {
|
||||
return { ...prev, unread: unReadErrors };
|
||||
});
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [errorLogs.length]);
|
||||
|
||||
return {
|
||||
errorLogs,
|
||||
clearErrorLogs,
|
||||
unReadErrorCount,
|
||||
allLog,
|
||||
};
|
||||
};
|
||||
|
||||
export default useDebugger;
|
||||
|
|
@ -36,8 +36,9 @@ export const SidebarItem = forwardRef(
|
|||
const content = (
|
||||
<Button
|
||||
{...rest}
|
||||
className={`${className} ${selectedSidebarItem === icon && selectedSidebarItem !== 'comments' && 'sidebar-item--active'
|
||||
} ${icon}-icon`}
|
||||
className={`${className} ${
|
||||
selectedSidebarItem === icon && selectedSidebarItem !== 'comments' && 'sidebar-item--active'
|
||||
} ${icon}-icon`}
|
||||
onClick={onClick && onClick}
|
||||
ref={ref}
|
||||
type="button"
|
||||
|
|
@ -77,7 +78,7 @@ export const SidebarItem = forwardRef(
|
|||
}
|
||||
);
|
||||
|
||||
function CommentBadge () {
|
||||
function CommentBadge() {
|
||||
return (
|
||||
<svg
|
||||
className="comment-badge"
|
||||
|
|
@ -92,7 +93,7 @@ function CommentBadge () {
|
|||
);
|
||||
}
|
||||
|
||||
function NotificationBadge ({ count }) {
|
||||
function NotificationBadge({ count }) {
|
||||
const fontSize = count > 999 ? '7.5px' : '8.5px';
|
||||
return (
|
||||
<>
|
||||
|
|
|
|||
|
|
@ -5,4 +5,4 @@ const SupportButton = () => {
|
|||
return null;
|
||||
};
|
||||
|
||||
export default withEditionSpecificComponent(SupportButton, 'Appbuilder');
|
||||
export default withEditionSpecificComponent(SupportButton, 'Appbuilder');
|
||||
|
|
|
|||
|
|
@ -103,7 +103,6 @@ function DataSourcePicker({ darkMode }) {
|
|||
</label>
|
||||
<div className="query-datasource-card-container d-flex justify-content-between mb-3 mt-2">
|
||||
{updatedStaticDataSources.map((source) => {
|
||||
|
||||
return (
|
||||
<ButtonSolid
|
||||
key={`${source.id}-${source.kind}`}
|
||||
|
|
|
|||
|
|
@ -154,31 +154,31 @@ function DataSourceSelect({
|
|||
const groupedSampleDataSources =
|
||||
sampleDataSources && sampleDataSources.length > 0
|
||||
? Object.entries(groupBy(sampleDataSources, 'kind')).map(([kind, sources]) => ({
|
||||
label: (
|
||||
<div>
|
||||
<DataSourceIcon source={sources[0]} height={16} />
|
||||
<span className="ms-1 small">{dataSourcesKinds.find((dsk) => dsk.kind === kind)?.name || kind}</span>
|
||||
</div>
|
||||
),
|
||||
options: sources.map((source) => ({
|
||||
label: (
|
||||
<div
|
||||
key={source.id}
|
||||
className="py-2 px-2 rounded option-nested-datasource-selector small text-truncate"
|
||||
style={{ fontSize: '13px' }}
|
||||
data-tooltip-id="tooltip-for-add-query-dd-option"
|
||||
data-tooltip-content={decodeEntities(source.name)}
|
||||
data-cy={`ds-${source.name.toLowerCase()}`}
|
||||
>
|
||||
{decodeEntities(source.name)}
|
||||
<Tooltip id="tooltip-for-add-query-dd-option" className="tooltip query-manager-ds-select-tooltip" />
|
||||
<div>
|
||||
<DataSourceIcon source={sources[0]} height={16} />
|
||||
<span className="ms-1 small">{dataSourcesKinds.find((dsk) => dsk.kind === kind)?.name || kind}</span>
|
||||
</div>
|
||||
),
|
||||
value: source.id,
|
||||
isNested: true,
|
||||
source,
|
||||
})),
|
||||
}))
|
||||
options: sources.map((source) => ({
|
||||
label: (
|
||||
<div
|
||||
key={source.id}
|
||||
className="py-2 px-2 rounded option-nested-datasource-selector small text-truncate"
|
||||
style={{ fontSize: '13px' }}
|
||||
data-tooltip-id="tooltip-for-add-query-dd-option"
|
||||
data-tooltip-content={decodeEntities(source.name)}
|
||||
data-cy={`ds-${source.name.toLowerCase()}`}
|
||||
>
|
||||
{decodeEntities(source.name)}
|
||||
<Tooltip id="tooltip-for-add-query-dd-option" className="tooltip query-manager-ds-select-tooltip" />
|
||||
</div>
|
||||
),
|
||||
value: source.id,
|
||||
isNested: true,
|
||||
source,
|
||||
})),
|
||||
}))
|
||||
: [];
|
||||
|
||||
const dataSourcesAvailable = [
|
||||
|
|
@ -206,18 +206,18 @@ function DataSourceSelect({
|
|||
// Sample data sources group header
|
||||
...(groupedSampleDataSources.length > 0
|
||||
? [
|
||||
{
|
||||
label: (
|
||||
<div>
|
||||
<span className="color-slate9" style={{ fontWeight: 500 }}>
|
||||
Sample data sources
|
||||
</span>
|
||||
</div>
|
||||
),
|
||||
isDisabled: true,
|
||||
},
|
||||
...groupedSampleDataSources,
|
||||
]
|
||||
{
|
||||
label: (
|
||||
<div>
|
||||
<span className="color-slate9" style={{ fontWeight: 500 }}>
|
||||
Sample data sources
|
||||
</span>
|
||||
</div>
|
||||
),
|
||||
isDisabled: true,
|
||||
},
|
||||
...groupedSampleDataSources,
|
||||
]
|
||||
: []),
|
||||
];
|
||||
|
||||
|
|
@ -240,8 +240,8 @@ function DataSourceSelect({
|
|||
source?.id !== 'if' && source?.id !== 'agent' && workflowDataSources
|
||||
? onNewNode(source.kind, source.id, source.plugin_id, source)
|
||||
: source && (source?.id === 'if' || source?.id === 'response' || source?.id === 'agent')
|
||||
? onNewNode(source.id)
|
||||
: handleChangeDataSource(source)
|
||||
? onNewNode(source.id)
|
||||
: handleChangeDataSource(source)
|
||||
}
|
||||
classNames={{
|
||||
menu: () => 'tj-scrollbar',
|
||||
|
|
@ -311,8 +311,8 @@ function DataSourceSelect({
|
|||
},
|
||||
...(isFocused &&
|
||||
isNested && {
|
||||
'.option-nested-datasource-selector': { backgroundColor: 'var(--slate4)' },
|
||||
}),
|
||||
'.option-nested-datasource-selector': { backgroundColor: 'var(--slate4)' },
|
||||
}),
|
||||
}),
|
||||
container: (styles) => ({
|
||||
...styles,
|
||||
|
|
|
|||
|
|
@ -22,14 +22,14 @@ const ParameterList = ({
|
|||
let totalWidth = 0;
|
||||
const formattedParams = containerWidth
|
||||
? parameters.map((param, index) => {
|
||||
const boxWidth = Math.min((param?.name || '').length * 6 + 63 + 8, 178);
|
||||
totalWidth = Math.min(totalWidth + boxWidth, containerWidth);
|
||||
return {
|
||||
...param,
|
||||
isVisible: totalWidth < containerWidth - 178,
|
||||
index,
|
||||
};
|
||||
})
|
||||
const boxWidth = Math.min((param?.name || '').length * 6 + 63 + 8, 178);
|
||||
totalWidth = Math.min(totalWidth + boxWidth, containerWidth);
|
||||
return {
|
||||
...param,
|
||||
isVisible: totalWidth < containerWidth - 178,
|
||||
index,
|
||||
};
|
||||
})
|
||||
: [];
|
||||
setFormattedParameters(formattedParams);
|
||||
if (formattedParams.every((param) => param.isVisible)) {
|
||||
|
|
|
|||
|
|
@ -203,7 +203,11 @@ const Preview = ({ darkMode, calculatePreviewHeight }) => {
|
|||
<Tab.Container activeKey={key} onSelect={(k) => setKey(k)} defaultActiveKey="raw">
|
||||
<div className="position-relative h-100">
|
||||
{previewLoading && (
|
||||
<center style={{ display: 'grid', placeItems: 'center' }} className="position-absolute w-100 h-100" data-cy="preview-loading-container">
|
||||
<center
|
||||
style={{ display: 'grid', placeItems: 'center' }}
|
||||
className="position-absolute w-100 h-100"
|
||||
data-cy="preview-loading-container"
|
||||
>
|
||||
<div className="spinner-border text-azure" role="status" data-cy="preview-loading-spinner"></div>
|
||||
</center>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -249,7 +249,9 @@ export const BaseQueryManagerBody = ({ darkMode, activeTab, renderCopilot = () =
|
|||
})}
|
||||
data-cy="query-events-section"
|
||||
>
|
||||
<div className={`form-label`} data-cy="query-manager-events-label">{t('editor.queryManager.eventsHandler', 'Events')}</div>
|
||||
<div className={`form-label`} data-cy="query-manager-events-label">
|
||||
{t('editor.queryManager.eventsHandler', 'Events')}
|
||||
</div>
|
||||
<div className="query-manager-events pb-4">
|
||||
<EventManager
|
||||
sourceId={selectedQuery?.id}
|
||||
|
|
@ -266,7 +268,9 @@ export const BaseQueryManagerBody = ({ darkMode, activeTab, renderCopilot = () =
|
|||
const renderTimeout = () => {
|
||||
return (
|
||||
<div className="d-flex" data-cy="query-timeout-section">
|
||||
<div className="form-label mt-2" data-cy="query-manager-timeout-label">{t('editor.queryManager.timeout', 'Timeout ( ms )')}</div>
|
||||
<div className="form-label mt-2" data-cy="query-manager-timeout-label">
|
||||
{t('editor.queryManager.timeout', 'Timeout ( ms )')}
|
||||
</div>
|
||||
<div className="query-manager-query-timeout">
|
||||
<CodeHinter
|
||||
theme={darkMode ? 'monokai' : 'base16-light'}
|
||||
|
|
@ -288,7 +292,9 @@ export const BaseQueryManagerBody = ({ darkMode, activeTab, renderCopilot = () =
|
|||
})}
|
||||
data-cy="query-triggers-section"
|
||||
>
|
||||
<div className="form-label mt-2" data-cy="query-manager-triggers-label">{t('editor.queryManager.settings', 'Triggers')}</div>
|
||||
<div className="form-label mt-2" data-cy="query-manager-triggers-label">
|
||||
{t('editor.queryManager.settings', 'Triggers')}
|
||||
</div>
|
||||
<div className="flex-grow-1">
|
||||
{Object.keys(customToggles).map((toggle, index) => (
|
||||
<CustomToggleFlag
|
||||
|
|
@ -314,7 +320,7 @@ export const BaseQueryManagerBody = ({ darkMode, activeTab, renderCopilot = () =
|
|||
</div>
|
||||
</div>
|
||||
<div className="d-flex">
|
||||
<div className="form-label">{ }</div>
|
||||
<div className="form-label">{}</div>
|
||||
<SuccessNotificationInputs
|
||||
// currentState={currentState}
|
||||
options={options}
|
||||
|
|
@ -339,8 +345,8 @@ export const BaseQueryManagerBody = ({ darkMode, activeTab, renderCopilot = () =
|
|||
const docLink = isSampleDb
|
||||
? 'https://docs.tooljet.com/docs/data-sources/sample-data-sources'
|
||||
: selectedDataSource?.plugin_id && selectedDataSource.plugin_id.trim() !== ''
|
||||
? `https://docs.tooljet.com/docs/marketplace/plugins/marketplace-plugin-${selectedDataSource?.kind}/`
|
||||
: `https://docs.tooljet.com/docs/data-sources/${selectedDataSource?.kind}`;
|
||||
? `https://docs.tooljet.com/docs/marketplace/plugins/marketplace-plugin-${selectedDataSource?.kind}/`
|
||||
: `https://docs.tooljet.com/docs/data-sources/${selectedDataSource?.kind}`;
|
||||
return (
|
||||
<>
|
||||
<div className="" ref={paramListContainerRef}>
|
||||
|
|
@ -362,7 +368,11 @@ export const BaseQueryManagerBody = ({ darkMode, activeTab, renderCopilot = () =
|
|||
>
|
||||
Source
|
||||
</div>
|
||||
<div className="d-flex flex-column align-items-start" style={{ width: '500px' }} data-cy="query-manager-change-data-source">
|
||||
<div
|
||||
className="d-flex flex-column align-items-start"
|
||||
style={{ width: '500px' }}
|
||||
data-cy="query-manager-change-data-source"
|
||||
>
|
||||
<ChangeDataSource
|
||||
dataSources={selectableDataSources}
|
||||
value={selectedDataSource}
|
||||
|
|
@ -406,14 +416,15 @@ export const BaseQueryManagerBody = ({ darkMode, activeTab, renderCopilot = () =
|
|||
const hasPermissions =
|
||||
selectedDataSource?.scope === 'global' && selectedDataSource?.type !== DATA_SOURCE_TYPE.SAMPLE
|
||||
? canUpdateDataSource(selectedQuery?.data_source_id) ||
|
||||
canReadDataSource(selectedQuery?.data_source_id) ||
|
||||
canDeleteDataSource()
|
||||
canReadDataSource(selectedQuery?.data_source_id) ||
|
||||
canDeleteDataSource()
|
||||
: true;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`query-details ${selectedDataSource?.kind === 'tooljetdb' ? 'tooljetdb-query-details' : ''} ${!hasPermissions || isFreezed ? 'disabled' : ''
|
||||
}`}
|
||||
className={`query-details ${selectedDataSource?.kind === 'tooljetdb' ? 'tooljetdb-query-details' : ''} ${
|
||||
!hasPermissions || isFreezed ? 'disabled' : ''
|
||||
}`}
|
||||
style={{
|
||||
height: `calc(100% - ${selectedQuery ? previewHeight + 40 : 0}px)`,
|
||||
overflowY: 'auto',
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import useStore from '@/AppBuilder/_stores/store';
|
|||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { withEditionSpecificComponent } from '@/modules/common/helpers/withEditionSpecificComponent';
|
||||
|
||||
const noop = () => { };
|
||||
const noop = () => {};
|
||||
|
||||
const defaultValue = {
|
||||
javascript: `// write your code here
|
||||
|
|
|
|||
|
|
@ -219,7 +219,7 @@ const HierarchicalDropdown = ({ options, value, onChange, placeholder, disabled,
|
|||
|
||||
{isOpen && (
|
||||
<div className="grpcv2-dropdown__menu">
|
||||
{(isLoading || (options.length === 0 && !debouncedSearchTerm.trim())) ? (
|
||||
{isLoading || (options.length === 0 && !debouncedSearchTerm.trim()) ? (
|
||||
<div className="grpcv2-dropdown__loading">Loading services...</div>
|
||||
) : getFilteredOptions.length === 0 ? (
|
||||
<div className="grpcv2-dropdown__no-results">No results found</div>
|
||||
|
|
@ -552,10 +552,10 @@ const GRPCv2Component = ({ darkMode, selectedDataSource, ...restProps }) => {
|
|||
options?.service && options?.method
|
||||
? `${options.service} → ${options.method}`
|
||||
: isLoadingServices
|
||||
? 'Loading services...'
|
||||
: hierarchicalOptions.length === 0
|
||||
? 'No services found'
|
||||
: 'Select service'
|
||||
? 'Loading services...'
|
||||
: hierarchicalOptions.length === 0
|
||||
? 'No services found'
|
||||
: 'Select service'
|
||||
}
|
||||
disabled={
|
||||
(!options?.service || !options?.method) && (isLoadingServices || hierarchicalOptions.length === 0)
|
||||
|
|
@ -728,8 +728,9 @@ const TabContent = ({
|
|||
/>
|
||||
</div>
|
||||
<button
|
||||
className={`d-flex justify-content-center align-items-center delete-field-option bg-transparent border-0 rounded-0 border-top border-bottom border-end rounded-end qm-delete-btn ${darkMode ? 'delete-field-option-dark' : ''
|
||||
}`}
|
||||
className={`d-flex justify-content-center align-items-center delete-field-option bg-transparent border-0 rounded-0 border-top border-bottom border-end rounded-end qm-delete-btn ${
|
||||
darkMode ? 'delete-field-option-dark' : ''
|
||||
}`}
|
||||
role="button"
|
||||
onClick={() => {
|
||||
removeKeyValuePair(index);
|
||||
|
|
|
|||
|
|
@ -37,11 +37,11 @@ export default function GraphqlKeyValueTabs({ tabs = [], options = {}, optioncha
|
|||
};
|
||||
|
||||
const handleInputChange = (tabKey, rowIndex) => (value) => {
|
||||
const rows = getRows(tabKey);
|
||||
if (rows.length > 0 && rows.length - 1 === rowIndex && value) {
|
||||
addNewKeyValuePair(tabKey);
|
||||
}
|
||||
};
|
||||
const rows = getRows(tabKey);
|
||||
if (rows.length > 0 && rows.length - 1 === rowIndex && value) {
|
||||
addNewKeyValuePair(tabKey);
|
||||
}
|
||||
};
|
||||
|
||||
if (!tabs.length) return null;
|
||||
|
||||
|
|
@ -51,11 +51,7 @@ export default function GraphqlKeyValueTabs({ tabs = [], options = {}, optioncha
|
|||
<div className="keys d-flex justify-content-between query-pane-tabs-header graphql-tabs-header">
|
||||
<ListGroup className="query-pane-rest-api-keys-list-group mx-1 mb-2" variant="flush">
|
||||
{tabs.map(({ label, key }) => (
|
||||
<ListGroup.Item
|
||||
key={key}
|
||||
eventKey={key}
|
||||
data-cy={generateCypressDataCy(`graphql-tab-${key}-button`)}
|
||||
>
|
||||
<ListGroup.Item key={key} eventKey={key} data-cy={generateCypressDataCy(`graphql-tab-${key}-button`)}>
|
||||
<span>{label}</span>
|
||||
</ListGroup.Item>
|
||||
))}
|
||||
|
|
@ -76,11 +72,7 @@ export default function GraphqlKeyValueTabs({ tabs = [], options = {}, optioncha
|
|||
</div>
|
||||
|
||||
<div className="col tw-pl-0">
|
||||
|
||||
<Tab.Content
|
||||
bsPrefix="graphql-tab-content"
|
||||
className="query-manager-border-color rounded"
|
||||
>
|
||||
<Tab.Content bsPrefix="graphql-tab-content" className="query-manager-border-color rounded">
|
||||
{tabs.map(({ key }) => (
|
||||
<Tab.Pane
|
||||
key={key}
|
||||
|
|
@ -94,7 +86,7 @@ export default function GraphqlKeyValueTabs({ tabs = [], options = {}, optioncha
|
|||
onChange={handleChange}
|
||||
removeKeyValuePair={removeKeyValuePair}
|
||||
addNewKeyValuePair={addNewKeyValuePair}
|
||||
onInputChange={handleInputChange}
|
||||
onInputChange={handleInputChange}
|
||||
componentName={componentName ?? 'graphql'}
|
||||
tabType={key}
|
||||
paramType={key}
|
||||
|
|
@ -106,4 +98,4 @@ export default function GraphqlKeyValueTabs({ tabs = [], options = {}, optioncha
|
|||
</Row>
|
||||
</Tab.Container>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,9 +18,7 @@ export default function GraphqlTabContent({
|
|||
|
||||
return (
|
||||
<div className="tab-content-wrapper" data-cy={`${generateCypressDataCy(tabType)}-tab-content`}>
|
||||
{options.length === 0 && (
|
||||
<EmptyTabContent addNewKeyValuePair={addNewKeyValuePair} paramType={paramType} />
|
||||
)}
|
||||
{options.length === 0 && <EmptyTabContent addNewKeyValuePair={addNewKeyValuePair} paramType={paramType} />}
|
||||
{options.map((option, index) => (
|
||||
<div
|
||||
className="row-container query-manager-border-color"
|
||||
|
|
@ -65,4 +63,4 @@ export default function GraphqlTabContent({
|
|||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,12 +18,7 @@ export const BaseUrl = ({ dataSourceURL, theme, className = 'col-auto', style =
|
|||
...style,
|
||||
}}
|
||||
>
|
||||
<OverflowTooltip
|
||||
text={dataSourceURL}
|
||||
width="559px"
|
||||
whiteSpace="nowrap"
|
||||
placement="auto"
|
||||
>
|
||||
<OverflowTooltip text={dataSourceURL} width="559px" whiteSpace="nowrap" placement="auto">
|
||||
{dataSourceURL}
|
||||
</OverflowTooltip>
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -30,7 +30,11 @@ export default ({
|
|||
options.map((option, index) => {
|
||||
return (
|
||||
<>
|
||||
<div className="row-container query-manager-border-color" key={index} data-cy={`${generateCypressDataCy(tabType)}-row-${index}`}>
|
||||
<div
|
||||
className="row-container query-manager-border-color"
|
||||
key={index}
|
||||
data-cy={`${generateCypressDataCy(tabType)}-row-${index}`}
|
||||
>
|
||||
<div className="fields-container mb-1 restapi-key-value">
|
||||
<div className="field col-4 rounded-start rest-api-codehinter-key-field">
|
||||
<CodeHinter
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ export const AggregateFilter = ({ darkMode, operation = '' }) => {
|
|||
case 'joinTable':
|
||||
return joinTableOptionsChange;
|
||||
default:
|
||||
return () => { };
|
||||
return () => {};
|
||||
}
|
||||
}, [operation, handleOptionsChange, joinTableOptionsChange]);
|
||||
|
||||
|
|
@ -216,12 +216,12 @@ export const AggregateFilter = ({ darkMode, operation = '' }) => {
|
|||
const isAnyAggregateTruthyValue = isEmpty(currentAggregates)
|
||||
? false
|
||||
: Object.values(currentAggregates).some((aggregate) => {
|
||||
if (aggregate.aggFx && aggregate.column) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
if (aggregate.aggFx && aggregate.column) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
return !isAnyAggregateTruthyValue;
|
||||
};
|
||||
const getTableName = (id) => {
|
||||
|
|
@ -360,8 +360,9 @@ export const AggregateFilter = ({ darkMode, operation = '' }) => {
|
|||
Aggregate
|
||||
</label>
|
||||
<div
|
||||
className={`field-container col d-flex custom-gap-8 flex-column ${!isEmpty(operationDetails?.aggregates) && 'minw-400-w-400'
|
||||
}`}
|
||||
className={`field-container col d-flex custom-gap-8 flex-column ${
|
||||
!isEmpty(operationDetails?.aggregates) && 'minw-400-w-400'
|
||||
}`}
|
||||
>
|
||||
{isEmpty(operationDetails?.aggregates || {}) && <NoCondition />}
|
||||
{operationDetails?.aggregates &&
|
||||
|
|
@ -391,11 +392,11 @@ export const AggregateFilter = ({ darkMode, operation = '' }) => {
|
|||
value={
|
||||
operation === 'joinTable'
|
||||
? constructAggregateValue(
|
||||
aggregateDetails.column,
|
||||
'joinTable',
|
||||
'column',
|
||||
aggregateDetails?.table_id
|
||||
)
|
||||
aggregateDetails.column,
|
||||
'joinTable',
|
||||
'column',
|
||||
aggregateDetails?.table_id
|
||||
)
|
||||
: constructAggregateValue(aggregateDetails.column, 'listRows', 'column')
|
||||
}
|
||||
options={operation === 'joinTable' ? tableListOptions : columnAccessorsOptions}
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ const DropDownSelect = ({
|
|||
loader,
|
||||
isLoading = false,
|
||||
columnDefaultValue = '',
|
||||
setColumnDefaultValue = () => { },
|
||||
setColumnDefaultValue = () => {},
|
||||
showControlComponent = false,
|
||||
placeholder = '',
|
||||
dataCy = 'show-ds-popover-button',
|
||||
|
|
@ -115,7 +115,7 @@ const DropDownSelect = ({
|
|||
// onChange && onChange(selected);
|
||||
const badges = document.querySelectorAll('.dd-select-value-badge');
|
||||
if (isEmpty(badges)) {
|
||||
return () => { };
|
||||
return () => {};
|
||||
}
|
||||
let isNewOverFlown = false;
|
||||
for (let i = 0; i < badges.length; i++) {
|
||||
|
|
@ -195,27 +195,28 @@ const DropDownSelect = ({
|
|||
<Popover
|
||||
key={'page.i'}
|
||||
id={popoverId.current}
|
||||
className={`${darkMode && 'popover-dark-themed dark-theme tj-dark-mode'
|
||||
} tjdb-workflow-query-editor-popover-index`}
|
||||
className={`${
|
||||
darkMode && 'popover-dark-themed dark-theme tj-dark-mode'
|
||||
} tjdb-workflow-query-editor-popover-index`}
|
||||
style={{
|
||||
width: isForeignKeyInEditCell
|
||||
? '300px'
|
||||
: foreignKeyAccess
|
||||
? '403px'
|
||||
: foreignKeyAccessInRowForm === true
|
||||
? '494px'
|
||||
: isCellEdit
|
||||
? '266px'
|
||||
: '244px',
|
||||
? '403px'
|
||||
: foreignKeyAccessInRowForm === true
|
||||
? '494px'
|
||||
: isCellEdit
|
||||
? '266px'
|
||||
: '244px',
|
||||
maxWidth: isForeignKeyInEditCell
|
||||
? '300px'
|
||||
: foreignKeyAccess
|
||||
? '403px'
|
||||
: foreignKeyAccessInRowForm === true
|
||||
? '494px'
|
||||
: isCellEdit
|
||||
? '266px'
|
||||
: '246px',
|
||||
? '403px'
|
||||
: foreignKeyAccessInRowForm === true
|
||||
? '494px'
|
||||
: isCellEdit
|
||||
? '266px'
|
||||
: '246px',
|
||||
overflow: 'hidden',
|
||||
boxShadow: '0px 2px 4px -2px rgba(16, 24, 40, 0.06), 0px 4px 8px -2px rgba(16, 24, 40, 0.10)',
|
||||
}}
|
||||
|
|
@ -368,8 +369,8 @@ const DropDownSelect = ({
|
|||
{foreignKeyAccessInRowForm || showPlaceHolderInForeignKeyDrawer
|
||||
? topPlaceHolder
|
||||
: placeholder
|
||||
? placeholder
|
||||
: 'Select...'}
|
||||
? placeholder
|
||||
: 'Select...'}
|
||||
</span>
|
||||
) : (
|
||||
''
|
||||
|
|
|
|||
|
|
@ -249,7 +249,7 @@ function DataSourceSelect({
|
|||
setIsLoadingFKDetails(false);
|
||||
toast.error(
|
||||
error?.message ??
|
||||
`Failed to fetch table "${foreignKeys?.length > 0 && foreignKeys[0].referenced_table_name}"`
|
||||
`Failed to fetch table "${foreignKeys?.length > 0 && foreignKeys[0].referenced_table_name}"`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
|
@ -286,21 +286,21 @@ function DataSourceSelect({
|
|||
if (scrollPercentage > 90 && !isLoadingFKDetails) {
|
||||
isEmpty(searchValue)
|
||||
? fetchForeignKeyDetails(
|
||||
pageNumber,
|
||||
totalRecords,
|
||||
isInitialForeignKeyDataLoaded,
|
||||
searchValue,
|
||||
foreignKeys,
|
||||
organizationId
|
||||
)
|
||||
pageNumber,
|
||||
totalRecords,
|
||||
isInitialForeignKeyDataLoaded,
|
||||
searchValue,
|
||||
foreignKeys,
|
||||
organizationId
|
||||
)
|
||||
: fetchForeignKeyDetails(
|
||||
searchPageNumber,
|
||||
totalSearchRecords,
|
||||
isInitialForeignKeySearchDataLoaded,
|
||||
searchValue,
|
||||
foreignKeys,
|
||||
organizationId
|
||||
);
|
||||
searchPageNumber,
|
||||
totalSearchRecords,
|
||||
isInitialForeignKeySearchDataLoaded,
|
||||
searchValue,
|
||||
foreignKeys,
|
||||
organizationId
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -400,12 +400,12 @@ function DataSourceSelect({
|
|||
isForeignKeyInEditCell
|
||||
? 'tj-scrollbar tjdb-mainCellEdit-scrollbar'
|
||||
: foreignKeyAccess
|
||||
? 'tj-scrollbar tjdb-dashboard-scrollbar'
|
||||
: foreignKeyAccessInRowForm
|
||||
? 'tj-scrollbar tjdb-rowForm-scrollbar'
|
||||
: isCellEdit
|
||||
? 'tj-scrollbar tjdb-cellEdit-scrollbar'
|
||||
: 'tj-scrollbar',
|
||||
? 'tj-scrollbar tjdb-dashboard-scrollbar'
|
||||
: foreignKeyAccessInRowForm
|
||||
? 'tj-scrollbar tjdb-rowForm-scrollbar'
|
||||
: isCellEdit
|
||||
? 'tj-scrollbar tjdb-cellEdit-scrollbar'
|
||||
: 'tj-scrollbar',
|
||||
}}
|
||||
ref={selectRef}
|
||||
controlShouldRenderValue={false}
|
||||
|
|
@ -475,7 +475,7 @@ function DataSourceSelect({
|
|||
id={props.value}
|
||||
className="me-1"
|
||||
checked={props.isSelected}
|
||||
// label={`default ${type}`}
|
||||
// label={`default ${type}`}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
|
@ -522,9 +522,9 @@ function DataSourceSelect({
|
|||
style={{
|
||||
...(props.isSelected &&
|
||||
highlightSelected && {
|
||||
marginRight: '10px',
|
||||
marginTop: '3px',
|
||||
}),
|
||||
marginRight: '10px',
|
||||
marginTop: '3px',
|
||||
}),
|
||||
}}
|
||||
onClick={() => {
|
||||
const data = { id: props.data.id, table_name: props.data.value };
|
||||
|
|
@ -632,12 +632,12 @@ function DataSourceSelect({
|
|||
isSelected && highlightSelected
|
||||
? 'var(--indigo3, #F0F4FF)'
|
||||
: isFocused && !isNested
|
||||
? 'var(--slate4)'
|
||||
: isDisabled
|
||||
? 'transparent'
|
||||
: isDisabled && isFocused
|
||||
? 'var(--slate3, #f1f3f5)'
|
||||
: 'transparent',
|
||||
? 'var(--slate4)'
|
||||
: isDisabled
|
||||
? 'transparent'
|
||||
: isDisabled && isFocused
|
||||
? 'var(--slate3, #f1f3f5)'
|
||||
: 'transparent',
|
||||
...(isNested
|
||||
? { padding: '0 8px', marginLeft: '19px', borderLeft: '1px solid var(--slate5)', width: 'auto' }
|
||||
: {}),
|
||||
|
|
@ -648,8 +648,8 @@ function DataSourceSelect({
|
|||
},
|
||||
...(isFocused &&
|
||||
isNested && {
|
||||
'.option-nested-datasource-selector': { backgroundColor: 'var(--slate4)' },
|
||||
}),
|
||||
'.option-nested-datasource-selector': { backgroundColor: 'var(--slate4)' },
|
||||
}),
|
||||
}),
|
||||
group: (style) => ({
|
||||
...style,
|
||||
|
|
|
|||
|
|
@ -130,9 +130,9 @@ const ToolJetDbOperations = ({
|
|||
...acc,
|
||||
...(tableInfo[newTable]
|
||||
? tableInfo[newTable].map((col) => ({
|
||||
name: col.Header,
|
||||
table: newTable,
|
||||
}))
|
||||
name: col.Header,
|
||||
table: newTable,
|
||||
}))
|
||||
: []),
|
||||
],
|
||||
[]
|
||||
|
|
@ -332,10 +332,10 @@ const ToolJetDbOperations = ({
|
|||
newFields.push(
|
||||
...(data?.result?.columns
|
||||
? data.result.columns.map((col) => ({
|
||||
name: col.column_name,
|
||||
table: tableId,
|
||||
// alias: `${tableId}_${col.column_name}`,
|
||||
}))
|
||||
name: col.column_name,
|
||||
table: tableId,
|
||||
// alias: `${tableId}_${col.column_name}`,
|
||||
}))
|
||||
: [])
|
||||
);
|
||||
|
||||
|
|
@ -571,14 +571,14 @@ const ToolJetDbOperations = ({
|
|||
activeTab === 'GUI mode' && !darkMode
|
||||
? 'white'
|
||||
: activeTab === 'GUI mode' && darkMode
|
||||
? '#242f3c'
|
||||
: 'transparent',
|
||||
? '#242f3c'
|
||||
: 'transparent',
|
||||
color:
|
||||
activeTab === 'GUI mode' && !darkMode
|
||||
? '#3E63DD'
|
||||
: activeTab === 'GUI mode' && darkMode
|
||||
? 'white'
|
||||
: '#687076',
|
||||
? 'white'
|
||||
: '#687076',
|
||||
}}
|
||||
className="row-tab-content"
|
||||
data-cy="tooljetdb-gui-mode-tab"
|
||||
|
|
@ -593,14 +593,14 @@ const ToolJetDbOperations = ({
|
|||
activeTab === 'SQL mode' && !darkMode
|
||||
? 'white'
|
||||
: activeTab === 'SQL mode' && darkMode
|
||||
? '#242f3c'
|
||||
: 'transparent',
|
||||
? '#242f3c'
|
||||
: 'transparent',
|
||||
color:
|
||||
activeTab === 'SQL mode' && !darkMode
|
||||
? '#3E63DD'
|
||||
: activeTab === 'SQL mode' && darkMode
|
||||
? 'white'
|
||||
: '#687076',
|
||||
? 'white'
|
||||
: '#687076',
|
||||
}}
|
||||
className="row-tab-content"
|
||||
data-cy="tooljetdb-sql-mode-tab"
|
||||
|
|
|
|||
|
|
@ -49,17 +49,20 @@ export function Workflows({ options, optionsChanged, currentState }) {
|
|||
|
||||
useEffect(() => {
|
||||
if (options.workflowId) {
|
||||
appVersionService.getAll(options.workflowId).then((data) => {
|
||||
const versions = (data?.versions || [])
|
||||
.filter((v) => v.status === 'PUBLISHED')
|
||||
.map((v) => ({
|
||||
value: v.id,
|
||||
name: v.name,
|
||||
}));
|
||||
setVersionOptions(versions);
|
||||
}).catch(() => {
|
||||
setVersionOptions([]);
|
||||
});
|
||||
appVersionService
|
||||
.getAll(options.workflowId)
|
||||
.then((data) => {
|
||||
const versions = (data?.versions || [])
|
||||
.filter((v) => v.status === 'PUBLISHED')
|
||||
.map((v) => ({
|
||||
value: v.id,
|
||||
name: v.name,
|
||||
}));
|
||||
setVersionOptions(versions);
|
||||
})
|
||||
.catch(() => {
|
||||
setVersionOptions([]);
|
||||
});
|
||||
} else {
|
||||
setVersionOptions([]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,12 @@ const QueryManager = ({ mode, darkMode }) => {
|
|||
const [activeTab, setActiveTab] = useState(1);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedQuery?.kind == 'runjs' || selectedQuery?.kind == 'runpy' || selectedQuery?.kind == 'restapi' || selectedQuery?.kind == 'postgresql') {
|
||||
if (
|
||||
selectedQuery?.kind == 'runjs' ||
|
||||
selectedQuery?.kind == 'runpy' ||
|
||||
selectedQuery?.kind == 'restapi' ||
|
||||
selectedQuery?.kind == 'postgresql'
|
||||
) {
|
||||
setActiveTab(1);
|
||||
}
|
||||
}, [selectedQuery?.id]);
|
||||
|
|
|
|||
|
|
@ -75,10 +75,10 @@ export const QueryCard = ({ dataQuery, darkMode = false, localDs }) => {
|
|||
|
||||
const getTooltip = () => {
|
||||
const permission = dataQuery.permissions?.[0];
|
||||
if (!permission) return "Access restricted";
|
||||
if (!permission) return 'Access restricted';
|
||||
|
||||
const users = permission.groups || permission.users || [];
|
||||
if (users.length === 0) return "Access restricted";
|
||||
if (users.length === 0) return 'Access restricted';
|
||||
|
||||
const isSingle = permission.type === 'SINGLE';
|
||||
const isGroup = permission.type === 'GROUP';
|
||||
|
|
@ -95,7 +95,7 @@ export const QueryCard = ({ dataQuery, darkMode = false, localDs }) => {
|
|||
: `Access restricted to ${users.length} user groups`;
|
||||
}
|
||||
|
||||
return "Access restricted";
|
||||
return 'Access restricted';
|
||||
};
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -177,7 +177,8 @@ export const QueryDataPane = ({ darkMode }) => {
|
|||
</div>
|
||||
) : (
|
||||
<div
|
||||
className={`query-list tj-scrollbar overflow-auto ${filteredQueries.length === 0 ? 'flex-grow-1 align-items-center justify-content-center' : ''
|
||||
className={`query-list tj-scrollbar overflow-auto ${
|
||||
filteredQueries.length === 0 ? 'flex-grow-1 align-items-center justify-content-center' : ''
|
||||
}`}
|
||||
>
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import { deepClone } from '@/_helpers/utilities/utils.helpers';
|
|||
import useStore from '@/AppBuilder/_stores/store';
|
||||
import { shallow } from 'zustand/shallow';
|
||||
import QueryKeyHooks from './QueryKeyHooks';
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import { diff } from 'deep-object-diff';
|
||||
|
||||
const MemoizedQueryDataPane = memo(QueryDataPane);
|
||||
|
|
@ -184,7 +185,13 @@ export const QueryPanel = ({ darkMode }) => {
|
|||
className="d-flex items-center justify-start mb-0 font-weight-500 text-dark select-none query-manager-toggle-button tw-gap-1.5"
|
||||
onClick={toggleQueryEditor}
|
||||
>
|
||||
<span>{isQueryPaneExpanded ? <PanelBottomClose size='14' color='var(--icon-strong)' /> : <PanelBottomOpen size='14' color='var(--icon-strong)' />}</span>
|
||||
<span>
|
||||
{isQueryPaneExpanded ? (
|
||||
<PanelBottomClose size="14" color="var(--icon-strong)" />
|
||||
) : (
|
||||
<PanelBottomOpen size="14" color="var(--icon-strong)" />
|
||||
)}
|
||||
</span>
|
||||
<span>Queries</span>
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -26,8 +26,7 @@ export const QueryRenameInput = ({ dataQuery, darkMode, onUpdate }) => {
|
|||
return (
|
||||
<input
|
||||
data-cy={`query-edit-input-field`}
|
||||
className={`query-name query-name-input-field border-indigo-09 bg-transparent ${darkMode && 'text-white'
|
||||
}`}
|
||||
className={`query-name query-name-input-field border-indigo-09 bg-transparent ${darkMode && 'text-white'}`}
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
|
|
@ -36,4 +35,4 @@ export const QueryRenameInput = ({ dataQuery, darkMode, onUpdate }) => {
|
|||
onBlur={handleBlur}
|
||||
/>
|
||||
);
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import React, { useMemo, useState } from 'react';
|
|||
import Accordion from '@/_ui/Accordion';
|
||||
import { baseComponentProperties } from '../DefaultComponent';
|
||||
import Select from '@/_ui/Select';
|
||||
import useStore from '@/AppBuilder/_stores/store';
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import flags from 'react-phone-number-input/flags';
|
||||
import FxButton from '@/AppBuilder/CodeBuilder/Elements/FxButton';
|
||||
import CodeHinter from '@/AppBuilder/CodeEditor';
|
||||
|
|
|
|||
|
|
@ -79,8 +79,6 @@ const FxSelect = ({
|
|||
);
|
||||
};
|
||||
|
||||
|
||||
|
||||
const getPropertiesBySection = (propertiesMeta) => {
|
||||
const properties = [];
|
||||
const additionalActions = [];
|
||||
|
|
@ -98,8 +96,6 @@ const getPropertiesBySection = (propertiesMeta) => {
|
|||
return { properties, additionalActions, dataProperties };
|
||||
};
|
||||
|
||||
|
||||
|
||||
export const FilePicker = ({ componentMeta, darkMode, ...restProps }) => {
|
||||
const {
|
||||
layoutPropertyChanged,
|
||||
|
|
@ -143,12 +139,12 @@ export const FilePicker = ({ componentMeta, darkMode, ...restProps }) => {
|
|||
// Insert FxSelect for file type
|
||||
// Note: Adjusting index if necessary, assuming properties is always first index 0.
|
||||
// Properties -> 0, Events -> 1, Validation -> 2
|
||||
// We need to double check where the fileType is located.
|
||||
// We need to double check where the fileType is located.
|
||||
// It is properly located in Validation section which is usually 3rd if Events exist.
|
||||
// baseComponentProperties returns [Properties, Events, Validation, ...].
|
||||
// Safe way is to find the Validation section.
|
||||
|
||||
const validationSection = accordionItems.find(item => item.title === 'Validation');
|
||||
const validationSection = accordionItems.find((item) => item.title === 'Validation');
|
||||
if (validationSection) {
|
||||
// Find the index of fileType
|
||||
// This part is a bit brittle in original code too: accordionItems[2].children[1]
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import useStore from '@/AppBuilder/_stores/store';
|
|||
import { shallow } from 'zustand/shallow';
|
||||
import { isTrueValue, isPropertyFxControlled, getComponentIcon } from '../utils/utils';
|
||||
|
||||
export const FormField = ({ field, onDelete, activeMenu, onMenuToggle, onSave}) => {
|
||||
export const FormField = ({ field, onDelete, activeMenu, onMenuToggle, onSave }) => {
|
||||
const setSelectedComponents = useStore((state) => state.setSelectedComponents, shallow);
|
||||
const [showPopover, setShowPopover] = useState(false);
|
||||
const [fieldData, setFieldData] = useState(field);
|
||||
|
|
@ -33,6 +33,7 @@ export const FormField = ({ field, onDelete, activeMenu, onMenuToggle, onSave})
|
|||
|
||||
const isCurrentlyMandatory = isTrueValue(fieldData.mandatory?.value);
|
||||
|
||||
// eslint-disable-next-line no-constant-binary-expression
|
||||
const darkMode = localStorage.getItem('darkMode') === 'true' ?? false;
|
||||
|
||||
const mainPopover = (
|
||||
|
|
@ -126,8 +127,9 @@ export const FormField = ({ field, onDelete, activeMenu, onMenuToggle, onSave})
|
|||
overlay={mainPopover}
|
||||
>
|
||||
<div
|
||||
className={`field-item tw-flex tw-items-center tw-justify-between tw-gap-2 hover:tw-cursor-pointer ${(fieldData.name === activeMenu || showPopover) && 'selected'
|
||||
}`}
|
||||
className={`field-item tw-flex tw-items-center tw-justify-between tw-gap-2 hover:tw-cursor-pointer ${
|
||||
(fieldData.name === activeMenu || showPopover) && 'selected'
|
||||
}`}
|
||||
>
|
||||
<div className="tw-flex tw-items-center tw-gap-[6px] tw-flex-1" style={{ width: 'calc(100% - 100px)' }}>
|
||||
<div className="field-icon tw-w-6 tw-h-6 tw-flex tw-items-center tw-justify-center tw-rounded tw-bg-gray-100">
|
||||
|
|
|
|||
|
|
@ -38,8 +38,7 @@ export const useFieldManager = ({ component, paramUpdated, currentState }) => {
|
|||
const handleRemove = useCallback(
|
||||
async (removedFields) => {
|
||||
// Get existing deletion history
|
||||
const existingFieldDeletionHistory =
|
||||
component.component.definition.properties.fieldDeletionHistory?.value ?? [];
|
||||
const existingFieldDeletionHistory = component.component.definition.properties.fieldDeletionHistory?.value ?? [];
|
||||
|
||||
// Add removed field keys to deletion history
|
||||
const newFieldDeletionHistory = [
|
||||
|
|
|
|||
|
|
@ -28,7 +28,9 @@ export const GroupMenuItem = ({ darkMode, item, highlight, onDeleteItem, onItemC
|
|||
<div style={{ position: 'relative', width: '100%' }}>
|
||||
<div
|
||||
ref={optionsBtnRef}
|
||||
className={`page-menu-item page-group-item ${highlight ? 'highlight' : ''} ${darkMode ? 'dark-theme theme-dark' : ''} ${isEditing ? 'is-selected' : ''}`}
|
||||
className={`page-menu-item page-group-item ${highlight ? 'highlight' : ''} ${
|
||||
darkMode ? 'dark-theme theme-dark' : ''
|
||||
} ${isEditing ? 'is-selected' : ''}`}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
setShowEditPopover(!showEditPopover);
|
||||
|
|
@ -69,11 +71,23 @@ export const GroupMenuItem = ({ darkMode, item, highlight, onDeleteItem, onItemC
|
|||
className={`${darkMode ? 'dark-theme theme-dark' : ''} nav-item-actions-popover`}
|
||||
>
|
||||
<Popover.Body className="p-2">
|
||||
<div className="nav-item-action-option" onClick={(e) => { e.stopPropagation(); handleEdit(); }}>
|
||||
<div
|
||||
className="nav-item-action-option"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleEdit();
|
||||
}}
|
||||
>
|
||||
<TablerIcon iconName="IconPencil" size={16} stroke={1.5} className="nav-item-action-option-icon" />
|
||||
<span className="nav-item-action-option-label">Edit group</span>
|
||||
</div>
|
||||
<div className="nav-item-action-option nav-item-action-option-danger" onClick={(e) => { e.stopPropagation(); handleDelete(); }}>
|
||||
<div
|
||||
className="nav-item-action-option nav-item-action-option-danger"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleDelete();
|
||||
}}
|
||||
>
|
||||
<TablerIcon iconName="IconTrash" size={16} stroke={1.5} className="nav-item-action-option-icon" />
|
||||
<span className="nav-item-action-option-label">Delete group</span>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -37,7 +37,13 @@ export const MenuItem = ({ darkMode, item, onDeleteItem, onItemChange, getResolv
|
|||
>
|
||||
<div className="left">
|
||||
<div className="main-page-icon-wrapper">
|
||||
<TablerIcon iconName={item?.icon?.value || 'IconFile'} fallbackIcon="IconFile" size={20} stroke={1.5} className="nav-item-icon" />
|
||||
<TablerIcon
|
||||
iconName={item?.icon?.value || 'IconFile'}
|
||||
fallbackIcon="IconFile"
|
||||
size={20}
|
||||
stroke={1.5}
|
||||
className="nav-item-icon"
|
||||
/>
|
||||
</div>
|
||||
<OverflowTooltip childrenClassName="page-name">
|
||||
{getSafeRenderableValue(getResolvedValue?.(item?.label) ?? item?.label)}
|
||||
|
|
@ -70,11 +76,23 @@ export const MenuItem = ({ darkMode, item, onDeleteItem, onItemChange, getResolv
|
|||
className={`${darkMode ? 'dark-theme theme-dark' : ''} nav-item-actions-popover`}
|
||||
>
|
||||
<Popover.Body className="p-2">
|
||||
<div className="nav-item-action-option" onClick={(e) => { e.stopPropagation(); handleEdit(); }}>
|
||||
<div
|
||||
className="nav-item-action-option"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleEdit();
|
||||
}}
|
||||
>
|
||||
<TablerIcon iconName="IconPencil" size={16} stroke={1.5} className="nav-item-action-option-icon" />
|
||||
<span className="nav-item-action-option-label">Edit menu item</span>
|
||||
</div>
|
||||
<div className="nav-item-action-option nav-item-action-option-danger" onClick={(e) => { e.stopPropagation(); handleDelete(); }}>
|
||||
<div
|
||||
className="nav-item-action-option nav-item-action-option-danger"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleDelete();
|
||||
}}
|
||||
>
|
||||
<TablerIcon iconName="IconTrash" size={16} stroke={1.5} className="nav-item-action-option-icon" />
|
||||
<span className="nav-item-action-option-label">Delete nav item</span>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,10 @@ import CodeHinter from '@/AppBuilder/CodeEditor';
|
|||
import { Button as ButtonComponent } from '@/components/ui/Button/Button.jsx';
|
||||
|
||||
const NavItemPopover = forwardRef(
|
||||
({ item, darkMode, onItemChange, onDeleteItem, onDuplicateItem, getResolvedValue, parentId = null, ...restProps }, ref) => {
|
||||
(
|
||||
{ item, darkMode, onItemChange, onDeleteItem, onDuplicateItem, getResolvedValue, parentId = null, ...restProps },
|
||||
ref
|
||||
) => {
|
||||
const iconVisibility = item?.iconVisibility;
|
||||
|
||||
// Common CodeHinter props
|
||||
|
|
@ -85,10 +88,7 @@ const NavItemPopover = forwardRef(
|
|||
<div className="nav-item-popover-fields-section">
|
||||
{/* Label field */}
|
||||
<div data-cy="inspector-nav-item-details-label-field" className="nav-item-popover-field">
|
||||
<label
|
||||
data-cy="inspector-nav-item-details-label-label"
|
||||
className="nav-item-popover-field-label"
|
||||
>
|
||||
<label data-cy="inspector-nav-item-details-label-label" className="nav-item-popover-field-label">
|
||||
Label
|
||||
</label>
|
||||
<CodeHinter
|
||||
|
|
|
|||
|
|
@ -61,7 +61,11 @@ const NavItemsList = ({
|
|||
}, []);
|
||||
|
||||
return (
|
||||
<div className="navigation-inspector" data-cy="inspector-navigation-menu-items-list" style={{ marginBottom: '12px' }}>
|
||||
<div
|
||||
className="navigation-inspector"
|
||||
data-cy="inspector-navigation-menu-items-list"
|
||||
style={{ marginBottom: '12px' }}
|
||||
>
|
||||
<SortableTree
|
||||
menuItems={menuItems}
|
||||
darkMode={darkMode}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,13 @@ const GhostMenuItem = ({ item, getResolvedValue }) => {
|
|||
<div className="page-menu-item" style={{ width: '100%' }}>
|
||||
<div className="left">
|
||||
<div className="main-page-icon-wrapper">
|
||||
<TablerIcon iconName={item?.icon?.value || 'IconFile'} fallbackIcon="IconFile" size={20} stroke={1.5} className="nav-item-icon" />
|
||||
<TablerIcon
|
||||
iconName={item?.icon?.value || 'IconFile'}
|
||||
fallbackIcon="IconFile"
|
||||
size={20}
|
||||
stroke={1.5}
|
||||
className="nav-item-icon"
|
||||
/>
|
||||
</div>
|
||||
<OverflowTooltip childrenClassName="page-name">
|
||||
{getSafeRenderableValue(getResolvedValue?.(item?.label) ?? item?.label)}
|
||||
|
|
|
|||
|
|
@ -79,8 +79,14 @@ export const useMenuItemsManager = (component, paramUpdated) => {
|
|||
const generateNewItem = (isGroup = false) => {
|
||||
const id = generateUniqueId(isGroup ? 'group' : 'item');
|
||||
const icons = [
|
||||
'IconHome2', 'IconLayoutDashboard', 'IconSettings', 'IconUser',
|
||||
'IconFolder', 'IconFile', 'IconStar', 'IconHeart'
|
||||
'IconHome2',
|
||||
'IconLayoutDashboard',
|
||||
'IconSettings',
|
||||
'IconUser',
|
||||
'IconFolder',
|
||||
'IconFile',
|
||||
'IconStar',
|
||||
'IconHeart',
|
||||
];
|
||||
const randomIcon = icons[Math.floor(Math.random() * icons.length)];
|
||||
|
||||
|
|
|
|||
|
|
@ -2,9 +2,11 @@ import React, { useMemo, useState } from 'react';
|
|||
import Accordion from '@/_ui/Accordion';
|
||||
import { baseComponentProperties } from '../DefaultComponent';
|
||||
import Select from '@/_ui/Select';
|
||||
import useStore from '@/AppBuilder/_stores/store';
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import { getCountries } from 'react-phone-number-input/input';
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import en from 'react-phone-number-input/locale/en';
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import flags from 'react-phone-number-input/flags';
|
||||
import FxButton from '@/AppBuilder/CodeBuilder/Elements/FxButton';
|
||||
import CodeHinter from '@/AppBuilder/CodeEditor';
|
||||
|
|
|
|||
|
|
@ -321,7 +321,9 @@ export function Select({ componentMeta, darkMode, ...restProps }) {
|
|||
</div>
|
||||
<div className="field mb-2" data-cy={`input-and-label-column-name`}>
|
||||
<CodeHinter
|
||||
initialValue={isMultiSelect || isTagsInput ? `{{${markedAsDefault?.includes(item?.value)}}}` : item?.default?.value}
|
||||
initialValue={
|
||||
isMultiSelect || isTagsInput ? `{{${markedAsDefault?.includes(item?.value)}}}` : item?.default?.value
|
||||
}
|
||||
theme={darkMode ? 'monokai' : 'default'}
|
||||
mode="javascript"
|
||||
lineNumbers={false}
|
||||
|
|
|
|||
|
|
@ -78,9 +78,11 @@ const DatepickerProperties = ({ column, index, darkMode, currentState, onColumnI
|
|||
const { t } = useTranslation();
|
||||
const items = [];
|
||||
const [isDateDisplayFormatFxOn, setIsDateDisplayFormatFxOn] = useState(
|
||||
// eslint-disable-next-line no-constant-binary-expression
|
||||
!column?.notActiveFxActiveFields?.includes('dateFormat') ?? true
|
||||
);
|
||||
const [isParseDateFormatFxOn, setIsParseDateFormatFxOn] = useState(
|
||||
// eslint-disable-next-line no-constant-binary-expression
|
||||
!column?.notActiveFxActiveFields?.includes('parseDateFormat') ?? true
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -68,5 +68,13 @@ export const useButtonManager = ({ column, index, onColumnItemChange }) => {
|
|||
return (column.buttons || []).find((b) => b.id === buttonId);
|
||||
};
|
||||
|
||||
return { addButton, removeButton, duplicateButton, updateButtonProperty, updateButtonProperties, reorderButtons, getButton };
|
||||
return {
|
||||
addButton,
|
||||
removeButton,
|
||||
duplicateButton,
|
||||
updateButtonProperty,
|
||||
updateButtonProperties,
|
||||
reorderButtons,
|
||||
getButton,
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import React from 'react';
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import CodeMirror from '@uiw/react-codemirror';
|
||||
import { ToolTip } from './Components/ToolTip';
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import React from 'react';
|
|||
import { ToolTip } from './Components/ToolTip';
|
||||
|
||||
export const Toggle = ({ param, definition, onChange, paramType, componentMeta }) => {
|
||||
// eslint-disable-next-line no-constant-binary-expression
|
||||
const value = definition?.value !== false ?? false;
|
||||
const paramMeta = componentMeta[paramType][param.name];
|
||||
const displayName = paramMeta.displayName || param.name;
|
||||
|
|
|
|||
|
|
@ -21,7 +21,9 @@ export function AddNewPageMenu({ darkMode }) {
|
|||
};
|
||||
|
||||
return (
|
||||
<div className={`page-type-buttons-container d-flex justify-content-between custom-gap-12 ${darkMode && 'dark-mode'}`}>
|
||||
<div
|
||||
className={`page-type-buttons-container d-flex justify-content-between custom-gap-12 ${darkMode && 'dark-mode'}`}
|
||||
>
|
||||
<Button
|
||||
ref={newPageBtnRef}
|
||||
key="new-page-btn"
|
||||
|
|
|
|||
|
|
@ -594,8 +594,9 @@ const HidePageOnNavigation = ({ hidden, darkMode, updatePageVisibility, page, is
|
|||
<div className={`field`}>
|
||||
<InspectorTooltip
|
||||
label={`${page?.type === 'default' ? 'Hide this page on navigation' : 'Hide this item on navigation'}`}
|
||||
labelClass={`tj-text-xsm color-slate12 ${forceCodeBox ? 'mb-2' : 'mb-0'} ${darkMode && 'color-whitish-darkmode'
|
||||
}`}
|
||||
labelClass={`tj-text-xsm color-slate12 ${forceCodeBox ? 'mb-2' : 'mb-0'} ${
|
||||
darkMode && 'color-whitish-darkmode'
|
||||
}`}
|
||||
/>
|
||||
</div>
|
||||
<div className={`flex-grow-1`}>
|
||||
|
|
|
|||
|
|
@ -173,12 +173,13 @@ const MobileNavigationMenu = ({ currentPageId, darkMode, switchDarkMode, bgStyle
|
|||
sheetProps={{
|
||||
container: document.getElementsByClassName('canvas-wrapper')[0],
|
||||
overlayClassName: 'tw-absolute tw-h-dvh',
|
||||
className: `tw-absolute tw-p-0 mobile-page-menu-popup ${isMobilePreviewMode && !isPreviewInEditor
|
||||
? 'tw-h-[calc(100%_-_44px)]' // To account for the preview settings header height
|
||||
: currentMode === 'view' && !isMobilePreviewMode
|
||||
className: `tw-absolute tw-p-0 mobile-page-menu-popup ${
|
||||
isMobilePreviewMode && !isPreviewInEditor
|
||||
? 'tw-h-[calc(100%_-_44px)]' // To account for the preview settings header height
|
||||
: currentMode === 'view' && !isMobilePreviewMode
|
||||
? 'tw-h-dvh' // In released app, the height should equal to mobile browsers viewport height
|
||||
: 'tw-h-full'
|
||||
}`,
|
||||
}`,
|
||||
style: bgStyles,
|
||||
}}
|
||||
className="group-data-[side=left]:!tw-border-r-0"
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ export const PageHandlerMenu = ({ darkMode }) => {
|
|||
id="rename-page"
|
||||
text="Rename"
|
||||
iconSrc={'assets/images/icons/input.svg'}
|
||||
closeMenu={() => { }}
|
||||
closeMenu={() => {}}
|
||||
callback={() => {
|
||||
toggleEditPageNameInput(true);
|
||||
}}
|
||||
|
|
@ -105,7 +105,7 @@ export const PageHandlerMenu = ({ darkMode }) => {
|
|||
id="mark-as-home-page"
|
||||
text="Mark home"
|
||||
iconSrc={'assets/images/icons/home.svg'}
|
||||
closeMenu={() => { }}
|
||||
closeMenu={() => {}}
|
||||
callback={() => markAsHomePage(editingPage.id, moduleId)}
|
||||
/>
|
||||
)}
|
||||
|
|
@ -114,7 +114,7 @@ export const PageHandlerMenu = ({ darkMode }) => {
|
|||
id={isHidden ? 'unhide-page' : 'hide-page'}
|
||||
text={isHidden ? 'Show page on app menu' : 'Hide page on app menu'}
|
||||
iconSrc={`assets/images/icons/${isHidden ? 'eye' : 'eye-off'}.svg`}
|
||||
closeMenu={() => { }}
|
||||
closeMenu={() => {}}
|
||||
callback={() => {
|
||||
updatePageVisibility(editingPage.id, !editingPage.hidden);
|
||||
}}
|
||||
|
|
@ -135,7 +135,7 @@ export const PageHandlerMenu = ({ darkMode }) => {
|
|||
text="Event Handlers"
|
||||
customClass={'delete-btn'}
|
||||
iconSrc={'assets/images/icons/editor/left-sidebar/page-settings.svg'}
|
||||
closeMenu={() => { }}
|
||||
closeMenu={() => {}}
|
||||
callback={() => {
|
||||
togglePageEventsModal(true);
|
||||
}}
|
||||
|
|
@ -145,7 +145,7 @@ export const PageHandlerMenu = ({ darkMode }) => {
|
|||
text={isDisabled ? 'Enable' : 'Disable'}
|
||||
customClass={'delete-btn'}
|
||||
iconSrc={`assets/images/icons/editor/left-sidebar/${isDisabled ? 'file-accept' : 'file-remove'}.svg`}
|
||||
closeMenu={() => { }}
|
||||
closeMenu={() => {}}
|
||||
callback={() => {
|
||||
disableOrEnablePage(editingPage.id, !editingPage.disabled);
|
||||
}}
|
||||
|
|
@ -159,7 +159,7 @@ export const PageHandlerMenu = ({ darkMode }) => {
|
|||
text={() => {
|
||||
return (
|
||||
<ToolTip
|
||||
message={'You don\'t have access to page permissions. Upgrade your plan to access this feature.'}
|
||||
message={"You don't have access to page permissions. Upgrade your plan to access this feature."}
|
||||
placement="right"
|
||||
show={!hasAppPermissionPages}
|
||||
>
|
||||
|
|
@ -182,7 +182,7 @@ export const PageHandlerMenu = ({ darkMode }) => {
|
|||
text="Delete page"
|
||||
iconSrc={'assets/images/icons/delete.svg'}
|
||||
customClass={isHomePage ? 'delete-btn' : 'field__danger delete-btn'}
|
||||
closeMenu={() => { }}
|
||||
closeMenu={() => {}}
|
||||
callback={() => {
|
||||
toggleDeleteConfirmationModal(true);
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -277,8 +277,9 @@ export const PageMenuItem = withRouter(
|
|||
>
|
||||
<>
|
||||
<div
|
||||
className={`page-menu-item ${darkMode && 'dark-theme theme-dark'} ${(showPageOptions || showEditPopover) && isEditingPage ? 'is-selected' : ''
|
||||
}`}
|
||||
className={`page-menu-item ${darkMode && 'dark-theme theme-dark'} ${
|
||||
(showPageOptions || showEditPopover) && isEditingPage ? 'is-selected' : ''
|
||||
}`}
|
||||
style={{
|
||||
position: 'relative',
|
||||
width: '100%',
|
||||
|
|
@ -458,7 +459,9 @@ export const PageMenuItem = withRouter(
|
|||
<PageOptions
|
||||
text={
|
||||
<ToolTip
|
||||
message={'You don\'t have access to page permissions. Upgrade your plan to access this feature.'}
|
||||
message={
|
||||
"You don't have access to page permissions. Upgrade your plan to access this feature."
|
||||
}
|
||||
placement="auto"
|
||||
show={!hasAppPermissionPages}
|
||||
tooltipClassName="!tw-z-[100000]"
|
||||
|
|
|
|||
|
|
@ -22,32 +22,34 @@ export function SortableTree({ collapsible, indicator = false, indentationWidth
|
|||
const treeItems = useMemo(() => buildTree(allpages, PROPERTY_NAMES), [allpages]);
|
||||
|
||||
// When reorder happens, flatten and persist via debounced store action
|
||||
const handleReorder = useCallback((newTreeItems) => {
|
||||
const flatItems = flattenTree(newTreeItems, PROPERTY_NAMES);
|
||||
debouncedReorderPages(flatItems);
|
||||
}, [debouncedReorderPages]);
|
||||
const handleReorder = useCallback(
|
||||
(newTreeItems) => {
|
||||
const flatItems = flattenTree(newTreeItems, PROPERTY_NAMES);
|
||||
debouncedReorderPages(flatItems);
|
||||
},
|
||||
[debouncedReorderPages]
|
||||
);
|
||||
|
||||
const renderItem = useCallback((item, props) => {
|
||||
if (!item?.isPageGroup) {
|
||||
const renderItem = useCallback(
|
||||
(item, props) => {
|
||||
if (!item?.isPageGroup) {
|
||||
return <PageMenuItem darkMode={darkMode} page={item} treeRef={treeRef} />;
|
||||
}
|
||||
return (
|
||||
<PageMenuItem darkMode={darkMode} page={item} treeRef={treeRef} />
|
||||
<PageGroupItem
|
||||
darkMode={darkMode}
|
||||
highlight={props.isHighlighted}
|
||||
collapsed={props.collapsed}
|
||||
onCollapse={props.onCollapse}
|
||||
page={item}
|
||||
treeRef={treeRef}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<PageGroupItem
|
||||
darkMode={darkMode}
|
||||
highlight={props.isHighlighted}
|
||||
collapsed={props.collapsed}
|
||||
onCollapse={props.onCollapse}
|
||||
page={item}
|
||||
treeRef={treeRef}
|
||||
/>
|
||||
);
|
||||
}, [darkMode, treeRef]);
|
||||
},
|
||||
[darkMode, treeRef]
|
||||
);
|
||||
|
||||
const renderGhost = useCallback((item) => (
|
||||
<PageMenuItemGhost darkMode={darkMode} page={item} />
|
||||
), [darkMode]);
|
||||
const renderGhost = useCallback((item) => <PageMenuItemGhost darkMode={darkMode} page={item} />, [darkMode]);
|
||||
|
||||
return (
|
||||
<SharedSortableTree
|
||||
|
|
|
|||
|
|
@ -32,9 +32,7 @@ export const SidebarItem = forwardRef(
|
|||
data-cy={`right-sidebar-${generateCypressDataCy(typeof tip === 'object' ? icon : tip) || 'unknown'}-button`}
|
||||
>
|
||||
{children && (
|
||||
<div
|
||||
className={`sidebar-svg-icon position-relative ${selectedSidebarItem && 'sidebar-item'}`}
|
||||
>
|
||||
<div className={`sidebar-svg-icon position-relative ${selectedSidebarItem && 'sidebar-item'}`}>
|
||||
{children}
|
||||
</div>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -43,12 +43,15 @@ const PreviewSettings = ({ isMobileLayout, showHeader, darkMode }) => {
|
|||
Preview settings
|
||||
</span>
|
||||
{editingVersion && appType !== 'module' && (
|
||||
<Suspense fallback={
|
||||
<div className="d-flex justify-content-center" style={{ width: '304px' }}>
|
||||
<div className="d-flex align-items-center" style={{ width: '16px', height: '16px' }}>
|
||||
<Loader width={16} height={16} />
|
||||
<Suspense
|
||||
fallback={
|
||||
<div className="d-flex justify-content-center" style={{ width: '304px' }}>
|
||||
<div className="d-flex align-items-center" style={{ width: '16px', height: '16px' }}>
|
||||
<Loader width={16} height={16} />
|
||||
</div>
|
||||
</div>
|
||||
</div>}>
|
||||
}
|
||||
>
|
||||
<AppVersionsManager darkMode={darkMode} />
|
||||
<div className="navbar-seperator"></div>
|
||||
<AppEnvironments darkMode={darkMode} />
|
||||
|
|
|
|||
|
|
@ -179,8 +179,8 @@ export const Viewer = ({
|
|||
isPagesSidebarHidden || currentLayout === 'mobile'
|
||||
? 'auto'
|
||||
: position === 'top'
|
||||
? '0px'
|
||||
: '256px',
|
||||
? '0px'
|
||||
: '256px',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -1,161 +1,161 @@
|
|||
export const audioRecorderConfig = {
|
||||
name: 'AudioRecorder',
|
||||
displayName: 'Audio Recorder',
|
||||
description: 'Records audio',
|
||||
component: 'AudioRecorder',
|
||||
defaultSize: {
|
||||
width: 10,
|
||||
height: 70,
|
||||
name: 'AudioRecorder',
|
||||
displayName: 'Audio Recorder',
|
||||
description: 'Records audio',
|
||||
component: 'AudioRecorder',
|
||||
defaultSize: {
|
||||
width: 10,
|
||||
height: 70,
|
||||
},
|
||||
others: {
|
||||
showOnDesktop: { type: 'toggle', displayName: 'Show on desktop' },
|
||||
showOnMobile: { type: 'toggle', displayName: 'Show on mobile' },
|
||||
},
|
||||
properties: {
|
||||
label: {
|
||||
type: 'code',
|
||||
displayName: 'Label',
|
||||
validation: { schema: { type: 'string' } },
|
||||
accordian: 'Content',
|
||||
},
|
||||
loadingState: {
|
||||
type: 'toggle',
|
||||
displayName: 'Loading state',
|
||||
validation: { schema: { type: 'boolean' } },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
visibility: {
|
||||
type: 'toggle',
|
||||
displayName: 'Visibility',
|
||||
validation: { schema: { type: 'boolean' } },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
disabledState: {
|
||||
type: 'toggle',
|
||||
displayName: 'Disable',
|
||||
validation: { schema: { type: 'boolean' } },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
tooltip: {
|
||||
type: 'code',
|
||||
displayName: 'Tooltip',
|
||||
validation: { schema: { type: 'string' } },
|
||||
section: 'additionalActions',
|
||||
placeholder: 'Enter tooltip text',
|
||||
},
|
||||
},
|
||||
events: {
|
||||
onRecordingStart: { displayName: 'On recording start' },
|
||||
onRecordingSave: { displayName: 'On recording save' },
|
||||
},
|
||||
styles: {
|
||||
recorderIcon: {
|
||||
type: 'icon',
|
||||
displayName: 'Icon',
|
||||
validation: { schema: { type: 'string' } },
|
||||
visibility: false,
|
||||
accordian: 'recorder',
|
||||
},
|
||||
recorderIconColor: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Icon color',
|
||||
validation: { schema: { type: 'string' } },
|
||||
defaultValue: '#F6430D',
|
||||
accordian: 'recorder',
|
||||
},
|
||||
labelColor: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Label text',
|
||||
validation: { schema: { type: 'string' } },
|
||||
defaultValue: 'var(--cc-primary-text)',
|
||||
accordian: 'recorder',
|
||||
},
|
||||
accentColor: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Accent color',
|
||||
validation: { schema: { type: 'string' } },
|
||||
defaultValue: 'var(--cc-primary-brand)',
|
||||
accordian: 'recorder',
|
||||
},
|
||||
backgroundColor: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Background',
|
||||
validation: { schema: { type: 'string' } },
|
||||
defaultValue: 'var(--cc-surface1-surface)',
|
||||
accordian: 'container',
|
||||
},
|
||||
borderColor: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Border',
|
||||
validation: { schema: { type: 'string' } },
|
||||
defaultValue: 'var(--cc-default-border)',
|
||||
accordian: 'container',
|
||||
},
|
||||
borderRadius: {
|
||||
type: 'numberInput',
|
||||
displayName: 'Border radius',
|
||||
validation: { schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] }, defaultValue: 6 },
|
||||
defaultValue: 6,
|
||||
accordian: 'container',
|
||||
},
|
||||
boxShadow: {
|
||||
type: 'boxShadow',
|
||||
displayName: 'Box shadow',
|
||||
validation: { schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] } },
|
||||
defaultValue: '0px 0px 0px 0px #00000040',
|
||||
accordian: 'container',
|
||||
},
|
||||
},
|
||||
exposedVariables: {
|
||||
isVisible: true,
|
||||
isDisabled: false,
|
||||
isLoading: false,
|
||||
dataURL: null,
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
handle: 'setVisibility',
|
||||
displayName: 'Set visibility',
|
||||
params: [{ handle: 'disable', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setDisable',
|
||||
displayName: 'Set disable',
|
||||
params: [{ handle: 'disable', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setLoading',
|
||||
displayName: 'Set loading',
|
||||
params: [{ handle: 'loading', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'resetAudio',
|
||||
displayName: 'Reset audio',
|
||||
},
|
||||
],
|
||||
definition: {
|
||||
others: {
|
||||
showOnDesktop: { type: 'toggle', displayName: 'Show on desktop' },
|
||||
showOnMobile: { type: 'toggle', displayName: 'Show on mobile' },
|
||||
showOnDesktop: { value: '{{true}}' },
|
||||
showOnMobile: { value: '{{false}}' },
|
||||
},
|
||||
properties: {
|
||||
label: {
|
||||
type: 'code',
|
||||
displayName: 'Label',
|
||||
validation: { schema: { type: 'string' } },
|
||||
accordian: 'Content',
|
||||
},
|
||||
loadingState: {
|
||||
type: 'toggle',
|
||||
displayName: 'Loading state',
|
||||
validation: { schema: { type: 'boolean' } },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
visibility: {
|
||||
type: 'toggle',
|
||||
displayName: 'Visibility',
|
||||
validation: { schema: { type: 'boolean' } },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
disabledState: {
|
||||
type: 'toggle',
|
||||
displayName: 'Disable',
|
||||
validation: { schema: { type: 'boolean' } },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
tooltip: {
|
||||
type: 'code',
|
||||
displayName: 'Tooltip',
|
||||
validation: { schema: { type: 'string' } },
|
||||
section: 'additionalActions',
|
||||
placeholder: 'Enter tooltip text',
|
||||
},
|
||||
},
|
||||
events: {
|
||||
onRecordingStart: { displayName: 'On recording start' },
|
||||
onRecordingSave: { displayName: 'On recording save' },
|
||||
label: { value: 'Click to start recording' },
|
||||
visibility: { value: '{{true}}' },
|
||||
disabledState: { value: '{{false}}' },
|
||||
loadingState: { value: '{{false}}' },
|
||||
tooltip: { value: '' },
|
||||
},
|
||||
events: [],
|
||||
styles: {
|
||||
recorderIcon: {
|
||||
type: 'icon',
|
||||
displayName: 'Icon',
|
||||
validation: { schema: { type: 'string' } },
|
||||
visibility: false,
|
||||
accordian: 'recorder',
|
||||
},
|
||||
recorderIconColor: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Icon color',
|
||||
validation: { schema: { type: 'string' } },
|
||||
defaultValue: '#F6430D',
|
||||
accordian: 'recorder',
|
||||
},
|
||||
labelColor: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Label text',
|
||||
validation: { schema: { type: 'string' } },
|
||||
defaultValue: 'var(--cc-primary-text)',
|
||||
accordian: 'recorder',
|
||||
},
|
||||
accentColor: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Accent color',
|
||||
validation: { schema: { type: 'string' } },
|
||||
defaultValue: 'var(--cc-primary-brand)',
|
||||
accordian: 'recorder',
|
||||
},
|
||||
backgroundColor: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Background',
|
||||
validation: { schema: { type: 'string' } },
|
||||
defaultValue: 'var(--cc-surface1-surface)',
|
||||
accordian: 'container',
|
||||
},
|
||||
borderColor: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Border',
|
||||
validation: { schema: { type: 'string' } },
|
||||
defaultValue: 'var(--cc-default-border)',
|
||||
accordian: 'container',
|
||||
},
|
||||
borderRadius: {
|
||||
type: 'numberInput',
|
||||
displayName: 'Border radius',
|
||||
validation: { schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] }, defaultValue: 6 },
|
||||
defaultValue: 6,
|
||||
accordian: 'container',
|
||||
},
|
||||
boxShadow: {
|
||||
type: 'boxShadow',
|
||||
displayName: 'Box shadow',
|
||||
validation: { schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] } },
|
||||
defaultValue: '0px 0px 0px 0px #00000040',
|
||||
accordian: 'container',
|
||||
},
|
||||
},
|
||||
exposedVariables: {
|
||||
isVisible: true,
|
||||
isDisabled: false,
|
||||
isLoading: false,
|
||||
dataURL: null,
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
handle: 'setVisibility',
|
||||
displayName: 'Set visibility',
|
||||
params: [{ handle: 'disable', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setDisable',
|
||||
displayName: 'Set disable',
|
||||
params: [{ handle: 'disable', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setLoading',
|
||||
displayName: 'Set loading',
|
||||
params: [{ handle: 'loading', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'resetAudio',
|
||||
displayName: 'Reset audio',
|
||||
}
|
||||
],
|
||||
definition: {
|
||||
others: {
|
||||
showOnDesktop: { value: '{{true}}' },
|
||||
showOnMobile: { value: '{{false}}' },
|
||||
},
|
||||
properties: {
|
||||
label: { value: 'Click to start recording' },
|
||||
visibility: { value: '{{true}}' },
|
||||
disabledState: { value: '{{false}}' },
|
||||
loadingState: { value: '{{false}}' },
|
||||
tooltip: { value: '' },
|
||||
},
|
||||
events: [],
|
||||
styles: {
|
||||
recorderIcon: { value: 'IconMicrophone' },
|
||||
recorderIconColor: { value: '#F6430D' },
|
||||
labelColor: { value: 'var(--cc-primary-text)' },
|
||||
accentColor: { value: 'var(--cc-primary-brand)' },
|
||||
backgroundColor: { value: 'var(--cc-surface1-surface)' },
|
||||
borderColor: { value: 'var(--cc-default-border)' },
|
||||
borderRadius: { value: '{{6}}' },
|
||||
boxShadow: { value: '0px 0px 0px 0px #00000040' },
|
||||
iconVisibility: { value: true },
|
||||
},
|
||||
recorderIcon: { value: 'IconMicrophone' },
|
||||
recorderIconColor: { value: '#F6430D' },
|
||||
labelColor: { value: 'var(--cc-primary-text)' },
|
||||
accentColor: { value: 'var(--cc-primary-brand)' },
|
||||
backgroundColor: { value: 'var(--cc-surface1-surface)' },
|
||||
borderColor: { value: 'var(--cc-default-border)' },
|
||||
borderRadius: { value: '{{6}}' },
|
||||
boxShadow: { value: '0px 0px 0px 0px #00000040' },
|
||||
iconVisibility: { value: true },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,142 +1,142 @@
|
|||
export const cameraConfig = {
|
||||
name: 'Camera',
|
||||
displayName: 'Camera',
|
||||
description: 'Captures video & photos from camera',
|
||||
component: 'Camera',
|
||||
defaultSize: {
|
||||
width: 15,
|
||||
height: 500,
|
||||
name: 'Camera',
|
||||
displayName: 'Camera',
|
||||
description: 'Captures video & photos from camera',
|
||||
component: 'Camera',
|
||||
defaultSize: {
|
||||
width: 15,
|
||||
height: 500,
|
||||
},
|
||||
others: {
|
||||
showOnDesktop: { type: 'toggle', displayName: 'Show on desktop' },
|
||||
showOnMobile: { type: 'toggle', displayName: 'Show on mobile' },
|
||||
},
|
||||
properties: {
|
||||
content: {
|
||||
type: 'switch',
|
||||
displayName: 'Content',
|
||||
validation: { schema: { type: 'string' } },
|
||||
options: [
|
||||
{ displayName: 'Image', value: 'image' },
|
||||
{ displayName: 'Video', value: 'video' },
|
||||
],
|
||||
accordian: 'Content',
|
||||
defaultValue: 'image',
|
||||
},
|
||||
visibility: {
|
||||
type: 'toggle',
|
||||
displayName: 'Visibility',
|
||||
validation: { schema: { type: 'boolean' } },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
disabledState: {
|
||||
type: 'toggle',
|
||||
displayName: 'Disable',
|
||||
validation: { schema: { type: 'boolean' } },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
tooltip: {
|
||||
type: 'code',
|
||||
displayName: 'Tooltip',
|
||||
validation: { schema: { type: 'string' } },
|
||||
section: 'additionalActions',
|
||||
placeholder: 'Enter tooltip text',
|
||||
},
|
||||
},
|
||||
events: {
|
||||
onRecordingStart: { displayName: 'On recording start' },
|
||||
onRecordingSave: { displayName: 'On recording save' },
|
||||
onImageSave: { displayName: 'On image save' },
|
||||
},
|
||||
styles: {
|
||||
textColor: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Text color',
|
||||
validation: { schema: { type: 'string' } },
|
||||
defaultValue: 'var(--cc-primary-text)',
|
||||
accordian: 'recorder',
|
||||
},
|
||||
accentColor: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Accent color',
|
||||
validation: { schema: { type: 'string' } },
|
||||
defaultValue: 'var(--cc-primary-brand)',
|
||||
accordian: 'recorder',
|
||||
},
|
||||
backgroundColor: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Background',
|
||||
validation: { schema: { type: 'string' } },
|
||||
defaultValue: 'var(--cc-surface1-surface)',
|
||||
accordian: 'container',
|
||||
},
|
||||
borderColor: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Border',
|
||||
validation: { schema: { type: 'string' } },
|
||||
defaultValue: 'var(--cc-default-border)',
|
||||
accordian: 'container',
|
||||
},
|
||||
borderRadius: {
|
||||
type: 'numberInput',
|
||||
displayName: 'Border radius',
|
||||
validation: { schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] }, defaultValue: 6 },
|
||||
defaultValue: 6,
|
||||
accordian: 'container',
|
||||
},
|
||||
boxShadow: {
|
||||
type: 'boxShadow',
|
||||
displayName: 'Box shadow',
|
||||
validation: { schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] } },
|
||||
defaultValue: '0px 0px 0px 0px #00000040',
|
||||
accordian: 'container',
|
||||
},
|
||||
},
|
||||
exposedVariables: {
|
||||
isVisible: true,
|
||||
isDisabled: false,
|
||||
imageDataURL: null,
|
||||
videoDataURL: null,
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
handle: 'setVisibility',
|
||||
displayName: 'Set visibility',
|
||||
params: [{ handle: 'disable', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setDisable',
|
||||
displayName: 'Set disable',
|
||||
params: [{ handle: 'disable', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'resetVideo',
|
||||
displayName: 'Reset video',
|
||||
},
|
||||
{
|
||||
handle: 'resetImage',
|
||||
displayName: 'Reset image',
|
||||
},
|
||||
],
|
||||
definition: {
|
||||
others: {
|
||||
showOnDesktop: { type: 'toggle', displayName: 'Show on desktop' },
|
||||
showOnMobile: { type: 'toggle', displayName: 'Show on mobile' },
|
||||
showOnDesktop: { value: '{{true}}' },
|
||||
showOnMobile: { value: '{{false}}' },
|
||||
},
|
||||
properties: {
|
||||
content: {
|
||||
type: 'switch',
|
||||
displayName: 'Content',
|
||||
validation: { schema: { type: 'string' } },
|
||||
options: [
|
||||
{ displayName: 'Image', value: 'image' },
|
||||
{ displayName: 'Video', value: 'video' },
|
||||
],
|
||||
accordian: 'Content',
|
||||
defaultValue: 'image',
|
||||
},
|
||||
visibility: {
|
||||
type: 'toggle',
|
||||
displayName: 'Visibility',
|
||||
validation: { schema: { type: 'boolean' } },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
disabledState: {
|
||||
type: 'toggle',
|
||||
displayName: 'Disable',
|
||||
validation: { schema: { type: 'boolean' } },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
tooltip: {
|
||||
type: 'code',
|
||||
displayName: 'Tooltip',
|
||||
validation: { schema: { type: 'string' } },
|
||||
section: 'additionalActions',
|
||||
placeholder: 'Enter tooltip text',
|
||||
},
|
||||
},
|
||||
events: {
|
||||
onRecordingStart: { displayName: 'On recording start' },
|
||||
onRecordingSave: { displayName: 'On recording save' },
|
||||
onImageSave: { displayName: 'On image save' },
|
||||
content: { value: 'image' },
|
||||
visibility: { value: '{{true}}' },
|
||||
disabledState: { value: '{{false}}' },
|
||||
tooltip: { value: '' },
|
||||
},
|
||||
events: [],
|
||||
styles: {
|
||||
textColor: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Text color',
|
||||
validation: { schema: { type: 'string' } },
|
||||
defaultValue: 'var(--cc-primary-text)',
|
||||
accordian: 'recorder',
|
||||
},
|
||||
accentColor: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Accent color',
|
||||
validation: { schema: { type: 'string' } },
|
||||
defaultValue: 'var(--cc-primary-brand)',
|
||||
accordian: 'recorder',
|
||||
},
|
||||
backgroundColor: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Background',
|
||||
validation: { schema: { type: 'string' } },
|
||||
defaultValue: 'var(--cc-surface1-surface)',
|
||||
accordian: 'container',
|
||||
},
|
||||
borderColor: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Border',
|
||||
validation: { schema: { type: 'string' } },
|
||||
defaultValue: 'var(--cc-default-border)',
|
||||
accordian: 'container',
|
||||
},
|
||||
borderRadius: {
|
||||
type: 'numberInput',
|
||||
displayName: 'Border radius',
|
||||
validation: { schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] }, defaultValue: 6 },
|
||||
defaultValue: 6,
|
||||
accordian: 'container',
|
||||
},
|
||||
boxShadow: {
|
||||
type: 'boxShadow',
|
||||
displayName: 'Box shadow',
|
||||
validation: { schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] } },
|
||||
defaultValue: '0px 0px 0px 0px #00000040',
|
||||
accordian: 'container',
|
||||
},
|
||||
},
|
||||
exposedVariables: {
|
||||
isVisible: true,
|
||||
isDisabled: false,
|
||||
imageDataURL: null,
|
||||
videoDataURL: null,
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
handle: 'setVisibility',
|
||||
displayName: 'Set visibility',
|
||||
params: [{ handle: 'disable', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setDisable',
|
||||
displayName: 'Set disable',
|
||||
params: [{ handle: 'disable', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'resetVideo',
|
||||
displayName: 'Reset video',
|
||||
},
|
||||
{
|
||||
handle: 'resetImage',
|
||||
displayName: 'Reset image',
|
||||
},
|
||||
],
|
||||
definition: {
|
||||
others: {
|
||||
showOnDesktop: { value: '{{true}}' },
|
||||
showOnMobile: { value: '{{false}}' },
|
||||
},
|
||||
properties: {
|
||||
content: { value: 'image' },
|
||||
visibility: { value: '{{true}}' },
|
||||
disabledState: { value: '{{false}}' },
|
||||
tooltip: { value: '' },
|
||||
},
|
||||
events: [],
|
||||
styles: {
|
||||
textColor: { value: 'var(--cc-primary-text)' },
|
||||
accentColor: { value: 'var(--cc-primary-brand)' },
|
||||
backgroundColor: { value: 'var(--cc-surface1-surface)' },
|
||||
borderColor: { value: 'var(--cc-default-border)' },
|
||||
borderRadius: { value: '{{6}}' },
|
||||
boxShadow: { value: '0px 0px 0px 0px #00000040' },
|
||||
},
|
||||
textColor: { value: 'var(--cc-primary-text)' },
|
||||
accentColor: { value: 'var(--cc-primary-brand)' },
|
||||
backgroundColor: { value: 'var(--cc-surface1-surface)' },
|
||||
borderColor: { value: 'var(--cc-default-border)' },
|
||||
borderRadius: { value: '{{6}}' },
|
||||
boxShadow: { value: '0px 0px 0px 0px #00000040' },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,29 +1,335 @@
|
|||
export const chatConfig = {
|
||||
name: 'Chat',
|
||||
displayName: 'Chat',
|
||||
description: 'Chat interface with message history',
|
||||
component: 'Chat',
|
||||
defaultSize: {
|
||||
width: 15,
|
||||
height: 400,
|
||||
name: 'Chat',
|
||||
displayName: 'Chat',
|
||||
description: 'Chat interface with message history',
|
||||
component: 'Chat',
|
||||
defaultSize: {
|
||||
width: 15,
|
||||
height: 400,
|
||||
},
|
||||
properties: {
|
||||
chatTitle: {
|
||||
type: 'code',
|
||||
displayName: 'Chat title',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'Chat',
|
||||
},
|
||||
},
|
||||
initialChat: {
|
||||
type: 'code',
|
||||
displayName: 'Initial chat',
|
||||
validation: {
|
||||
schema: {
|
||||
type: 'array',
|
||||
element: { type: 'object' },
|
||||
defaultValue: `{{[{
|
||||
message: 'Ask me anything!',
|
||||
messageId: 'e3dd6f60-d5e8-46c5-b73b-006f2f4a34f2',
|
||||
timestamp: 'new Date().toISOString()',
|
||||
name: 'Assistant',
|
||||
avatar: '',
|
||||
type: 'response',
|
||||
},
|
||||
{
|
||||
message: 'Explain software development cycle',
|
||||
messageId: 'aad219d2-0349-4f61-a959-424bf62795f6',
|
||||
timestamp: 'new Date().toISOString()',
|
||||
name: 'User',
|
||||
avatar: '',
|
||||
type: 'message',
|
||||
}]}}`,
|
||||
},
|
||||
},
|
||||
},
|
||||
userName: {
|
||||
type: 'code',
|
||||
displayName: 'User name',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: '{{globals.currentUser.firstName}}',
|
||||
},
|
||||
},
|
||||
userAvatar: {
|
||||
type: 'code',
|
||||
displayName: 'User avatar',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: '',
|
||||
},
|
||||
},
|
||||
respondentName: {
|
||||
type: 'code',
|
||||
displayName: 'Respondent name',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'Assistant',
|
||||
},
|
||||
},
|
||||
respondentAvatar: {
|
||||
type: 'code',
|
||||
displayName: 'Respondent avatar',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: '',
|
||||
},
|
||||
},
|
||||
visibility: {
|
||||
type: 'toggle',
|
||||
displayName: 'Visibility',
|
||||
validation: {
|
||||
schema: { type: 'boolean' },
|
||||
defaultValue: true,
|
||||
},
|
||||
},
|
||||
disableInput: {
|
||||
type: 'toggle',
|
||||
displayName: 'Disable input state',
|
||||
validation: {
|
||||
schema: { type: 'boolean' },
|
||||
defaultValue: false,
|
||||
},
|
||||
},
|
||||
loadingHistory: {
|
||||
type: 'toggle',
|
||||
displayName: 'History loading state',
|
||||
validation: {
|
||||
schema: { type: 'boolean' },
|
||||
defaultValue: false,
|
||||
},
|
||||
},
|
||||
loadingResponse: {
|
||||
type: 'toggle',
|
||||
displayName: 'Response loading state',
|
||||
validation: {
|
||||
schema: { type: 'boolean' },
|
||||
defaultValue: false,
|
||||
},
|
||||
},
|
||||
enableClearHistoryButton: {
|
||||
type: 'toggle',
|
||||
displayName: 'Enable clear history icon',
|
||||
validation: {
|
||||
schema: { type: 'boolean' },
|
||||
defaultValue: true,
|
||||
},
|
||||
},
|
||||
enableDownloadHistoryButton: {
|
||||
type: 'toggle',
|
||||
displayName: 'Enable download history icon',
|
||||
validation: {
|
||||
schema: { type: 'boolean' },
|
||||
defaultValue: true,
|
||||
},
|
||||
},
|
||||
placeholder: {
|
||||
type: 'code',
|
||||
displayName: 'Placeholder for input field',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'Ask me anything!',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
events: {
|
||||
onMessageSent: { displayName: 'On message sent' },
|
||||
onClearHistory: { displayName: 'On history cleared' },
|
||||
},
|
||||
styles: {
|
||||
name: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Name',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'var(--cc-primary-text)',
|
||||
},
|
||||
accordian: 'Message',
|
||||
},
|
||||
message: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Message',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'var(--cc-primary-text)',
|
||||
},
|
||||
accordian: 'Message',
|
||||
},
|
||||
timestamp: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Timestamp',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'var(--cc-placeholder-text)',
|
||||
},
|
||||
accordian: 'Message',
|
||||
},
|
||||
backgroundColorField: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Background',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'var(--cc-surface1-surface)',
|
||||
},
|
||||
accordian: 'Field',
|
||||
},
|
||||
borderColorField: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Border',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'var(--cc-default-border)',
|
||||
},
|
||||
accordian: 'Field',
|
||||
},
|
||||
accentColorField: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Accent',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'var(--cc-primary-brand)',
|
||||
},
|
||||
accordian: 'Field',
|
||||
},
|
||||
textColorField: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Text',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'var(--cc-primary-text)',
|
||||
},
|
||||
accordian: 'Field',
|
||||
},
|
||||
sendIconColorField: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Send icon',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'var(--cc-primary-brand)',
|
||||
},
|
||||
accordian: 'Field',
|
||||
},
|
||||
containerBackgroundColor: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Background',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'var(--cc-surface1-surface)',
|
||||
},
|
||||
accordian: 'Container',
|
||||
},
|
||||
borderColorContainer: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Border',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'var(--cc-default-border)',
|
||||
},
|
||||
accordian: 'Container',
|
||||
},
|
||||
boxShadowContainer: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Box shadow',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: '#121212',
|
||||
},
|
||||
accordian: 'Container',
|
||||
},
|
||||
borderRadius: {
|
||||
type: 'numberInput',
|
||||
displayName: 'Border radius',
|
||||
validation: {
|
||||
schema: { type: 'number' },
|
||||
defaultValue: 6,
|
||||
},
|
||||
accordian: 'Container',
|
||||
},
|
||||
},
|
||||
exposedVariables: {
|
||||
history: [],
|
||||
isHistoryLoading: false,
|
||||
isInputDisabled: false,
|
||||
isResponseLoading: false,
|
||||
isVisible: true,
|
||||
lastMessage: {},
|
||||
lastResponse: {},
|
||||
},
|
||||
others: {
|
||||
showOnDesktop: { type: 'toggle', displayName: 'Show on desktop' },
|
||||
showOnMobile: { type: 'toggle', displayName: 'Show on mobile' },
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
handle: 'appendHistory',
|
||||
displayName: 'Append history',
|
||||
params: [{ handle: 'message', displayName: 'Message', defaultValue: '{{{}}}', type: 'code' }],
|
||||
},
|
||||
{
|
||||
handle: 'clearHistory',
|
||||
displayName: 'Clear history',
|
||||
params: [],
|
||||
},
|
||||
{
|
||||
handle: 'downloadChat',
|
||||
displayName: 'Download chat',
|
||||
params: [],
|
||||
},
|
||||
{
|
||||
handle: 'sendMessage',
|
||||
displayName: 'Send message',
|
||||
params: [{ handle: 'message', displayName: 'Message', defaultValue: '{{{}}}', type: 'code' }],
|
||||
},
|
||||
{
|
||||
handle: 'setError',
|
||||
displayName: 'Set error',
|
||||
params: [{ handle: 'error', displayName: 'Error', defaultValue: '', type: 'code' }],
|
||||
},
|
||||
{
|
||||
handle: 'setHistory',
|
||||
displayName: 'Set history',
|
||||
params: [{ handle: 'history', displayName: 'History', defaultValue: '{{[]}}', type: 'code' }],
|
||||
},
|
||||
{
|
||||
handle: 'setHistoryLoading',
|
||||
displayName: 'Set history loading',
|
||||
params: [{ handle: 'loading', displayName: 'Loading', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setInputDisable',
|
||||
displayName: 'Set input disable',
|
||||
params: [{ handle: 'disabled', displayName: 'Disabled', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setResponderAvatar',
|
||||
displayName: 'Set respondent avatar',
|
||||
params: [{ handle: 'avatar', displayName: 'Avatar', defaultValue: '', type: 'code' }],
|
||||
},
|
||||
{
|
||||
handle: 'setResponseLoading',
|
||||
displayName: 'Set response loading',
|
||||
params: [{ handle: 'loading', displayName: 'Loading', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setUserAvatar',
|
||||
displayName: 'Set user avatar',
|
||||
params: [{ handle: 'avatar', displayName: 'Avatar', defaultValue: '', type: 'code' }],
|
||||
},
|
||||
{
|
||||
handle: 'setVisibility',
|
||||
displayName: 'Set visibility',
|
||||
params: [{ handle: 'visible', displayName: 'Visible', defaultValue: '{{true}}', type: 'toggle' }],
|
||||
},
|
||||
],
|
||||
definition: {
|
||||
others: {
|
||||
showOnDesktop: { value: '{{true}}' },
|
||||
showOnMobile: { value: '{{false}}' },
|
||||
},
|
||||
properties: {
|
||||
chatTitle: {
|
||||
type: 'code',
|
||||
displayName: 'Chat title',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'Chat',
|
||||
},
|
||||
},
|
||||
initialChat: {
|
||||
type: 'code',
|
||||
displayName: 'Initial chat',
|
||||
validation: {
|
||||
schema: {
|
||||
type: 'array',
|
||||
element: { type: 'object' },
|
||||
defaultValue: `{{[{
|
||||
chatTitle: { value: 'Chat' },
|
||||
initialChat: {
|
||||
value: `{{[{
|
||||
message: 'Ask me anything!',
|
||||
messageId: 'e3dd6f60-d5e8-46c5-b73b-006f2f4a34f2',
|
||||
timestamp: 'new Date().toISOString()',
|
||||
|
|
@ -39,339 +345,33 @@ export const chatConfig = {
|
|||
avatar: '',
|
||||
type: 'message',
|
||||
}]}}`,
|
||||
},
|
||||
},
|
||||
},
|
||||
userName: {
|
||||
type: 'code',
|
||||
displayName: 'User name',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: '{{globals.currentUser.firstName}}',
|
||||
},
|
||||
},
|
||||
userAvatar: {
|
||||
type: 'code',
|
||||
displayName: 'User avatar',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: '',
|
||||
},
|
||||
},
|
||||
respondentName: {
|
||||
type: 'code',
|
||||
displayName: 'Respondent name',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'Assistant',
|
||||
},
|
||||
},
|
||||
respondentAvatar: {
|
||||
type: 'code',
|
||||
displayName: 'Respondent avatar',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: '',
|
||||
},
|
||||
},
|
||||
visibility: {
|
||||
type: 'toggle',
|
||||
displayName: 'Visibility',
|
||||
validation: {
|
||||
schema: { type: 'boolean' },
|
||||
defaultValue: true,
|
||||
},
|
||||
},
|
||||
disableInput: {
|
||||
type: 'toggle',
|
||||
displayName: 'Disable input state',
|
||||
validation: {
|
||||
schema: { type: 'boolean' },
|
||||
defaultValue: false,
|
||||
},
|
||||
},
|
||||
loadingHistory: {
|
||||
type: 'toggle',
|
||||
displayName: 'History loading state',
|
||||
validation: {
|
||||
schema: { type: 'boolean' },
|
||||
defaultValue: false,
|
||||
},
|
||||
},
|
||||
loadingResponse: {
|
||||
type: 'toggle',
|
||||
displayName: 'Response loading state',
|
||||
validation: {
|
||||
schema: { type: 'boolean' },
|
||||
defaultValue: false,
|
||||
},
|
||||
},
|
||||
enableClearHistoryButton: {
|
||||
type: 'toggle',
|
||||
displayName: 'Enable clear history icon',
|
||||
validation: {
|
||||
schema: { type: 'boolean' },
|
||||
defaultValue: true,
|
||||
},
|
||||
},
|
||||
enableDownloadHistoryButton: {
|
||||
type: 'toggle',
|
||||
displayName: 'Enable download history icon',
|
||||
validation: {
|
||||
schema: { type: 'boolean' },
|
||||
defaultValue: true,
|
||||
},
|
||||
},
|
||||
placeholder: {
|
||||
type: 'code',
|
||||
displayName: 'Placeholder for input field',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'Ask me anything!',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
events: {
|
||||
onMessageSent: { displayName: 'On message sent' },
|
||||
onClearHistory: { displayName: 'On history cleared' },
|
||||
},
|
||||
userName: { value: '{{globals.currentUser.firstName}}' },
|
||||
userAvatar: { value: '' },
|
||||
respondentName: { value: 'Assistant' },
|
||||
respondentAvatar: { value: '' },
|
||||
visibility: { value: '{{true}}' },
|
||||
disableInput: { value: '{{false}}' },
|
||||
loadingHistory: { value: '{{false}}' },
|
||||
loadingResponse: { value: '{{false}}' },
|
||||
enableClearHistoryButton: { value: '{{true}}' },
|
||||
enableDownloadHistoryButton: { value: '{{true}}' },
|
||||
placeholder: { value: 'Ask me anything!' },
|
||||
},
|
||||
events: [],
|
||||
styles: {
|
||||
name: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Name',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'var(--cc-primary-text)',
|
||||
},
|
||||
accordian: 'Message',
|
||||
},
|
||||
message: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Message',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'var(--cc-primary-text)',
|
||||
},
|
||||
accordian: 'Message',
|
||||
},
|
||||
timestamp: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Timestamp',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'var(--cc-placeholder-text)',
|
||||
},
|
||||
accordian: 'Message',
|
||||
},
|
||||
backgroundColorField: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Background',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'var(--cc-surface1-surface)',
|
||||
},
|
||||
accordian: 'Field',
|
||||
},
|
||||
borderColorField: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Border',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'var(--cc-default-border)',
|
||||
},
|
||||
accordian: 'Field',
|
||||
},
|
||||
accentColorField: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Accent',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'var(--cc-primary-brand)',
|
||||
},
|
||||
accordian: 'Field',
|
||||
},
|
||||
textColorField: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Text',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'var(--cc-primary-text)',
|
||||
},
|
||||
accordian: 'Field',
|
||||
},
|
||||
sendIconColorField: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Send icon',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'var(--cc-primary-brand)',
|
||||
},
|
||||
accordian: 'Field',
|
||||
},
|
||||
containerBackgroundColor: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Background',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'var(--cc-surface1-surface)',
|
||||
},
|
||||
accordian: 'Container',
|
||||
},
|
||||
borderColorContainer: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Border',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'var(--cc-default-border)',
|
||||
},
|
||||
accordian: 'Container',
|
||||
},
|
||||
boxShadowContainer: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Box shadow',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: '#121212',
|
||||
},
|
||||
accordian: 'Container',
|
||||
},
|
||||
borderRadius: {
|
||||
type: 'numberInput',
|
||||
displayName: 'Border radius',
|
||||
validation: {
|
||||
schema: { type: 'number' },
|
||||
defaultValue: 6,
|
||||
},
|
||||
accordian: 'Container',
|
||||
},
|
||||
},
|
||||
exposedVariables: {
|
||||
history: [],
|
||||
isHistoryLoading: false,
|
||||
isInputDisabled: false,
|
||||
isResponseLoading: false,
|
||||
isVisible: true,
|
||||
lastMessage: {},
|
||||
lastResponse: {},
|
||||
},
|
||||
others: {
|
||||
showOnDesktop: { type: 'toggle', displayName: 'Show on desktop' },
|
||||
showOnMobile: { type: 'toggle', displayName: 'Show on mobile' },
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
handle: 'appendHistory',
|
||||
displayName: 'Append history',
|
||||
params: [{ handle: 'message', displayName: 'Message', defaultValue: '{{{}}}', type: 'code' }],
|
||||
},
|
||||
{
|
||||
handle: 'clearHistory',
|
||||
displayName: 'Clear history',
|
||||
params: [],
|
||||
},
|
||||
{
|
||||
handle: 'downloadChat',
|
||||
displayName: 'Download chat',
|
||||
params: [],
|
||||
},
|
||||
{
|
||||
handle: 'sendMessage',
|
||||
displayName: 'Send message',
|
||||
params: [{ handle: 'message', displayName: 'Message', defaultValue: '{{{}}}', type: 'code' }],
|
||||
},
|
||||
{
|
||||
handle: 'setError',
|
||||
displayName: 'Set error',
|
||||
params: [{ handle: 'error', displayName: 'Error', defaultValue: '', type: 'code' }],
|
||||
},
|
||||
{
|
||||
handle: 'setHistory',
|
||||
displayName: 'Set history',
|
||||
params: [{ handle: 'history', displayName: 'History', defaultValue: '{{[]}}', type: 'code' }],
|
||||
},
|
||||
{
|
||||
handle: 'setHistoryLoading',
|
||||
displayName: 'Set history loading',
|
||||
params: [{ handle: 'loading', displayName: 'Loading', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setInputDisable',
|
||||
displayName: 'Set input disable',
|
||||
params: [{ handle: 'disabled', displayName: 'Disabled', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setResponderAvatar',
|
||||
displayName: 'Set respondent avatar',
|
||||
params: [{ handle: 'avatar', displayName: 'Avatar', defaultValue: '', type: 'code' }],
|
||||
},
|
||||
{
|
||||
handle: 'setResponseLoading',
|
||||
displayName: 'Set response loading',
|
||||
params: [{ handle: 'loading', displayName: 'Loading', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setUserAvatar',
|
||||
displayName: 'Set user avatar',
|
||||
params: [{ handle: 'avatar', displayName: 'Avatar', defaultValue: '', type: 'code' }],
|
||||
},
|
||||
{
|
||||
handle: 'setVisibility',
|
||||
displayName: 'Set visibility',
|
||||
params: [{ handle: 'visible', displayName: 'Visible', defaultValue: '{{true}}', type: 'toggle' }],
|
||||
},
|
||||
],
|
||||
definition: {
|
||||
others: {
|
||||
showOnDesktop: { value: '{{true}}' },
|
||||
showOnMobile: { value: '{{false}}' },
|
||||
},
|
||||
properties: {
|
||||
chatTitle: { value: 'Chat' },
|
||||
initialChat: {
|
||||
value: `{{[{
|
||||
message: 'Ask me anything!',
|
||||
messageId: 'e3dd6f60-d5e8-46c5-b73b-006f2f4a34f2',
|
||||
timestamp: 'new Date().toISOString()',
|
||||
name: 'Assistant',
|
||||
avatar: '',
|
||||
type: 'response',
|
||||
},
|
||||
{
|
||||
message: 'Explain software development cycle',
|
||||
messageId: 'aad219d2-0349-4f61-a959-424bf62795f6',
|
||||
timestamp: 'new Date().toISOString()',
|
||||
name: 'User',
|
||||
avatar: '',
|
||||
type: 'message',
|
||||
}]}}`,
|
||||
},
|
||||
userName: { value: '{{globals.currentUser.firstName}}' },
|
||||
userAvatar: { value: '' },
|
||||
respondentName: { value: 'Assistant' },
|
||||
respondentAvatar: { value: '' },
|
||||
visibility: { value: '{{true}}' },
|
||||
disableInput: { value: '{{false}}' },
|
||||
loadingHistory: { value: '{{false}}' },
|
||||
loadingResponse: { value: '{{false}}' },
|
||||
enableClearHistoryButton: { value: '{{true}}' },
|
||||
enableDownloadHistoryButton: { value: '{{true}}' },
|
||||
placeholder: { value: 'Ask me anything!' },
|
||||
},
|
||||
events: [],
|
||||
styles: {
|
||||
name: { value: 'var(--cc-primary-text)' },
|
||||
message: { value: 'var(--cc-primary-text)' },
|
||||
timestamp: { value: 'var(--cc-placeholder-text)' },
|
||||
backgroundColorField: { value: 'var(--cc-surface1-surface)' },
|
||||
borderColorField: { value: 'var(--cc-default-border)' },
|
||||
accentColorField: { value: 'var(--cc-primary-brand)' },
|
||||
textColorField: { value: 'var(--cc-primary-text)' },
|
||||
sendIconColorField: { value: 'var(--cc-primary-brand)' },
|
||||
containerBackgroundColor: { value: 'var(--cc-surface1-surface)' },
|
||||
borderColorContainer: { value: 'var(--cc-weak-border)' },
|
||||
boxShadowContainer: { value: '#121212' },
|
||||
borderRadius: { value: '{{6}}' },
|
||||
},
|
||||
name: { value: 'var(--cc-primary-text)' },
|
||||
message: { value: 'var(--cc-primary-text)' },
|
||||
timestamp: { value: 'var(--cc-placeholder-text)' },
|
||||
backgroundColorField: { value: 'var(--cc-surface1-surface)' },
|
||||
borderColorField: { value: 'var(--cc-default-border)' },
|
||||
accentColorField: { value: 'var(--cc-primary-brand)' },
|
||||
textColorField: { value: 'var(--cc-primary-text)' },
|
||||
sendIconColorField: { value: 'var(--cc-primary-brand)' },
|
||||
containerBackgroundColor: { value: 'var(--cc-surface1-surface)' },
|
||||
borderColorContainer: { value: 'var(--cc-weak-border)' },
|
||||
boxShadowContainer: { value: '#121212' },
|
||||
borderRadius: { value: '{{6}}' },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -37,32 +37,6 @@ export const dividerConfig = {
|
|||
},
|
||||
},
|
||||
events: {},
|
||||
styles: {
|
||||
dividerColor: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Divider color',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
},
|
||||
},
|
||||
visibility: {
|
||||
type: 'toggle',
|
||||
displayName: 'Visibility',
|
||||
validation: {
|
||||
schema: { type: 'boolean' },
|
||||
defaultValue: true,
|
||||
},
|
||||
section: 'additionalActions',
|
||||
},
|
||||
tooltip: {
|
||||
type: 'code',
|
||||
displayName: 'Tooltip',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'Tooltip text' },
|
||||
section: 'additionalActions',
|
||||
placeholder: 'Enter tooltip text',
|
||||
},
|
||||
},
|
||||
events: {},
|
||||
styles: {
|
||||
dividerColor: {
|
||||
type: 'colorSwatches',
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ export const iframeConfig = {
|
|||
{
|
||||
handle: 'reload',
|
||||
displayName: 'Reload',
|
||||
}
|
||||
},
|
||||
],
|
||||
definition: {
|
||||
others: {
|
||||
|
|
|
|||
|
|
@ -186,14 +186,14 @@ export const modalV2Config = {
|
|||
type: 'icon',
|
||||
displayName: 'Icon',
|
||||
validation: { schema: { type: 'string' } },
|
||||
accordian: 'trigger',
|
||||
accordian: 'trigger button',
|
||||
visibility: false,
|
||||
},
|
||||
iconColor: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Icon color',
|
||||
validation: { schema: { type: 'string' } },
|
||||
accordian: 'trigger',
|
||||
accordian: 'trigger button',
|
||||
visibility: false,
|
||||
},
|
||||
direction: {
|
||||
|
|
@ -206,7 +206,7 @@ export const modalV2Config = {
|
|||
{ displayName: 'alignleftinspector', value: 'left', iconName: 'alignleftinspector' },
|
||||
{ displayName: 'alignrightinspector', value: 'right', iconName: 'alignrightinspector' },
|
||||
],
|
||||
accordian: 'trigger',
|
||||
accordian: 'trigger button',
|
||||
},
|
||||
headerBackgroundColor: {
|
||||
type: 'colorSwatches',
|
||||
|
|
@ -271,32 +271,6 @@ export const modalV2Config = {
|
|||
},
|
||||
accordian: 'trigger button',
|
||||
},
|
||||
icon: {
|
||||
type: 'icon',
|
||||
displayName: 'Icon',
|
||||
validation: { schema: { type: 'string' } },
|
||||
accordian: 'trigger button',
|
||||
visibility: false,
|
||||
},
|
||||
iconColor: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Icon color',
|
||||
validation: { schema: { type: 'string' } },
|
||||
accordian: 'trigger button',
|
||||
visibility: false,
|
||||
},
|
||||
direction: {
|
||||
type: 'switch',
|
||||
displayName: '',
|
||||
validation: { schema: { type: 'string' } },
|
||||
showLabel: false,
|
||||
isIcon: true,
|
||||
options: [
|
||||
{ displayName: 'alignleftinspector', value: 'left', iconName: 'alignleftinspector' },
|
||||
{ displayName: 'alignrightinspector', value: 'right', iconName: 'alignrightinspector' },
|
||||
],
|
||||
accordian: 'trigger button',
|
||||
},
|
||||
},
|
||||
exposedVariables: {
|
||||
show: false,
|
||||
|
|
|
|||
|
|
@ -1,289 +1,288 @@
|
|||
export const popoverMenuConfig = {
|
||||
name: 'PopoverMenu',
|
||||
displayName: 'Popover Menu',
|
||||
description: 'Popover Menu',
|
||||
component: 'PopoverMenu',
|
||||
defaultSize: {
|
||||
width: 6,
|
||||
height: 40,
|
||||
name: 'PopoverMenu',
|
||||
displayName: 'Popover Menu',
|
||||
description: 'Popover Menu',
|
||||
component: 'PopoverMenu',
|
||||
defaultSize: {
|
||||
width: 6,
|
||||
height: 40,
|
||||
},
|
||||
others: {
|
||||
showOnDesktop: { type: 'toggle', displayName: 'Show on desktop' },
|
||||
showOnMobile: { type: 'toggle', displayName: 'Show on mobile' },
|
||||
},
|
||||
properties: {
|
||||
label: {
|
||||
type: 'code',
|
||||
displayName: 'Button label',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'Menu' },
|
||||
accordian: 'Menu',
|
||||
},
|
||||
buttonType: {
|
||||
type: 'switch',
|
||||
displayName: 'Button type',
|
||||
validation: { schema: { type: 'string' } },
|
||||
options: [
|
||||
{ displayName: 'Primary', value: 'primary' },
|
||||
{ displayName: 'Outline', value: 'outline' },
|
||||
],
|
||||
accordian: 'Menu',
|
||||
},
|
||||
trigger: {
|
||||
type: 'switch',
|
||||
displayName: 'Show menu',
|
||||
validation: { schema: { type: 'string' } },
|
||||
options: [
|
||||
{ displayName: 'On hover', value: 'hover' },
|
||||
{ displayName: 'On click', value: 'click' },
|
||||
],
|
||||
accordian: 'Menu',
|
||||
},
|
||||
advanced: {
|
||||
type: 'toggle',
|
||||
displayName: 'Dynamic options',
|
||||
validation: {
|
||||
schema: { type: 'boolean' },
|
||||
},
|
||||
accordian: 'Options',
|
||||
},
|
||||
schema: {
|
||||
type: 'code',
|
||||
displayName: 'Schema',
|
||||
conditionallyRender: {
|
||||
key: 'advanced',
|
||||
value: true,
|
||||
},
|
||||
accordian: 'Options',
|
||||
},
|
||||
optionsLoadingState: {
|
||||
type: 'toggle',
|
||||
displayName: 'Options loading state',
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: false },
|
||||
accordian: 'Options',
|
||||
conditionallyRender: {
|
||||
key: 'advanced',
|
||||
value: true,
|
||||
},
|
||||
},
|
||||
loadingState: {
|
||||
type: 'toggle',
|
||||
displayName: 'Loading state',
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: false },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
visibility: {
|
||||
type: 'toggle',
|
||||
displayName: 'Visibility',
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: true },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
disabledState: {
|
||||
type: 'toggle',
|
||||
displayName: 'Disable',
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: false },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
tooltip: {
|
||||
type: 'code',
|
||||
displayName: 'Tooltip',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'Tooltip text' },
|
||||
section: 'additionalActions',
|
||||
placeholder: 'Enter tooltip text',
|
||||
},
|
||||
},
|
||||
events: {
|
||||
onSelect: { displayName: 'On select' },
|
||||
},
|
||||
styles: {
|
||||
backgroundColor: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Background',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-brand)' },
|
||||
conditionallyRender: {
|
||||
key: 'buttonType',
|
||||
value: 'primary',
|
||||
},
|
||||
accordian: 'Menu',
|
||||
},
|
||||
textColor: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Text',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: '#FFFFFF',
|
||||
},
|
||||
accordian: 'Menu',
|
||||
},
|
||||
borderColor: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Border',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-brand)' },
|
||||
accordian: 'Menu',
|
||||
},
|
||||
loaderColor: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Loader',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-surface1-surface)' },
|
||||
accordian: 'Menu',
|
||||
},
|
||||
icon: {
|
||||
type: 'icon',
|
||||
displayName: 'Icon',
|
||||
validation: { schema: { type: 'string' } },
|
||||
accordian: 'Menu',
|
||||
visibility: false,
|
||||
},
|
||||
iconColor: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Icon color',
|
||||
validation: { schema: { type: 'string' } },
|
||||
accordian: 'Menu',
|
||||
visibility: false,
|
||||
},
|
||||
direction: {
|
||||
type: 'switch',
|
||||
displayName: '',
|
||||
validation: { schema: { type: 'string' } },
|
||||
showLabel: false,
|
||||
isIcon: true,
|
||||
options: [
|
||||
{ displayName: 'alignleftinspector', value: 'left', iconName: 'alignleftinspector' },
|
||||
{ displayName: 'alignrightinspector', value: 'right', iconName: 'alignrightinspector' },
|
||||
],
|
||||
accordian: 'Menu',
|
||||
},
|
||||
borderRadius: {
|
||||
type: 'numberInput',
|
||||
displayName: 'Border radius',
|
||||
validation: { schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] }, defaultValue: 6 },
|
||||
accordian: 'Menu',
|
||||
},
|
||||
boxShadow: {
|
||||
type: 'boxShadow',
|
||||
displayName: 'Box Shadow',
|
||||
validation: {
|
||||
schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] },
|
||||
defaultValue: '0px 0px 0px 0px #00000040',
|
||||
},
|
||||
conditionallyRender: {
|
||||
key: 'buttonType',
|
||||
value: 'primary',
|
||||
},
|
||||
accordian: 'Menu',
|
||||
},
|
||||
|
||||
optionsTextColor: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Label',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-text)' },
|
||||
accordian: 'Options',
|
||||
},
|
||||
optionsIconColor: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Icon color',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-default-icon)' },
|
||||
visibility: false,
|
||||
accordian: 'Options',
|
||||
},
|
||||
optionsDescriptionColor: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Description',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-placeholder-text)' },
|
||||
accordian: 'Options',
|
||||
},
|
||||
},
|
||||
exposedVariables: {
|
||||
isVisible: true,
|
||||
isDisabled: false,
|
||||
isLoading: false,
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
handle: 'setDisable',
|
||||
displayName: 'Set disable',
|
||||
params: [{ handle: 'disable', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setLoading',
|
||||
displayName: 'Set loading',
|
||||
params: [{ handle: 'loading', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setVisibility',
|
||||
displayName: 'Set visibility',
|
||||
params: [{ handle: 'disable', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
],
|
||||
definition: {
|
||||
others: {
|
||||
showOnDesktop: { type: 'toggle', displayName: 'Show on desktop' },
|
||||
showOnMobile: { type: 'toggle', displayName: 'Show on mobile' },
|
||||
showOnDesktop: { value: '{{true}}' },
|
||||
showOnMobile: { value: '{{false}}' },
|
||||
},
|
||||
properties: {
|
||||
label: {
|
||||
type: 'code',
|
||||
displayName: 'Button label',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'Menu' },
|
||||
accordian: 'Menu',
|
||||
},
|
||||
buttonType: {
|
||||
type: 'switch',
|
||||
displayName: 'Button type',
|
||||
validation: { schema: { type: 'string' } },
|
||||
options: [
|
||||
{ displayName: 'Primary', value: 'primary' },
|
||||
{ displayName: 'Outline', value: 'outline' },
|
||||
],
|
||||
accordian: 'Menu',
|
||||
},
|
||||
trigger: {
|
||||
type: 'switch',
|
||||
displayName: 'Show menu',
|
||||
validation: { schema: { type: 'string' } },
|
||||
options: [
|
||||
{ displayName: 'On hover', value: 'hover' },
|
||||
{ displayName: 'On click', value: 'click' },
|
||||
|
||||
],
|
||||
accordian: 'Menu',
|
||||
},
|
||||
advanced: {
|
||||
type: 'toggle',
|
||||
displayName: 'Dynamic options',
|
||||
validation: {
|
||||
schema: { type: 'boolean' },
|
||||
},
|
||||
accordian: 'Options',
|
||||
},
|
||||
schema: {
|
||||
type: 'code',
|
||||
displayName: 'Schema',
|
||||
conditionallyRender: {
|
||||
key: 'advanced',
|
||||
value: true,
|
||||
},
|
||||
accordian: 'Options',
|
||||
},
|
||||
optionsLoadingState: {
|
||||
type: 'toggle',
|
||||
displayName: 'Options loading state',
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: false },
|
||||
accordian: 'Options',
|
||||
conditionallyRender: {
|
||||
key: 'advanced',
|
||||
value: true,
|
||||
},
|
||||
},
|
||||
loadingState: {
|
||||
type: 'toggle',
|
||||
displayName: 'Loading state',
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: false },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
visibility: {
|
||||
type: 'toggle',
|
||||
displayName: 'Visibility',
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: true },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
disabledState: {
|
||||
type: 'toggle',
|
||||
displayName: 'Disable',
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: false },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
tooltip: {
|
||||
type: 'code',
|
||||
displayName: 'Tooltip',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'Tooltip text' },
|
||||
section: 'additionalActions',
|
||||
placeholder: 'Enter tooltip text',
|
||||
},
|
||||
},
|
||||
events: {
|
||||
onSelect: { displayName: 'On select' },
|
||||
label: { value: 'Menu' },
|
||||
buttonType: { value: 'primary' },
|
||||
trigger: { value: 'click' },
|
||||
advanced: { value: '{{false}}' },
|
||||
schema: {
|
||||
value:
|
||||
'{{[{"label":"option1","description":"","value":"1","icon":"IconBolt", "iconVisibility":false, "disable":false,"visible":true},{"label":"option2","description":"","value":"2","icon":"IconBulb", "iconVisibility":false, "disable":false,"visible":true},{"label":"option3","description":"","value":"3","icon":"IconTag", "iconVisibility":false, "disable":false,"visible":true}]}}',
|
||||
},
|
||||
options: {
|
||||
value: [
|
||||
{
|
||||
format: 'plain',
|
||||
label: 'option1',
|
||||
description: '',
|
||||
value: '1',
|
||||
icon: { value: 'IconBolt' },
|
||||
iconVisibility: false,
|
||||
disable: { value: false },
|
||||
visible: { value: true },
|
||||
},
|
||||
{
|
||||
format: 'plain',
|
||||
label: 'option2',
|
||||
description: '',
|
||||
value: '2',
|
||||
icon: { value: 'IconBulb' },
|
||||
iconVisibility: false,
|
||||
disable: { value: false },
|
||||
visible: { value: true },
|
||||
},
|
||||
{
|
||||
format: 'plain',
|
||||
label: 'option3',
|
||||
description: '',
|
||||
value: '3',
|
||||
icon: { value: 'IconTag' },
|
||||
iconVisibility: false,
|
||||
disable: { value: false },
|
||||
visible: { value: true },
|
||||
},
|
||||
],
|
||||
},
|
||||
optionsLoadingState: { value: '{{false}}' },
|
||||
visibility: { value: '{{true}}' },
|
||||
disabledState: { value: '{{false}}' },
|
||||
loadingState: { value: '{{false}}' },
|
||||
tooltip: { value: '' },
|
||||
},
|
||||
events: [],
|
||||
styles: {
|
||||
backgroundColor: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Background',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-brand)' },
|
||||
conditionallyRender: {
|
||||
key: 'buttonType',
|
||||
value: 'primary',
|
||||
},
|
||||
accordian: 'Menu',
|
||||
},
|
||||
textColor: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Text',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: '#FFFFFF',
|
||||
},
|
||||
accordian: 'Menu',
|
||||
},
|
||||
borderColor: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Border',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-brand)' },
|
||||
accordian: 'Menu',
|
||||
},
|
||||
loaderColor: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Loader',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-surface1-surface)' },
|
||||
accordian: 'Menu',
|
||||
},
|
||||
icon: {
|
||||
type: 'icon',
|
||||
displayName: 'Icon',
|
||||
validation: { schema: { type: 'string' } },
|
||||
accordian: 'Menu',
|
||||
visibility: false,
|
||||
},
|
||||
iconColor: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Icon color',
|
||||
validation: { schema: { type: 'string' } },
|
||||
accordian: 'Menu',
|
||||
visibility: false,
|
||||
},
|
||||
direction: {
|
||||
type: 'switch',
|
||||
displayName: '',
|
||||
validation: { schema: { type: 'string' } },
|
||||
showLabel: false,
|
||||
isIcon: true,
|
||||
options: [
|
||||
{ displayName: 'alignleftinspector', value: 'left', iconName: 'alignleftinspector' },
|
||||
{ displayName: 'alignrightinspector', value: 'right', iconName: 'alignrightinspector' },
|
||||
],
|
||||
accordian: 'Menu',
|
||||
},
|
||||
borderRadius: {
|
||||
type: 'numberInput',
|
||||
displayName: 'Border radius',
|
||||
validation: { schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] }, defaultValue: 6 },
|
||||
accordian: 'Menu',
|
||||
},
|
||||
boxShadow: {
|
||||
type: 'boxShadow',
|
||||
displayName: 'Box Shadow',
|
||||
validation: {
|
||||
schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] },
|
||||
defaultValue: '0px 0px 0px 0px #00000040',
|
||||
},
|
||||
conditionallyRender: {
|
||||
key: 'buttonType',
|
||||
value: 'primary',
|
||||
},
|
||||
accordian: 'Menu',
|
||||
},
|
||||
|
||||
optionsTextColor: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Label',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-text)' },
|
||||
accordian: 'Options',
|
||||
},
|
||||
optionsIconColor: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Icon color',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-default-icon)' },
|
||||
visibility: false,
|
||||
accordian: 'Options',
|
||||
},
|
||||
optionsDescriptionColor: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Description',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-placeholder-text)' },
|
||||
accordian: 'Options',
|
||||
},
|
||||
},
|
||||
exposedVariables: {
|
||||
isVisible: true,
|
||||
isDisabled: false,
|
||||
isLoading: false,
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
handle: 'setDisable',
|
||||
displayName: 'Set disable',
|
||||
params: [{ handle: 'disable', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setLoading',
|
||||
displayName: 'Set loading',
|
||||
params: [{ handle: 'loading', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setVisibility',
|
||||
displayName: 'Set visibility',
|
||||
params: [{ handle: 'disable', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
}
|
||||
],
|
||||
definition: {
|
||||
others: {
|
||||
showOnDesktop: { value: '{{true}}' },
|
||||
showOnMobile: { value: '{{false}}' },
|
||||
},
|
||||
properties: {
|
||||
label: { value: 'Menu' },
|
||||
buttonType: { value: 'primary' },
|
||||
trigger: { value: 'click' },
|
||||
advanced: { value: '{{false}}' },
|
||||
schema: {
|
||||
value:
|
||||
'{{[{"label":"option1","description":"","value":"1","icon":"IconBolt", "iconVisibility":false, "disable":false,"visible":true},{"label":"option2","description":"","value":"2","icon":"IconBulb", "iconVisibility":false, "disable":false,"visible":true},{"label":"option3","description":"","value":"3","icon":"IconTag", "iconVisibility":false, "disable":false,"visible":true}]}}',
|
||||
},
|
||||
options: {
|
||||
value: [
|
||||
{
|
||||
format: 'plain',
|
||||
label: 'option1',
|
||||
description: '',
|
||||
value: '1',
|
||||
icon: { value: 'IconBolt' },
|
||||
iconVisibility: false,
|
||||
disable: { value: false },
|
||||
visible: { value: true },
|
||||
},
|
||||
{
|
||||
format: 'plain',
|
||||
label: 'option2',
|
||||
description: '',
|
||||
value: '2',
|
||||
icon: { value: 'IconBulb' },
|
||||
iconVisibility: false,
|
||||
disable: { value: false },
|
||||
visible: { value: true },
|
||||
},
|
||||
{
|
||||
format: 'plain',
|
||||
label: 'option3',
|
||||
description: '',
|
||||
value: '3',
|
||||
icon: { value: 'IconTag' },
|
||||
iconVisibility: false,
|
||||
disable: { value: false },
|
||||
visible: { value: true },
|
||||
},
|
||||
],
|
||||
},
|
||||
optionsLoadingState: { value: '{{false}}' },
|
||||
visibility: { value: '{{true}}' },
|
||||
disabledState: { value: '{{false}}' },
|
||||
loadingState: { value: '{{false}}' },
|
||||
tooltip: { value: '' },
|
||||
},
|
||||
events: [],
|
||||
styles: {
|
||||
backgroundColor: { value: 'var(--cc-primary-brand)' },
|
||||
textColor: { value: '#FFFFFF' },
|
||||
borderColor: { value: 'var(--cc-primary-brand)' },
|
||||
loaderColor: { value: 'var(--cc-surface1-surface)' },
|
||||
icon: { value: 'IconMenu2' },
|
||||
iconVisibility: { value: '{{true}}' },
|
||||
iconColor: { value: '#FFFFFF' },
|
||||
direction: { value: 'left' },
|
||||
borderRadius: { value: '6' },
|
||||
boxShadow: { value: '0px 0px 0px 0px #00000040' },
|
||||
optionsTextColor: { value: 'var(--cc-primary-text)' },
|
||||
optionsIconColor: { value: 'var(--cc-default-icon)' },
|
||||
optionsDescriptionColor: { value: 'var(--cc-placeholder-text)' },
|
||||
},
|
||||
backgroundColor: { value: 'var(--cc-primary-brand)' },
|
||||
textColor: { value: '#FFFFFF' },
|
||||
borderColor: { value: 'var(--cc-primary-brand)' },
|
||||
loaderColor: { value: 'var(--cc-surface1-surface)' },
|
||||
icon: { value: 'IconMenu2' },
|
||||
iconVisibility: { value: '{{true}}' },
|
||||
iconColor: { value: '#FFFFFF' },
|
||||
direction: { value: 'left' },
|
||||
borderRadius: { value: '6' },
|
||||
boxShadow: { value: '0px 0px 0px 0px #00000040' },
|
||||
optionsTextColor: { value: 'var(--cc-primary-text)' },
|
||||
optionsIconColor: { value: 'var(--cc-default-icon)' },
|
||||
optionsDescriptionColor: { value: 'var(--cc-placeholder-text)' },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -113,4 +113,4 @@ export const rangeSliderConfig = {
|
|||
visibility: { value: '{{true}}' },
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -368,7 +368,6 @@ export const rangeSliderV2Config = {
|
|||
auto: { value: '{{true}}' },
|
||||
padding: { value: 'default' },
|
||||
visibility: { value: '{{true}}' },
|
||||
padding: { value: 'default' },
|
||||
widthType: { value: 'ofComponent' },
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -75,8 +75,7 @@ export const BaseInput = ({
|
|||
const { label, placeholder } = properties;
|
||||
const _width = getLabelWidthOfInput(widthType, width);
|
||||
const defaultAlignment = alignment === 'side' || alignment === 'top' ? alignment : 'side';
|
||||
const hasLabel =
|
||||
(label?.length > 0 && width > 0) || (auto && width == 0 && label && label?.length != 0);
|
||||
const hasLabel = (label?.length > 0 && width > 0) || (auto && width == 0 && label && label?.length != 0);
|
||||
const hasValue = value !== '' && value !== null && value !== undefined;
|
||||
const shouldShowClearBtn = showClearBtn && hasValue && !disable && !loading;
|
||||
|
||||
|
|
@ -84,8 +83,8 @@ export const BaseInput = ({
|
|||
color: !['#1B1F24', '#000', '#000000ff'].includes(textColor)
|
||||
? textColor
|
||||
: disable || loading
|
||||
? 'var(--text-disabled)'
|
||||
: 'var(--text-primary)',
|
||||
? 'var(--text-disabled)'
|
||||
: 'var(--text-primary)',
|
||||
textOverflow: 'ellipsis',
|
||||
backgroundColor: 'inherit',
|
||||
};
|
||||
|
|
@ -145,11 +144,12 @@ export const BaseInput = ({
|
|||
return (
|
||||
<>
|
||||
<div
|
||||
className={`text-input scrollbar-container d-flex ${defaultAlignment === 'top' &&
|
||||
className={`text-input scrollbar-container d-flex ${
|
||||
defaultAlignment === 'top' &&
|
||||
((width != 0 && label?.length != 0) || (auto && width == 0 && label && label?.length != 0))
|
||||
? 'flex-column'
|
||||
: ''
|
||||
} ${direction === 'right' && defaultAlignment === 'side' ? 'flex-row-reverse' : ''}
|
||||
? 'flex-column'
|
||||
: ''
|
||||
} ${direction === 'right' && defaultAlignment === 'side' ? 'flex-row-reverse' : ''}
|
||||
${direction === 'right' && defaultAlignment === 'top' ? 'text-right' : ''}
|
||||
${visibility || 'invisible'}`}
|
||||
style={{
|
||||
|
|
@ -195,30 +195,30 @@ export const BaseInput = ({
|
|||
!isValid && showValidationError
|
||||
? 'var(--cc-error-systemStatus)'
|
||||
: isFocused
|
||||
? accentColor != '4368E3'
|
||||
? accentColor
|
||||
: 'var(--primary-accent-strong)'
|
||||
: borderColor != '#CCD1D5'
|
||||
? borderColor
|
||||
: disable || loading
|
||||
? '1px solid var(--borders-disabled-on-white)'
|
||||
: 'var(--borders-default)',
|
||||
? accentColor != '4368E3'
|
||||
? accentColor
|
||||
: 'var(--primary-accent-strong)'
|
||||
: borderColor != '#CCD1D5'
|
||||
? borderColor
|
||||
: disable || loading
|
||||
? '1px solid var(--borders-disabled-on-white)'
|
||||
: 'var(--borders-default)',
|
||||
'--tblr-input-border-color-darker': getModifiedColor(borderColor, 8),
|
||||
backgroundColor:
|
||||
backgroundColor != '#fff'
|
||||
? backgroundColor
|
||||
: disable || loading
|
||||
? darkMode
|
||||
? 'var(--surfaces-app-bg-default)'
|
||||
: 'var(--surfaces-surface-03)'
|
||||
: 'var(--surfaces-surface-01)',
|
||||
? darkMode
|
||||
? 'var(--surfaces-app-bg-default)'
|
||||
: 'var(--surfaces-surface-03)'
|
||||
: 'var(--surfaces-surface-01)',
|
||||
boxShadow,
|
||||
...(isDynamicHeightEnabled && { minHeight: `${height}px` }),
|
||||
...(defaultAlignment === 'top' &&
|
||||
label?.length != 0 && {
|
||||
height: `calc(100% - 20px - ${padding === 'default' ? BOX_PADDING * 2 : 0}px)`, // 20px is label height
|
||||
flex: 1,
|
||||
}),
|
||||
height: `calc(100% - 20px - ${padding === 'default' ? BOX_PADDING * 2 : 0}px)`, // 20px is label height
|
||||
flex: 1,
|
||||
}),
|
||||
...getWidthTypeOfComponentStyles(widthType, width, auto, alignment),
|
||||
}}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -18,10 +18,10 @@ export const BoundedBox = ({ properties, fireEvent, darkMode, setExposedVariable
|
|||
const [typeState, setType] = useState(properties.selector);
|
||||
const labels = _.isArray(properties.labels)
|
||||
? [
|
||||
...properties.labels.map((label) => {
|
||||
return { name: getSafeRenderableValue(label), value: label };
|
||||
}),
|
||||
]
|
||||
...properties.labels.map((label) => {
|
||||
return { name: getSafeRenderableValue(label), value: label };
|
||||
}),
|
||||
]
|
||||
: [];
|
||||
const annotateRef = useRef(null);
|
||||
|
||||
|
|
|
|||
|
|
@ -73,8 +73,8 @@ export const Button = function Button(props) {
|
|||
? 'var(--cc-primary-brand)'
|
||||
: 'transparent'
|
||||
: type === 'primary'
|
||||
? backgroundColor
|
||||
: 'transparent';
|
||||
? backgroundColor
|
||||
: 'transparent';
|
||||
|
||||
const computedStyles = {
|
||||
backgroundColor: computedBgColor,
|
||||
|
|
|
|||
|
|
@ -53,4 +53,4 @@ const GetAvatar = ({ chatType, userAvatar, respondentAvatar, chatAvatar }) => {
|
|||
}
|
||||
};
|
||||
|
||||
export default GetAvatar;
|
||||
export default GetAvatar;
|
||||
|
|
|
|||
|
|
@ -42,4 +42,4 @@ export const ChatHeader = ({ title, onDownload, onClear, enableDownloadHistoryBu
|
|||
</ToolTip>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
);
|
||||
|
|
|
|||
|
|
@ -88,4 +88,4 @@ export const ChatInput = ({
|
|||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -57,4 +57,4 @@ export const ChatMessage = React.memo(
|
|||
);
|
||||
|
||||
// Add display name for debugging
|
||||
ChatMessage.displayName = 'ChatMessage';
|
||||
ChatMessage.displayName = 'ChatMessage';
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue