chore: upgrade to prettier v2 + enforce import types (#21013)Co-authored-by: Satish Gandham <hello@satishgandham.com> Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
## Description
This PR upgrades Prettier to v2 + enforces TypeScript’s [`import
type`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export)
syntax where applicable. It’s submitted as a separate PR so we can merge
it easily.
As a part of this PR, we reformat the codebase heavily:
- add `import type` everywhere where it’s required, and
- re-format the code to account for Prettier 2’s breaking changes:
https://prettier.io/blog/2020/03/21/2.0.0.html#breaking-changes
This PR is submitted against `release` to make sure all new code by team
members will adhere to new formatting standards, and we’ll have fewer
conflicts when merging `bundle-optimizations` into `release`. (I’ll
merge `release` back into `bundle-optimizations` once this PR is
merged.)
### Why is this needed?
This PR is needed because, for the Lodash optimization from
https://github.com/appsmithorg/appsmith/commit/7cbb12af886621256224be0c93e6a465dd710ad3,
we need to use `import type`. Otherwise, `babel-plugin-lodash` complains
that `LoDashStatic` is not a lodash function.
However, just using `import type` in the current codebase will give you
this:
<img width="962" alt="Screenshot 2023-03-08 at 17 45 59"
src="https://user-images.githubusercontent.com/2953267/223775744-407afa0c-e8b9-44a1-90f9-b879348da57f.png">
That’s because Prettier 1 can’t parse `import type` at all. To parse it,
we need to upgrade to Prettier 2.
### Why enforce `import type`?
Apart from just enabling `import type` support, this PR enforces
specifying `import type` everywhere it’s needed. (Developers will get
immediate TypeScript and ESLint errors when they forget to do so.)
I’m doing this because I believe `import type` improves DX and makes
refactorings easier.
Let’s say you had a few imports like below. Can you tell which of these
imports will increase the bundle size? (Tip: it’s not all of them!)
```ts
// app/client/src/workers/Linting/utils.ts
import { Position } from "codemirror";
import { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
It’s pretty hard, right?
What about now?
```ts
// app/client/src/workers/Linting/utils.ts
import type { Position } from "codemirror";
import type { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
Now, it’s clear that only `lodash` will be bundled.
This helps developers to see which imports are problematic, but it
_also_ helps with refactorings. Now, if you want to see where
`codemirror` is bundled, you can just grep for `import \{.*\} from
"codemirror"` – and you won’t get any type-only imports.
This also helps (some) bundlers. Upon transpiling, TypeScript erases
type-only imports completely. In some environment (not ours), this makes
the bundle smaller, as the bundler doesn’t need to bundle type-only
imports anymore.
## Type of change
- Chore (housekeeping or task changes that don't impact user perception)
## How Has This Been Tested?
This was tested to not break the build.
### Test Plan
> Add Testsmith test cases links that relate to this PR
### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
## Checklist:
### Dev activity
- [x] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag
### QA activity:
- [ ] Test plan has been approved by relevant developers
- [ ] Test plan has been peer reviewed by QA
- [ ] Cypress test cases have been added and approved by either SDET or
manual QA
- [ ] Organized project review call with relevant stakeholders after
Round 1/2 of QA
- [ ] Added Test Plan Approved label after reveiwing all Cypress test
---------
Co-authored-by: Satish Gandham <hello@satishgandham.com>
Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
2023-03-16 11:41:47 +00:00
|
|
|
import type {
|
2019-09-19 22:25:37 +00:00
|
|
|
ReduxAction,
|
2022-11-23 09:48:23 +00:00
|
|
|
ReduxActionType,
|
chore: upgrade to prettier v2 + enforce import types (#21013)Co-authored-by: Satish Gandham <hello@satishgandham.com> Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
## Description
This PR upgrades Prettier to v2 + enforces TypeScript’s [`import
type`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export)
syntax where applicable. It’s submitted as a separate PR so we can merge
it easily.
As a part of this PR, we reformat the codebase heavily:
- add `import type` everywhere where it’s required, and
- re-format the code to account for Prettier 2’s breaking changes:
https://prettier.io/blog/2020/03/21/2.0.0.html#breaking-changes
This PR is submitted against `release` to make sure all new code by team
members will adhere to new formatting standards, and we’ll have fewer
conflicts when merging `bundle-optimizations` into `release`. (I’ll
merge `release` back into `bundle-optimizations` once this PR is
merged.)
### Why is this needed?
This PR is needed because, for the Lodash optimization from
https://github.com/appsmithorg/appsmith/commit/7cbb12af886621256224be0c93e6a465dd710ad3,
we need to use `import type`. Otherwise, `babel-plugin-lodash` complains
that `LoDashStatic` is not a lodash function.
However, just using `import type` in the current codebase will give you
this:
<img width="962" alt="Screenshot 2023-03-08 at 17 45 59"
src="https://user-images.githubusercontent.com/2953267/223775744-407afa0c-e8b9-44a1-90f9-b879348da57f.png">
That’s because Prettier 1 can’t parse `import type` at all. To parse it,
we need to upgrade to Prettier 2.
### Why enforce `import type`?
Apart from just enabling `import type` support, this PR enforces
specifying `import type` everywhere it’s needed. (Developers will get
immediate TypeScript and ESLint errors when they forget to do so.)
I’m doing this because I believe `import type` improves DX and makes
refactorings easier.
Let’s say you had a few imports like below. Can you tell which of these
imports will increase the bundle size? (Tip: it’s not all of them!)
```ts
// app/client/src/workers/Linting/utils.ts
import { Position } from "codemirror";
import { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
It’s pretty hard, right?
What about now?
```ts
// app/client/src/workers/Linting/utils.ts
import type { Position } from "codemirror";
import type { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
Now, it’s clear that only `lodash` will be bundled.
This helps developers to see which imports are problematic, but it
_also_ helps with refactorings. Now, if you want to see where
`codemirror` is bundled, you can just grep for `import \{.*\} from
"codemirror"` – and you won’t get any type-only imports.
This also helps (some) bundlers. Upon transpiling, TypeScript erases
type-only imports completely. In some environment (not ours), this makes
the bundle smaller, as the bundler doesn’t need to bundle type-only
imports anymore.
## Type of change
- Chore (housekeeping or task changes that don't impact user perception)
## How Has This Been Tested?
This was tested to not break the build.
### Test Plan
> Add Testsmith test cases links that relate to this PR
### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
## Checklist:
### Dev activity
- [x] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag
### QA activity:
- [ ] Test plan has been approved by relevant developers
- [ ] Test plan has been peer reviewed by QA
- [ ] Cypress test cases have been added and approved by either SDET or
manual QA
- [ ] Organized project review call with relevant stakeholders after
Round 1/2 of QA
- [ ] Added Test Plan Approved label after reveiwing all Cypress test
---------
Co-authored-by: Satish Gandham <hello@satishgandham.com>
Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
2023-03-16 11:41:47 +00:00
|
|
|
} from "@appsmith/constants/ReduxActionConstants";
|
|
|
|
|
import {
|
|
|
|
|
ReduxActionErrorTypes,
|
2021-01-25 08:57:26 +00:00
|
|
|
ReduxActionTypes,
|
2021-08-03 08:06:48 +00:00
|
|
|
WidgetReduxActionTypes,
|
2022-04-12 10:50:01 +00:00
|
|
|
} from "@appsmith/constants/ReduxActionConstants";
|
2023-04-07 13:51:35 +00:00
|
|
|
import { resetWidgetMetaProperty } from "actions/metaActions";
|
|
|
|
|
import { selectWidgetInitAction } from "actions/widgetSelectionActions";
|
|
|
|
|
import {
|
|
|
|
|
GridDefaults,
|
|
|
|
|
MAIN_CONTAINER_WIDGET_ID,
|
|
|
|
|
RenderModes,
|
2023-07-27 13:00:23 +00:00
|
|
|
WIDGET_ID_SHOW_WALKTHROUGH,
|
2023-04-07 13:51:35 +00:00
|
|
|
} from "constants/WidgetConstants";
|
|
|
|
|
import log from "loglevel";
|
chore: upgrade to prettier v2 + enforce import types (#21013)Co-authored-by: Satish Gandham <hello@satishgandham.com> Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
## Description
This PR upgrades Prettier to v2 + enforces TypeScript’s [`import
type`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export)
syntax where applicable. It’s submitted as a separate PR so we can merge
it easily.
As a part of this PR, we reformat the codebase heavily:
- add `import type` everywhere where it’s required, and
- re-format the code to account for Prettier 2’s breaking changes:
https://prettier.io/blog/2020/03/21/2.0.0.html#breaking-changes
This PR is submitted against `release` to make sure all new code by team
members will adhere to new formatting standards, and we’ll have fewer
conflicts when merging `bundle-optimizations` into `release`. (I’ll
merge `release` back into `bundle-optimizations` once this PR is
merged.)
### Why is this needed?
This PR is needed because, for the Lodash optimization from
https://github.com/appsmithorg/appsmith/commit/7cbb12af886621256224be0c93e6a465dd710ad3,
we need to use `import type`. Otherwise, `babel-plugin-lodash` complains
that `LoDashStatic` is not a lodash function.
However, just using `import type` in the current codebase will give you
this:
<img width="962" alt="Screenshot 2023-03-08 at 17 45 59"
src="https://user-images.githubusercontent.com/2953267/223775744-407afa0c-e8b9-44a1-90f9-b879348da57f.png">
That’s because Prettier 1 can’t parse `import type` at all. To parse it,
we need to upgrade to Prettier 2.
### Why enforce `import type`?
Apart from just enabling `import type` support, this PR enforces
specifying `import type` everywhere it’s needed. (Developers will get
immediate TypeScript and ESLint errors when they forget to do so.)
I’m doing this because I believe `import type` improves DX and makes
refactorings easier.
Let’s say you had a few imports like below. Can you tell which of these
imports will increase the bundle size? (Tip: it’s not all of them!)
```ts
// app/client/src/workers/Linting/utils.ts
import { Position } from "codemirror";
import { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
It’s pretty hard, right?
What about now?
```ts
// app/client/src/workers/Linting/utils.ts
import type { Position } from "codemirror";
import type { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
Now, it’s clear that only `lodash` will be bundled.
This helps developers to see which imports are problematic, but it
_also_ helps with refactorings. Now, if you want to see where
`codemirror` is bundled, you can just grep for `import \{.*\} from
"codemirror"` – and you won’t get any type-only imports.
This also helps (some) bundlers. Upon transpiling, TypeScript erases
type-only imports completely. In some environment (not ours), this makes
the bundle smaller, as the bundler doesn’t need to bundle type-only
imports anymore.
## Type of change
- Chore (housekeeping or task changes that don't impact user perception)
## How Has This Been Tested?
This was tested to not break the build.
### Test Plan
> Add Testsmith test cases links that relate to this PR
### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
## Checklist:
### Dev activity
- [x] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag
### QA activity:
- [ ] Test plan has been approved by relevant developers
- [ ] Test plan has been peer reviewed by QA
- [ ] Cypress test cases have been added and approved by either SDET or
manual QA
- [ ] Organized project review call with relevant stakeholders after
Round 1/2 of QA
- [ ] Added Test Plan Approved label after reveiwing all Cypress test
---------
Co-authored-by: Satish Gandham <hello@satishgandham.com>
Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
2023-03-16 11:41:47 +00:00
|
|
|
import type { WidgetResize } from "actions/pageActions";
|
|
|
|
|
import { updateAndSaveLayout } from "actions/pageActions";
|
|
|
|
|
import type {
|
2020-09-16 10:28:01 +00:00
|
|
|
CanvasWidgetsReduxState,
|
2021-01-25 08:57:26 +00:00
|
|
|
FlattenedWidgetProps,
|
2020-09-16 10:28:01 +00:00
|
|
|
} from "reducers/entityReducers/canvasWidgetsReducer";
|
2020-03-06 09:45:21 +00:00
|
|
|
import {
|
2022-05-06 05:42:35 +00:00
|
|
|
actionChannel,
|
2021-01-25 08:57:26 +00:00
|
|
|
all,
|
2020-03-06 09:45:21 +00:00
|
|
|
call,
|
2021-06-17 13:26:54 +00:00
|
|
|
fork,
|
2020-03-06 09:45:21 +00:00
|
|
|
put,
|
|
|
|
|
select,
|
2023-01-28 02:17:06 +00:00
|
|
|
take,
|
2020-03-06 09:45:21 +00:00
|
|
|
takeEvery,
|
|
|
|
|
takeLatest,
|
2022-05-11 09:16:22 +00:00
|
|
|
takeLeading,
|
2020-03-06 09:45:21 +00:00
|
|
|
} from "redux-saga/effects";
|
2023-04-07 13:51:35 +00:00
|
|
|
import {
|
|
|
|
|
getCanvasWidth,
|
|
|
|
|
getContainerWidgetSpacesSelector,
|
|
|
|
|
getCurrentPageId,
|
|
|
|
|
getIsAutoLayout,
|
|
|
|
|
getIsAutoLayoutMobileBreakPoint,
|
|
|
|
|
} from "selectors/editorSelectors";
|
|
|
|
|
import AnalyticsUtil from "utils/AnalyticsUtil";
|
2021-09-21 07:55:56 +00:00
|
|
|
import { convertToString } from "utils/AppsmithUtils";
|
chore: upgrade to prettier v2 + enforce import types (#21013)Co-authored-by: Satish Gandham <hello@satishgandham.com> Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
## Description
This PR upgrades Prettier to v2 + enforces TypeScript’s [`import
type`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export)
syntax where applicable. It’s submitted as a separate PR so we can merge
it easily.
As a part of this PR, we reformat the codebase heavily:
- add `import type` everywhere where it’s required, and
- re-format the code to account for Prettier 2’s breaking changes:
https://prettier.io/blog/2020/03/21/2.0.0.html#breaking-changes
This PR is submitted against `release` to make sure all new code by team
members will adhere to new formatting standards, and we’ll have fewer
conflicts when merging `bundle-optimizations` into `release`. (I’ll
merge `release` back into `bundle-optimizations` once this PR is
merged.)
### Why is this needed?
This PR is needed because, for the Lodash optimization from
https://github.com/appsmithorg/appsmith/commit/7cbb12af886621256224be0c93e6a465dd710ad3,
we need to use `import type`. Otherwise, `babel-plugin-lodash` complains
that `LoDashStatic` is not a lodash function.
However, just using `import type` in the current codebase will give you
this:
<img width="962" alt="Screenshot 2023-03-08 at 17 45 59"
src="https://user-images.githubusercontent.com/2953267/223775744-407afa0c-e8b9-44a1-90f9-b879348da57f.png">
That’s because Prettier 1 can’t parse `import type` at all. To parse it,
we need to upgrade to Prettier 2.
### Why enforce `import type`?
Apart from just enabling `import type` support, this PR enforces
specifying `import type` everywhere it’s needed. (Developers will get
immediate TypeScript and ESLint errors when they forget to do so.)
I’m doing this because I believe `import type` improves DX and makes
refactorings easier.
Let’s say you had a few imports like below. Can you tell which of these
imports will increase the bundle size? (Tip: it’s not all of them!)
```ts
// app/client/src/workers/Linting/utils.ts
import { Position } from "codemirror";
import { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
It’s pretty hard, right?
What about now?
```ts
// app/client/src/workers/Linting/utils.ts
import type { Position } from "codemirror";
import type { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
Now, it’s clear that only `lodash` will be bundled.
This helps developers to see which imports are problematic, but it
_also_ helps with refactorings. Now, if you want to see where
`codemirror` is bundled, you can just grep for `import \{.*\} from
"codemirror"` – and you won’t get any type-only imports.
This also helps (some) bundlers. Upon transpiling, TypeScript erases
type-only imports completely. In some environment (not ours), this makes
the bundle smaller, as the bundler doesn’t need to bundle type-only
imports anymore.
## Type of change
- Chore (housekeeping or task changes that don't impact user perception)
## How Has This Been Tested?
This was tested to not break the build.
### Test Plan
> Add Testsmith test cases links that relate to this PR
### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
## Checklist:
### Dev activity
- [x] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag
### QA activity:
- [ ] Test plan has been approved by relevant developers
- [ ] Test plan has been peer reviewed by QA
- [ ] Cypress test cases have been added and approved by either SDET or
manual QA
- [ ] Organized project review call with relevant stakeholders after
Round 1/2 of QA
- [ ] Added Test Plan Approved label after reveiwing all Cypress test
---------
Co-authored-by: Satish Gandham <hello@satishgandham.com>
Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
2023-03-16 11:41:47 +00:00
|
|
|
import type {
|
2023-07-26 05:38:11 +00:00
|
|
|
BatchUpdateDynamicPropertyUpdates,
|
|
|
|
|
BatchUpdateWidgetDynamicPropertyPayload,
|
2021-01-25 08:57:26 +00:00
|
|
|
DeleteWidgetPropertyPayload,
|
2020-02-26 12:44:56 +00:00
|
|
|
SetWidgetDynamicPropertyPayload,
|
2021-01-25 08:57:26 +00:00
|
|
|
UpdateWidgetPropertyPayload,
|
2020-02-26 12:44:56 +00:00
|
|
|
UpdateWidgetPropertyRequestPayload,
|
|
|
|
|
} from "actions/controlActions";
|
2020-11-12 11:23:32 +00:00
|
|
|
import {
|
chore: upgrade to prettier v2 + enforce import types (#21013)Co-authored-by: Satish Gandham <hello@satishgandham.com> Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
## Description
This PR upgrades Prettier to v2 + enforces TypeScript’s [`import
type`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export)
syntax where applicable. It’s submitted as a separate PR so we can merge
it easily.
As a part of this PR, we reformat the codebase heavily:
- add `import type` everywhere where it’s required, and
- re-format the code to account for Prettier 2’s breaking changes:
https://prettier.io/blog/2020/03/21/2.0.0.html#breaking-changes
This PR is submitted against `release` to make sure all new code by team
members will adhere to new formatting standards, and we’ll have fewer
conflicts when merging `bundle-optimizations` into `release`. (I’ll
merge `release` back into `bundle-optimizations` once this PR is
merged.)
### Why is this needed?
This PR is needed because, for the Lodash optimization from
https://github.com/appsmithorg/appsmith/commit/7cbb12af886621256224be0c93e6a465dd710ad3,
we need to use `import type`. Otherwise, `babel-plugin-lodash` complains
that `LoDashStatic` is not a lodash function.
However, just using `import type` in the current codebase will give you
this:
<img width="962" alt="Screenshot 2023-03-08 at 17 45 59"
src="https://user-images.githubusercontent.com/2953267/223775744-407afa0c-e8b9-44a1-90f9-b879348da57f.png">
That’s because Prettier 1 can’t parse `import type` at all. To parse it,
we need to upgrade to Prettier 2.
### Why enforce `import type`?
Apart from just enabling `import type` support, this PR enforces
specifying `import type` everywhere it’s needed. (Developers will get
immediate TypeScript and ESLint errors when they forget to do so.)
I’m doing this because I believe `import type` improves DX and makes
refactorings easier.
Let’s say you had a few imports like below. Can you tell which of these
imports will increase the bundle size? (Tip: it’s not all of them!)
```ts
// app/client/src/workers/Linting/utils.ts
import { Position } from "codemirror";
import { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
It’s pretty hard, right?
What about now?
```ts
// app/client/src/workers/Linting/utils.ts
import type { Position } from "codemirror";
import type { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
Now, it’s clear that only `lodash` will be bundled.
This helps developers to see which imports are problematic, but it
_also_ helps with refactorings. Now, if you want to see where
`codemirror` is bundled, you can just grep for `import \{.*\} from
"codemirror"` – and you won’t get any type-only imports.
This also helps (some) bundlers. Upon transpiling, TypeScript erases
type-only imports completely. In some environment (not ours), this makes
the bundle smaller, as the bundler doesn’t need to bundle type-only
imports anymore.
## Type of change
- Chore (housekeeping or task changes that don't impact user perception)
## How Has This Been Tested?
This was tested to not break the build.
### Test Plan
> Add Testsmith test cases links that relate to this PR
### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
## Checklist:
### Dev activity
- [x] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag
### QA activity:
- [ ] Test plan has been approved by relevant developers
- [ ] Test plan has been peer reviewed by QA
- [ ] Cypress test cases have been added and approved by either SDET or
manual QA
- [ ] Organized project review call with relevant stakeholders after
Round 1/2 of QA
- [ ] Added Test Plan Approved label after reveiwing all Cypress test
---------
Co-authored-by: Satish Gandham <hello@satishgandham.com>
Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
2023-03-16 11:41:47 +00:00
|
|
|
batchUpdateWidgetProperty,
|
|
|
|
|
updateMultipleWidgetPropertiesAction,
|
|
|
|
|
} from "actions/controlActions";
|
|
|
|
|
import type { DynamicPath } from "utils/DynamicBindingUtils";
|
|
|
|
|
import {
|
2020-11-12 11:23:32 +00:00
|
|
|
getEntityDynamicBindingPathList,
|
|
|
|
|
getWidgetDynamicPropertyPathList,
|
|
|
|
|
getWidgetDynamicTriggerPathList,
|
2021-01-25 08:57:26 +00:00
|
|
|
isChildPropertyPath,
|
2020-11-12 11:23:32 +00:00
|
|
|
isDynamicValue,
|
|
|
|
|
isPathADynamicBinding,
|
2022-12-19 10:15:50 +00:00
|
|
|
isPathDynamicTrigger,
|
2020-11-12 11:23:32 +00:00
|
|
|
} from "utils/DynamicBindingUtils";
|
chore: upgrade to prettier v2 + enforce import types (#21013)Co-authored-by: Satish Gandham <hello@satishgandham.com> Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
## Description
This PR upgrades Prettier to v2 + enforces TypeScript’s [`import
type`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export)
syntax where applicable. It’s submitted as a separate PR so we can merge
it easily.
As a part of this PR, we reformat the codebase heavily:
- add `import type` everywhere where it’s required, and
- re-format the code to account for Prettier 2’s breaking changes:
https://prettier.io/blog/2020/03/21/2.0.0.html#breaking-changes
This PR is submitted against `release` to make sure all new code by team
members will adhere to new formatting standards, and we’ll have fewer
conflicts when merging `bundle-optimizations` into `release`. (I’ll
merge `release` back into `bundle-optimizations` once this PR is
merged.)
### Why is this needed?
This PR is needed because, for the Lodash optimization from
https://github.com/appsmithorg/appsmith/commit/7cbb12af886621256224be0c93e6a465dd710ad3,
we need to use `import type`. Otherwise, `babel-plugin-lodash` complains
that `LoDashStatic` is not a lodash function.
However, just using `import type` in the current codebase will give you
this:
<img width="962" alt="Screenshot 2023-03-08 at 17 45 59"
src="https://user-images.githubusercontent.com/2953267/223775744-407afa0c-e8b9-44a1-90f9-b879348da57f.png">
That’s because Prettier 1 can’t parse `import type` at all. To parse it,
we need to upgrade to Prettier 2.
### Why enforce `import type`?
Apart from just enabling `import type` support, this PR enforces
specifying `import type` everywhere it’s needed. (Developers will get
immediate TypeScript and ESLint errors when they forget to do so.)
I’m doing this because I believe `import type` improves DX and makes
refactorings easier.
Let’s say you had a few imports like below. Can you tell which of these
imports will increase the bundle size? (Tip: it’s not all of them!)
```ts
// app/client/src/workers/Linting/utils.ts
import { Position } from "codemirror";
import { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
It’s pretty hard, right?
What about now?
```ts
// app/client/src/workers/Linting/utils.ts
import type { Position } from "codemirror";
import type { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
Now, it’s clear that only `lodash` will be bundled.
This helps developers to see which imports are problematic, but it
_also_ helps with refactorings. Now, if you want to see where
`codemirror` is bundled, you can just grep for `import \{.*\} from
"codemirror"` – and you won’t get any type-only imports.
This also helps (some) bundlers. Upon transpiling, TypeScript erases
type-only imports completely. In some environment (not ours), this makes
the bundle smaller, as the bundler doesn’t need to bundle type-only
imports anymore.
## Type of change
- Chore (housekeeping or task changes that don't impact user perception)
## How Has This Been Tested?
This was tested to not break the build.
### Test Plan
> Add Testsmith test cases links that relate to this PR
### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
## Checklist:
### Dev activity
- [x] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag
### QA activity:
- [ ] Test plan has been approved by relevant developers
- [ ] Test plan has been peer reviewed by QA
- [ ] Cypress test cases have been added and approved by either SDET or
manual QA
- [ ] Organized project review call with relevant stakeholders after
Round 1/2 of QA
- [ ] Added Test Plan Approved label after reveiwing all Cypress test
---------
Co-authored-by: Satish Gandham <hello@satishgandham.com>
Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
2023-03-16 11:41:47 +00:00
|
|
|
import type { WidgetProps } from "widgets/BaseWidget";
|
2023-09-15 15:53:51 +00:00
|
|
|
import _, { cloneDeep, get, isString, set, uniq } from "lodash";
|
2023-09-06 12:15:04 +00:00
|
|
|
import WidgetFactory from "WidgetProvider/factory";
|
2020-09-16 10:28:01 +00:00
|
|
|
import { generateReactKey } from "utils/generators";
|
2023-04-07 13:51:35 +00:00
|
|
|
import { getCopiedWidgets, saveCopiedWidgets } from "utils/storage";
|
|
|
|
|
import { getWidget, getWidgets, getWidgetsMeta } from "./selectors";
|
2021-06-17 13:26:54 +00:00
|
|
|
|
2023-04-07 13:51:35 +00:00
|
|
|
import {
|
|
|
|
|
ERROR_WIDGET_COPY_NOT_ALLOWED,
|
|
|
|
|
ERROR_WIDGET_COPY_NO_WIDGET_SELECTED,
|
|
|
|
|
ERROR_WIDGET_CUT_NOT_ALLOWED,
|
|
|
|
|
ERROR_WIDGET_CUT_NO_WIDGET_SELECTED,
|
|
|
|
|
WIDGET_COPY,
|
|
|
|
|
WIDGET_CUT,
|
|
|
|
|
createMessage,
|
|
|
|
|
} from "@appsmith/constants/messages";
|
|
|
|
|
import { getAllPaths } from "@appsmith/workers/Evaluation/evaluationUtils";
|
2023-03-20 11:04:02 +00:00
|
|
|
import { getDataTree, getConfigTree } from "selectors/dataTreeSelectors";
|
2021-09-21 07:55:56 +00:00
|
|
|
import { validateProperty } from "./EvaluationsSaga";
|
chore: upgrade to prettier v2 + enforce import types (#21013)Co-authored-by: Satish Gandham <hello@satishgandham.com> Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
## Description
This PR upgrades Prettier to v2 + enforces TypeScript’s [`import
type`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export)
syntax where applicable. It’s submitted as a separate PR so we can merge
it easily.
As a part of this PR, we reformat the codebase heavily:
- add `import type` everywhere where it’s required, and
- re-format the code to account for Prettier 2’s breaking changes:
https://prettier.io/blog/2020/03/21/2.0.0.html#breaking-changes
This PR is submitted against `release` to make sure all new code by team
members will adhere to new formatting standards, and we’ll have fewer
conflicts when merging `bundle-optimizations` into `release`. (I’ll
merge `release` back into `bundle-optimizations` once this PR is
merged.)
### Why is this needed?
This PR is needed because, for the Lodash optimization from
https://github.com/appsmithorg/appsmith/commit/7cbb12af886621256224be0c93e6a465dd710ad3,
we need to use `import type`. Otherwise, `babel-plugin-lodash` complains
that `LoDashStatic` is not a lodash function.
However, just using `import type` in the current codebase will give you
this:
<img width="962" alt="Screenshot 2023-03-08 at 17 45 59"
src="https://user-images.githubusercontent.com/2953267/223775744-407afa0c-e8b9-44a1-90f9-b879348da57f.png">
That’s because Prettier 1 can’t parse `import type` at all. To parse it,
we need to upgrade to Prettier 2.
### Why enforce `import type`?
Apart from just enabling `import type` support, this PR enforces
specifying `import type` everywhere it’s needed. (Developers will get
immediate TypeScript and ESLint errors when they forget to do so.)
I’m doing this because I believe `import type` improves DX and makes
refactorings easier.
Let’s say you had a few imports like below. Can you tell which of these
imports will increase the bundle size? (Tip: it’s not all of them!)
```ts
// app/client/src/workers/Linting/utils.ts
import { Position } from "codemirror";
import { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
It’s pretty hard, right?
What about now?
```ts
// app/client/src/workers/Linting/utils.ts
import type { Position } from "codemirror";
import type { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
Now, it’s clear that only `lodash` will be bundled.
This helps developers to see which imports are problematic, but it
_also_ helps with refactorings. Now, if you want to see where
`codemirror` is bundled, you can just grep for `import \{.*\} from
"codemirror"` – and you won’t get any type-only imports.
This also helps (some) bundlers. Upon transpiling, TypeScript erases
type-only imports completely. In some environment (not ours), this makes
the bundle smaller, as the bundler doesn’t need to bundle type-only
imports anymore.
## Type of change
- Chore (housekeeping or task changes that don't impact user perception)
## How Has This Been Tested?
This was tested to not break the build.
### Test Plan
> Add Testsmith test cases links that relate to this PR
### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
## Checklist:
### Dev activity
- [x] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag
### QA activity:
- [ ] Test plan has been approved by relevant developers
- [ ] Test plan has been peer reviewed by QA
- [ ] Cypress test cases have been added and approved by either SDET or
manual QA
- [ ] Organized project review call with relevant stakeholders after
Round 1/2 of QA
- [ ] Added Test Plan Approved label after reveiwing all Cypress test
---------
Co-authored-by: Satish Gandham <hello@satishgandham.com>
Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
2023-03-16 11:41:47 +00:00
|
|
|
import type { ColumnProperties } from "widgets/TableWidget/component/Constants";
|
2021-03-16 05:01:37 +00:00
|
|
|
import {
|
|
|
|
|
getAllPathsFromPropertyConfig,
|
|
|
|
|
nextAvailableRowInContainer,
|
|
|
|
|
} from "entities/Widget/utils";
|
2023-04-07 13:51:35 +00:00
|
|
|
import { getSelectedWidgets } from "selectors/ui";
|
|
|
|
|
import { getReflow } from "selectors/widgetReflowSelectors";
|
2021-03-13 14:24:45 +00:00
|
|
|
import {
|
2023-04-07 13:51:35 +00:00
|
|
|
addChildToPastedFlexLayers,
|
|
|
|
|
getFlexLayersForSelectedWidgets,
|
|
|
|
|
getLayerIndexOfWidget,
|
|
|
|
|
getNewFlexLayers,
|
|
|
|
|
isStack,
|
|
|
|
|
pasteWidgetInFlexLayers,
|
2023-09-11 15:55:11 +00:00
|
|
|
} from "../layoutSystems/autolayout/utils/AutoLayoutUtils";
|
chore: upgrade to prettier v2 + enforce import types (#21013)Co-authored-by: Satish Gandham <hello@satishgandham.com> Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
## Description
This PR upgrades Prettier to v2 + enforces TypeScript’s [`import
type`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export)
syntax where applicable. It’s submitted as a separate PR so we can merge
it easily.
As a part of this PR, we reformat the codebase heavily:
- add `import type` everywhere where it’s required, and
- re-format the code to account for Prettier 2’s breaking changes:
https://prettier.io/blog/2020/03/21/2.0.0.html#breaking-changes
This PR is submitted against `release` to make sure all new code by team
members will adhere to new formatting standards, and we’ll have fewer
conflicts when merging `bundle-optimizations` into `release`. (I’ll
merge `release` back into `bundle-optimizations` once this PR is
merged.)
### Why is this needed?
This PR is needed because, for the Lodash optimization from
https://github.com/appsmithorg/appsmith/commit/7cbb12af886621256224be0c93e6a465dd710ad3,
we need to use `import type`. Otherwise, `babel-plugin-lodash` complains
that `LoDashStatic` is not a lodash function.
However, just using `import type` in the current codebase will give you
this:
<img width="962" alt="Screenshot 2023-03-08 at 17 45 59"
src="https://user-images.githubusercontent.com/2953267/223775744-407afa0c-e8b9-44a1-90f9-b879348da57f.png">
That’s because Prettier 1 can’t parse `import type` at all. To parse it,
we need to upgrade to Prettier 2.
### Why enforce `import type`?
Apart from just enabling `import type` support, this PR enforces
specifying `import type` everywhere it’s needed. (Developers will get
immediate TypeScript and ESLint errors when they forget to do so.)
I’m doing this because I believe `import type` improves DX and makes
refactorings easier.
Let’s say you had a few imports like below. Can you tell which of these
imports will increase the bundle size? (Tip: it’s not all of them!)
```ts
// app/client/src/workers/Linting/utils.ts
import { Position } from "codemirror";
import { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
It’s pretty hard, right?
What about now?
```ts
// app/client/src/workers/Linting/utils.ts
import type { Position } from "codemirror";
import type { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
Now, it’s clear that only `lodash` will be bundled.
This helps developers to see which imports are problematic, but it
_also_ helps with refactorings. Now, if you want to see where
`codemirror` is bundled, you can just grep for `import \{.*\} from
"codemirror"` – and you won’t get any type-only imports.
This also helps (some) bundlers. Upon transpiling, TypeScript erases
type-only imports completely. In some environment (not ours), this makes
the bundle smaller, as the bundler doesn’t need to bundle type-only
imports anymore.
## Type of change
- Chore (housekeeping or task changes that don't impact user perception)
## How Has This Been Tested?
This was tested to not break the build.
### Test Plan
> Add Testsmith test cases links that relate to this PR
### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
## Checklist:
### Dev activity
- [x] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag
### QA activity:
- [ ] Test plan has been approved by relevant developers
- [ ] Test plan has been peer reviewed by QA
- [ ] Cypress test cases have been added and approved by either SDET or
manual QA
- [ ] Organized project review call with relevant stakeholders after
Round 1/2 of QA
- [ ] Added Test Plan Approved label after reveiwing all Cypress test
---------
Co-authored-by: Satish Gandham <hello@satishgandham.com>
Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
2023-03-16 11:41:47 +00:00
|
|
|
import type {
|
|
|
|
|
CopiedWidgetGroup,
|
|
|
|
|
NewPastePositionVariables,
|
|
|
|
|
} from "./WidgetOperationUtils";
|
2023-04-07 13:51:35 +00:00
|
|
|
import { WIDGET_PASTE_PADDING } from "./WidgetOperationUtils";
|
2021-04-23 05:43:13 +00:00
|
|
|
import {
|
2023-01-28 02:17:06 +00:00
|
|
|
changeIdsOfPastePositions,
|
2021-08-25 05:00:31 +00:00
|
|
|
createSelectedWidgetsAsCopiedWidgets,
|
2023-01-28 02:17:06 +00:00
|
|
|
createWidgetCopy,
|
|
|
|
|
doesTriggerPathsContainPropertyPath,
|
2021-08-25 05:00:31 +00:00
|
|
|
filterOutSelectedWidgets,
|
2023-01-28 02:17:06 +00:00
|
|
|
getBoundariesFromSelectedWidgets,
|
2021-08-25 05:00:31 +00:00
|
|
|
getBoundaryWidgetsFromCopiedGroups,
|
2023-01-28 02:17:06 +00:00
|
|
|
getCanvasIdForContainer,
|
2022-05-04 07:58:57 +00:00
|
|
|
getContainerIdForCanvas,
|
2023-01-28 02:17:06 +00:00
|
|
|
getDefaultCanvas,
|
|
|
|
|
getMousePositions,
|
2022-05-04 07:58:57 +00:00
|
|
|
getNewPositionsForCopiedWidgets,
|
2023-01-28 02:17:06 +00:00
|
|
|
getNextWidgetName,
|
2022-05-04 07:58:57 +00:00
|
|
|
getOccupiedSpacesFromProps,
|
2023-01-28 02:17:06 +00:00
|
|
|
getParentWidgetIdForGrouping,
|
|
|
|
|
getParentWidgetIdForPasting,
|
2022-05-04 07:58:57 +00:00
|
|
|
getPastePositionMapFromMousePointer,
|
2023-01-28 02:17:06 +00:00
|
|
|
getReflowedPositions,
|
|
|
|
|
getSelectedWidgetWhenPasting,
|
|
|
|
|
getSnappedGrid,
|
2022-05-06 05:42:35 +00:00
|
|
|
getValueFromTree,
|
2022-05-11 09:16:22 +00:00
|
|
|
getVerifiedSelectedWidgets,
|
2023-01-28 02:17:06 +00:00
|
|
|
getVerticallyAdjustedPositions,
|
|
|
|
|
getWidgetDescendantToReset,
|
|
|
|
|
groupWidgetsIntoContainer,
|
|
|
|
|
handleSpecificCasesWhilePasting,
|
|
|
|
|
isDropTarget,
|
|
|
|
|
isSelectedWidgetsColliding,
|
2022-07-14 07:02:35 +00:00
|
|
|
mergeDynamicPropertyPaths,
|
2023-01-28 02:17:06 +00:00
|
|
|
purgeOrphanedDynamicPaths,
|
2021-04-23 05:43:13 +00:00
|
|
|
} from "./WidgetOperationUtils";
|
2023-11-17 07:16:18 +00:00
|
|
|
import {
|
|
|
|
|
partialImportSaga,
|
|
|
|
|
partialExportSaga,
|
|
|
|
|
widgetSelectionSagas,
|
|
|
|
|
} from "./WidgetSelectionSagas";
|
2023-10-10 12:32:17 +00:00
|
|
|
import type { WidgetEntityConfig } from "@appsmith/entities/DataTree/types";
|
|
|
|
|
import type { DataTree, ConfigTree } from "entities/DataTree/dataTreeTypes";
|
2022-01-25 15:28:31 +00:00
|
|
|
import { getCanvasSizeAfterWidgetMove } from "./CanvasSagas/DraggingCanvasSagas";
|
2021-09-21 07:55:56 +00:00
|
|
|
import widgetAdditionSagas from "./WidgetAdditionSagas";
|
|
|
|
|
import widgetDeletionSagas from "./WidgetDeletionSagas";
|
chore: upgrade to prettier v2 + enforce import types (#21013)Co-authored-by: Satish Gandham <hello@satishgandham.com> Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
## Description
This PR upgrades Prettier to v2 + enforces TypeScript’s [`import
type`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export)
syntax where applicable. It’s submitted as a separate PR so we can merge
it easily.
As a part of this PR, we reformat the codebase heavily:
- add `import type` everywhere where it’s required, and
- re-format the code to account for Prettier 2’s breaking changes:
https://prettier.io/blog/2020/03/21/2.0.0.html#breaking-changes
This PR is submitted against `release` to make sure all new code by team
members will adhere to new formatting standards, and we’ll have fewer
conflicts when merging `bundle-optimizations` into `release`. (I’ll
merge `release` back into `bundle-optimizations` once this PR is
merged.)
### Why is this needed?
This PR is needed because, for the Lodash optimization from
https://github.com/appsmithorg/appsmith/commit/7cbb12af886621256224be0c93e6a465dd710ad3,
we need to use `import type`. Otherwise, `babel-plugin-lodash` complains
that `LoDashStatic` is not a lodash function.
However, just using `import type` in the current codebase will give you
this:
<img width="962" alt="Screenshot 2023-03-08 at 17 45 59"
src="https://user-images.githubusercontent.com/2953267/223775744-407afa0c-e8b9-44a1-90f9-b879348da57f.png">
That’s because Prettier 1 can’t parse `import type` at all. To parse it,
we need to upgrade to Prettier 2.
### Why enforce `import type`?
Apart from just enabling `import type` support, this PR enforces
specifying `import type` everywhere it’s needed. (Developers will get
immediate TypeScript and ESLint errors when they forget to do so.)
I’m doing this because I believe `import type` improves DX and makes
refactorings easier.
Let’s say you had a few imports like below. Can you tell which of these
imports will increase the bundle size? (Tip: it’s not all of them!)
```ts
// app/client/src/workers/Linting/utils.ts
import { Position } from "codemirror";
import { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
It’s pretty hard, right?
What about now?
```ts
// app/client/src/workers/Linting/utils.ts
import type { Position } from "codemirror";
import type { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
Now, it’s clear that only `lodash` will be bundled.
This helps developers to see which imports are problematic, but it
_also_ helps with refactorings. Now, if you want to see where
`codemirror` is bundled, you can just grep for `import \{.*\} from
"codemirror"` – and you won’t get any type-only imports.
This also helps (some) bundlers. Upon transpiling, TypeScript erases
type-only imports completely. In some environment (not ours), this makes
the bundle smaller, as the bundler doesn’t need to bundle type-only
imports anymore.
## Type of change
- Chore (housekeeping or task changes that don't impact user perception)
## How Has This Been Tested?
This was tested to not break the build.
### Test Plan
> Add Testsmith test cases links that relate to this PR
### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
## Checklist:
### Dev activity
- [x] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag
### QA activity:
- [ ] Test plan has been approved by relevant developers
- [ ] Test plan has been peer reviewed by QA
- [ ] Cypress test cases have been added and approved by either SDET or
manual QA
- [ ] Organized project review call with relevant stakeholders after
Round 1/2 of QA
- [ ] Added Test Plan Approved label after reveiwing all Cypress test
---------
Co-authored-by: Satish Gandham <hello@satishgandham.com>
Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
2023-03-16 11:41:47 +00:00
|
|
|
import type { widgetReflow } from "reducers/uiReducers/reflowReducer";
|
2022-01-13 13:21:57 +00:00
|
|
|
import { stopReflowAction } from "actions/reflowActions";
|
2022-05-04 07:58:57 +00:00
|
|
|
import {
|
|
|
|
|
collisionCheckPostReflow,
|
|
|
|
|
getBottomRowAfterReflow,
|
|
|
|
|
} from "utils/reflowHookUtils";
|
chore: upgrade to prettier v2 + enforce import types (#21013)Co-authored-by: Satish Gandham <hello@satishgandham.com> Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
## Description
This PR upgrades Prettier to v2 + enforces TypeScript’s [`import
type`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export)
syntax where applicable. It’s submitted as a separate PR so we can merge
it easily.
As a part of this PR, we reformat the codebase heavily:
- add `import type` everywhere where it’s required, and
- re-format the code to account for Prettier 2’s breaking changes:
https://prettier.io/blog/2020/03/21/2.0.0.html#breaking-changes
This PR is submitted against `release` to make sure all new code by team
members will adhere to new formatting standards, and we’ll have fewer
conflicts when merging `bundle-optimizations` into `release`. (I’ll
merge `release` back into `bundle-optimizations` once this PR is
merged.)
### Why is this needed?
This PR is needed because, for the Lodash optimization from
https://github.com/appsmithorg/appsmith/commit/7cbb12af886621256224be0c93e6a465dd710ad3,
we need to use `import type`. Otherwise, `babel-plugin-lodash` complains
that `LoDashStatic` is not a lodash function.
However, just using `import type` in the current codebase will give you
this:
<img width="962" alt="Screenshot 2023-03-08 at 17 45 59"
src="https://user-images.githubusercontent.com/2953267/223775744-407afa0c-e8b9-44a1-90f9-b879348da57f.png">
That’s because Prettier 1 can’t parse `import type` at all. To parse it,
we need to upgrade to Prettier 2.
### Why enforce `import type`?
Apart from just enabling `import type` support, this PR enforces
specifying `import type` everywhere it’s needed. (Developers will get
immediate TypeScript and ESLint errors when they forget to do so.)
I’m doing this because I believe `import type` improves DX and makes
refactorings easier.
Let’s say you had a few imports like below. Can you tell which of these
imports will increase the bundle size? (Tip: it’s not all of them!)
```ts
// app/client/src/workers/Linting/utils.ts
import { Position } from "codemirror";
import { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
It’s pretty hard, right?
What about now?
```ts
// app/client/src/workers/Linting/utils.ts
import type { Position } from "codemirror";
import type { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
Now, it’s clear that only `lodash` will be bundled.
This helps developers to see which imports are problematic, but it
_also_ helps with refactorings. Now, if you want to see where
`codemirror` is bundled, you can just grep for `import \{.*\} from
"codemirror"` – and you won’t get any type-only imports.
This also helps (some) bundlers. Upon transpiling, TypeScript erases
type-only imports completely. In some environment (not ours), this makes
the bundle smaller, as the bundler doesn’t need to bundle type-only
imports anymore.
## Type of change
- Chore (housekeeping or task changes that don't impact user perception)
## How Has This Been Tested?
This was tested to not break the build.
### Test Plan
> Add Testsmith test cases links that relate to this PR
### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
## Checklist:
### Dev activity
- [x] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag
### QA activity:
- [ ] Test plan has been approved by relevant developers
- [ ] Test plan has been peer reviewed by QA
- [ ] Cypress test cases have been added and approved by either SDET or
manual QA
- [ ] Organized project review call with relevant stakeholders after
Round 1/2 of QA
- [ ] Added Test Plan Approved label after reveiwing all Cypress test
---------
Co-authored-by: Satish Gandham <hello@satishgandham.com>
Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
2023-03-16 11:41:47 +00:00
|
|
|
import type { GridProps, PrevReflowState, SpaceMap } from "reflow/reflowTypes";
|
|
|
|
|
import { ReflowDirection } from "reflow/reflowTypes";
|
|
|
|
|
import type { WidgetSpace } from "constants/CanvasEditorConstants";
|
2022-05-04 07:58:57 +00:00
|
|
|
import { reflow } from "reflow";
|
|
|
|
|
import { getBottomMostRow } from "reflow/reflowUtils";
|
|
|
|
|
import { flashElementsById } from "utils/helpers";
|
2022-12-29 11:07:54 +00:00
|
|
|
import { getSlidingArenaName } from "constants/componentClassNameConstants";
|
2023-10-12 05:31:22 +00:00
|
|
|
import { builderURL } from "@appsmith/RouteBuilder";
|
2022-06-09 11:47:47 +00:00
|
|
|
import history from "utils/history";
|
2022-11-23 09:48:23 +00:00
|
|
|
import { generateAutoHeightLayoutTreeAction } from "actions/autoHeightActions";
|
2023-02-21 04:13:25 +00:00
|
|
|
import {
|
|
|
|
|
executeWidgetBlueprintBeforeOperations,
|
|
|
|
|
traverseTreeAndExecuteBlueprintChildOperations,
|
|
|
|
|
} from "./WidgetBlueprintSagas";
|
chore: upgrade to prettier v2 + enforce import types (#21013)Co-authored-by: Satish Gandham <hello@satishgandham.com> Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
## Description
This PR upgrades Prettier to v2 + enforces TypeScript’s [`import
type`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export)
syntax where applicable. It’s submitted as a separate PR so we can merge
it easily.
As a part of this PR, we reformat the codebase heavily:
- add `import type` everywhere where it’s required, and
- re-format the code to account for Prettier 2’s breaking changes:
https://prettier.io/blog/2020/03/21/2.0.0.html#breaking-changes
This PR is submitted against `release` to make sure all new code by team
members will adhere to new formatting standards, and we’ll have fewer
conflicts when merging `bundle-optimizations` into `release`. (I’ll
merge `release` back into `bundle-optimizations` once this PR is
merged.)
### Why is this needed?
This PR is needed because, for the Lodash optimization from
https://github.com/appsmithorg/appsmith/commit/7cbb12af886621256224be0c93e6a465dd710ad3,
we need to use `import type`. Otherwise, `babel-plugin-lodash` complains
that `LoDashStatic` is not a lodash function.
However, just using `import type` in the current codebase will give you
this:
<img width="962" alt="Screenshot 2023-03-08 at 17 45 59"
src="https://user-images.githubusercontent.com/2953267/223775744-407afa0c-e8b9-44a1-90f9-b879348da57f.png">
That’s because Prettier 1 can’t parse `import type` at all. To parse it,
we need to upgrade to Prettier 2.
### Why enforce `import type`?
Apart from just enabling `import type` support, this PR enforces
specifying `import type` everywhere it’s needed. (Developers will get
immediate TypeScript and ESLint errors when they forget to do so.)
I’m doing this because I believe `import type` improves DX and makes
refactorings easier.
Let’s say you had a few imports like below. Can you tell which of these
imports will increase the bundle size? (Tip: it’s not all of them!)
```ts
// app/client/src/workers/Linting/utils.ts
import { Position } from "codemirror";
import { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
It’s pretty hard, right?
What about now?
```ts
// app/client/src/workers/Linting/utils.ts
import type { Position } from "codemirror";
import type { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
Now, it’s clear that only `lodash` will be bundled.
This helps developers to see which imports are problematic, but it
_also_ helps with refactorings. Now, if you want to see where
`codemirror` is bundled, you can just grep for `import \{.*\} from
"codemirror"` – and you won’t get any type-only imports.
This also helps (some) bundlers. Upon transpiling, TypeScript erases
type-only imports completely. In some environment (not ours), this makes
the bundle smaller, as the bundler doesn’t need to bundle type-only
imports anymore.
## Type of change
- Chore (housekeeping or task changes that don't impact user perception)
## How Has This Been Tested?
This was tested to not break the build.
### Test Plan
> Add Testsmith test cases links that relate to this PR
### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
## Checklist:
### Dev activity
- [x] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag
### QA activity:
- [ ] Test plan has been approved by relevant developers
- [ ] Test plan has been peer reviewed by QA
- [ ] Cypress test cases have been added and approved by either SDET or
manual QA
- [ ] Organized project review call with relevant stakeholders after
Round 1/2 of QA
- [ ] Added Test Plan Approved label after reveiwing all Cypress test
---------
Co-authored-by: Satish Gandham <hello@satishgandham.com>
Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
2023-03-16 11:41:47 +00:00
|
|
|
import type { MetaState } from "reducers/entityReducers/metaReducer";
|
2023-01-28 02:17:06 +00:00
|
|
|
import { SelectionRequestType } from "sagas/WidgetSelectUtils";
|
2023-09-06 12:15:04 +00:00
|
|
|
import { BlueprintOperationTypes } from "WidgetProvider/constants";
|
2023-05-19 18:37:06 +00:00
|
|
|
import { toast } from "design-system";
|
|
|
|
|
|
2023-10-04 08:54:16 +00:00
|
|
|
import { LayoutSystemTypes } from "layoutSystems/types";
|
2023-05-11 04:45:14 +00:00
|
|
|
import {
|
|
|
|
|
updatePositionsOfParentAndSiblings,
|
|
|
|
|
updateWidgetPositions,
|
2023-09-11 15:55:11 +00:00
|
|
|
} from "layoutSystems/autolayout/utils/positionUtils";
|
|
|
|
|
import { getWidgetWidth } from "layoutSystems/autolayout/utils/flexWidgetUtils";
|
2023-04-21 06:23:17 +00:00
|
|
|
import {
|
|
|
|
|
FlexLayerAlignment,
|
|
|
|
|
LayoutDirection,
|
2023-10-02 19:41:05 +00:00
|
|
|
} from "layoutSystems/common/utils/constants";
|
2023-07-27 13:00:23 +00:00
|
|
|
import localStorage from "utils/localStorage";
|
2023-10-02 19:41:05 +00:00
|
|
|
import type { FlexLayer } from "layoutSystems/autolayout/utils/types";
|
2023-09-15 15:53:51 +00:00
|
|
|
import { EMPTY_BINDING } from "components/editorComponents/ActionCreator/constants";
|
2023-10-04 08:54:16 +00:00
|
|
|
import { getLayoutSystemType } from "selectors/layoutSystemSelectors";
|
2023-11-15 12:31:54 +00:00
|
|
|
import { addSuggestedWidgetAnvilAction } from "layoutSystems/anvil/integrations/actions/draggingActions";
|
2023-12-29 02:41:49 +00:00
|
|
|
import { updateAndSaveAnvilLayout } from "layoutSystems/anvil/utils/anvilChecksUtils";
|
2023-03-04 07:25:54 +00:00
|
|
|
|
2019-09-22 20:25:05 +00:00
|
|
|
export function* resizeSaga(resizeAction: ReduxAction<WidgetResize>) {
|
|
|
|
|
try {
|
2023-05-19 18:37:06 +00:00
|
|
|
toast.dismiss();
|
2020-09-30 12:42:09 +00:00
|
|
|
const start = performance.now();
|
2023-04-07 13:51:35 +00:00
|
|
|
const stateWidgets: CanvasWidgetsReduxState = yield select(getWidgets);
|
|
|
|
|
const stateWidget: FlattenedWidgetProps = yield select(
|
|
|
|
|
getWidget,
|
|
|
|
|
resizeAction.payload.widgetId,
|
|
|
|
|
);
|
|
|
|
|
const isMobile: boolean = yield select(getIsAutoLayoutMobileBreakPoint);
|
|
|
|
|
const widgets = { ...stateWidgets };
|
|
|
|
|
let widget = { ...stateWidget };
|
2019-10-02 19:42:25 +00:00
|
|
|
const {
|
2023-04-07 13:51:35 +00:00
|
|
|
bottomRow = widget.bottomRow,
|
|
|
|
|
leftColumn = widget.leftColumn,
|
|
|
|
|
mobileBottomRow = widget.mobileBottomRow,
|
|
|
|
|
mobileLeftColumn = widget.mobileLeftColumn,
|
|
|
|
|
mobileRightColumn = widget.mobileRightColumn,
|
|
|
|
|
mobileTopRow = widget.mobileTopRow,
|
2021-09-21 07:55:56 +00:00
|
|
|
parentId,
|
2023-04-07 13:51:35 +00:00
|
|
|
rightColumn = widget.rightColumn,
|
2022-01-13 13:21:57 +00:00
|
|
|
snapColumnSpace,
|
|
|
|
|
snapRowSpace,
|
2023-04-07 13:51:35 +00:00
|
|
|
topRow = widget.topRow,
|
2021-05-13 08:35:39 +00:00
|
|
|
widgetId,
|
2019-10-02 19:42:25 +00:00
|
|
|
} = resizeAction.payload;
|
2019-09-22 20:25:05 +00:00
|
|
|
|
2023-10-11 07:14:38 +00:00
|
|
|
const layoutSystemType: LayoutSystemTypes =
|
|
|
|
|
yield select(getLayoutSystemType);
|
2023-04-07 13:51:35 +00:00
|
|
|
const mainCanvasWidth: number = yield select(getCanvasWidth);
|
|
|
|
|
widget = {
|
|
|
|
|
...widget,
|
|
|
|
|
leftColumn,
|
|
|
|
|
rightColumn,
|
|
|
|
|
topRow,
|
|
|
|
|
bottomRow,
|
|
|
|
|
mobileLeftColumn,
|
|
|
|
|
mobileRightColumn,
|
|
|
|
|
mobileTopRow,
|
|
|
|
|
mobileBottomRow,
|
|
|
|
|
};
|
|
|
|
|
|
2023-10-04 08:54:16 +00:00
|
|
|
if (layoutSystemType === LayoutSystemTypes.AUTO) {
|
2023-04-07 13:51:35 +00:00
|
|
|
// Keeps track of user defined widget width in terms of percentage
|
|
|
|
|
if (isMobile) {
|
|
|
|
|
widget.mobileWidthInPercentage =
|
|
|
|
|
(getWidgetWidth(widget, true) * snapColumnSpace) / mainCanvasWidth;
|
|
|
|
|
} else {
|
|
|
|
|
widget.widthInPercentage =
|
|
|
|
|
(getWidgetWidth(widget, false) * snapColumnSpace) / mainCanvasWidth;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-03 05:47:40 +00:00
|
|
|
const movedWidgets: {
|
2022-01-13 13:21:57 +00:00
|
|
|
[widgetId: string]: FlattenedWidgetProps;
|
|
|
|
|
} = yield call(
|
|
|
|
|
reflowWidgets,
|
|
|
|
|
widgets,
|
|
|
|
|
widget,
|
|
|
|
|
snapColumnSpace,
|
|
|
|
|
snapRowSpace,
|
|
|
|
|
);
|
|
|
|
|
|
2021-09-21 07:55:56 +00:00
|
|
|
const updatedCanvasBottomRow: number = yield call(
|
|
|
|
|
getCanvasSizeAfterWidgetMove,
|
|
|
|
|
parentId,
|
2022-01-25 15:28:31 +00:00
|
|
|
[widgetId],
|
2021-09-21 07:55:56 +00:00
|
|
|
bottomRow,
|
|
|
|
|
);
|
2023-05-11 04:45:14 +00:00
|
|
|
// If it is a fixed canvas, update bottomRow directly.
|
|
|
|
|
if (
|
|
|
|
|
updatedCanvasBottomRow &&
|
2023-10-04 08:54:16 +00:00
|
|
|
layoutSystemType === LayoutSystemTypes.FIXED
|
2023-05-11 04:45:14 +00:00
|
|
|
) {
|
2022-01-13 13:21:57 +00:00
|
|
|
const canvasWidget = movedWidgets[parentId];
|
|
|
|
|
movedWidgets[parentId] = {
|
2021-09-21 07:55:56 +00:00
|
|
|
...canvasWidget,
|
|
|
|
|
bottomRow: updatedCanvasBottomRow,
|
|
|
|
|
};
|
|
|
|
|
}
|
2023-06-09 08:52:27 +00:00
|
|
|
// If it is an auto-layout canvas, then use positionUtils to update canvas bottomRow.
|
2023-03-04 07:25:54 +00:00
|
|
|
let updatedWidgetsAfterResizing = movedWidgets;
|
2023-10-04 08:54:16 +00:00
|
|
|
if (layoutSystemType === LayoutSystemTypes.AUTO) {
|
2023-05-11 04:45:14 +00:00
|
|
|
const metaProps: Record<string, any> = yield select(getWidgetsMeta);
|
2023-04-07 13:51:35 +00:00
|
|
|
updatedWidgetsAfterResizing = updatePositionsOfParentAndSiblings(
|
2023-03-04 07:25:54 +00:00
|
|
|
movedWidgets,
|
|
|
|
|
parentId,
|
2023-04-07 13:51:35 +00:00
|
|
|
getLayerIndexOfWidget(widgets[parentId]?.flexLayers, widgetId),
|
2023-03-04 07:25:54 +00:00
|
|
|
isMobile,
|
2023-04-07 13:51:35 +00:00
|
|
|
mainCanvasWidth,
|
2023-05-11 04:45:14 +00:00
|
|
|
false,
|
|
|
|
|
metaProps,
|
2023-03-04 07:25:54 +00:00
|
|
|
);
|
|
|
|
|
}
|
2020-09-30 12:42:09 +00:00
|
|
|
log.debug("resize computations took", performance.now() - start, "ms");
|
2022-01-13 13:21:57 +00:00
|
|
|
yield put(stopReflowAction());
|
2023-03-04 07:25:54 +00:00
|
|
|
yield put(updateAndSaveLayout(updatedWidgetsAfterResizing));
|
2023-04-07 13:51:35 +00:00
|
|
|
|
|
|
|
|
// Widget resize based auto-height is only required for fixed-layout
|
|
|
|
|
// Auto-layout has UPDATE_WIDGET_DIMENSIONS to handle auto height
|
2023-10-04 08:54:16 +00:00
|
|
|
if (layoutSystemType === LayoutSystemTypes.FIXED) {
|
2023-04-07 13:51:35 +00:00
|
|
|
yield put(generateAutoHeightLayoutTreeAction(true, true));
|
|
|
|
|
}
|
2019-10-02 18:13:04 +00:00
|
|
|
} catch (error) {
|
2019-09-22 20:25:05 +00:00
|
|
|
yield put({
|
2019-10-02 18:13:04 +00:00
|
|
|
type: ReduxActionErrorTypes.WIDGET_OPERATION_ERROR,
|
|
|
|
|
payload: {
|
2021-08-03 08:06:48 +00:00
|
|
|
action: WidgetReduxActionTypes.WIDGET_RESIZE,
|
2019-10-02 18:13:04 +00:00
|
|
|
error,
|
|
|
|
|
},
|
2019-09-22 20:25:05 +00:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-09-19 22:25:37 +00:00
|
|
|
|
2022-01-13 13:21:57 +00:00
|
|
|
export function* reflowWidgets(
|
|
|
|
|
widgets: {
|
|
|
|
|
[widgetId: string]: FlattenedWidgetProps;
|
|
|
|
|
},
|
|
|
|
|
widget: FlattenedWidgetProps,
|
|
|
|
|
snapColumnSpace: number,
|
|
|
|
|
snapRowSpace: number,
|
|
|
|
|
) {
|
2022-04-20 13:03:30 +00:00
|
|
|
const reflowState: widgetReflow = yield select(getReflow);
|
2022-01-13 13:21:57 +00:00
|
|
|
|
|
|
|
|
const currentWidgets: {
|
|
|
|
|
[widgetId: string]: FlattenedWidgetProps;
|
|
|
|
|
} = { ...widgets, [widget.widgetId]: { ...widget } };
|
|
|
|
|
|
|
|
|
|
if (!reflowState || !reflowState.isReflowing || !reflowState.reflowingWidgets)
|
|
|
|
|
return currentWidgets;
|
|
|
|
|
|
|
|
|
|
const reflowingWidgets = reflowState.reflowingWidgets;
|
|
|
|
|
|
|
|
|
|
const reflowWidgetKeys = Object.keys(reflowingWidgets || {});
|
|
|
|
|
|
|
|
|
|
if (reflowWidgetKeys.length <= 0) return widgets;
|
|
|
|
|
|
|
|
|
|
for (const reflowedWidgetId of reflowWidgetKeys) {
|
|
|
|
|
const reflowWidget = reflowingWidgets[reflowedWidgetId];
|
|
|
|
|
const canvasWidget = { ...currentWidgets[reflowedWidgetId] };
|
|
|
|
|
if (reflowWidget.X !== undefined && reflowWidget.width !== undefined) {
|
|
|
|
|
const leftColumn =
|
|
|
|
|
canvasWidget.leftColumn + reflowWidget.X / snapColumnSpace;
|
|
|
|
|
const rightColumn = leftColumn + reflowWidget.width / snapColumnSpace;
|
|
|
|
|
currentWidgets[reflowedWidgetId] = {
|
|
|
|
|
...canvasWidget,
|
|
|
|
|
leftColumn,
|
|
|
|
|
rightColumn,
|
|
|
|
|
};
|
|
|
|
|
} else if (
|
|
|
|
|
reflowWidget.Y !== undefined &&
|
|
|
|
|
reflowWidget.height !== undefined
|
|
|
|
|
) {
|
|
|
|
|
const topRow = canvasWidget.topRow + reflowWidget.Y / snapRowSpace;
|
|
|
|
|
const bottomRow = topRow + reflowWidget.height / snapRowSpace;
|
|
|
|
|
currentWidgets[reflowedWidgetId] = { ...canvasWidget, topRow, bottomRow };
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
collisionCheckPostReflow(currentWidgets, reflowWidgetKeys, widget.parentId)
|
|
|
|
|
) {
|
|
|
|
|
return currentWidgets;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return widgets;
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-25 08:57:26 +00:00
|
|
|
enum DynamicPathUpdateEffectEnum {
|
|
|
|
|
ADD = "ADD",
|
|
|
|
|
REMOVE = "REMOVE",
|
|
|
|
|
NOOP = "NOOP",
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-11 07:35:24 +00:00
|
|
|
interface DynamicPathUpdate {
|
2021-01-25 08:57:26 +00:00
|
|
|
propertyPath: string;
|
|
|
|
|
effect: DynamicPathUpdateEffectEnum;
|
2023-10-11 07:35:24 +00:00
|
|
|
}
|
2021-01-25 08:57:26 +00:00
|
|
|
|
|
|
|
|
function getDynamicTriggerPathListUpdate(
|
2020-03-06 09:33:20 +00:00
|
|
|
widget: WidgetProps,
|
2020-11-12 11:23:32 +00:00
|
|
|
propertyPath: string,
|
2020-03-06 09:33:20 +00:00
|
|
|
propertyValue: string,
|
2021-01-25 08:57:26 +00:00
|
|
|
): DynamicPathUpdate {
|
2022-12-19 10:15:50 +00:00
|
|
|
if (propertyValue && !isPathDynamicTrigger(widget, propertyPath)) {
|
2021-01-25 08:57:26 +00:00
|
|
|
return {
|
|
|
|
|
propertyPath,
|
|
|
|
|
effect: DynamicPathUpdateEffectEnum.ADD,
|
|
|
|
|
};
|
2022-12-19 10:15:50 +00:00
|
|
|
} else if (!propertyValue && !isPathDynamicTrigger(widget, propertyPath)) {
|
2021-01-25 08:57:26 +00:00
|
|
|
return {
|
|
|
|
|
propertyPath,
|
|
|
|
|
effect: DynamicPathUpdateEffectEnum.REMOVE,
|
|
|
|
|
};
|
2019-11-06 06:35:15 +00:00
|
|
|
}
|
2021-01-25 08:57:26 +00:00
|
|
|
return {
|
|
|
|
|
propertyPath,
|
|
|
|
|
effect: DynamicPathUpdateEffectEnum.NOOP,
|
|
|
|
|
};
|
2020-03-06 09:33:20 +00:00
|
|
|
}
|
|
|
|
|
|
chore: misc updates to custom widget (#30114)
#### PR fixes following issue(s)
Fixes https://github.com/appsmithorg/appsmith/issues/29991
Fixes https://github.com/appsmithorg/appsmith/issues/30154
Fixes https://github.com/appsmithorg/appsmith/issues/30020
Fixes https://github.com/appsmithorg/appsmith/issues/30019
Fixes https://github.com/appsmithorg/appsmith/issues/30130
Fixes https://github.com/appsmithorg/appsmith/issues/30159
Fixes https://github.com/appsmithorg/appsmith/issues/30223
#### Media
> A video or a GIF is preferred. when using Loom, don’t embed because it
looks like it’s a GIF. instead, just link to the video
>
>
#### Type of change
> Please delete options that are not relevant.
- Bug fix (non-breaking change which fixes an issue)
- New feature (non-breaking change which adds functionality)
- Breaking change (fix or feature that would cause existing
functionality to not work as expected)
- Chore (housekeeping or task changes that don't impact user perception)
- This change requires a documentation update
>
>
>
## Testing
>
#### How Has This Been Tested?
> Please describe the tests that you ran to verify your changes. Also
list any relevant details for your test configuration.
> Delete anything that is not relevant
- [ ] Manual
- [ ] JUnit
- [ ] Jest
- [ ] Cypress
>
>
#### Test Plan
> Add Testsmith test cases links that relate to this PR
>
>
#### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
>
>
>
## Checklist:
#### Dev activity
- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag
#### QA activity:
- [ ] [Speedbreak
features](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#speedbreakers-)
have been covered
- [ ] Test plan covers all impacted features and [areas of
interest](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#areas-of-interest-)
- [ ] Test plan has been peer reviewed by project stakeholders and other
QA members
- [ ] Manually tested functionality on DP
- [ ] We had an implementation alignment call with stakeholders post QA
Round 2
- [ ] Cypress test cases have been added and approved by SDET/manual QA
- [ ] Added `Test Plan Approved` label after Cypress tests were reviewed
- [ ] Added `Test Plan Approved` label after JUnit tests were reviewed
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
- **New Features**
- Custom widgets now support analytics events, enhancing visibility into
user interactions.
- Template selection, layout controls, and reference triggers in the
Custom Widget Builder are now integrated with analytics.
- Added new style options for custom widgets, including `primaryColor`,
`backgroundColor`, `borderRadius`, and `boxShadow`.
- **Bug Fixes**
- Corrected a typo in the constant title for better clarity.
- Updated help text for the Container Widget to accurately describe the
widget's border edge.
- **Enhancements**
- Improved user interface with additional styling for reference names in
the Custom Widget Builder.
- Enhanced debugger functionality with `useCallback` optimization and
new analytics logging.
- **Refactor**
- Streamlined the property pane by introducing a new `LabelContainer`
styled component.
- Refined the handling of dynamic binding paths to ignore certain
properties efficiently.
- **Documentation**
- Added a new constant for the default model documentation URL in the
Custom Widget Builder.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2024-01-16 05:22:17 +00:00
|
|
|
const DYNAMIC_BINDING_IGNORED_LIST = [
|
|
|
|
|
/* Table widget */
|
|
|
|
|
"primaryColumns",
|
|
|
|
|
"derivedColumns",
|
|
|
|
|
|
|
|
|
|
/* custom widget */
|
|
|
|
|
"srcDoc.html",
|
|
|
|
|
"srcDoc.css",
|
|
|
|
|
"srcDoc.js",
|
|
|
|
|
"uncompiledSrcDoc.html",
|
|
|
|
|
"uncompiledSrcDoc.css",
|
|
|
|
|
"uncompiledSrcDoc.js",
|
|
|
|
|
];
|
|
|
|
|
|
2021-01-25 08:57:26 +00:00
|
|
|
function getDynamicBindingPathListUpdate(
|
2020-03-06 09:33:20 +00:00
|
|
|
widget: WidgetProps,
|
2021-01-25 08:57:26 +00:00
|
|
|
propertyPath: string,
|
2020-09-15 16:54:15 +00:00
|
|
|
propertyValue: any,
|
2021-01-25 08:57:26 +00:00
|
|
|
): DynamicPathUpdate {
|
2020-09-15 16:54:15 +00:00
|
|
|
let stringProp = propertyValue;
|
|
|
|
|
if (_.isObject(propertyValue)) {
|
|
|
|
|
// Stringify this because composite controls may have bindings in the sub controls
|
|
|
|
|
stringProp = JSON.stringify(propertyValue);
|
|
|
|
|
}
|
2021-02-16 10:29:08 +00:00
|
|
|
|
chore: misc updates to custom widget (#30114)
#### PR fixes following issue(s)
Fixes https://github.com/appsmithorg/appsmith/issues/29991
Fixes https://github.com/appsmithorg/appsmith/issues/30154
Fixes https://github.com/appsmithorg/appsmith/issues/30020
Fixes https://github.com/appsmithorg/appsmith/issues/30019
Fixes https://github.com/appsmithorg/appsmith/issues/30130
Fixes https://github.com/appsmithorg/appsmith/issues/30159
Fixes https://github.com/appsmithorg/appsmith/issues/30223
#### Media
> A video or a GIF is preferred. when using Loom, don’t embed because it
looks like it’s a GIF. instead, just link to the video
>
>
#### Type of change
> Please delete options that are not relevant.
- Bug fix (non-breaking change which fixes an issue)
- New feature (non-breaking change which adds functionality)
- Breaking change (fix or feature that would cause existing
functionality to not work as expected)
- Chore (housekeeping or task changes that don't impact user perception)
- This change requires a documentation update
>
>
>
## Testing
>
#### How Has This Been Tested?
> Please describe the tests that you ran to verify your changes. Also
list any relevant details for your test configuration.
> Delete anything that is not relevant
- [ ] Manual
- [ ] JUnit
- [ ] Jest
- [ ] Cypress
>
>
#### Test Plan
> Add Testsmith test cases links that relate to this PR
>
>
#### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
>
>
>
## Checklist:
#### Dev activity
- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag
#### QA activity:
- [ ] [Speedbreak
features](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#speedbreakers-)
have been covered
- [ ] Test plan covers all impacted features and [areas of
interest](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#areas-of-interest-)
- [ ] Test plan has been peer reviewed by project stakeholders and other
QA members
- [ ] Manually tested functionality on DP
- [ ] We had an implementation alignment call with stakeholders post QA
Round 2
- [ ] Cypress test cases have been added and approved by SDET/manual QA
- [ ] Added `Test Plan Approved` label after Cypress tests were reviewed
- [ ] Added `Test Plan Approved` label after JUnit tests were reviewed
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
- **New Features**
- Custom widgets now support analytics events, enhancing visibility into
user interactions.
- Template selection, layout controls, and reference triggers in the
Custom Widget Builder are now integrated with analytics.
- Added new style options for custom widgets, including `primaryColor`,
`backgroundColor`, `borderRadius`, and `boxShadow`.
- **Bug Fixes**
- Corrected a typo in the constant title for better clarity.
- Updated help text for the Container Widget to accurately describe the
widget's border edge.
- **Enhancements**
- Improved user interface with additional styling for reference names in
the Custom Widget Builder.
- Enhanced debugger functionality with `useCallback` optimization and
new analytics logging.
- **Refactor**
- Streamlined the property pane by introducing a new `LabelContainer`
styled component.
- Refined the handling of dynamic binding paths to ignore certain
properties efficiently.
- **Documentation**
- Added a new constant for the default model documentation URL in the
Custom Widget Builder.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2024-01-16 05:22:17 +00:00
|
|
|
/*
|
|
|
|
|
* TODO(Balaji Soundararajan): This is not appropriate from the platform's archtecture's point of view.
|
|
|
|
|
* This setting should come from widget configuration
|
|
|
|
|
*/
|
2021-02-16 10:29:08 +00:00
|
|
|
// Figure out a holistic solutions where we donot have to stringify above.
|
chore: misc updates to custom widget (#30114)
#### PR fixes following issue(s)
Fixes https://github.com/appsmithorg/appsmith/issues/29991
Fixes https://github.com/appsmithorg/appsmith/issues/30154
Fixes https://github.com/appsmithorg/appsmith/issues/30020
Fixes https://github.com/appsmithorg/appsmith/issues/30019
Fixes https://github.com/appsmithorg/appsmith/issues/30130
Fixes https://github.com/appsmithorg/appsmith/issues/30159
Fixes https://github.com/appsmithorg/appsmith/issues/30223
#### Media
> A video or a GIF is preferred. when using Loom, don’t embed because it
looks like it’s a GIF. instead, just link to the video
>
>
#### Type of change
> Please delete options that are not relevant.
- Bug fix (non-breaking change which fixes an issue)
- New feature (non-breaking change which adds functionality)
- Breaking change (fix or feature that would cause existing
functionality to not work as expected)
- Chore (housekeeping or task changes that don't impact user perception)
- This change requires a documentation update
>
>
>
## Testing
>
#### How Has This Been Tested?
> Please describe the tests that you ran to verify your changes. Also
list any relevant details for your test configuration.
> Delete anything that is not relevant
- [ ] Manual
- [ ] JUnit
- [ ] Jest
- [ ] Cypress
>
>
#### Test Plan
> Add Testsmith test cases links that relate to this PR
>
>
#### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
>
>
>
## Checklist:
#### Dev activity
- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag
#### QA activity:
- [ ] [Speedbreak
features](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#speedbreakers-)
have been covered
- [ ] Test plan covers all impacted features and [areas of
interest](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#areas-of-interest-)
- [ ] Test plan has been peer reviewed by project stakeholders and other
QA members
- [ ] Manually tested functionality on DP
- [ ] We had an implementation alignment call with stakeholders post QA
Round 2
- [ ] Cypress test cases have been added and approved by SDET/manual QA
- [ ] Added `Test Plan Approved` label after Cypress tests were reviewed
- [ ] Added `Test Plan Approved` label after JUnit tests were reviewed
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
- **New Features**
- Custom widgets now support analytics events, enhancing visibility into
user interactions.
- Template selection, layout controls, and reference triggers in the
Custom Widget Builder are now integrated with analytics.
- Added new style options for custom widgets, including `primaryColor`,
`backgroundColor`, `borderRadius`, and `boxShadow`.
- **Bug Fixes**
- Corrected a typo in the constant title for better clarity.
- Updated help text for the Container Widget to accurately describe the
widget's border edge.
- **Enhancements**
- Improved user interface with additional styling for reference names in
the Custom Widget Builder.
- Enhanced debugger functionality with `useCallback` optimization and
new analytics logging.
- **Refactor**
- Streamlined the property pane by introducing a new `LabelContainer`
styled component.
- Refined the handling of dynamic binding paths to ignore certain
properties efficiently.
- **Documentation**
- Added a new constant for the default model documentation URL in the
Custom Widget Builder.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2024-01-16 05:22:17 +00:00
|
|
|
if (DYNAMIC_BINDING_IGNORED_LIST.includes(propertyPath)) {
|
2021-02-16 10:29:08 +00:00
|
|
|
return {
|
|
|
|
|
propertyPath,
|
|
|
|
|
effect: DynamicPathUpdateEffectEnum.NOOP,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-15 16:54:15 +00:00
|
|
|
const isDynamic = isDynamicValue(stringProp);
|
2021-01-25 08:57:26 +00:00
|
|
|
if (!isDynamic && isPathADynamicBinding(widget, propertyPath)) {
|
|
|
|
|
return {
|
|
|
|
|
propertyPath,
|
|
|
|
|
effect: DynamicPathUpdateEffectEnum.REMOVE,
|
|
|
|
|
};
|
|
|
|
|
} else if (isDynamic && !isPathADynamicBinding(widget, propertyPath)) {
|
|
|
|
|
return {
|
|
|
|
|
propertyPath,
|
|
|
|
|
effect: DynamicPathUpdateEffectEnum.ADD,
|
|
|
|
|
};
|
2020-03-06 09:33:20 +00:00
|
|
|
}
|
2021-01-25 08:57:26 +00:00
|
|
|
return {
|
|
|
|
|
propertyPath,
|
|
|
|
|
effect: DynamicPathUpdateEffectEnum.NOOP,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function applyDynamicPathUpdates(
|
|
|
|
|
currentList: DynamicPath[],
|
|
|
|
|
update: DynamicPathUpdate,
|
|
|
|
|
): DynamicPath[] {
|
|
|
|
|
if (update.effect === DynamicPathUpdateEffectEnum.ADD) {
|
|
|
|
|
currentList.push({
|
|
|
|
|
key: update.propertyPath,
|
2020-11-12 11:23:32 +00:00
|
|
|
});
|
2021-01-25 08:57:26 +00:00
|
|
|
} else if (update.effect === DynamicPathUpdateEffectEnum.REMOVE) {
|
2021-03-04 18:35:41 +00:00
|
|
|
currentList = _.reject(currentList, { key: update.propertyPath });
|
2020-03-06 09:33:20 +00:00
|
|
|
}
|
2021-01-25 08:57:26 +00:00
|
|
|
return currentList;
|
2020-03-06 09:33:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function* updateWidgetPropertySaga(
|
|
|
|
|
updateAction: ReduxAction<UpdateWidgetPropertyRequestPayload>,
|
|
|
|
|
) {
|
|
|
|
|
const {
|
2021-05-13 08:35:39 +00:00
|
|
|
payload: { propertyPath, propertyValue, widgetId },
|
2020-03-06 09:33:20 +00:00
|
|
|
} = updateAction;
|
|
|
|
|
|
2021-01-25 08:57:26 +00:00
|
|
|
// Holder object to collect all updates
|
|
|
|
|
const updates: Record<string, unknown> = {
|
|
|
|
|
[propertyPath]: propertyValue,
|
|
|
|
|
};
|
2021-02-25 14:00:02 +00:00
|
|
|
// Push these updates via the batch update
|
|
|
|
|
yield call(
|
|
|
|
|
batchUpdateWidgetPropertySaga,
|
2021-03-01 09:45:54 +00:00
|
|
|
batchUpdateWidgetProperty(widgetId, { modify: updates }),
|
2020-03-06 09:33:20 +00:00
|
|
|
);
|
2020-02-26 12:44:56 +00:00
|
|
|
}
|
|
|
|
|
|
2022-05-05 06:38:27 +00:00
|
|
|
export function removeDynamicBindingProperties(
|
|
|
|
|
propertyPath: string,
|
|
|
|
|
dynamicBindingPathList: DynamicPath[],
|
|
|
|
|
) {
|
|
|
|
|
/*
|
2022-10-13 20:13:44 +00:00
|
|
|
we are doing this because when you toggle js off we only
|
2022-05-05 06:38:27 +00:00
|
|
|
receive the `primaryColumns.` properties not the `derivedColumns.`
|
|
|
|
|
properties therefore we need just a hard-codded check.
|
|
|
|
|
(TODO) - Arsalan remove this primaryColumns check when the Table widget v2 is live.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (_.startsWith(propertyPath, "primaryColumns")) {
|
|
|
|
|
// primaryColumns.customColumn1.isVisible -> customColumn1.isVisible
|
chore: upgrade to prettier v2 + enforce import types (#21013)Co-authored-by: Satish Gandham <hello@satishgandham.com> Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
## Description
This PR upgrades Prettier to v2 + enforces TypeScript’s [`import
type`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export)
syntax where applicable. It’s submitted as a separate PR so we can merge
it easily.
As a part of this PR, we reformat the codebase heavily:
- add `import type` everywhere where it’s required, and
- re-format the code to account for Prettier 2’s breaking changes:
https://prettier.io/blog/2020/03/21/2.0.0.html#breaking-changes
This PR is submitted against `release` to make sure all new code by team
members will adhere to new formatting standards, and we’ll have fewer
conflicts when merging `bundle-optimizations` into `release`. (I’ll
merge `release` back into `bundle-optimizations` once this PR is
merged.)
### Why is this needed?
This PR is needed because, for the Lodash optimization from
https://github.com/appsmithorg/appsmith/commit/7cbb12af886621256224be0c93e6a465dd710ad3,
we need to use `import type`. Otherwise, `babel-plugin-lodash` complains
that `LoDashStatic` is not a lodash function.
However, just using `import type` in the current codebase will give you
this:
<img width="962" alt="Screenshot 2023-03-08 at 17 45 59"
src="https://user-images.githubusercontent.com/2953267/223775744-407afa0c-e8b9-44a1-90f9-b879348da57f.png">
That’s because Prettier 1 can’t parse `import type` at all. To parse it,
we need to upgrade to Prettier 2.
### Why enforce `import type`?
Apart from just enabling `import type` support, this PR enforces
specifying `import type` everywhere it’s needed. (Developers will get
immediate TypeScript and ESLint errors when they forget to do so.)
I’m doing this because I believe `import type` improves DX and makes
refactorings easier.
Let’s say you had a few imports like below. Can you tell which of these
imports will increase the bundle size? (Tip: it’s not all of them!)
```ts
// app/client/src/workers/Linting/utils.ts
import { Position } from "codemirror";
import { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
It’s pretty hard, right?
What about now?
```ts
// app/client/src/workers/Linting/utils.ts
import type { Position } from "codemirror";
import type { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
Now, it’s clear that only `lodash` will be bundled.
This helps developers to see which imports are problematic, but it
_also_ helps with refactorings. Now, if you want to see where
`codemirror` is bundled, you can just grep for `import \{.*\} from
"codemirror"` – and you won’t get any type-only imports.
This also helps (some) bundlers. Upon transpiling, TypeScript erases
type-only imports completely. In some environment (not ours), this makes
the bundle smaller, as the bundler doesn’t need to bundle type-only
imports anymore.
## Type of change
- Chore (housekeeping or task changes that don't impact user perception)
## How Has This Been Tested?
This was tested to not break the build.
### Test Plan
> Add Testsmith test cases links that relate to this PR
### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
## Checklist:
### Dev activity
- [x] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag
### QA activity:
- [ ] Test plan has been approved by relevant developers
- [ ] Test plan has been peer reviewed by QA
- [ ] Cypress test cases have been added and approved by either SDET or
manual QA
- [ ] Organized project review call with relevant stakeholders after
Round 1/2 of QA
- [ ] Added Test Plan Approved label after reveiwing all Cypress test
---------
Co-authored-by: Satish Gandham <hello@satishgandham.com>
Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
2023-03-16 11:41:47 +00:00
|
|
|
const tableProperty = propertyPath.split(".").splice(1).join(".");
|
2022-05-05 06:38:27 +00:00
|
|
|
const tablePropertyPathsToRemove = [
|
|
|
|
|
propertyPath, // primaryColumns.customColumn1.isVisible
|
|
|
|
|
`derivedColumns.${tableProperty}`, // derivedColumns.customColumn1.isVisible
|
|
|
|
|
];
|
|
|
|
|
return _.reject(dynamicBindingPathList, ({ key }) =>
|
|
|
|
|
tablePropertyPathsToRemove.includes(key),
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
return _.reject(dynamicBindingPathList, {
|
|
|
|
|
key: propertyPath,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-26 05:38:11 +00:00
|
|
|
export function* handleUpdateWidgetDynamicProperty(
|
|
|
|
|
widget: WidgetProps,
|
|
|
|
|
update: BatchUpdateDynamicPropertyUpdates,
|
2020-02-26 12:44:56 +00:00
|
|
|
) {
|
2022-05-04 09:45:57 +00:00
|
|
|
const {
|
|
|
|
|
isDynamic,
|
|
|
|
|
propertyPath,
|
|
|
|
|
shouldRejectDynamicBindingPathList = true,
|
2023-06-16 09:16:56 +00:00
|
|
|
skipValidation = false,
|
2023-07-26 05:38:11 +00:00
|
|
|
} = update;
|
2021-05-24 06:57:33 +00:00
|
|
|
|
2023-07-26 05:38:11 +00:00
|
|
|
const propertyValue = _.get(widget, propertyPath);
|
2020-11-12 11:23:32 +00:00
|
|
|
let dynamicPropertyPathList = getWidgetDynamicPropertyPathList(widget);
|
2022-03-25 09:55:01 +00:00
|
|
|
let dynamicBindingPathList = getEntityDynamicBindingPathList(widget);
|
2023-07-26 05:38:11 +00:00
|
|
|
|
2020-02-26 12:44:56 +00:00
|
|
|
if (isDynamic) {
|
2021-03-09 05:30:57 +00:00
|
|
|
const keyExists =
|
|
|
|
|
dynamicPropertyPathList.findIndex((path) => path.key === propertyPath) >
|
|
|
|
|
-1;
|
|
|
|
|
if (!keyExists) {
|
|
|
|
|
dynamicPropertyPathList.push({
|
|
|
|
|
key: propertyPath,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
widget = set(widget, propertyPath, convertToString(propertyValue));
|
2020-02-26 12:44:56 +00:00
|
|
|
} else {
|
2020-11-12 11:23:32 +00:00
|
|
|
dynamicPropertyPathList = _.reject(dynamicPropertyPathList, {
|
2021-01-25 08:57:26 +00:00
|
|
|
key: propertyPath,
|
2020-11-12 11:23:32 +00:00
|
|
|
});
|
2022-05-04 09:45:57 +00:00
|
|
|
|
|
|
|
|
if (shouldRejectDynamicBindingPathList) {
|
2022-05-05 06:38:27 +00:00
|
|
|
dynamicBindingPathList = removeDynamicBindingProperties(
|
|
|
|
|
propertyPath,
|
|
|
|
|
dynamicBindingPathList,
|
|
|
|
|
);
|
2022-05-04 09:45:57 +00:00
|
|
|
}
|
2023-06-01 17:26:05 +00:00
|
|
|
|
2023-06-16 09:16:56 +00:00
|
|
|
/*
|
|
|
|
|
* We need to run the validation function to parse the value present in the
|
|
|
|
|
* js mode to use that in the non js mode.
|
|
|
|
|
* - if the value is valid to be used on non js mode, we will use the same value
|
|
|
|
|
* - if the value is invalid to be used on non js mode, we will use the default value
|
|
|
|
|
* returned by the validation function.
|
|
|
|
|
*
|
|
|
|
|
* Sometimes (eg: in one click binding control) we don't want to do validation and retain the
|
|
|
|
|
* same value while switching from js to non js mode. use `skipValidation` flag to turn off validation.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (!skipValidation) {
|
|
|
|
|
const { parsed } = yield call(
|
|
|
|
|
validateProperty,
|
|
|
|
|
propertyPath,
|
|
|
|
|
propertyValue,
|
|
|
|
|
widget,
|
|
|
|
|
);
|
2023-06-01 17:26:05 +00:00
|
|
|
|
2023-06-16 09:16:56 +00:00
|
|
|
widget = set(widget, propertyPath, parsed);
|
|
|
|
|
}
|
2020-02-26 12:44:56 +00:00
|
|
|
}
|
2021-03-09 05:30:57 +00:00
|
|
|
widget.dynamicPropertyPathList = dynamicPropertyPathList;
|
2022-03-25 09:55:01 +00:00
|
|
|
widget.dynamicBindingPathList = dynamicBindingPathList;
|
2023-07-26 05:38:11 +00:00
|
|
|
return widget;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function* batchUpdateWidgetDynamicPropertySaga(
|
|
|
|
|
action: ReduxAction<BatchUpdateWidgetDynamicPropertyPayload>,
|
|
|
|
|
) {
|
|
|
|
|
const { updates, widgetId } = action.payload;
|
|
|
|
|
const stateWidget: WidgetProps = yield select(getWidget, widgetId);
|
|
|
|
|
let widget = cloneDeep({ ...stateWidget });
|
|
|
|
|
|
|
|
|
|
for (const update of updates) {
|
|
|
|
|
widget = yield call(handleUpdateWidgetDynamicProperty, widget, update);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const stateWidgets: CanvasWidgetsReduxState = yield select(getWidgets);
|
|
|
|
|
const widgets = { ...stateWidgets, [widgetId]: widget };
|
|
|
|
|
// Save the layout
|
|
|
|
|
yield put(updateAndSaveLayout(widgets));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function* setWidgetDynamicPropertySaga(
|
|
|
|
|
action: ReduxAction<SetWidgetDynamicPropertyPayload>,
|
|
|
|
|
) {
|
|
|
|
|
const {
|
|
|
|
|
isDynamic,
|
|
|
|
|
propertyPath,
|
|
|
|
|
shouldRejectDynamicBindingPathList = true,
|
|
|
|
|
skipValidation = false,
|
|
|
|
|
widgetId,
|
|
|
|
|
} = action.payload;
|
|
|
|
|
const stateWidget: WidgetProps = yield select(getWidget, widgetId);
|
|
|
|
|
let widget = cloneDeep({ ...stateWidget });
|
|
|
|
|
const update = {
|
|
|
|
|
isDynamic,
|
|
|
|
|
propertyPath,
|
|
|
|
|
shouldRejectDynamicBindingPathList,
|
|
|
|
|
skipValidation,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
widget = yield call(handleUpdateWidgetDynamicProperty, widget, update);
|
|
|
|
|
|
2023-09-15 15:53:51 +00:00
|
|
|
const propertyValue = get(widget, propertyPath);
|
|
|
|
|
if (!propertyValue && isDynamic) {
|
|
|
|
|
set(widget, propertyPath, EMPTY_BINDING);
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-21 13:57:34 +00:00
|
|
|
const stateWidgets: CanvasWidgetsReduxState = yield select(getWidgets);
|
2021-01-25 08:57:26 +00:00
|
|
|
const widgets = { ...stateWidgets, [widgetId]: widget };
|
|
|
|
|
|
|
|
|
|
// Save the layout
|
|
|
|
|
yield put(updateAndSaveLayout(widgets));
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-04 09:45:57 +00:00
|
|
|
export function getPropertiesToUpdate(
|
2021-03-04 18:35:41 +00:00
|
|
|
widget: WidgetProps,
|
2021-03-01 09:45:54 +00:00
|
|
|
updates: Record<string, unknown>,
|
2021-04-23 05:43:13 +00:00
|
|
|
triggerPaths?: string[],
|
2021-03-04 18:35:41 +00:00
|
|
|
): {
|
|
|
|
|
propertyUpdates: Record<string, unknown>;
|
|
|
|
|
dynamicTriggerPathList: DynamicPath[];
|
|
|
|
|
dynamicBindingPathList: DynamicPath[];
|
|
|
|
|
} {
|
2021-02-25 14:00:02 +00:00
|
|
|
// Create a
|
|
|
|
|
const widgetWithUpdates = _.cloneDeep(widget);
|
|
|
|
|
Object.entries(updates).forEach(([propertyPath, propertyValue]) => {
|
|
|
|
|
set(widgetWithUpdates, propertyPath, propertyValue);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// get the flat list of all updates (in case values are objects)
|
|
|
|
|
const updatePaths = getAllPaths(updates);
|
|
|
|
|
|
|
|
|
|
const propertyUpdates: Record<string, unknown> = {
|
|
|
|
|
...updates,
|
|
|
|
|
};
|
chore: upgrade to prettier v2 + enforce import types (#21013)Co-authored-by: Satish Gandham <hello@satishgandham.com> Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
## Description
This PR upgrades Prettier to v2 + enforces TypeScript’s [`import
type`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export)
syntax where applicable. It’s submitted as a separate PR so we can merge
it easily.
As a part of this PR, we reformat the codebase heavily:
- add `import type` everywhere where it’s required, and
- re-format the code to account for Prettier 2’s breaking changes:
https://prettier.io/blog/2020/03/21/2.0.0.html#breaking-changes
This PR is submitted against `release` to make sure all new code by team
members will adhere to new formatting standards, and we’ll have fewer
conflicts when merging `bundle-optimizations` into `release`. (I’ll
merge `release` back into `bundle-optimizations` once this PR is
merged.)
### Why is this needed?
This PR is needed because, for the Lodash optimization from
https://github.com/appsmithorg/appsmith/commit/7cbb12af886621256224be0c93e6a465dd710ad3,
we need to use `import type`. Otherwise, `babel-plugin-lodash` complains
that `LoDashStatic` is not a lodash function.
However, just using `import type` in the current codebase will give you
this:
<img width="962" alt="Screenshot 2023-03-08 at 17 45 59"
src="https://user-images.githubusercontent.com/2953267/223775744-407afa0c-e8b9-44a1-90f9-b879348da57f.png">
That’s because Prettier 1 can’t parse `import type` at all. To parse it,
we need to upgrade to Prettier 2.
### Why enforce `import type`?
Apart from just enabling `import type` support, this PR enforces
specifying `import type` everywhere it’s needed. (Developers will get
immediate TypeScript and ESLint errors when they forget to do so.)
I’m doing this because I believe `import type` improves DX and makes
refactorings easier.
Let’s say you had a few imports like below. Can you tell which of these
imports will increase the bundle size? (Tip: it’s not all of them!)
```ts
// app/client/src/workers/Linting/utils.ts
import { Position } from "codemirror";
import { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
It’s pretty hard, right?
What about now?
```ts
// app/client/src/workers/Linting/utils.ts
import type { Position } from "codemirror";
import type { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
Now, it’s clear that only `lodash` will be bundled.
This helps developers to see which imports are problematic, but it
_also_ helps with refactorings. Now, if you want to see where
`codemirror` is bundled, you can just grep for `import \{.*\} from
"codemirror"` – and you won’t get any type-only imports.
This also helps (some) bundlers. Upon transpiling, TypeScript erases
type-only imports completely. In some environment (not ours), this makes
the bundle smaller, as the bundler doesn’t need to bundle type-only
imports anymore.
## Type of change
- Chore (housekeeping or task changes that don't impact user perception)
## How Has This Been Tested?
This was tested to not break the build.
### Test Plan
> Add Testsmith test cases links that relate to this PR
### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
## Checklist:
### Dev activity
- [x] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag
### QA activity:
- [ ] Test plan has been approved by relevant developers
- [ ] Test plan has been peer reviewed by QA
- [ ] Cypress test cases have been added and approved by either SDET or
manual QA
- [ ] Organized project review call with relevant stakeholders after
Round 1/2 of QA
- [ ] Added Test Plan Approved label after reveiwing all Cypress test
---------
Co-authored-by: Satish Gandham <hello@satishgandham.com>
Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
2023-03-16 11:41:47 +00:00
|
|
|
const currentDynamicTriggerPathList: DynamicPath[] =
|
|
|
|
|
getWidgetDynamicTriggerPathList(widget);
|
|
|
|
|
const currentDynamicBindingPathList: DynamicPath[] =
|
|
|
|
|
getEntityDynamicBindingPathList(widget);
|
2021-01-25 08:57:26 +00:00
|
|
|
const dynamicTriggerPathListUpdates: DynamicPathUpdate[] = [];
|
|
|
|
|
const dynamicBindingPathListUpdates: DynamicPathUpdate[] = [];
|
2021-02-25 14:00:02 +00:00
|
|
|
|
2023-11-14 04:33:37 +00:00
|
|
|
const widgetConfig = WidgetFactory.getWidgetPropertyPaneConfig(
|
|
|
|
|
widget.type,
|
|
|
|
|
widget,
|
|
|
|
|
);
|
chore: upgrade to prettier v2 + enforce import types (#21013)Co-authored-by: Satish Gandham <hello@satishgandham.com> Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
## Description
This PR upgrades Prettier to v2 + enforces TypeScript’s [`import
type`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export)
syntax where applicable. It’s submitted as a separate PR so we can merge
it easily.
As a part of this PR, we reformat the codebase heavily:
- add `import type` everywhere where it’s required, and
- re-format the code to account for Prettier 2’s breaking changes:
https://prettier.io/blog/2020/03/21/2.0.0.html#breaking-changes
This PR is submitted against `release` to make sure all new code by team
members will adhere to new formatting standards, and we’ll have fewer
conflicts when merging `bundle-optimizations` into `release`. (I’ll
merge `release` back into `bundle-optimizations` once this PR is
merged.)
### Why is this needed?
This PR is needed because, for the Lodash optimization from
https://github.com/appsmithorg/appsmith/commit/7cbb12af886621256224be0c93e6a465dd710ad3,
we need to use `import type`. Otherwise, `babel-plugin-lodash` complains
that `LoDashStatic` is not a lodash function.
However, just using `import type` in the current codebase will give you
this:
<img width="962" alt="Screenshot 2023-03-08 at 17 45 59"
src="https://user-images.githubusercontent.com/2953267/223775744-407afa0c-e8b9-44a1-90f9-b879348da57f.png">
That’s because Prettier 1 can’t parse `import type` at all. To parse it,
we need to upgrade to Prettier 2.
### Why enforce `import type`?
Apart from just enabling `import type` support, this PR enforces
specifying `import type` everywhere it’s needed. (Developers will get
immediate TypeScript and ESLint errors when they forget to do so.)
I’m doing this because I believe `import type` improves DX and makes
refactorings easier.
Let’s say you had a few imports like below. Can you tell which of these
imports will increase the bundle size? (Tip: it’s not all of them!)
```ts
// app/client/src/workers/Linting/utils.ts
import { Position } from "codemirror";
import { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
It’s pretty hard, right?
What about now?
```ts
// app/client/src/workers/Linting/utils.ts
import type { Position } from "codemirror";
import type { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
Now, it’s clear that only `lodash` will be bundled.
This helps developers to see which imports are problematic, but it
_also_ helps with refactorings. Now, if you want to see where
`codemirror` is bundled, you can just grep for `import \{.*\} from
"codemirror"` – and you won’t get any type-only imports.
This also helps (some) bundlers. Upon transpiling, TypeScript erases
type-only imports completely. In some environment (not ours), this makes
the bundle smaller, as the bundler doesn’t need to bundle type-only
imports anymore.
## Type of change
- Chore (housekeeping or task changes that don't impact user perception)
## How Has This Been Tested?
This was tested to not break the build.
### Test Plan
> Add Testsmith test cases links that relate to this PR
### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
## Checklist:
### Dev activity
- [x] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag
### QA activity:
- [ ] Test plan has been approved by relevant developers
- [ ] Test plan has been peer reviewed by QA
- [ ] Cypress test cases have been added and approved by either SDET or
manual QA
- [ ] Organized project review call with relevant stakeholders after
Round 1/2 of QA
- [ ] Added Test Plan Approved label after reveiwing all Cypress test
---------
Co-authored-by: Satish Gandham <hello@satishgandham.com>
Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
2023-03-16 11:41:47 +00:00
|
|
|
const { triggerPaths: triggerPathsFromPropertyConfig = {} } =
|
|
|
|
|
getAllPathsFromPropertyConfig(widgetWithUpdates, widgetConfig, {});
|
2021-10-27 12:58:34 +00:00
|
|
|
|
2021-02-25 14:00:02 +00:00
|
|
|
Object.keys(updatePaths).forEach((propertyPath) => {
|
2022-05-06 05:42:35 +00:00
|
|
|
const propertyValue = getValueFromTree(updates, propertyPath);
|
2021-02-25 14:00:02 +00:00
|
|
|
// only check if
|
|
|
|
|
if (!_.isString(propertyValue)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-01-25 08:57:26 +00:00
|
|
|
|
2021-10-27 12:58:34 +00:00
|
|
|
let isTriggerProperty = propertyPath in triggerPathsFromPropertyConfig;
|
2021-02-16 10:29:08 +00:00
|
|
|
|
2021-04-23 05:43:13 +00:00
|
|
|
isTriggerProperty = doesTriggerPathsContainPropertyPath(
|
|
|
|
|
isTriggerProperty,
|
|
|
|
|
propertyPath,
|
|
|
|
|
triggerPaths,
|
|
|
|
|
);
|
|
|
|
|
|
2021-01-25 08:57:26 +00:00
|
|
|
// If it is a trigger property, it will go in a different list than the general
|
|
|
|
|
// dynamicBindingPathList.
|
2021-02-25 14:00:02 +00:00
|
|
|
if (isTriggerProperty) {
|
2021-01-25 08:57:26 +00:00
|
|
|
dynamicTriggerPathListUpdates.push(
|
|
|
|
|
getDynamicTriggerPathListUpdate(widget, propertyPath, propertyValue),
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
dynamicBindingPathListUpdates.push(
|
|
|
|
|
getDynamicBindingPathListUpdate(widget, propertyPath, propertyValue),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2021-02-25 14:00:02 +00:00
|
|
|
const dynamicTriggerPathList = dynamicTriggerPathListUpdates.reduce(
|
2021-01-25 08:57:26 +00:00
|
|
|
applyDynamicPathUpdates,
|
|
|
|
|
currentDynamicTriggerPathList,
|
|
|
|
|
);
|
2021-02-25 14:00:02 +00:00
|
|
|
const dynamicBindingPathList = dynamicBindingPathListUpdates.reduce(
|
2021-01-25 08:57:26 +00:00
|
|
|
applyDynamicPathUpdates,
|
|
|
|
|
currentDynamicBindingPathList,
|
|
|
|
|
);
|
|
|
|
|
|
2021-03-01 09:45:54 +00:00
|
|
|
return {
|
|
|
|
|
propertyUpdates,
|
|
|
|
|
dynamicTriggerPathList,
|
|
|
|
|
dynamicBindingPathList,
|
|
|
|
|
};
|
2021-01-25 08:57:26 +00:00
|
|
|
}
|
|
|
|
|
|
2022-11-23 09:48:23 +00:00
|
|
|
export function* getIsContainerLikeWidget(widget: FlattenedWidgetProps) {
|
|
|
|
|
const children = widget.children;
|
|
|
|
|
if (Array.isArray(children) && children.length > 0) {
|
|
|
|
|
const firstChild: FlattenedWidgetProps = yield select(
|
|
|
|
|
getWidget,
|
|
|
|
|
children[0],
|
|
|
|
|
);
|
|
|
|
|
if (firstChild.type === "CANVAS_WIDGET") return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2023-01-28 02:17:06 +00:00
|
|
|
|
2021-09-21 07:55:56 +00:00
|
|
|
export function* getPropertiesUpdatedWidget(
|
|
|
|
|
updatesObj: UpdateWidgetPropertyPayload,
|
2021-01-25 08:57:26 +00:00
|
|
|
) {
|
2022-07-14 07:02:35 +00:00
|
|
|
const { dynamicUpdates, updates, widgetId } = updatesObj;
|
2021-09-21 07:55:56 +00:00
|
|
|
|
2023-10-11 07:14:38 +00:00
|
|
|
const { modify = {}, postUpdateAction, remove = [], triggerPaths } = updates;
|
2021-01-25 08:57:26 +00:00
|
|
|
|
2021-03-01 09:45:54 +00:00
|
|
|
const stateWidget: WidgetProps = yield select(getWidget, widgetId);
|
2021-03-05 04:34:35 +00:00
|
|
|
|
|
|
|
|
// if there is no widget in the state, don't do anything
|
|
|
|
|
if (!stateWidget) return;
|
|
|
|
|
|
2021-03-01 09:45:54 +00:00
|
|
|
let widget = cloneDeep(stateWidget);
|
|
|
|
|
try {
|
|
|
|
|
if (Object.keys(modify).length > 0) {
|
|
|
|
|
const {
|
|
|
|
|
dynamicBindingPathList,
|
2021-05-13 08:35:39 +00:00
|
|
|
dynamicTriggerPathList,
|
|
|
|
|
propertyUpdates,
|
2021-04-23 05:43:13 +00:00
|
|
|
} = getPropertiesToUpdate(widget, modify, triggerPaths);
|
2021-03-01 09:45:54 +00:00
|
|
|
|
|
|
|
|
// We loop over all updates
|
|
|
|
|
Object.entries(propertyUpdates).forEach(
|
|
|
|
|
([propertyPath, propertyValue]) => {
|
|
|
|
|
// since property paths could be nested, we use lodash set method
|
|
|
|
|
widget = set(widget, propertyPath, propertyValue);
|
|
|
|
|
},
|
|
|
|
|
);
|
2021-03-04 18:35:41 +00:00
|
|
|
widget.dynamicBindingPathList = dynamicBindingPathList;
|
|
|
|
|
widget.dynamicTriggerPathList = dynamicTriggerPathList;
|
2022-07-14 07:02:35 +00:00
|
|
|
|
|
|
|
|
if (dynamicUpdates?.dynamicPropertyPathList?.length) {
|
|
|
|
|
widget.dynamicPropertyPathList = mergeDynamicPropertyPaths(
|
|
|
|
|
widget.dynamicPropertyPathList,
|
|
|
|
|
dynamicUpdates.dynamicPropertyPathList,
|
|
|
|
|
);
|
|
|
|
|
}
|
2021-03-01 09:45:54 +00:00
|
|
|
}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
log.debug("Error updating property paths: ", { e });
|
|
|
|
|
}
|
2021-01-25 08:57:26 +00:00
|
|
|
|
2021-03-01 09:45:54 +00:00
|
|
|
if (Array.isArray(remove) && remove.length > 0) {
|
|
|
|
|
widget = yield removeWidgetProperties(widget, remove);
|
|
|
|
|
}
|
2022-02-02 09:25:16 +00:00
|
|
|
|
|
|
|
|
// Note: This may not be the best place to do this.
|
|
|
|
|
// If there exists another spot in this workflow, where we are iterating over the dynamicTriggerPathList and dynamicBindingPathList, after
|
|
|
|
|
// performing all updates to the widget, we can piggy back on that iteration to purge orphaned paths
|
|
|
|
|
// I couldn't find it, so here it is.
|
2022-11-23 09:48:23 +00:00
|
|
|
return {
|
|
|
|
|
updatedWidget: purgeOrphanedDynamicPaths(widget),
|
|
|
|
|
actionToDispatch: postUpdateAction,
|
|
|
|
|
};
|
2021-09-21 07:55:56 +00:00
|
|
|
}
|
2021-01-25 08:57:26 +00:00
|
|
|
|
2021-09-21 07:55:56 +00:00
|
|
|
function* batchUpdateWidgetPropertySaga(
|
|
|
|
|
action: ReduxAction<UpdateWidgetPropertyPayload>,
|
|
|
|
|
) {
|
|
|
|
|
const start = performance.now();
|
|
|
|
|
const { shouldReplay, widgetId } = action.payload;
|
|
|
|
|
if (!widgetId) {
|
|
|
|
|
// Handling the case where sometimes widget id is not passed through here
|
|
|
|
|
return;
|
|
|
|
|
}
|
2022-11-23 09:48:23 +00:00
|
|
|
const updatedWidgetAndActionsToDispatch: {
|
|
|
|
|
updatedWidget: WidgetProps;
|
|
|
|
|
actionToDispatch?: ReduxActionType;
|
|
|
|
|
} = yield call(getPropertiesUpdatedWidget, action.payload);
|
2022-06-21 13:57:34 +00:00
|
|
|
const stateWidgets: CanvasWidgetsReduxState = yield select(getWidgets);
|
2022-11-23 09:48:23 +00:00
|
|
|
const widgets = {
|
|
|
|
|
...stateWidgets,
|
|
|
|
|
[widgetId]: updatedWidgetAndActionsToDispatch.updatedWidget,
|
|
|
|
|
};
|
2021-03-01 09:45:54 +00:00
|
|
|
log.debug(
|
|
|
|
|
"Batch widget property update calculations took: ",
|
2023-02-14 16:07:31 +00:00
|
|
|
action,
|
2021-03-01 09:45:54 +00:00
|
|
|
performance.now() - start,
|
|
|
|
|
"ms",
|
|
|
|
|
);
|
2021-01-25 08:57:26 +00:00
|
|
|
// Save the layout
|
2022-08-19 10:10:36 +00:00
|
|
|
yield put(updateAndSaveLayout(widgets, { shouldReplay }));
|
2022-11-23 09:48:23 +00:00
|
|
|
if (updatedWidgetAndActionsToDispatch.actionToDispatch) {
|
|
|
|
|
yield put({
|
|
|
|
|
type: updatedWidgetAndActionsToDispatch.actionToDispatch,
|
|
|
|
|
payload: { widgetId },
|
|
|
|
|
});
|
|
|
|
|
}
|
2021-09-21 07:55:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function* batchUpdateMultipleWidgetsPropertiesSaga(
|
|
|
|
|
action: ReduxAction<{ updatesArray: UpdateWidgetPropertyPayload[] }>,
|
|
|
|
|
) {
|
|
|
|
|
const start = performance.now();
|
|
|
|
|
const { updatesArray } = action.payload;
|
2022-06-21 13:57:34 +00:00
|
|
|
const stateWidgets: CanvasWidgetsReduxState = yield select(getWidgets);
|
2022-11-23 09:48:23 +00:00
|
|
|
const updatedWidgetsAndActionsToDispatch: Array<{
|
|
|
|
|
updatedWidget: WidgetProps;
|
|
|
|
|
actionToDispatch?: ReduxActionType;
|
|
|
|
|
}> = yield all(
|
2021-09-21 07:55:56 +00:00
|
|
|
updatesArray.map((eachUpdate) => {
|
|
|
|
|
return call(getPropertiesUpdatedWidget, eachUpdate);
|
|
|
|
|
}),
|
|
|
|
|
);
|
2022-11-23 09:48:23 +00:00
|
|
|
|
|
|
|
|
const updatedStateWidgets = updatedWidgetsAndActionsToDispatch.reduce(
|
|
|
|
|
(allWidgets, eachUpdatedWidgetAndActionsToDispatch) => {
|
2021-09-21 07:55:56 +00:00
|
|
|
return {
|
|
|
|
|
...allWidgets,
|
2022-11-23 09:48:23 +00:00
|
|
|
[eachUpdatedWidgetAndActionsToDispatch.updatedWidget.widgetId]:
|
|
|
|
|
eachUpdatedWidgetAndActionsToDispatch.updatedWidget,
|
2021-09-21 07:55:56 +00:00
|
|
|
};
|
|
|
|
|
},
|
|
|
|
|
stateWidgets,
|
|
|
|
|
);
|
|
|
|
|
|
2022-11-23 09:48:23 +00:00
|
|
|
const updatedWidgetIds = uniq(
|
|
|
|
|
updatedWidgetsAndActionsToDispatch.map(
|
|
|
|
|
(each) => each.updatedWidget.widgetId,
|
|
|
|
|
),
|
|
|
|
|
);
|
2022-08-19 10:10:36 +00:00
|
|
|
|
2021-09-21 07:55:56 +00:00
|
|
|
log.debug(
|
|
|
|
|
"Batch multi-widget properties update calculations took: ",
|
|
|
|
|
performance.now() - start,
|
|
|
|
|
"ms",
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Save the layout
|
2022-08-19 10:10:36 +00:00
|
|
|
yield put(
|
|
|
|
|
updateAndSaveLayout(updatedStateWidgets, {
|
|
|
|
|
updatedWidgetIds,
|
|
|
|
|
}),
|
|
|
|
|
);
|
2022-11-23 09:48:23 +00:00
|
|
|
for (const updatedWidgetAndActions of updatedWidgetsAndActionsToDispatch) {
|
|
|
|
|
if (updatedWidgetAndActions.actionToDispatch) {
|
|
|
|
|
yield put({
|
|
|
|
|
type: updatedWidgetAndActions.actionToDispatch,
|
|
|
|
|
payload: { widgetId: updatedWidgetAndActions.updatedWidget.widgetId },
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-11-06 06:35:15 +00:00
|
|
|
}
|
|
|
|
|
|
2021-03-01 09:45:54 +00:00
|
|
|
function* removeWidgetProperties(widget: WidgetProps, paths: string[]) {
|
|
|
|
|
try {
|
chore: upgrade to prettier v2 + enforce import types (#21013)Co-authored-by: Satish Gandham <hello@satishgandham.com> Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
## Description
This PR upgrades Prettier to v2 + enforces TypeScript’s [`import
type`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export)
syntax where applicable. It’s submitted as a separate PR so we can merge
it easily.
As a part of this PR, we reformat the codebase heavily:
- add `import type` everywhere where it’s required, and
- re-format the code to account for Prettier 2’s breaking changes:
https://prettier.io/blog/2020/03/21/2.0.0.html#breaking-changes
This PR is submitted against `release` to make sure all new code by team
members will adhere to new formatting standards, and we’ll have fewer
conflicts when merging `bundle-optimizations` into `release`. (I’ll
merge `release` back into `bundle-optimizations` once this PR is
merged.)
### Why is this needed?
This PR is needed because, for the Lodash optimization from
https://github.com/appsmithorg/appsmith/commit/7cbb12af886621256224be0c93e6a465dd710ad3,
we need to use `import type`. Otherwise, `babel-plugin-lodash` complains
that `LoDashStatic` is not a lodash function.
However, just using `import type` in the current codebase will give you
this:
<img width="962" alt="Screenshot 2023-03-08 at 17 45 59"
src="https://user-images.githubusercontent.com/2953267/223775744-407afa0c-e8b9-44a1-90f9-b879348da57f.png">
That’s because Prettier 1 can’t parse `import type` at all. To parse it,
we need to upgrade to Prettier 2.
### Why enforce `import type`?
Apart from just enabling `import type` support, this PR enforces
specifying `import type` everywhere it’s needed. (Developers will get
immediate TypeScript and ESLint errors when they forget to do so.)
I’m doing this because I believe `import type` improves DX and makes
refactorings easier.
Let’s say you had a few imports like below. Can you tell which of these
imports will increase the bundle size? (Tip: it’s not all of them!)
```ts
// app/client/src/workers/Linting/utils.ts
import { Position } from "codemirror";
import { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
It’s pretty hard, right?
What about now?
```ts
// app/client/src/workers/Linting/utils.ts
import type { Position } from "codemirror";
import type { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
Now, it’s clear that only `lodash` will be bundled.
This helps developers to see which imports are problematic, but it
_also_ helps with refactorings. Now, if you want to see where
`codemirror` is bundled, you can just grep for `import \{.*\} from
"codemirror"` – and you won’t get any type-only imports.
This also helps (some) bundlers. Upon transpiling, TypeScript erases
type-only imports completely. In some environment (not ours), this makes
the bundle smaller, as the bundler doesn’t need to bundle type-only
imports anymore.
## Type of change
- Chore (housekeeping or task changes that don't impact user perception)
## How Has This Been Tested?
This was tested to not break the build.
### Test Plan
> Add Testsmith test cases links that relate to this PR
### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
## Checklist:
### Dev activity
- [x] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag
### QA activity:
- [ ] Test plan has been approved by relevant developers
- [ ] Test plan has been peer reviewed by QA
- [ ] Cypress test cases have been added and approved by either SDET or
manual QA
- [ ] Organized project review call with relevant stakeholders after
Round 1/2 of QA
- [ ] Added Test Plan Approved label after reveiwing all Cypress test
---------
Co-authored-by: Satish Gandham <hello@satishgandham.com>
Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
2023-03-16 11:41:47 +00:00
|
|
|
let dynamicTriggerPathList: DynamicPath[] =
|
|
|
|
|
getWidgetDynamicTriggerPathList(widget);
|
|
|
|
|
let dynamicBindingPathList: DynamicPath[] =
|
|
|
|
|
getEntityDynamicBindingPathList(widget);
|
|
|
|
|
let dynamicPropertyPathList: DynamicPath[] =
|
|
|
|
|
getWidgetDynamicPropertyPathList(widget);
|
2021-03-01 09:45:54 +00:00
|
|
|
|
|
|
|
|
paths.forEach((propertyPath) => {
|
|
|
|
|
dynamicTriggerPathList = dynamicTriggerPathList.filter((dynamicPath) => {
|
|
|
|
|
return !isChildPropertyPath(propertyPath, dynamicPath.key);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
dynamicBindingPathList = dynamicBindingPathList.filter((dynamicPath) => {
|
|
|
|
|
return !isChildPropertyPath(propertyPath, dynamicPath.key);
|
|
|
|
|
});
|
2021-04-27 07:16:54 +00:00
|
|
|
|
|
|
|
|
dynamicPropertyPathList = dynamicPropertyPathList.filter(
|
|
|
|
|
(dynamicPath) => {
|
|
|
|
|
return !isChildPropertyPath(propertyPath, dynamicPath.key);
|
|
|
|
|
},
|
|
|
|
|
);
|
2021-03-01 09:45:54 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
widget.dynamicBindingPathList = dynamicBindingPathList;
|
|
|
|
|
widget.dynamicTriggerPathList = dynamicTriggerPathList;
|
2021-04-27 07:16:54 +00:00
|
|
|
widget.dynamicPropertyPathList = dynamicPropertyPathList;
|
|
|
|
|
|
2021-03-01 09:45:54 +00:00
|
|
|
paths.forEach((propertyPath) => {
|
|
|
|
|
widget = unsetPropertyPath(widget, propertyPath) as WidgetProps;
|
|
|
|
|
});
|
|
|
|
|
} catch (e) {
|
|
|
|
|
log.debug("Error removing propertyPaths: ", { e });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return widget;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function* deleteWidgetPropertySaga(
|
|
|
|
|
action: ReduxAction<DeleteWidgetPropertyPayload>,
|
|
|
|
|
) {
|
2021-05-13 08:35:39 +00:00
|
|
|
const { propertyPaths, widgetId } = action.payload;
|
2021-03-01 09:45:54 +00:00
|
|
|
if (!widgetId) {
|
|
|
|
|
// Handling the case where sometimes widget id is not passed through here
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
yield put(batchUpdateWidgetProperty(widgetId, { remove: propertyPaths }));
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-16 10:29:08 +00:00
|
|
|
//TODO(abhinav): Move this to helpers and add tests
|
|
|
|
|
const unsetPropertyPath = (obj: Record<string, unknown>, path: string) => {
|
|
|
|
|
const regex = /(.*)\[\d+\]$/;
|
|
|
|
|
if (regex.test(path)) {
|
|
|
|
|
const matches = path.match(regex);
|
|
|
|
|
if (
|
|
|
|
|
matches &&
|
|
|
|
|
Array.isArray(matches) &&
|
|
|
|
|
matches[1] &&
|
|
|
|
|
matches[1].length > 0
|
|
|
|
|
) {
|
|
|
|
|
_.unset(obj, path);
|
|
|
|
|
const arr = _.get(obj, matches[1]);
|
|
|
|
|
if (arr && Array.isArray(arr)) {
|
|
|
|
|
_.set(obj, matches[1], arr.filter(Boolean));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
_.unset(obj, path);
|
|
|
|
|
}
|
|
|
|
|
return obj;
|
|
|
|
|
};
|
|
|
|
|
|
2020-03-06 09:45:21 +00:00
|
|
|
function* resetChildrenMetaSaga(action: ReduxAction<{ widgetId: string }>) {
|
2022-06-25 05:30:54 +00:00
|
|
|
const { widgetId: parentWidgetId } = action.payload;
|
2021-07-06 06:54:34 +00:00
|
|
|
const canvasWidgets: CanvasWidgetsReduxState = yield select(getWidgets);
|
2022-06-25 05:30:54 +00:00
|
|
|
const evaluatedDataTree: DataTree = yield select(getDataTree);
|
2023-03-20 11:04:02 +00:00
|
|
|
const configTree: ConfigTree = yield select(getConfigTree);
|
2022-12-15 08:23:09 +00:00
|
|
|
const widgetsMeta: MetaState = yield select(getWidgetsMeta);
|
|
|
|
|
const childrenList = getWidgetDescendantToReset(
|
2021-07-06 06:54:34 +00:00
|
|
|
canvasWidgets,
|
|
|
|
|
parentWidgetId,
|
2022-06-25 05:30:54 +00:00
|
|
|
evaluatedDataTree,
|
2022-12-15 08:23:09 +00:00
|
|
|
widgetsMeta,
|
2021-07-06 06:54:34 +00:00
|
|
|
);
|
2022-06-25 05:30:54 +00:00
|
|
|
|
|
|
|
|
for (const childIndex in childrenList) {
|
chore: upgrade to prettier v2 + enforce import types (#21013)Co-authored-by: Satish Gandham <hello@satishgandham.com> Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
## Description
This PR upgrades Prettier to v2 + enforces TypeScript’s [`import
type`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export)
syntax where applicable. It’s submitted as a separate PR so we can merge
it easily.
As a part of this PR, we reformat the codebase heavily:
- add `import type` everywhere where it’s required, and
- re-format the code to account for Prettier 2’s breaking changes:
https://prettier.io/blog/2020/03/21/2.0.0.html#breaking-changes
This PR is submitted against `release` to make sure all new code by team
members will adhere to new formatting standards, and we’ll have fewer
conflicts when merging `bundle-optimizations` into `release`. (I’ll
merge `release` back into `bundle-optimizations` once this PR is
merged.)
### Why is this needed?
This PR is needed because, for the Lodash optimization from
https://github.com/appsmithorg/appsmith/commit/7cbb12af886621256224be0c93e6a465dd710ad3,
we need to use `import type`. Otherwise, `babel-plugin-lodash` complains
that `LoDashStatic` is not a lodash function.
However, just using `import type` in the current codebase will give you
this:
<img width="962" alt="Screenshot 2023-03-08 at 17 45 59"
src="https://user-images.githubusercontent.com/2953267/223775744-407afa0c-e8b9-44a1-90f9-b879348da57f.png">
That’s because Prettier 1 can’t parse `import type` at all. To parse it,
we need to upgrade to Prettier 2.
### Why enforce `import type`?
Apart from just enabling `import type` support, this PR enforces
specifying `import type` everywhere it’s needed. (Developers will get
immediate TypeScript and ESLint errors when they forget to do so.)
I’m doing this because I believe `import type` improves DX and makes
refactorings easier.
Let’s say you had a few imports like below. Can you tell which of these
imports will increase the bundle size? (Tip: it’s not all of them!)
```ts
// app/client/src/workers/Linting/utils.ts
import { Position } from "codemirror";
import { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
It’s pretty hard, right?
What about now?
```ts
// app/client/src/workers/Linting/utils.ts
import type { Position } from "codemirror";
import type { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
Now, it’s clear that only `lodash` will be bundled.
This helps developers to see which imports are problematic, but it
_also_ helps with refactorings. Now, if you want to see where
`codemirror` is bundled, you can just grep for `import \{.*\} from
"codemirror"` – and you won’t get any type-only imports.
This also helps (some) bundlers. Upon transpiling, TypeScript erases
type-only imports completely. In some environment (not ours), this makes
the bundle smaller, as the bundler doesn’t need to bundle type-only
imports anymore.
## Type of change
- Chore (housekeeping or task changes that don't impact user perception)
## How Has This Been Tested?
This was tested to not break the build.
### Test Plan
> Add Testsmith test cases links that relate to this PR
### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
## Checklist:
### Dev activity
- [x] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag
### QA activity:
- [ ] Test plan has been approved by relevant developers
- [ ] Test plan has been peer reviewed by QA
- [ ] Cypress test cases have been added and approved by either SDET or
manual QA
- [ ] Organized project review call with relevant stakeholders after
Round 1/2 of QA
- [ ] Added Test Plan Approved label after reveiwing all Cypress test
---------
Co-authored-by: Satish Gandham <hello@satishgandham.com>
Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
2023-03-16 11:41:47 +00:00
|
|
|
const { evaluatedWidget: childWidget, id: childId } =
|
|
|
|
|
childrenList[childIndex];
|
2023-03-20 11:04:02 +00:00
|
|
|
const evaluatedWidgetConfig =
|
|
|
|
|
childWidget && configTree[childWidget?.widgetName];
|
|
|
|
|
yield put(
|
|
|
|
|
resetWidgetMetaProperty(
|
|
|
|
|
childId,
|
|
|
|
|
childWidget,
|
|
|
|
|
evaluatedWidgetConfig as WidgetEntityConfig,
|
|
|
|
|
),
|
|
|
|
|
);
|
2020-03-06 09:45:21 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-27 09:02:11 +00:00
|
|
|
function* updateCanvasSize(
|
|
|
|
|
action: ReduxAction<{ canvasWidgetId: string; snapRows: number }>,
|
|
|
|
|
) {
|
|
|
|
|
const { canvasWidgetId, snapRows } = action.payload;
|
2022-11-23 09:48:23 +00:00
|
|
|
const canvasWidget: FlattenedWidgetProps = yield select(
|
|
|
|
|
getWidget,
|
|
|
|
|
canvasWidgetId,
|
|
|
|
|
);
|
2020-03-27 09:02:11 +00:00
|
|
|
|
|
|
|
|
const originalSnapRows = canvasWidget.bottomRow - canvasWidget.topRow;
|
|
|
|
|
|
|
|
|
|
const newBottomRow = Math.round(
|
|
|
|
|
snapRows * GridDefaults.DEFAULT_GRID_ROW_HEIGHT,
|
|
|
|
|
);
|
|
|
|
|
/* Update the canvas's rows, ONLY if it has changed since the last render */
|
|
|
|
|
if (originalSnapRows !== newBottomRow) {
|
|
|
|
|
// TODO(abhinav): This considers that the topRow will always be zero
|
|
|
|
|
// Check this out when non canvas widgets are updating snapRows
|
|
|
|
|
// erstwhile: Math.round((rows * props.snapRowSpace) / props.parentRowSpace),
|
2021-01-25 08:57:26 +00:00
|
|
|
yield put(
|
feat: Non auto height invisible widgets (#20118)
## Description
This PR adds another feature update we had planned for Auto Height
- [ ] For new applications, in View and Preview mode, any widget which
is invisible will let go of its space and collapse if it's either on the
main Canvas or a container-like widget which has Auto-height enabled.
- [ ] Widgets within a container-like Widget, say Tabs, that doesn't
have Auto-height enabled, will now let go of their space if they're
invisible.
- [ ] The experience in Edit mode has not changed.
TL;DR: In new applications, in the Preview and Published _AKA_ View
modes, if a widget is invisible and within an Auto-height-enabled
container like a Tab, a Modal, a Form, or the main Canvas, it will fully
collapse, allowing widgets below it to move up and take its space. This
changes the behavior today prior to the release of this PR for
Auto-height-enabled widgets.
Fixes #19983
Fixes #18681
2023-02-14 13:36:19 +00:00
|
|
|
updateMultipleWidgetPropertiesAction({
|
2022-11-23 09:48:23 +00:00
|
|
|
[canvasWidgetId]: [
|
|
|
|
|
{
|
|
|
|
|
propertyPath: "bottomRow",
|
|
|
|
|
propertyValue: newBottomRow,
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
}),
|
2021-01-25 08:57:26 +00:00
|
|
|
);
|
2020-03-27 09:02:11 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-07 13:51:35 +00:00
|
|
|
function* createSelectedWidgetsCopy(
|
|
|
|
|
selectedWidgets: FlattenedWidgetProps[],
|
|
|
|
|
flexLayers: FlexLayer[],
|
|
|
|
|
) {
|
2021-06-28 07:11:47 +00:00
|
|
|
if (!selectedWidgets || !selectedWidgets.length) return;
|
|
|
|
|
const widgetListsToStore: {
|
|
|
|
|
widgetId: string;
|
|
|
|
|
parentId: string;
|
|
|
|
|
list: FlattenedWidgetProps[];
|
|
|
|
|
}[] = yield all(selectedWidgets.map((each) => call(createWidgetCopy, each)));
|
2021-08-25 05:00:31 +00:00
|
|
|
|
2022-06-21 13:57:34 +00:00
|
|
|
const saveResult: boolean = yield saveCopiedWidgets(
|
2023-04-07 13:51:35 +00:00
|
|
|
JSON.stringify({
|
|
|
|
|
widgets: widgetListsToStore,
|
|
|
|
|
flexLayers,
|
|
|
|
|
}),
|
2022-06-21 13:57:34 +00:00
|
|
|
);
|
|
|
|
|
return saveResult;
|
2020-12-10 07:33:43 +00:00
|
|
|
}
|
|
|
|
|
|
2021-04-23 05:43:13 +00:00
|
|
|
/**
|
|
|
|
|
* copy here actually means saving a JSON in local storage
|
|
|
|
|
* so when a user hits copy on a selected widget, we save widget in localStorage
|
|
|
|
|
*
|
|
|
|
|
* @param action
|
|
|
|
|
* @returns
|
|
|
|
|
*/
|
2020-12-10 07:33:43 +00:00
|
|
|
function* copyWidgetSaga(action: ReduxAction<{ isShortcut: boolean }>) {
|
2023-10-11 07:14:38 +00:00
|
|
|
const allWidgets: { [widgetId: string]: FlattenedWidgetProps } =
|
|
|
|
|
yield select(getWidgets);
|
2021-06-28 07:11:47 +00:00
|
|
|
const selectedWidgets: string[] = yield select(getSelectedWidgets);
|
|
|
|
|
if (!selectedWidgets) {
|
2023-05-19 18:37:06 +00:00
|
|
|
toast.show(createMessage(ERROR_WIDGET_COPY_NO_WIDGET_SELECTED), {
|
|
|
|
|
kind: "info",
|
2020-12-10 07:33:43 +00:00
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-28 07:11:47 +00:00
|
|
|
const allAllowedToCopy = selectedWidgets.some((each) => {
|
2023-06-13 12:09:40 +00:00
|
|
|
//should not allow canvas widgets to be copied
|
|
|
|
|
return (
|
|
|
|
|
allWidgets[each] &&
|
|
|
|
|
!allWidgets[each].disallowCopy &&
|
|
|
|
|
allWidgets[each].type !== "CANVAS_WIDGET"
|
|
|
|
|
);
|
2021-06-28 07:11:47 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!allAllowedToCopy) {
|
2023-05-19 18:37:06 +00:00
|
|
|
toast.show(createMessage(ERROR_WIDGET_COPY_NOT_ALLOWED), {
|
|
|
|
|
kind: "info",
|
2021-04-23 05:43:13 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-06-28 07:11:47 +00:00
|
|
|
const selectedWidgetProps = selectedWidgets.map((each) => allWidgets[each]);
|
2021-04-23 05:43:13 +00:00
|
|
|
|
2023-04-07 13:51:35 +00:00
|
|
|
const canvasId = selectedWidgetProps?.[0]?.parentId || "";
|
|
|
|
|
|
|
|
|
|
const flexLayers: FlexLayer[] = getFlexLayersForSelectedWidgets(
|
|
|
|
|
selectedWidgets,
|
|
|
|
|
canvasId ? allWidgets[canvasId] : undefined,
|
|
|
|
|
);
|
|
|
|
|
|
2022-06-21 13:57:34 +00:00
|
|
|
const saveResult: boolean = yield createSelectedWidgetsCopy(
|
|
|
|
|
selectedWidgetProps,
|
2023-04-07 13:51:35 +00:00
|
|
|
flexLayers,
|
2022-06-21 13:57:34 +00:00
|
|
|
);
|
2020-12-10 07:33:43 +00:00
|
|
|
|
2021-06-28 07:11:47 +00:00
|
|
|
selectedWidgetProps.forEach((each) => {
|
|
|
|
|
const eventName = action.payload.isShortcut
|
|
|
|
|
? "WIDGET_COPY_VIA_SHORTCUT"
|
|
|
|
|
: "WIDGET_COPY";
|
|
|
|
|
AnalyticsUtil.logEvent(eventName, {
|
|
|
|
|
widgetName: each.widgetName,
|
|
|
|
|
widgetType: each.type,
|
|
|
|
|
});
|
2020-09-16 10:28:01 +00:00
|
|
|
});
|
2020-12-10 07:33:43 +00:00
|
|
|
|
2020-09-16 10:28:01 +00:00
|
|
|
if (saveResult) {
|
2023-05-19 18:37:06 +00:00
|
|
|
toast.show(
|
|
|
|
|
createMessage(
|
2021-06-28 07:11:47 +00:00
|
|
|
WIDGET_COPY,
|
|
|
|
|
selectedWidgetProps.length > 1
|
|
|
|
|
? `${selectedWidgetProps.length} Widgets`
|
|
|
|
|
: selectedWidgetProps[0].widgetName,
|
|
|
|
|
),
|
2023-05-19 18:37:06 +00:00
|
|
|
{
|
|
|
|
|
kind: "success",
|
|
|
|
|
},
|
|
|
|
|
);
|
2020-09-16 10:28:01 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-25 05:00:31 +00:00
|
|
|
/**
|
|
|
|
|
* We take the bottom most widget in the canvas, then calculate the top,left,right,bottom
|
|
|
|
|
* co-ordinates for the new widget, such that it can be placed at the bottom of the canvas.
|
|
|
|
|
*
|
|
|
|
|
* @param widget
|
|
|
|
|
* @param parentId
|
|
|
|
|
* @param canvasWidgets
|
|
|
|
|
* @param parentBottomRow
|
2022-05-04 07:58:57 +00:00
|
|
|
* @param newPastingPositionMap
|
|
|
|
|
* @param shouldPersistColumnPosition
|
|
|
|
|
* @param isThereACollision
|
|
|
|
|
* @param shouldGroup
|
2021-08-25 05:00:31 +00:00
|
|
|
* @returns
|
|
|
|
|
*/
|
2021-02-11 06:36:07 +00:00
|
|
|
export function calculateNewWidgetPosition(
|
2020-09-16 10:28:01 +00:00
|
|
|
widget: WidgetProps,
|
|
|
|
|
parentId: string,
|
2021-03-16 05:01:37 +00:00
|
|
|
canvasWidgets: { [widgetId: string]: FlattenedWidgetProps },
|
2021-06-28 07:11:47 +00:00
|
|
|
parentBottomRow?: number,
|
2022-05-04 07:58:57 +00:00
|
|
|
newPastingPositionMap?: SpaceMap,
|
2021-08-25 05:00:31 +00:00
|
|
|
shouldPersistColumnPosition = false,
|
|
|
|
|
isThereACollision = false,
|
|
|
|
|
shouldGroup = false,
|
|
|
|
|
): {
|
|
|
|
|
topRow: number;
|
|
|
|
|
bottomRow: number;
|
|
|
|
|
leftColumn: number;
|
|
|
|
|
rightColumn: number;
|
|
|
|
|
} {
|
2022-05-04 07:58:57 +00:00
|
|
|
if (
|
|
|
|
|
!shouldGroup &&
|
|
|
|
|
newPastingPositionMap &&
|
|
|
|
|
newPastingPositionMap[widget.widgetId]
|
|
|
|
|
) {
|
|
|
|
|
const newPastingPosition = newPastingPositionMap[widget.widgetId];
|
|
|
|
|
return {
|
|
|
|
|
topRow: newPastingPosition.top,
|
|
|
|
|
bottomRow: newPastingPosition.bottom,
|
|
|
|
|
leftColumn: newPastingPosition.left,
|
|
|
|
|
rightColumn: newPastingPosition.right,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-28 07:11:47 +00:00
|
|
|
const nextAvailableRow = parentBottomRow
|
|
|
|
|
? parentBottomRow
|
|
|
|
|
: nextAvailableRowInContainer(parentId, canvasWidgets);
|
2020-09-16 10:28:01 +00:00
|
|
|
return {
|
2021-08-25 05:00:31 +00:00
|
|
|
leftColumn: shouldPersistColumnPosition ? widget.leftColumn : 0,
|
|
|
|
|
rightColumn: shouldPersistColumnPosition
|
2021-06-28 07:11:47 +00:00
|
|
|
? widget.rightColumn
|
|
|
|
|
: widget.rightColumn - widget.leftColumn,
|
2021-08-25 05:00:31 +00:00
|
|
|
topRow:
|
|
|
|
|
!isThereACollision && shouldGroup
|
|
|
|
|
? widget.topRow
|
|
|
|
|
: parentBottomRow
|
|
|
|
|
? nextAvailableRow + widget.topRow
|
|
|
|
|
: nextAvailableRow,
|
|
|
|
|
bottomRow:
|
|
|
|
|
!isThereACollision && shouldGroup
|
|
|
|
|
? widget.bottomRow
|
|
|
|
|
: parentBottomRow
|
|
|
|
|
? nextAvailableRow + widget.bottomRow
|
|
|
|
|
: nextAvailableRow + (widget.bottomRow - widget.topRow),
|
2020-09-16 10:28:01 +00:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-04 07:58:57 +00:00
|
|
|
/**
|
|
|
|
|
* Method to provide the new positions where the widgets can be pasted.
|
|
|
|
|
* It will return an empty object if it doesn't have any selected widgets, or if the mouse is outside the canvas.
|
|
|
|
|
*
|
|
|
|
|
* @param copiedWidgetGroups Contains information on the copied widgets
|
|
|
|
|
* @param mouseLocation location of the mouse in absolute pixels
|
|
|
|
|
* @param copiedTotalWidth total width of the copied widgets
|
|
|
|
|
* @param copiedTopMostRow top row of the top most copied widget
|
|
|
|
|
* @param copiedLeftMostColumn left column of the left most copied widget
|
|
|
|
|
* @returns
|
|
|
|
|
*/
|
chore: upgrade to prettier v2 + enforce import types (#21013)Co-authored-by: Satish Gandham <hello@satishgandham.com> Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
## Description
This PR upgrades Prettier to v2 + enforces TypeScript’s [`import
type`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export)
syntax where applicable. It’s submitted as a separate PR so we can merge
it easily.
As a part of this PR, we reformat the codebase heavily:
- add `import type` everywhere where it’s required, and
- re-format the code to account for Prettier 2’s breaking changes:
https://prettier.io/blog/2020/03/21/2.0.0.html#breaking-changes
This PR is submitted against `release` to make sure all new code by team
members will adhere to new formatting standards, and we’ll have fewer
conflicts when merging `bundle-optimizations` into `release`. (I’ll
merge `release` back into `bundle-optimizations` once this PR is
merged.)
### Why is this needed?
This PR is needed because, for the Lodash optimization from
https://github.com/appsmithorg/appsmith/commit/7cbb12af886621256224be0c93e6a465dd710ad3,
we need to use `import type`. Otherwise, `babel-plugin-lodash` complains
that `LoDashStatic` is not a lodash function.
However, just using `import type` in the current codebase will give you
this:
<img width="962" alt="Screenshot 2023-03-08 at 17 45 59"
src="https://user-images.githubusercontent.com/2953267/223775744-407afa0c-e8b9-44a1-90f9-b879348da57f.png">
That’s because Prettier 1 can’t parse `import type` at all. To parse it,
we need to upgrade to Prettier 2.
### Why enforce `import type`?
Apart from just enabling `import type` support, this PR enforces
specifying `import type` everywhere it’s needed. (Developers will get
immediate TypeScript and ESLint errors when they forget to do so.)
I’m doing this because I believe `import type` improves DX and makes
refactorings easier.
Let’s say you had a few imports like below. Can you tell which of these
imports will increase the bundle size? (Tip: it’s not all of them!)
```ts
// app/client/src/workers/Linting/utils.ts
import { Position } from "codemirror";
import { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
It’s pretty hard, right?
What about now?
```ts
// app/client/src/workers/Linting/utils.ts
import type { Position } from "codemirror";
import type { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
Now, it’s clear that only `lodash` will be bundled.
This helps developers to see which imports are problematic, but it
_also_ helps with refactorings. Now, if you want to see where
`codemirror` is bundled, you can just grep for `import \{.*\} from
"codemirror"` – and you won’t get any type-only imports.
This also helps (some) bundlers. Upon transpiling, TypeScript erases
type-only imports completely. In some environment (not ours), this makes
the bundle smaller, as the bundler doesn’t need to bundle type-only
imports anymore.
## Type of change
- Chore (housekeeping or task changes that don't impact user perception)
## How Has This Been Tested?
This was tested to not break the build.
### Test Plan
> Add Testsmith test cases links that relate to this PR
### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
## Checklist:
### Dev activity
- [x] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag
### QA activity:
- [ ] Test plan has been approved by relevant developers
- [ ] Test plan has been peer reviewed by QA
- [ ] Cypress test cases have been added and approved by either SDET or
manual QA
- [ ] Organized project review call with relevant stakeholders after
Round 1/2 of QA
- [ ] Added Test Plan Approved label after reveiwing all Cypress test
---------
Co-authored-by: Satish Gandham <hello@satishgandham.com>
Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
2023-03-16 11:41:47 +00:00
|
|
|
const getNewPositions = function* (
|
2022-05-04 07:58:57 +00:00
|
|
|
copiedWidgetGroups: CopiedWidgetGroup[],
|
|
|
|
|
mouseLocation: { x: number; y: number },
|
|
|
|
|
copiedTotalWidth: number,
|
|
|
|
|
copiedTopMostRow: number,
|
|
|
|
|
copiedLeftMostColumn: number,
|
|
|
|
|
) {
|
|
|
|
|
const selectedWidgetIDs: string[] = yield select(getSelectedWidgets);
|
|
|
|
|
const canvasWidgets: CanvasWidgetsReduxState = yield select(getWidgets);
|
chore: upgrade to prettier v2 + enforce import types (#21013)Co-authored-by: Satish Gandham <hello@satishgandham.com> Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
## Description
This PR upgrades Prettier to v2 + enforces TypeScript’s [`import
type`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export)
syntax where applicable. It’s submitted as a separate PR so we can merge
it easily.
As a part of this PR, we reformat the codebase heavily:
- add `import type` everywhere where it’s required, and
- re-format the code to account for Prettier 2’s breaking changes:
https://prettier.io/blog/2020/03/21/2.0.0.html#breaking-changes
This PR is submitted against `release` to make sure all new code by team
members will adhere to new formatting standards, and we’ll have fewer
conflicts when merging `bundle-optimizations` into `release`. (I’ll
merge `release` back into `bundle-optimizations` once this PR is
merged.)
### Why is this needed?
This PR is needed because, for the Lodash optimization from
https://github.com/appsmithorg/appsmith/commit/7cbb12af886621256224be0c93e6a465dd710ad3,
we need to use `import type`. Otherwise, `babel-plugin-lodash` complains
that `LoDashStatic` is not a lodash function.
However, just using `import type` in the current codebase will give you
this:
<img width="962" alt="Screenshot 2023-03-08 at 17 45 59"
src="https://user-images.githubusercontent.com/2953267/223775744-407afa0c-e8b9-44a1-90f9-b879348da57f.png">
That’s because Prettier 1 can’t parse `import type` at all. To parse it,
we need to upgrade to Prettier 2.
### Why enforce `import type`?
Apart from just enabling `import type` support, this PR enforces
specifying `import type` everywhere it’s needed. (Developers will get
immediate TypeScript and ESLint errors when they forget to do so.)
I’m doing this because I believe `import type` improves DX and makes
refactorings easier.
Let’s say you had a few imports like below. Can you tell which of these
imports will increase the bundle size? (Tip: it’s not all of them!)
```ts
// app/client/src/workers/Linting/utils.ts
import { Position } from "codemirror";
import { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
It’s pretty hard, right?
What about now?
```ts
// app/client/src/workers/Linting/utils.ts
import type { Position } from "codemirror";
import type { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
Now, it’s clear that only `lodash` will be bundled.
This helps developers to see which imports are problematic, but it
_also_ helps with refactorings. Now, if you want to see where
`codemirror` is bundled, you can just grep for `import \{.*\} from
"codemirror"` – and you won’t get any type-only imports.
This also helps (some) bundlers. Upon transpiling, TypeScript erases
type-only imports completely. In some environment (not ours), this makes
the bundle smaller, as the bundler doesn’t need to bundle type-only
imports anymore.
## Type of change
- Chore (housekeeping or task changes that don't impact user perception)
## How Has This Been Tested?
This was tested to not break the build.
### Test Plan
> Add Testsmith test cases links that relate to this PR
### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
## Checklist:
### Dev activity
- [x] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag
### QA activity:
- [ ] Test plan has been approved by relevant developers
- [ ] Test plan has been peer reviewed by QA
- [ ] Cypress test cases have been added and approved by either SDET or
manual QA
- [ ] Organized project review call with relevant stakeholders after
Round 1/2 of QA
- [ ] Added Test Plan Approved label after reveiwing all Cypress test
---------
Co-authored-by: Satish Gandham <hello@satishgandham.com>
Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
2023-03-16 11:41:47 +00:00
|
|
|
const { isListWidgetPastingOnItself, selectedWidgets } =
|
|
|
|
|
getVerifiedSelectedWidgets(
|
|
|
|
|
selectedWidgetIDs,
|
|
|
|
|
copiedWidgetGroups,
|
|
|
|
|
canvasWidgets,
|
|
|
|
|
);
|
2022-05-04 07:58:57 +00:00
|
|
|
|
|
|
|
|
//if the copied widget is a modal widget, then it has to paste on the main container
|
|
|
|
|
if (
|
|
|
|
|
copiedWidgetGroups.length === 1 &&
|
|
|
|
|
copiedWidgetGroups[0].list[0] &&
|
|
|
|
|
copiedWidgetGroups[0].list[0].type === "MODAL_WIDGET"
|
|
|
|
|
)
|
|
|
|
|
return {};
|
|
|
|
|
|
|
|
|
|
//if multiple widgets are selected or if a single non-layout widget is selected,
|
|
|
|
|
// then call the method to calculate and return positions based on selected widgets.
|
|
|
|
|
if (
|
|
|
|
|
!(
|
|
|
|
|
selectedWidgets.length === 1 &&
|
2022-05-06 14:11:09 +00:00
|
|
|
isDropTarget(selectedWidgets[0].type, true) &&
|
2022-05-11 09:16:22 +00:00
|
|
|
!isListWidgetPastingOnItself
|
2022-05-04 07:58:57 +00:00
|
|
|
) &&
|
|
|
|
|
selectedWidgets.length > 0
|
|
|
|
|
) {
|
|
|
|
|
const newPastingPositionDetails: NewPastePositionVariables = yield call(
|
|
|
|
|
getNewPositionsBasedOnSelectedWidgets,
|
|
|
|
|
copiedWidgetGroups,
|
|
|
|
|
selectedWidgets,
|
|
|
|
|
canvasWidgets,
|
|
|
|
|
copiedTotalWidth,
|
|
|
|
|
copiedTopMostRow,
|
|
|
|
|
copiedLeftMostColumn,
|
|
|
|
|
);
|
|
|
|
|
return newPastingPositionDetails;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//if a layout widget is selected or mouse is on the main canvas
|
|
|
|
|
// then call the method to calculate and return positions mouse positions.
|
|
|
|
|
const newPastingPositionDetails: NewPastePositionVariables = yield call(
|
|
|
|
|
getNewPositionsBasedOnMousePositions,
|
|
|
|
|
copiedWidgetGroups,
|
|
|
|
|
mouseLocation,
|
|
|
|
|
selectedWidgets,
|
|
|
|
|
canvasWidgets,
|
|
|
|
|
copiedTotalWidth,
|
|
|
|
|
copiedTopMostRow,
|
|
|
|
|
copiedLeftMostColumn,
|
|
|
|
|
);
|
|
|
|
|
return newPastingPositionDetails;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Calculates the new positions of the pasting widgets, based on the selected widgets
|
|
|
|
|
* The new positions will be just below the selected widgets
|
|
|
|
|
*
|
|
|
|
|
* @param copiedWidgetGroups Contains information on the copied widgets
|
|
|
|
|
* @param selectedWidgets array of selected widgets
|
|
|
|
|
* @param canvasWidgets canvas widgets from the DSL
|
|
|
|
|
* @param copiedTotalWidth total width of the copied widgets
|
|
|
|
|
* @param copiedTopMostRow top row of the top most copied widget
|
|
|
|
|
* @param copiedLeftMostColumn left column of the left most copied widget
|
|
|
|
|
* @returns
|
|
|
|
|
*/
|
|
|
|
|
function* getNewPositionsBasedOnSelectedWidgets(
|
|
|
|
|
copiedWidgetGroups: CopiedWidgetGroup[],
|
|
|
|
|
selectedWidgets: WidgetProps[],
|
|
|
|
|
canvasWidgets: CanvasWidgetsReduxState,
|
|
|
|
|
copiedTotalWidth: number,
|
|
|
|
|
copiedTopMostRow: number,
|
|
|
|
|
copiedLeftMostColumn: number,
|
|
|
|
|
) {
|
|
|
|
|
//get Parent canvasId
|
2023-09-13 06:29:41 +00:00
|
|
|
const parentId: string | undefined = selectedWidgets[0].parentId;
|
2022-05-04 07:58:57 +00:00
|
|
|
|
2023-09-13 06:29:41 +00:00
|
|
|
// If we failed to get the parent canvas widget Id then return empty object
|
|
|
|
|
if (parentId === undefined) return {};
|
|
|
|
|
|
|
|
|
|
// get the Id of the container like widget based on the canvasId
|
2022-05-04 07:58:57 +00:00
|
|
|
const containerId = getContainerIdForCanvas(parentId);
|
|
|
|
|
|
2023-09-13 06:29:41 +00:00
|
|
|
// If we failed to get the containing container like widget Id then return empty object
|
|
|
|
|
if (containerId === undefined) return {};
|
|
|
|
|
|
2022-05-04 07:58:57 +00:00
|
|
|
const containerWidget = canvasWidgets[containerId];
|
2022-12-29 11:07:54 +00:00
|
|
|
const canvasDOM = document.querySelector(`#${getSlidingArenaName(parentId)}`);
|
2022-05-04 07:58:57 +00:00
|
|
|
|
|
|
|
|
if (!canvasDOM || !containerWidget) return {};
|
|
|
|
|
|
|
|
|
|
const rect = canvasDOM.getBoundingClientRect();
|
|
|
|
|
|
|
|
|
|
// get Grid values such as snapRowSpace and snapColumnSpace
|
|
|
|
|
const { snapGrid } = getSnappedGrid(containerWidget, rect.width);
|
|
|
|
|
|
|
|
|
|
const selectedWidgetsArray = selectedWidgets.length ? selectedWidgets : [];
|
|
|
|
|
//from selected widgets get some information required for position calculation
|
|
|
|
|
const {
|
|
|
|
|
leftMostColumn: selectedLeftMostColumn,
|
|
|
|
|
maxThickness,
|
|
|
|
|
topMostRow: selectedTopMostRow,
|
|
|
|
|
totalWidth,
|
|
|
|
|
} = getBoundariesFromSelectedWidgets(selectedWidgetsArray);
|
|
|
|
|
|
|
|
|
|
// calculation of left most column of where widgets are to be pasted
|
|
|
|
|
let pasteLeftMostColumn =
|
|
|
|
|
selectedLeftMostColumn - (copiedTotalWidth - totalWidth) / 2;
|
|
|
|
|
|
|
|
|
|
pasteLeftMostColumn = Math.round(pasteLeftMostColumn);
|
|
|
|
|
|
|
|
|
|
// conditions to adjust to the edges of the boundary, so that it doesn't go out of canvas
|
|
|
|
|
if (pasteLeftMostColumn < 0) pasteLeftMostColumn = 0;
|
|
|
|
|
if (
|
|
|
|
|
pasteLeftMostColumn + copiedTotalWidth >
|
|
|
|
|
GridDefaults.DEFAULT_GRID_COLUMNS
|
|
|
|
|
)
|
|
|
|
|
pasteLeftMostColumn = GridDefaults.DEFAULT_GRID_COLUMNS - copiedTotalWidth;
|
|
|
|
|
|
|
|
|
|
// based on the above calculation get the new Positions that are aligned to the top left of selected widgets
|
|
|
|
|
// i.e., the top of the selected widgets will be equal to the top of copied widgets and both are horizontally centered
|
|
|
|
|
const newPositionsForCopiedWidgets = getNewPositionsForCopiedWidgets(
|
|
|
|
|
copiedWidgetGroups,
|
|
|
|
|
copiedTopMostRow,
|
|
|
|
|
selectedTopMostRow,
|
|
|
|
|
copiedLeftMostColumn,
|
|
|
|
|
pasteLeftMostColumn,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// with the new positions, calculate the map of new position, which are moved down to the point where
|
|
|
|
|
// it doesn't overlap with any of the selected widgets.
|
|
|
|
|
const newPastingPositionMap = getVerticallyAdjustedPositions(
|
|
|
|
|
newPositionsForCopiedWidgets,
|
|
|
|
|
getOccupiedSpacesFromProps(selectedWidgetsArray),
|
|
|
|
|
maxThickness,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (!newPastingPositionMap) return {};
|
|
|
|
|
|
|
|
|
|
const gridProps = {
|
|
|
|
|
parentColumnSpace: snapGrid.snapColumnSpace,
|
|
|
|
|
parentRowSpace: snapGrid.snapRowSpace,
|
|
|
|
|
maxGridColumns: GridDefaults.DEFAULT_GRID_COLUMNS,
|
|
|
|
|
};
|
|
|
|
|
|
2022-08-19 10:10:36 +00:00
|
|
|
const reflowSpacesSelector = getContainerWidgetSpacesSelector(parentId);
|
2022-05-04 07:58:57 +00:00
|
|
|
const widgetSpaces: WidgetSpace[] = yield select(reflowSpacesSelector) || [];
|
|
|
|
|
|
|
|
|
|
// Ids of each pasting are changed just for reflow
|
|
|
|
|
const newPastePositions = changeIdsOfPastePositions(newPastingPositionMap);
|
|
|
|
|
|
|
|
|
|
const { movementMap: reflowedMovementMap } = reflow(
|
|
|
|
|
newPastePositions,
|
|
|
|
|
newPastePositions,
|
|
|
|
|
widgetSpaces,
|
|
|
|
|
ReflowDirection.BOTTOM,
|
|
|
|
|
gridProps,
|
|
|
|
|
true,
|
|
|
|
|
false,
|
|
|
|
|
{ prevSpacesMap: {} } as PrevReflowState,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// calculate the new bottom most row of the canvas
|
|
|
|
|
const bottomMostRow = getBottomRowAfterReflow(
|
|
|
|
|
reflowedMovementMap,
|
|
|
|
|
getBottomMostRow(newPastePositions),
|
|
|
|
|
widgetSpaces,
|
|
|
|
|
gridProps,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
bottomMostRow:
|
|
|
|
|
(bottomMostRow + GridDefaults.CANVAS_EXTENSION_OFFSET) *
|
|
|
|
|
gridProps.parentRowSpace,
|
|
|
|
|
gridProps,
|
|
|
|
|
newPastingPositionMap,
|
|
|
|
|
reflowedMovementMap,
|
|
|
|
|
canvasId: parentId,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Calculates the new positions of the pasting widgets, based on the mouse position
|
|
|
|
|
* If the mouse position is on the canvas it the top left of the new positions aligns itself to the mouse position
|
|
|
|
|
* returns a empty object if the mouse is out of canvas
|
|
|
|
|
*
|
|
|
|
|
* @param copiedWidgetGroups Contains information on the copied widgets
|
|
|
|
|
* @param mouseLocation location of the mouse in absolute pixels
|
|
|
|
|
* @param selectedWidgets array of selected widgets
|
|
|
|
|
* @param canvasWidgets canvas widgets from the DSL
|
|
|
|
|
* @param copiedTotalWidth total width of the copied widgets
|
|
|
|
|
* @param copiedTopMostRow top row of the top most copied widget
|
|
|
|
|
* @param copiedLeftMostColumn left column of the left most copied widget
|
|
|
|
|
* @returns
|
|
|
|
|
*/
|
|
|
|
|
function* getNewPositionsBasedOnMousePositions(
|
|
|
|
|
copiedWidgetGroups: CopiedWidgetGroup[],
|
|
|
|
|
mouseLocation: { x: number; y: number },
|
|
|
|
|
selectedWidgets: WidgetProps[],
|
|
|
|
|
canvasWidgets: CanvasWidgetsReduxState,
|
|
|
|
|
copiedTotalWidth: number,
|
|
|
|
|
copiedTopMostRow: number,
|
|
|
|
|
copiedLeftMostColumn: number,
|
|
|
|
|
) {
|
chore: upgrade to prettier v2 + enforce import types (#21013)Co-authored-by: Satish Gandham <hello@satishgandham.com> Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
## Description
This PR upgrades Prettier to v2 + enforces TypeScript’s [`import
type`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export)
syntax where applicable. It’s submitted as a separate PR so we can merge
it easily.
As a part of this PR, we reformat the codebase heavily:
- add `import type` everywhere where it’s required, and
- re-format the code to account for Prettier 2’s breaking changes:
https://prettier.io/blog/2020/03/21/2.0.0.html#breaking-changes
This PR is submitted against `release` to make sure all new code by team
members will adhere to new formatting standards, and we’ll have fewer
conflicts when merging `bundle-optimizations` into `release`. (I’ll
merge `release` back into `bundle-optimizations` once this PR is
merged.)
### Why is this needed?
This PR is needed because, for the Lodash optimization from
https://github.com/appsmithorg/appsmith/commit/7cbb12af886621256224be0c93e6a465dd710ad3,
we need to use `import type`. Otherwise, `babel-plugin-lodash` complains
that `LoDashStatic` is not a lodash function.
However, just using `import type` in the current codebase will give you
this:
<img width="962" alt="Screenshot 2023-03-08 at 17 45 59"
src="https://user-images.githubusercontent.com/2953267/223775744-407afa0c-e8b9-44a1-90f9-b879348da57f.png">
That’s because Prettier 1 can’t parse `import type` at all. To parse it,
we need to upgrade to Prettier 2.
### Why enforce `import type`?
Apart from just enabling `import type` support, this PR enforces
specifying `import type` everywhere it’s needed. (Developers will get
immediate TypeScript and ESLint errors when they forget to do so.)
I’m doing this because I believe `import type` improves DX and makes
refactorings easier.
Let’s say you had a few imports like below. Can you tell which of these
imports will increase the bundle size? (Tip: it’s not all of them!)
```ts
// app/client/src/workers/Linting/utils.ts
import { Position } from "codemirror";
import { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
It’s pretty hard, right?
What about now?
```ts
// app/client/src/workers/Linting/utils.ts
import type { Position } from "codemirror";
import type { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
Now, it’s clear that only `lodash` will be bundled.
This helps developers to see which imports are problematic, but it
_also_ helps with refactorings. Now, if you want to see where
`codemirror` is bundled, you can just grep for `import \{.*\} from
"codemirror"` – and you won’t get any type-only imports.
This also helps (some) bundlers. Upon transpiling, TypeScript erases
type-only imports completely. In some environment (not ours), this makes
the bundle smaller, as the bundler doesn’t need to bundle type-only
imports anymore.
## Type of change
- Chore (housekeeping or task changes that don't impact user perception)
## How Has This Been Tested?
This was tested to not break the build.
### Test Plan
> Add Testsmith test cases links that relate to this PR
### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
## Checklist:
### Dev activity
- [x] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag
### QA activity:
- [ ] Test plan has been approved by relevant developers
- [ ] Test plan has been peer reviewed by QA
- [ ] Cypress test cases have been added and approved by either SDET or
manual QA
- [ ] Organized project review call with relevant stakeholders after
Round 1/2 of QA
- [ ] Added Test Plan Approved label after reveiwing all Cypress test
---------
Co-authored-by: Satish Gandham <hello@satishgandham.com>
Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
2023-03-16 11:41:47 +00:00
|
|
|
let { canvasDOM, canvasId, containerWidget } =
|
|
|
|
|
getDefaultCanvas(canvasWidgets);
|
2022-05-04 07:58:57 +00:00
|
|
|
|
|
|
|
|
//if the selected widget is a layout widget then change the pasting canvas.
|
|
|
|
|
if (selectedWidgets.length === 1 && isDropTarget(selectedWidgets[0].type)) {
|
|
|
|
|
containerWidget = selectedWidgets[0];
|
|
|
|
|
({ canvasDOM, canvasId } = getCanvasIdForContainer(containerWidget));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!canvasDOM || !containerWidget || !canvasId) return {};
|
|
|
|
|
|
|
|
|
|
const canvasRect = canvasDOM.getBoundingClientRect();
|
|
|
|
|
|
|
|
|
|
// get Grid values such as snapRowSpace and snapColumnSpace
|
|
|
|
|
const { padding, snapGrid } = getSnappedGrid(
|
|
|
|
|
containerWidget,
|
|
|
|
|
canvasRect.width,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// get mouse positions in terms of grid rows and columns of the pasting canvas
|
|
|
|
|
const mousePositions = getMousePositions(
|
|
|
|
|
canvasRect,
|
|
|
|
|
canvasId,
|
|
|
|
|
snapGrid,
|
|
|
|
|
padding,
|
|
|
|
|
mouseLocation,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (!snapGrid || !mousePositions) return {};
|
|
|
|
|
|
2022-08-19 10:10:36 +00:00
|
|
|
const reflowSpacesSelector = getContainerWidgetSpacesSelector(canvasId);
|
2022-05-04 07:58:57 +00:00
|
|
|
const widgetSpaces: WidgetSpace[] = yield select(reflowSpacesSelector) || [];
|
|
|
|
|
|
|
|
|
|
let mouseTopRow = mousePositions.top;
|
|
|
|
|
let mouseLeftColumn = mousePositions.left;
|
|
|
|
|
|
|
|
|
|
// if the mouse position is on another widget on the canvas, then new positions are below it.
|
|
|
|
|
for (const widgetSpace of widgetSpaces) {
|
|
|
|
|
if (
|
|
|
|
|
widgetSpace.top < mousePositions.top &&
|
|
|
|
|
widgetSpace.left < mousePositions.left &&
|
|
|
|
|
widgetSpace.bottom > mousePositions.top &&
|
|
|
|
|
widgetSpace.right > mousePositions.left
|
|
|
|
|
) {
|
|
|
|
|
mouseTopRow = widgetSpace.bottom + WIDGET_PASTE_PADDING;
|
|
|
|
|
mouseLeftColumn =
|
|
|
|
|
widgetSpace.left -
|
|
|
|
|
(copiedTotalWidth - (widgetSpace.right - widgetSpace.left)) / 2;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mouseLeftColumn = Math.round(mouseLeftColumn);
|
|
|
|
|
|
|
|
|
|
// adjust the top left based on the edges of the canvas
|
|
|
|
|
if (mouseLeftColumn < 0) mouseLeftColumn = 0;
|
|
|
|
|
if (mouseLeftColumn + copiedTotalWidth > GridDefaults.DEFAULT_GRID_COLUMNS)
|
|
|
|
|
mouseLeftColumn = GridDefaults.DEFAULT_GRID_COLUMNS - copiedTotalWidth;
|
|
|
|
|
|
|
|
|
|
// get the new Pasting positions of the widgets based on the adjusted mouse top-left
|
|
|
|
|
const newPastingPositionMap = getPastePositionMapFromMousePointer(
|
|
|
|
|
copiedWidgetGroups,
|
|
|
|
|
copiedTopMostRow,
|
|
|
|
|
mouseTopRow,
|
|
|
|
|
copiedLeftMostColumn,
|
|
|
|
|
mouseLeftColumn,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const gridProps = {
|
|
|
|
|
parentColumnSpace: snapGrid.snapColumnSpace,
|
|
|
|
|
parentRowSpace: snapGrid.snapRowSpace,
|
|
|
|
|
maxGridColumns: GridDefaults.DEFAULT_GRID_COLUMNS,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Ids of each pasting are changed just for reflow
|
|
|
|
|
const newPastePositions = changeIdsOfPastePositions(newPastingPositionMap);
|
|
|
|
|
|
|
|
|
|
const { movementMap: reflowedMovementMap } = reflow(
|
|
|
|
|
newPastePositions,
|
|
|
|
|
newPastePositions,
|
|
|
|
|
widgetSpaces,
|
|
|
|
|
ReflowDirection.BOTTOM,
|
|
|
|
|
gridProps,
|
|
|
|
|
true,
|
|
|
|
|
false,
|
|
|
|
|
{ prevSpacesMap: {} } as PrevReflowState,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// calculate the new bottom most row of the canvas.
|
|
|
|
|
const bottomMostRow = getBottomRowAfterReflow(
|
|
|
|
|
reflowedMovementMap,
|
|
|
|
|
getBottomMostRow(newPastePositions),
|
|
|
|
|
widgetSpaces,
|
|
|
|
|
gridProps,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
bottomMostRow:
|
|
|
|
|
(bottomMostRow + GridDefaults.CANVAS_EXTENSION_OFFSET) *
|
|
|
|
|
gridProps.parentRowSpace,
|
|
|
|
|
gridProps,
|
|
|
|
|
newPastingPositionMap,
|
|
|
|
|
reflowedMovementMap,
|
|
|
|
|
canvasId,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-23 05:43:13 +00:00
|
|
|
/**
|
|
|
|
|
* this saga create a new widget from the copied one to store
|
|
|
|
|
*/
|
2022-05-04 07:58:57 +00:00
|
|
|
function* pasteWidgetSaga(
|
|
|
|
|
action: ReduxAction<{
|
|
|
|
|
groupWidgets: boolean;
|
|
|
|
|
mouseLocation: { x: number; y: number };
|
|
|
|
|
}>,
|
|
|
|
|
) {
|
2023-04-07 13:51:35 +00:00
|
|
|
const {
|
|
|
|
|
flexLayers,
|
|
|
|
|
widgets: copiedWidgets,
|
|
|
|
|
}: {
|
|
|
|
|
widgets: CopiedWidgetGroup[];
|
|
|
|
|
flexLayers: FlexLayer[];
|
|
|
|
|
} = yield getCopiedWidgets();
|
|
|
|
|
|
|
|
|
|
let copiedWidgetGroups = copiedWidgets ? [...copiedWidgets] : [];
|
2021-08-25 05:00:31 +00:00
|
|
|
const shouldGroup: boolean = action.payload.groupWidgets;
|
2021-07-06 06:54:34 +00:00
|
|
|
|
2021-08-25 05:00:31 +00:00
|
|
|
const newlyCreatedWidgetIds: string[] = [];
|
|
|
|
|
const evalTree: DataTree = yield select(getDataTree);
|
|
|
|
|
const canvasWidgets: CanvasWidgetsReduxState = yield select(getWidgets);
|
|
|
|
|
let widgets: CanvasWidgetsReduxState = canvasWidgets;
|
chore: upgrade to prettier v2 + enforce import types (#21013)Co-authored-by: Satish Gandham <hello@satishgandham.com> Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
## Description
This PR upgrades Prettier to v2 + enforces TypeScript’s [`import
type`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export)
syntax where applicable. It’s submitted as a separate PR so we can merge
it easily.
As a part of this PR, we reformat the codebase heavily:
- add `import type` everywhere where it’s required, and
- re-format the code to account for Prettier 2’s breaking changes:
https://prettier.io/blog/2020/03/21/2.0.0.html#breaking-changes
This PR is submitted against `release` to make sure all new code by team
members will adhere to new formatting standards, and we’ll have fewer
conflicts when merging `bundle-optimizations` into `release`. (I’ll
merge `release` back into `bundle-optimizations` once this PR is
merged.)
### Why is this needed?
This PR is needed because, for the Lodash optimization from
https://github.com/appsmithorg/appsmith/commit/7cbb12af886621256224be0c93e6a465dd710ad3,
we need to use `import type`. Otherwise, `babel-plugin-lodash` complains
that `LoDashStatic` is not a lodash function.
However, just using `import type` in the current codebase will give you
this:
<img width="962" alt="Screenshot 2023-03-08 at 17 45 59"
src="https://user-images.githubusercontent.com/2953267/223775744-407afa0c-e8b9-44a1-90f9-b879348da57f.png">
That’s because Prettier 1 can’t parse `import type` at all. To parse it,
we need to upgrade to Prettier 2.
### Why enforce `import type`?
Apart from just enabling `import type` support, this PR enforces
specifying `import type` everywhere it’s needed. (Developers will get
immediate TypeScript and ESLint errors when they forget to do so.)
I’m doing this because I believe `import type` improves DX and makes
refactorings easier.
Let’s say you had a few imports like below. Can you tell which of these
imports will increase the bundle size? (Tip: it’s not all of them!)
```ts
// app/client/src/workers/Linting/utils.ts
import { Position } from "codemirror";
import { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
It’s pretty hard, right?
What about now?
```ts
// app/client/src/workers/Linting/utils.ts
import type { Position } from "codemirror";
import type { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
Now, it’s clear that only `lodash` will be bundled.
This helps developers to see which imports are problematic, but it
_also_ helps with refactorings. Now, if you want to see where
`codemirror` is bundled, you can just grep for `import \{.*\} from
"codemirror"` – and you won’t get any type-only imports.
This also helps (some) bundlers. Upon transpiling, TypeScript erases
type-only imports completely. In some environment (not ours), this makes
the bundle smaller, as the bundler doesn’t need to bundle type-only
imports anymore.
## Type of change
- Chore (housekeeping or task changes that don't impact user perception)
## How Has This Been Tested?
This was tested to not break the build.
### Test Plan
> Add Testsmith test cases links that relate to this PR
### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
## Checklist:
### Dev activity
- [x] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag
### QA activity:
- [ ] Test plan has been approved by relevant developers
- [ ] Test plan has been peer reviewed by QA
- [ ] Cypress test cases have been added and approved by either SDET or
manual QA
- [ ] Organized project review call with relevant stakeholders after
Round 1/2 of QA
- [ ] Added Test Plan Approved label after reveiwing all Cypress test
---------
Co-authored-by: Satish Gandham <hello@satishgandham.com>
Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
2023-03-16 11:41:47 +00:00
|
|
|
const selectedWidget: FlattenedWidgetProps<undefined> =
|
|
|
|
|
yield getSelectedWidgetWhenPasting();
|
2021-07-08 06:30:19 +00:00
|
|
|
|
2023-04-07 13:51:35 +00:00
|
|
|
const isMobile: boolean = yield select(getIsAutoLayoutMobileBreakPoint);
|
|
|
|
|
const mainCanvasWidth: number = yield select(getCanvasWidth);
|
2023-03-04 07:25:54 +00:00
|
|
|
|
2023-02-21 04:13:25 +00:00
|
|
|
try {
|
|
|
|
|
let reflowedMovementMap,
|
|
|
|
|
gridProps: GridProps | undefined,
|
|
|
|
|
newPastingPositionMap: SpaceMap | undefined,
|
|
|
|
|
canvasId;
|
2022-05-20 13:57:12 +00:00
|
|
|
|
2023-02-21 04:13:25 +00:00
|
|
|
let pastingIntoWidgetId: string = yield getParentWidgetIdForPasting(
|
|
|
|
|
canvasWidgets,
|
|
|
|
|
selectedWidget,
|
|
|
|
|
);
|
2021-07-06 06:54:34 +00:00
|
|
|
|
2023-02-21 04:13:25 +00:00
|
|
|
let isThereACollision = false;
|
2021-07-06 06:54:34 +00:00
|
|
|
|
2023-02-21 04:13:25 +00:00
|
|
|
// if this is true, selected widgets will be grouped in container
|
|
|
|
|
if (shouldGroup) {
|
|
|
|
|
copiedWidgetGroups = yield createSelectedWidgetsAsCopiedWidgets();
|
|
|
|
|
pastingIntoWidgetId = yield getParentWidgetIdForGrouping(
|
|
|
|
|
widgets,
|
|
|
|
|
copiedWidgetGroups,
|
|
|
|
|
);
|
|
|
|
|
widgets = yield filterOutSelectedWidgets(
|
|
|
|
|
copiedWidgetGroups[0].parentId,
|
|
|
|
|
copiedWidgetGroups,
|
|
|
|
|
);
|
|
|
|
|
isThereACollision = yield isSelectedWidgetsColliding(
|
|
|
|
|
widgets,
|
|
|
|
|
copiedWidgetGroups,
|
|
|
|
|
pastingIntoWidgetId,
|
|
|
|
|
);
|
2020-09-16 10:28:01 +00:00
|
|
|
|
2023-02-21 04:13:25 +00:00
|
|
|
//while grouping, the container around the selected widgets will increase by 2 rows,
|
|
|
|
|
//hence if there are any widgets in that path then we reflow those widgets
|
|
|
|
|
// If there are already widgets inside the selection box even before grouping
|
|
|
|
|
//then we will have to move it down to the bottom most row
|
chore: upgrade to prettier v2 + enforce import types (#21013)Co-authored-by: Satish Gandham <hello@satishgandham.com> Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
## Description
This PR upgrades Prettier to v2 + enforces TypeScript’s [`import
type`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export)
syntax where applicable. It’s submitted as a separate PR so we can merge
it easily.
As a part of this PR, we reformat the codebase heavily:
- add `import type` everywhere where it’s required, and
- re-format the code to account for Prettier 2’s breaking changes:
https://prettier.io/blog/2020/03/21/2.0.0.html#breaking-changes
This PR is submitted against `release` to make sure all new code by team
members will adhere to new formatting standards, and we’ll have fewer
conflicts when merging `bundle-optimizations` into `release`. (I’ll
merge `release` back into `bundle-optimizations` once this PR is
merged.)
### Why is this needed?
This PR is needed because, for the Lodash optimization from
https://github.com/appsmithorg/appsmith/commit/7cbb12af886621256224be0c93e6a465dd710ad3,
we need to use `import type`. Otherwise, `babel-plugin-lodash` complains
that `LoDashStatic` is not a lodash function.
However, just using `import type` in the current codebase will give you
this:
<img width="962" alt="Screenshot 2023-03-08 at 17 45 59"
src="https://user-images.githubusercontent.com/2953267/223775744-407afa0c-e8b9-44a1-90f9-b879348da57f.png">
That’s because Prettier 1 can’t parse `import type` at all. To parse it,
we need to upgrade to Prettier 2.
### Why enforce `import type`?
Apart from just enabling `import type` support, this PR enforces
specifying `import type` everywhere it’s needed. (Developers will get
immediate TypeScript and ESLint errors when they forget to do so.)
I’m doing this because I believe `import type` improves DX and makes
refactorings easier.
Let’s say you had a few imports like below. Can you tell which of these
imports will increase the bundle size? (Tip: it’s not all of them!)
```ts
// app/client/src/workers/Linting/utils.ts
import { Position } from "codemirror";
import { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
It’s pretty hard, right?
What about now?
```ts
// app/client/src/workers/Linting/utils.ts
import type { Position } from "codemirror";
import type { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
Now, it’s clear that only `lodash` will be bundled.
This helps developers to see which imports are problematic, but it
_also_ helps with refactorings. Now, if you want to see where
`codemirror` is bundled, you can just grep for `import \{.*\} from
"codemirror"` – and you won’t get any type-only imports.
This also helps (some) bundlers. Upon transpiling, TypeScript erases
type-only imports completely. In some environment (not ours), this makes
the bundle smaller, as the bundler doesn’t need to bundle type-only
imports anymore.
## Type of change
- Chore (housekeeping or task changes that don't impact user perception)
## How Has This Been Tested?
This was tested to not break the build.
### Test Plan
> Add Testsmith test cases links that relate to this PR
### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
## Checklist:
### Dev activity
- [x] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag
### QA activity:
- [ ] Test plan has been approved by relevant developers
- [ ] Test plan has been peer reviewed by QA
- [ ] Cypress test cases have been added and approved by either SDET or
manual QA
- [ ] Organized project review call with relevant stakeholders after
Round 1/2 of QA
- [ ] Added Test Plan Approved label after reveiwing all Cypress test
---------
Co-authored-by: Satish Gandham <hello@satishgandham.com>
Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
2023-03-16 11:41:47 +00:00
|
|
|
({ copiedWidgetGroups, gridProps, reflowedMovementMap } =
|
|
|
|
|
yield groupWidgetsIntoContainer(
|
|
|
|
|
copiedWidgetGroups,
|
|
|
|
|
pastingIntoWidgetId,
|
|
|
|
|
isThereACollision,
|
|
|
|
|
));
|
2023-02-21 04:13:25 +00:00
|
|
|
}
|
2021-08-25 05:00:31 +00:00
|
|
|
|
2023-02-21 04:13:25 +00:00
|
|
|
if (
|
|
|
|
|
// to avoid invoking old way of copied widgets implementaion
|
|
|
|
|
!Array.isArray(copiedWidgetGroups) ||
|
|
|
|
|
!copiedWidgetGroups.length
|
|
|
|
|
)
|
|
|
|
|
return;
|
2021-08-25 05:00:31 +00:00
|
|
|
|
2023-02-21 04:13:25 +00:00
|
|
|
const {
|
|
|
|
|
leftMostWidget,
|
|
|
|
|
topMostWidget,
|
|
|
|
|
totalWidth: copiedTotalWidth,
|
|
|
|
|
} = getBoundaryWidgetsFromCopiedGroups(copiedWidgetGroups);
|
2021-08-25 05:00:31 +00:00
|
|
|
|
2023-02-21 04:13:25 +00:00
|
|
|
const nextAvailableRow: number = nextAvailableRowInContainer(
|
|
|
|
|
pastingIntoWidgetId,
|
|
|
|
|
widgets,
|
|
|
|
|
);
|
2022-05-04 07:58:57 +00:00
|
|
|
|
2023-02-21 04:13:25 +00:00
|
|
|
// skip new position calculation if grouping
|
|
|
|
|
if (!shouldGroup) {
|
|
|
|
|
// new pasting positions, the variables are undefined if the positions cannot be calculated,
|
|
|
|
|
// then it pastes the regular way at the bottom of the canvas
|
chore: upgrade to prettier v2 + enforce import types (#21013)Co-authored-by: Satish Gandham <hello@satishgandham.com> Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
## Description
This PR upgrades Prettier to v2 + enforces TypeScript’s [`import
type`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export)
syntax where applicable. It’s submitted as a separate PR so we can merge
it easily.
As a part of this PR, we reformat the codebase heavily:
- add `import type` everywhere where it’s required, and
- re-format the code to account for Prettier 2’s breaking changes:
https://prettier.io/blog/2020/03/21/2.0.0.html#breaking-changes
This PR is submitted against `release` to make sure all new code by team
members will adhere to new formatting standards, and we’ll have fewer
conflicts when merging `bundle-optimizations` into `release`. (I’ll
merge `release` back into `bundle-optimizations` once this PR is
merged.)
### Why is this needed?
This PR is needed because, for the Lodash optimization from
https://github.com/appsmithorg/appsmith/commit/7cbb12af886621256224be0c93e6a465dd710ad3,
we need to use `import type`. Otherwise, `babel-plugin-lodash` complains
that `LoDashStatic` is not a lodash function.
However, just using `import type` in the current codebase will give you
this:
<img width="962" alt="Screenshot 2023-03-08 at 17 45 59"
src="https://user-images.githubusercontent.com/2953267/223775744-407afa0c-e8b9-44a1-90f9-b879348da57f.png">
That’s because Prettier 1 can’t parse `import type` at all. To parse it,
we need to upgrade to Prettier 2.
### Why enforce `import type`?
Apart from just enabling `import type` support, this PR enforces
specifying `import type` everywhere it’s needed. (Developers will get
immediate TypeScript and ESLint errors when they forget to do so.)
I’m doing this because I believe `import type` improves DX and makes
refactorings easier.
Let’s say you had a few imports like below. Can you tell which of these
imports will increase the bundle size? (Tip: it’s not all of them!)
```ts
// app/client/src/workers/Linting/utils.ts
import { Position } from "codemirror";
import { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
It’s pretty hard, right?
What about now?
```ts
// app/client/src/workers/Linting/utils.ts
import type { Position } from "codemirror";
import type { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
Now, it’s clear that only `lodash` will be bundled.
This helps developers to see which imports are problematic, but it
_also_ helps with refactorings. Now, if you want to see where
`codemirror` is bundled, you can just grep for `import \{.*\} from
"codemirror"` – and you won’t get any type-only imports.
This also helps (some) bundlers. Upon transpiling, TypeScript erases
type-only imports completely. In some environment (not ours), this makes
the bundle smaller, as the bundler doesn’t need to bundle type-only
imports anymore.
## Type of change
- Chore (housekeeping or task changes that don't impact user perception)
## How Has This Been Tested?
This was tested to not break the build.
### Test Plan
> Add Testsmith test cases links that relate to this PR
### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
## Checklist:
### Dev activity
- [x] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag
### QA activity:
- [ ] Test plan has been approved by relevant developers
- [ ] Test plan has been peer reviewed by QA
- [ ] Cypress test cases have been added and approved by either SDET or
manual QA
- [ ] Organized project review call with relevant stakeholders after
Round 1/2 of QA
- [ ] Added Test Plan Approved label after reveiwing all Cypress test
---------
Co-authored-by: Satish Gandham <hello@satishgandham.com>
Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
2023-03-16 11:41:47 +00:00
|
|
|
({ canvasId, gridProps, newPastingPositionMap, reflowedMovementMap } =
|
|
|
|
|
yield call(
|
|
|
|
|
getNewPositions,
|
|
|
|
|
copiedWidgetGroups,
|
|
|
|
|
action.payload.mouseLocation,
|
|
|
|
|
copiedTotalWidth,
|
|
|
|
|
topMostWidget.topRow,
|
|
|
|
|
leftMostWidget.leftColumn,
|
|
|
|
|
));
|
2023-02-21 04:13:25 +00:00
|
|
|
|
|
|
|
|
if (canvasId) pastingIntoWidgetId = canvasId;
|
|
|
|
|
}
|
2022-05-04 07:58:57 +00:00
|
|
|
|
2023-02-21 04:13:25 +00:00
|
|
|
for (const widgetGroup of copiedWidgetGroups) {
|
|
|
|
|
//This is required when you cut the widget as CanvasWidgetState doesn't have the widget anymore
|
|
|
|
|
const widgetType = widgetGroup.list.find(
|
|
|
|
|
(widget) => widget.widgetId === widgetGroup.widgetId,
|
|
|
|
|
)?.type;
|
2021-02-01 14:32:43 +00:00
|
|
|
|
2023-02-21 04:13:25 +00:00
|
|
|
if (!widgetType) break;
|
|
|
|
|
|
|
|
|
|
yield call(
|
|
|
|
|
executeWidgetBlueprintBeforeOperations,
|
|
|
|
|
BlueprintOperationTypes.BEFORE_PASTE,
|
|
|
|
|
{
|
|
|
|
|
parentId: pastingIntoWidgetId,
|
|
|
|
|
widgetId: widgetGroup.widgetId,
|
2021-08-25 05:00:31 +00:00
|
|
|
widgets,
|
2023-02-21 04:13:25 +00:00
|
|
|
widgetType,
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
2020-09-16 10:28:01 +00:00
|
|
|
|
2023-04-07 13:51:35 +00:00
|
|
|
const widgetIdMap: Record<string, string> = {};
|
2023-05-11 04:45:14 +00:00
|
|
|
const reverseWidgetIdMap: Record<string, string> = {};
|
2023-02-21 04:13:25 +00:00
|
|
|
yield all(
|
|
|
|
|
copiedWidgetGroups.map((copiedWidgets) =>
|
chore: upgrade to prettier v2 + enforce import types (#21013)Co-authored-by: Satish Gandham <hello@satishgandham.com> Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
## Description
This PR upgrades Prettier to v2 + enforces TypeScript’s [`import
type`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export)
syntax where applicable. It’s submitted as a separate PR so we can merge
it easily.
As a part of this PR, we reformat the codebase heavily:
- add `import type` everywhere where it’s required, and
- re-format the code to account for Prettier 2’s breaking changes:
https://prettier.io/blog/2020/03/21/2.0.0.html#breaking-changes
This PR is submitted against `release` to make sure all new code by team
members will adhere to new formatting standards, and we’ll have fewer
conflicts when merging `bundle-optimizations` into `release`. (I’ll
merge `release` back into `bundle-optimizations` once this PR is
merged.)
### Why is this needed?
This PR is needed because, for the Lodash optimization from
https://github.com/appsmithorg/appsmith/commit/7cbb12af886621256224be0c93e6a465dd710ad3,
we need to use `import type`. Otherwise, `babel-plugin-lodash` complains
that `LoDashStatic` is not a lodash function.
However, just using `import type` in the current codebase will give you
this:
<img width="962" alt="Screenshot 2023-03-08 at 17 45 59"
src="https://user-images.githubusercontent.com/2953267/223775744-407afa0c-e8b9-44a1-90f9-b879348da57f.png">
That’s because Prettier 1 can’t parse `import type` at all. To parse it,
we need to upgrade to Prettier 2.
### Why enforce `import type`?
Apart from just enabling `import type` support, this PR enforces
specifying `import type` everywhere it’s needed. (Developers will get
immediate TypeScript and ESLint errors when they forget to do so.)
I’m doing this because I believe `import type` improves DX and makes
refactorings easier.
Let’s say you had a few imports like below. Can you tell which of these
imports will increase the bundle size? (Tip: it’s not all of them!)
```ts
// app/client/src/workers/Linting/utils.ts
import { Position } from "codemirror";
import { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
It’s pretty hard, right?
What about now?
```ts
// app/client/src/workers/Linting/utils.ts
import type { Position } from "codemirror";
import type { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
Now, it’s clear that only `lodash` will be bundled.
This helps developers to see which imports are problematic, but it
_also_ helps with refactorings. Now, if you want to see where
`codemirror` is bundled, you can just grep for `import \{.*\} from
"codemirror"` – and you won’t get any type-only imports.
This also helps (some) bundlers. Upon transpiling, TypeScript erases
type-only imports completely. In some environment (not ours), this makes
the bundle smaller, as the bundler doesn’t need to bundle type-only
imports anymore.
## Type of change
- Chore (housekeeping or task changes that don't impact user perception)
## How Has This Been Tested?
This was tested to not break the build.
### Test Plan
> Add Testsmith test cases links that relate to this PR
### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
## Checklist:
### Dev activity
- [x] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag
### QA activity:
- [ ] Test plan has been approved by relevant developers
- [ ] Test plan has been peer reviewed by QA
- [ ] Cypress test cases have been added and approved by either SDET or
manual QA
- [ ] Organized project review call with relevant stakeholders after
Round 1/2 of QA
- [ ] Added Test Plan Approved label after reveiwing all Cypress test
---------
Co-authored-by: Satish Gandham <hello@satishgandham.com>
Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
2023-03-16 11:41:47 +00:00
|
|
|
call(function* () {
|
2023-02-21 04:13:25 +00:00
|
|
|
// Don't try to paste if there is no copied widget
|
|
|
|
|
if (!copiedWidgets) return;
|
|
|
|
|
|
|
|
|
|
const copiedWidgetId = copiedWidgets.widgetId;
|
|
|
|
|
const unUpdatedCopyOfWidget = copiedWidgets.list[0];
|
|
|
|
|
const newTopRow = shouldGroup
|
|
|
|
|
? isThereACollision
|
|
|
|
|
? topMostWidget.topRow
|
|
|
|
|
: 0
|
|
|
|
|
: topMostWidget.topRow;
|
|
|
|
|
|
|
|
|
|
const copiedWidget = {
|
|
|
|
|
...unUpdatedCopyOfWidget,
|
|
|
|
|
topRow: unUpdatedCopyOfWidget.topRow - newTopRow,
|
|
|
|
|
bottomRow: unUpdatedCopyOfWidget.bottomRow - newTopRow,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Log the paste or group event.
|
|
|
|
|
if (shouldGroup) {
|
|
|
|
|
AnalyticsUtil.logEvent("WIDGET_GROUP", {
|
|
|
|
|
widgetName: copiedWidget.widgetName,
|
|
|
|
|
widgetType: copiedWidget.type,
|
2021-08-25 05:00:31 +00:00
|
|
|
});
|
2023-02-21 04:13:25 +00:00
|
|
|
} else {
|
|
|
|
|
AnalyticsUtil.logEvent("WIDGET_PASTE", {
|
|
|
|
|
widgetName: copiedWidget.widgetName,
|
|
|
|
|
widgetType: copiedWidget.type,
|
2021-08-25 05:00:31 +00:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-21 04:13:25 +00:00
|
|
|
// Compute the new widget's positional properties
|
|
|
|
|
const newWidgetPosition = calculateNewWidgetPosition(
|
|
|
|
|
copiedWidget,
|
|
|
|
|
pastingIntoWidgetId,
|
|
|
|
|
widgets,
|
|
|
|
|
nextAvailableRow,
|
|
|
|
|
newPastingPositionMap,
|
|
|
|
|
true,
|
|
|
|
|
isThereACollision,
|
|
|
|
|
shouldGroup,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Get a flat list of all the widgets to be updated
|
|
|
|
|
const widgetList = copiedWidgets.list;
|
|
|
|
|
const widgetNameMap: Record<string, string> = {};
|
|
|
|
|
const newWidgetList: FlattenedWidgetProps[] = [];
|
|
|
|
|
// Generate new widgetIds for the flat list of all the widgets to be updated
|
|
|
|
|
|
|
|
|
|
widgetList.forEach((widget) => {
|
|
|
|
|
// Create a copy of the widget properties
|
|
|
|
|
const newWidget = cloneDeep(widget);
|
|
|
|
|
newWidget.widgetId = generateReactKey();
|
|
|
|
|
// Add the new widget id so that it maps the previous widget id
|
|
|
|
|
widgetIdMap[widget.widgetId] = newWidget.widgetId;
|
2023-03-04 07:25:54 +00:00
|
|
|
reverseWidgetIdMap[newWidget.widgetId] = widget.widgetId;
|
2023-02-21 04:13:25 +00:00
|
|
|
// Add the new widget to the list
|
|
|
|
|
newWidgetList.push(newWidget);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// For each of the new widgets generated
|
|
|
|
|
for (let i = 0; i < newWidgetList.length; i++) {
|
|
|
|
|
const widget = newWidgetList[i];
|
|
|
|
|
const oldWidgetName = widget.widgetName;
|
|
|
|
|
let newWidgetName = oldWidgetName;
|
|
|
|
|
|
|
|
|
|
if (!shouldGroup) {
|
|
|
|
|
newWidgetName = getNextWidgetName(
|
|
|
|
|
widgets,
|
|
|
|
|
widget.type,
|
|
|
|
|
evalTree,
|
|
|
|
|
{
|
|
|
|
|
prefix: oldWidgetName,
|
|
|
|
|
startWithoutIndex: true,
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Update the children widgetIds if it has children
|
|
|
|
|
if (widget.children && widget.children.length > 0) {
|
|
|
|
|
widget.children.forEach(
|
|
|
|
|
(childWidgetId: string, index: number) => {
|
|
|
|
|
if (widget.children) {
|
|
|
|
|
widget.children[index] = widgetIdMap[childWidgetId];
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Update the tabs for the tabs widget.
|
|
|
|
|
if (widget.tabsObj && widget.type === "TABS_WIDGET") {
|
|
|
|
|
try {
|
|
|
|
|
const tabs = Object.values(widget.tabsObj);
|
|
|
|
|
if (Array.isArray(tabs)) {
|
|
|
|
|
widget.tabsObj = tabs.reduce((obj: any, tab) => {
|
|
|
|
|
tab.widgetId = widgetIdMap[tab.widgetId];
|
|
|
|
|
obj[tab.id] = tab;
|
|
|
|
|
return obj;
|
|
|
|
|
}, {});
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
log.debug("Error updating tabs", error);
|
2021-06-28 07:11:47 +00:00
|
|
|
}
|
|
|
|
|
}
|
2020-10-19 08:56:04 +00:00
|
|
|
|
2023-02-21 04:13:25 +00:00
|
|
|
// Update the table widget column properties
|
|
|
|
|
if (
|
|
|
|
|
widget.type === "TABLE_WIDGET_V2" ||
|
|
|
|
|
widget.type === "TABLE_WIDGET"
|
|
|
|
|
) {
|
|
|
|
|
try {
|
|
|
|
|
// If the primaryColumns of the table exist
|
|
|
|
|
if (widget.primaryColumns) {
|
|
|
|
|
// For each column
|
|
|
|
|
for (const [columnId, column] of Object.entries(
|
|
|
|
|
widget.primaryColumns,
|
2021-06-28 07:11:47 +00:00
|
|
|
)) {
|
2023-02-21 04:13:25 +00:00
|
|
|
// For each property in the column
|
|
|
|
|
for (const [key, value] of Object.entries(
|
|
|
|
|
column as ColumnProperties,
|
|
|
|
|
)) {
|
|
|
|
|
// Replace reference of previous widget with the new widgetName
|
|
|
|
|
// This handles binding scenarios like `{{Table2.tableData.map((currentRow) => (currentRow.id))}}`
|
|
|
|
|
widget.primaryColumns[columnId][key] = isString(value)
|
|
|
|
|
? value.replace(
|
|
|
|
|
`${oldWidgetName}.`,
|
|
|
|
|
`${newWidgetName}.`,
|
|
|
|
|
)
|
|
|
|
|
: value;
|
|
|
|
|
}
|
2021-06-28 07:11:47 +00:00
|
|
|
}
|
|
|
|
|
}
|
2023-02-21 04:13:25 +00:00
|
|
|
// Use the new widget name we used to replace the column properties above.
|
|
|
|
|
widget.widgetName = newWidgetName;
|
|
|
|
|
} catch (error) {
|
|
|
|
|
log.debug("Error updating table widget properties", error);
|
2021-06-28 07:11:47 +00:00
|
|
|
}
|
|
|
|
|
}
|
2020-10-19 08:56:04 +00:00
|
|
|
|
2023-02-21 04:13:25 +00:00
|
|
|
// TODO: here to move this to the widget definition
|
|
|
|
|
// Update the Select widget defaultValue properties
|
|
|
|
|
if (
|
|
|
|
|
widget.type === "MULTI_SELECT_WIDGET_V2" ||
|
|
|
|
|
widget.type === "SELECT_WIDGET"
|
|
|
|
|
) {
|
|
|
|
|
try {
|
|
|
|
|
// If the defaultOptionValue exist
|
|
|
|
|
if (widget.defaultOptionValue) {
|
|
|
|
|
const value = widget.defaultOptionValue;
|
|
|
|
|
// replace All occurrence of old widget name
|
|
|
|
|
widget.defaultOptionValue = isString(value)
|
|
|
|
|
? value.replaceAll(`${oldWidgetName}.`, `${newWidgetName}.`)
|
|
|
|
|
: value;
|
|
|
|
|
}
|
|
|
|
|
// Use the new widget name we used to replace the defaultValue properties above.
|
|
|
|
|
widget.widgetName = newWidgetName;
|
|
|
|
|
} catch (error) {
|
|
|
|
|
log.debug("Error updating widget properties", error);
|
2022-08-18 07:10:58 +00:00
|
|
|
}
|
|
|
|
|
}
|
2023-02-21 04:13:25 +00:00
|
|
|
// If it is the copied widget, update position properties
|
|
|
|
|
if (widget.widgetId === widgetIdMap[copiedWidget.widgetId]) {
|
|
|
|
|
//when the widget is a modal widget, it has to paste on the main container
|
|
|
|
|
const pastingParentId =
|
|
|
|
|
widget.type === "MODAL_WIDGET"
|
|
|
|
|
? MAIN_CONTAINER_WIDGET_ID
|
|
|
|
|
: pastingIntoWidgetId;
|
chore: upgrade to prettier v2 + enforce import types (#21013)Co-authored-by: Satish Gandham <hello@satishgandham.com> Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
## Description
This PR upgrades Prettier to v2 + enforces TypeScript’s [`import
type`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export)
syntax where applicable. It’s submitted as a separate PR so we can merge
it easily.
As a part of this PR, we reformat the codebase heavily:
- add `import type` everywhere where it’s required, and
- re-format the code to account for Prettier 2’s breaking changes:
https://prettier.io/blog/2020/03/21/2.0.0.html#breaking-changes
This PR is submitted against `release` to make sure all new code by team
members will adhere to new formatting standards, and we’ll have fewer
conflicts when merging `bundle-optimizations` into `release`. (I’ll
merge `release` back into `bundle-optimizations` once this PR is
merged.)
### Why is this needed?
This PR is needed because, for the Lodash optimization from
https://github.com/appsmithorg/appsmith/commit/7cbb12af886621256224be0c93e6a465dd710ad3,
we need to use `import type`. Otherwise, `babel-plugin-lodash` complains
that `LoDashStatic` is not a lodash function.
However, just using `import type` in the current codebase will give you
this:
<img width="962" alt="Screenshot 2023-03-08 at 17 45 59"
src="https://user-images.githubusercontent.com/2953267/223775744-407afa0c-e8b9-44a1-90f9-b879348da57f.png">
That’s because Prettier 1 can’t parse `import type` at all. To parse it,
we need to upgrade to Prettier 2.
### Why enforce `import type`?
Apart from just enabling `import type` support, this PR enforces
specifying `import type` everywhere it’s needed. (Developers will get
immediate TypeScript and ESLint errors when they forget to do so.)
I’m doing this because I believe `import type` improves DX and makes
refactorings easier.
Let’s say you had a few imports like below. Can you tell which of these
imports will increase the bundle size? (Tip: it’s not all of them!)
```ts
// app/client/src/workers/Linting/utils.ts
import { Position } from "codemirror";
import { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
It’s pretty hard, right?
What about now?
```ts
// app/client/src/workers/Linting/utils.ts
import type { Position } from "codemirror";
import type { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
Now, it’s clear that only `lodash` will be bundled.
This helps developers to see which imports are problematic, but it
_also_ helps with refactorings. Now, if you want to see where
`codemirror` is bundled, you can just grep for `import \{.*\} from
"codemirror"` – and you won’t get any type-only imports.
This also helps (some) bundlers. Upon transpiling, TypeScript erases
type-only imports completely. In some environment (not ours), this makes
the bundle smaller, as the bundler doesn’t need to bundle type-only
imports anymore.
## Type of change
- Chore (housekeeping or task changes that don't impact user perception)
## How Has This Been Tested?
This was tested to not break the build.
### Test Plan
> Add Testsmith test cases links that relate to this PR
### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
## Checklist:
### Dev activity
- [x] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag
### QA activity:
- [ ] Test plan has been approved by relevant developers
- [ ] Test plan has been peer reviewed by QA
- [ ] Cypress test cases have been added and approved by either SDET or
manual QA
- [ ] Organized project review call with relevant stakeholders after
Round 1/2 of QA
- [ ] Added Test Plan Approved label after reveiwing all Cypress test
---------
Co-authored-by: Satish Gandham <hello@satishgandham.com>
Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
2023-03-16 11:41:47 +00:00
|
|
|
const { bottomRow, leftColumn, rightColumn, topRow } =
|
|
|
|
|
newWidgetPosition;
|
2023-02-21 04:13:25 +00:00
|
|
|
widget.leftColumn = leftColumn;
|
|
|
|
|
widget.topRow = topRow;
|
|
|
|
|
widget.bottomRow = bottomRow;
|
|
|
|
|
widget.rightColumn = rightColumn;
|
|
|
|
|
widget.parentId = pastingParentId;
|
|
|
|
|
// Also, update the parent widget in the canvas widgets
|
|
|
|
|
// to include this new copied widget's id in the parent's children
|
|
|
|
|
let parentChildren = [widget.widgetId];
|
|
|
|
|
const widgetChildren = widgets[pastingParentId].children;
|
2023-03-04 07:25:54 +00:00
|
|
|
|
2023-02-21 04:13:25 +00:00
|
|
|
if (widgetChildren && Array.isArray(widgetChildren)) {
|
2023-03-04 07:25:54 +00:00
|
|
|
// Add the new child to existing children after it's original siblings position.
|
|
|
|
|
|
|
|
|
|
const originalWidgetId: string = widgetList[i].widgetId;
|
chore: upgrade to prettier v2 + enforce import types (#21013)Co-authored-by: Satish Gandham <hello@satishgandham.com> Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
## Description
This PR upgrades Prettier to v2 + enforces TypeScript’s [`import
type`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export)
syntax where applicable. It’s submitted as a separate PR so we can merge
it easily.
As a part of this PR, we reformat the codebase heavily:
- add `import type` everywhere where it’s required, and
- re-format the code to account for Prettier 2’s breaking changes:
https://prettier.io/blog/2020/03/21/2.0.0.html#breaking-changes
This PR is submitted against `release` to make sure all new code by team
members will adhere to new formatting standards, and we’ll have fewer
conflicts when merging `bundle-optimizations` into `release`. (I’ll
merge `release` back into `bundle-optimizations` once this PR is
merged.)
### Why is this needed?
This PR is needed because, for the Lodash optimization from
https://github.com/appsmithorg/appsmith/commit/7cbb12af886621256224be0c93e6a465dd710ad3,
we need to use `import type`. Otherwise, `babel-plugin-lodash` complains
that `LoDashStatic` is not a lodash function.
However, just using `import type` in the current codebase will give you
this:
<img width="962" alt="Screenshot 2023-03-08 at 17 45 59"
src="https://user-images.githubusercontent.com/2953267/223775744-407afa0c-e8b9-44a1-90f9-b879348da57f.png">
That’s because Prettier 1 can’t parse `import type` at all. To parse it,
we need to upgrade to Prettier 2.
### Why enforce `import type`?
Apart from just enabling `import type` support, this PR enforces
specifying `import type` everywhere it’s needed. (Developers will get
immediate TypeScript and ESLint errors when they forget to do so.)
I’m doing this because I believe `import type` improves DX and makes
refactorings easier.
Let’s say you had a few imports like below. Can you tell which of these
imports will increase the bundle size? (Tip: it’s not all of them!)
```ts
// app/client/src/workers/Linting/utils.ts
import { Position } from "codemirror";
import { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
It’s pretty hard, right?
What about now?
```ts
// app/client/src/workers/Linting/utils.ts
import type { Position } from "codemirror";
import type { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
Now, it’s clear that only `lodash` will be bundled.
This helps developers to see which imports are problematic, but it
_also_ helps with refactorings. Now, if you want to see where
`codemirror` is bundled, you can just grep for `import \{.*\} from
"codemirror"` – and you won’t get any type-only imports.
This also helps (some) bundlers. Upon transpiling, TypeScript erases
type-only imports completely. In some environment (not ours), this makes
the bundle smaller, as the bundler doesn’t need to bundle type-only
imports anymore.
## Type of change
- Chore (housekeeping or task changes that don't impact user perception)
## How Has This Been Tested?
This was tested to not break the build.
### Test Plan
> Add Testsmith test cases links that relate to this PR
### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
## Checklist:
### Dev activity
- [x] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag
### QA activity:
- [ ] Test plan has been approved by relevant developers
- [ ] Test plan has been peer reviewed by QA
- [ ] Cypress test cases have been added and approved by either SDET or
manual QA
- [ ] Organized project review call with relevant stakeholders after
Round 1/2 of QA
- [ ] Added Test Plan Approved label after reveiwing all Cypress test
---------
Co-authored-by: Satish Gandham <hello@satishgandham.com>
Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
2023-03-16 11:41:47 +00:00
|
|
|
const originalWidgetIndex: number =
|
|
|
|
|
widgetChildren.indexOf(originalWidgetId);
|
2023-03-04 07:25:54 +00:00
|
|
|
parentChildren = [
|
|
|
|
|
...widgetChildren.slice(0, originalWidgetIndex + 1),
|
|
|
|
|
...parentChildren,
|
|
|
|
|
...widgetChildren.slice(originalWidgetIndex + 1),
|
|
|
|
|
];
|
2023-02-21 04:13:25 +00:00
|
|
|
}
|
2021-08-12 05:45:38 +00:00
|
|
|
|
2023-02-21 04:13:25 +00:00
|
|
|
widgets = {
|
|
|
|
|
...widgets,
|
|
|
|
|
[pastingParentId]: {
|
|
|
|
|
...widgets[pastingParentId],
|
|
|
|
|
children: parentChildren,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
// If the copied widget's boundaries exceed the parent's
|
|
|
|
|
// Make the parent scrollable
|
2021-06-28 07:11:47 +00:00
|
|
|
if (
|
2023-02-21 04:13:25 +00:00
|
|
|
widgets[pastingParentId].bottomRow *
|
|
|
|
|
widgets[widget.parentId].parentRowSpace <=
|
|
|
|
|
widget.bottomRow * widget.parentRowSpace &&
|
|
|
|
|
!widget.detachFromLayout
|
2021-06-28 07:11:47 +00:00
|
|
|
) {
|
2023-02-21 04:13:25 +00:00
|
|
|
const parentOfPastingWidget = widgets[pastingParentId].parentId;
|
|
|
|
|
if (
|
|
|
|
|
parentOfPastingWidget &&
|
|
|
|
|
widget.parentId !== MAIN_CONTAINER_WIDGET_ID
|
|
|
|
|
) {
|
|
|
|
|
const parent = widgets[parentOfPastingWidget];
|
|
|
|
|
widgets[parentOfPastingWidget] = {
|
|
|
|
|
...parent,
|
|
|
|
|
shouldScrollContents: true,
|
|
|
|
|
};
|
|
|
|
|
}
|
2021-02-16 10:29:08 +00:00
|
|
|
}
|
2023-02-21 04:13:25 +00:00
|
|
|
} else {
|
|
|
|
|
// For all other widgets in the list
|
|
|
|
|
// (These widgets will be descendants of the copied widget)
|
|
|
|
|
// This means, that their parents will also be newly copied widgets
|
|
|
|
|
// Update widget's parent widget ids with the new parent widget ids
|
|
|
|
|
const newParentId = newWidgetList.find((newWidget) =>
|
|
|
|
|
widget.parentId
|
|
|
|
|
? newWidget.widgetId === widgetIdMap[widget.parentId]
|
|
|
|
|
: false,
|
|
|
|
|
)?.widgetId;
|
|
|
|
|
if (newParentId) widget.parentId = newParentId;
|
2021-02-16 10:29:08 +00:00
|
|
|
}
|
2023-02-21 04:13:25 +00:00
|
|
|
// Generate a new unique widget name
|
|
|
|
|
if (!shouldGroup) {
|
|
|
|
|
widget.widgetName = newWidgetName;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
widgetNameMap[oldWidgetName] = widget.widgetName;
|
|
|
|
|
// Add the new widget to the canvas widgets
|
|
|
|
|
widgets[widget.widgetId] = widget;
|
2023-03-04 07:25:54 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* If new parent is a vertical stack, then update flex layers.
|
|
|
|
|
*/
|
|
|
|
|
if (widget.parentId) {
|
|
|
|
|
const pastingIntoWidget = widgets[widget.parentId];
|
2023-04-07 13:51:35 +00:00
|
|
|
if (
|
|
|
|
|
pastingIntoWidget &&
|
|
|
|
|
isStack(widgets, pastingIntoWidget) &&
|
|
|
|
|
(pastingIntoWidgetId !== pastingIntoWidget.widgetId ||
|
|
|
|
|
!flexLayers ||
|
|
|
|
|
flexLayers.length <= 0)
|
|
|
|
|
) {
|
2023-10-11 07:14:38 +00:00
|
|
|
const metaProps: Record<string, any> =
|
|
|
|
|
yield select(getWidgetsMeta);
|
2023-03-04 07:25:54 +00:00
|
|
|
if (widget.widgetId === widgetIdMap[copiedWidget.widgetId])
|
|
|
|
|
widgets = pasteWidgetInFlexLayers(
|
|
|
|
|
widgets,
|
|
|
|
|
widget.parentId,
|
|
|
|
|
widget,
|
|
|
|
|
reverseWidgetIdMap[widget.widgetId],
|
|
|
|
|
isMobile,
|
2023-04-07 13:51:35 +00:00
|
|
|
mainCanvasWidth,
|
2023-05-11 04:45:14 +00:00
|
|
|
metaProps,
|
2023-03-04 07:25:54 +00:00
|
|
|
);
|
|
|
|
|
else if (widget.type !== "CANVAS_WIDGET")
|
|
|
|
|
widgets = addChildToPastedFlexLayers(
|
|
|
|
|
widgets,
|
|
|
|
|
widget,
|
|
|
|
|
widgetIdMap,
|
|
|
|
|
isMobile,
|
2023-04-07 13:51:35 +00:00
|
|
|
mainCanvasWidth,
|
2023-05-11 04:45:14 +00:00
|
|
|
metaProps,
|
2023-03-04 07:25:54 +00:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-08-25 05:00:31 +00:00
|
|
|
}
|
2023-02-21 04:13:25 +00:00
|
|
|
newlyCreatedWidgetIds.push(widgetIdMap[copiedWidgetId]);
|
|
|
|
|
// 1. updating template in the copied widget and deleting old template associations
|
|
|
|
|
// 2. updating dynamicBindingPathList in the copied grid widget
|
|
|
|
|
for (let i = 0; i < newWidgetList.length; i++) {
|
|
|
|
|
const widget = newWidgetList[i];
|
|
|
|
|
|
|
|
|
|
widgets = handleSpecificCasesWhilePasting(
|
|
|
|
|
widget,
|
|
|
|
|
widgets,
|
|
|
|
|
widgetNameMap,
|
|
|
|
|
newWidgetList,
|
|
|
|
|
);
|
2021-02-16 10:29:08 +00:00
|
|
|
}
|
2023-02-21 04:13:25 +00:00
|
|
|
}),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
//calculate the new positions of the reflowed widgets
|
2023-05-11 04:45:14 +00:00
|
|
|
let reflowedWidgets = getReflowedPositions(
|
2023-02-21 04:13:25 +00:00
|
|
|
widgets,
|
|
|
|
|
gridProps,
|
|
|
|
|
reflowedMovementMap,
|
|
|
|
|
);
|
2021-08-25 05:00:31 +00:00
|
|
|
|
2023-04-07 13:51:35 +00:00
|
|
|
if (
|
|
|
|
|
pastingIntoWidgetId &&
|
|
|
|
|
reflowedWidgets[pastingIntoWidgetId] &&
|
|
|
|
|
flexLayers &&
|
|
|
|
|
flexLayers.length > 0
|
|
|
|
|
) {
|
|
|
|
|
const newFlexLayers = getNewFlexLayers(flexLayers, widgetIdMap);
|
|
|
|
|
reflowedWidgets[pastingIntoWidgetId] = {
|
|
|
|
|
...reflowedWidgets[pastingIntoWidgetId],
|
|
|
|
|
flexLayers: [
|
|
|
|
|
...(reflowedWidgets[pastingIntoWidgetId]?.flexLayers || []),
|
|
|
|
|
...newFlexLayers,
|
|
|
|
|
],
|
|
|
|
|
};
|
2023-05-11 04:45:14 +00:00
|
|
|
const metaProps: Record<string, any> = yield select(getWidgetsMeta);
|
|
|
|
|
reflowedWidgets = updateWidgetPositions(
|
|
|
|
|
reflowedWidgets,
|
|
|
|
|
pastingIntoWidgetId,
|
|
|
|
|
isMobile,
|
|
|
|
|
mainCanvasWidth,
|
|
|
|
|
false,
|
|
|
|
|
metaProps,
|
|
|
|
|
);
|
2023-04-07 13:51:35 +00:00
|
|
|
}
|
|
|
|
|
|
2023-02-21 04:13:25 +00:00
|
|
|
// some widgets need to update property of parent if the parent have CHILD_OPERATIONS
|
|
|
|
|
// so here we are traversing up the tree till we get to MAIN_CONTAINER_WIDGET_ID
|
|
|
|
|
// while traversing, if we find any widget which has CHILD_OPERATION, we will call the fn in it
|
|
|
|
|
const updatedWidgets: CanvasWidgetsReduxState = yield call(
|
|
|
|
|
traverseTreeAndExecuteBlueprintChildOperations,
|
|
|
|
|
reflowedWidgets[pastingIntoWidgetId],
|
|
|
|
|
newlyCreatedWidgetIds.filter(
|
|
|
|
|
(widgetId) => !reflowedWidgets[widgetId]?.detachFromLayout,
|
|
|
|
|
),
|
|
|
|
|
reflowedWidgets,
|
|
|
|
|
);
|
2023-12-29 02:41:49 +00:00
|
|
|
yield call(updateAndSaveAnvilLayout, updatedWidgets);
|
2022-05-04 07:58:57 +00:00
|
|
|
|
2023-02-21 04:13:25 +00:00
|
|
|
const pageId: string = yield select(getCurrentPageId);
|
2021-08-25 05:00:31 +00:00
|
|
|
|
2023-02-21 04:13:25 +00:00
|
|
|
if (copiedWidgetGroups && copiedWidgetGroups.length > 0) {
|
|
|
|
|
history.push(builderURL({ pageId }));
|
|
|
|
|
}
|
2022-07-11 04:06:29 +00:00
|
|
|
|
2023-02-21 04:13:25 +00:00
|
|
|
yield put({
|
|
|
|
|
type: ReduxActionTypes.RECORD_RECENTLY_ADDED_WIDGET,
|
|
|
|
|
payload: newlyCreatedWidgetIds,
|
|
|
|
|
});
|
|
|
|
|
yield put(generateAutoHeightLayoutTreeAction(true, true));
|
2022-06-09 11:47:47 +00:00
|
|
|
|
2023-02-21 04:13:25 +00:00
|
|
|
//if pasting at the bottom of the canvas, then flash it.
|
|
|
|
|
if (shouldGroup || !newPastingPositionMap) {
|
|
|
|
|
flashElementsById(newlyCreatedWidgetIds, 100);
|
|
|
|
|
}
|
2022-05-25 10:05:53 +00:00
|
|
|
|
2023-02-21 04:13:25 +00:00
|
|
|
yield put(
|
|
|
|
|
selectWidgetInitAction(
|
|
|
|
|
SelectionRequestType.Multiple,
|
|
|
|
|
newlyCreatedWidgetIds,
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
yield put({
|
|
|
|
|
type: ReduxActionErrorTypes.WIDGET_OPERATION_ERROR,
|
|
|
|
|
payload: {
|
|
|
|
|
action: ReduxActionTypes.PASTE_COPIED_WIDGET_INIT,
|
|
|
|
|
error,
|
|
|
|
|
},
|
|
|
|
|
});
|
2022-05-04 07:58:57 +00:00
|
|
|
}
|
2020-09-16 10:28:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function* cutWidgetSaga() {
|
2023-10-11 07:14:38 +00:00
|
|
|
const allWidgets: { [widgetId: string]: FlattenedWidgetProps } =
|
|
|
|
|
yield select(getWidgets);
|
2021-06-28 07:11:47 +00:00
|
|
|
const selectedWidgets: string[] = yield select(getSelectedWidgets);
|
|
|
|
|
if (!selectedWidgets) {
|
2023-05-19 18:37:06 +00:00
|
|
|
toast.show(createMessage(ERROR_WIDGET_CUT_NO_WIDGET_SELECTED), {
|
|
|
|
|
kind: "info",
|
2020-12-10 07:33:43 +00:00
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-14 16:07:31 +00:00
|
|
|
const allAllowedToCut = selectedWidgets.some((each) => {
|
2023-06-13 12:09:40 +00:00
|
|
|
//should not allow canvas widgets to be cut
|
|
|
|
|
return (
|
|
|
|
|
allWidgets[each] &&
|
|
|
|
|
!allWidgets[each].disallowCopy &&
|
|
|
|
|
allWidgets[each].type !== "CANVAS_WIDGET"
|
|
|
|
|
);
|
2023-02-14 16:07:31 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!allAllowedToCut) {
|
2023-05-19 18:37:06 +00:00
|
|
|
toast.show(createMessage(ERROR_WIDGET_CUT_NOT_ALLOWED), {
|
|
|
|
|
kind: "info",
|
2023-02-14 16:07:31 +00:00
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-28 07:11:47 +00:00
|
|
|
const selectedWidgetProps = selectedWidgets.map((each) => allWidgets[each]);
|
|
|
|
|
|
2023-04-07 13:51:35 +00:00
|
|
|
const canvasId = selectedWidgetProps?.[0]?.parentId || "";
|
|
|
|
|
|
|
|
|
|
const flexLayers: FlexLayer[] = getFlexLayersForSelectedWidgets(
|
|
|
|
|
selectedWidgets,
|
|
|
|
|
canvasId ? allWidgets[canvasId] : undefined,
|
|
|
|
|
);
|
|
|
|
|
|
2022-06-21 13:57:34 +00:00
|
|
|
const saveResult: boolean = yield createSelectedWidgetsCopy(
|
|
|
|
|
selectedWidgetProps,
|
2023-04-07 13:51:35 +00:00
|
|
|
flexLayers,
|
2022-06-21 13:57:34 +00:00
|
|
|
);
|
2020-12-10 07:33:43 +00:00
|
|
|
|
2021-06-28 07:11:47 +00:00
|
|
|
selectedWidgetProps.forEach((each) => {
|
|
|
|
|
const eventName = "WIDGET_CUT_VIA_SHORTCUT"; // cut only supported through a shortcut
|
|
|
|
|
AnalyticsUtil.logEvent(eventName, {
|
|
|
|
|
widgetName: each.widgetName,
|
|
|
|
|
widgetType: each.type,
|
|
|
|
|
});
|
2020-09-16 10:28:01 +00:00
|
|
|
});
|
2020-12-10 07:33:43 +00:00
|
|
|
|
|
|
|
|
if (saveResult) {
|
2023-05-19 18:37:06 +00:00
|
|
|
toast.show(
|
|
|
|
|
createMessage(
|
2021-06-28 07:11:47 +00:00
|
|
|
WIDGET_CUT,
|
|
|
|
|
selectedWidgetProps.length > 1
|
|
|
|
|
? `${selectedWidgetProps.length} Widgets`
|
|
|
|
|
: selectedWidgetProps[0].widgetName,
|
|
|
|
|
),
|
2023-05-19 18:37:06 +00:00
|
|
|
{
|
|
|
|
|
kind: "success",
|
|
|
|
|
},
|
|
|
|
|
);
|
2020-12-10 07:33:43 +00:00
|
|
|
}
|
|
|
|
|
|
2020-09-16 10:28:01 +00:00
|
|
|
yield put({
|
2021-08-03 08:06:48 +00:00
|
|
|
type: WidgetReduxActionTypes.WIDGET_DELETE,
|
2020-09-16 10:28:01 +00:00
|
|
|
payload: {
|
|
|
|
|
disallowUndo: true,
|
2020-09-17 11:52:58 +00:00
|
|
|
isShortcut: true,
|
2020-09-16 10:28:01 +00:00
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-26 16:44:10 +00:00
|
|
|
function* addSuggestedWidget(action: ReduxAction<Partial<WidgetProps>>) {
|
2023-07-27 13:00:23 +00:00
|
|
|
const isSetWidgetIdForWalkthrough = !!(
|
|
|
|
|
action.payload.props.setWidgetIdForWalkthrough === "true"
|
|
|
|
|
);
|
2021-07-26 16:44:10 +00:00
|
|
|
const widgetConfig = action.payload;
|
2023-07-27 13:00:23 +00:00
|
|
|
delete widgetConfig.props?.setWidgetIdForWalkthrough;
|
2020-10-15 07:21:00 +00:00
|
|
|
|
2021-07-26 16:44:10 +00:00
|
|
|
if (!widgetConfig.type) return;
|
|
|
|
|
|
2021-09-09 15:10:22 +00:00
|
|
|
const defaultConfig = WidgetFactory.widgetConfigMap.get(widgetConfig.type);
|
|
|
|
|
|
2022-06-21 13:57:34 +00:00
|
|
|
const evalTree: DataTree = yield select(getDataTree);
|
|
|
|
|
const widgets: CanvasWidgetsReduxState = yield select(getWidgets);
|
2021-07-26 16:44:10 +00:00
|
|
|
|
|
|
|
|
const widgetName = getNextWidgetName(widgets, widgetConfig.type, evalTree);
|
2023-11-15 12:31:54 +00:00
|
|
|
const layoutSystemType: LayoutSystemTypes = yield select(getLayoutSystemType);
|
2021-07-26 16:44:10 +00:00
|
|
|
try {
|
2020-10-15 07:21:00 +00:00
|
|
|
let newWidget = {
|
|
|
|
|
newWidgetId: generateReactKey(),
|
|
|
|
|
widgetId: "0",
|
2021-07-26 16:44:10 +00:00
|
|
|
parentId: "0",
|
2020-10-15 07:21:00 +00:00
|
|
|
renderMode: RenderModes.CANVAS,
|
|
|
|
|
isLoading: false,
|
2021-07-26 16:44:10 +00:00
|
|
|
...defaultConfig,
|
|
|
|
|
widgetName,
|
|
|
|
|
...widgetConfig,
|
2020-10-15 07:21:00 +00:00
|
|
|
};
|
2021-07-26 16:44:10 +00:00
|
|
|
|
chore: upgrade to prettier v2 + enforce import types (#21013)Co-authored-by: Satish Gandham <hello@satishgandham.com> Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
## Description
This PR upgrades Prettier to v2 + enforces TypeScript’s [`import
type`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export)
syntax where applicable. It’s submitted as a separate PR so we can merge
it easily.
As a part of this PR, we reformat the codebase heavily:
- add `import type` everywhere where it’s required, and
- re-format the code to account for Prettier 2’s breaking changes:
https://prettier.io/blog/2020/03/21/2.0.0.html#breaking-changes
This PR is submitted against `release` to make sure all new code by team
members will adhere to new formatting standards, and we’ll have fewer
conflicts when merging `bundle-optimizations` into `release`. (I’ll
merge `release` back into `bundle-optimizations` once this PR is
merged.)
### Why is this needed?
This PR is needed because, for the Lodash optimization from
https://github.com/appsmithorg/appsmith/commit/7cbb12af886621256224be0c93e6a465dd710ad3,
we need to use `import type`. Otherwise, `babel-plugin-lodash` complains
that `LoDashStatic` is not a lodash function.
However, just using `import type` in the current codebase will give you
this:
<img width="962" alt="Screenshot 2023-03-08 at 17 45 59"
src="https://user-images.githubusercontent.com/2953267/223775744-407afa0c-e8b9-44a1-90f9-b879348da57f.png">
That’s because Prettier 1 can’t parse `import type` at all. To parse it,
we need to upgrade to Prettier 2.
### Why enforce `import type`?
Apart from just enabling `import type` support, this PR enforces
specifying `import type` everywhere it’s needed. (Developers will get
immediate TypeScript and ESLint errors when they forget to do so.)
I’m doing this because I believe `import type` improves DX and makes
refactorings easier.
Let’s say you had a few imports like below. Can you tell which of these
imports will increase the bundle size? (Tip: it’s not all of them!)
```ts
// app/client/src/workers/Linting/utils.ts
import { Position } from "codemirror";
import { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
It’s pretty hard, right?
What about now?
```ts
// app/client/src/workers/Linting/utils.ts
import type { Position } from "codemirror";
import type { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
Now, it’s clear that only `lodash` will be bundled.
This helps developers to see which imports are problematic, but it
_also_ helps with refactorings. Now, if you want to see where
`codemirror` is bundled, you can just grep for `import \{.*\} from
"codemirror"` – and you won’t get any type-only imports.
This also helps (some) bundlers. Upon transpiling, TypeScript erases
type-only imports completely. In some environment (not ours), this makes
the bundle smaller, as the bundler doesn’t need to bundle type-only
imports anymore.
## Type of change
- Chore (housekeeping or task changes that don't impact user perception)
## How Has This Been Tested?
This was tested to not break the build.
### Test Plan
> Add Testsmith test cases links that relate to this PR
### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
## Checklist:
### Dev activity
- [x] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag
### QA activity:
- [ ] Test plan has been approved by relevant developers
- [ ] Test plan has been peer reviewed by QA
- [ ] Cypress test cases have been added and approved by either SDET or
manual QA
- [ ] Organized project review call with relevant stakeholders after
Round 1/2 of QA
- [ ] Added Test Plan Approved label after reveiwing all Cypress test
---------
Co-authored-by: Satish Gandham <hello@satishgandham.com>
Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
2023-03-16 11:41:47 +00:00
|
|
|
const { bottomRow, leftColumn, rightColumn, topRow } =
|
|
|
|
|
yield calculateNewWidgetPosition(
|
|
|
|
|
newWidget as WidgetProps,
|
|
|
|
|
MAIN_CONTAINER_WIDGET_ID,
|
|
|
|
|
widgets,
|
|
|
|
|
);
|
2020-10-15 07:21:00 +00:00
|
|
|
|
|
|
|
|
newWidget = {
|
|
|
|
|
...newWidget,
|
|
|
|
|
leftColumn,
|
|
|
|
|
topRow,
|
|
|
|
|
rightColumn,
|
|
|
|
|
bottomRow,
|
2021-08-12 05:45:38 +00:00
|
|
|
parentRowSpace: GridDefaults.DEFAULT_GRID_ROW_HEIGHT,
|
2020-10-15 07:21:00 +00:00
|
|
|
};
|
2023-11-15 12:31:54 +00:00
|
|
|
switch (layoutSystemType) {
|
|
|
|
|
case LayoutSystemTypes.AUTO:
|
|
|
|
|
yield put({
|
|
|
|
|
type: ReduxActionTypes.AUTOLAYOUT_ADD_NEW_WIDGETS,
|
|
|
|
|
payload: {
|
|
|
|
|
dropPayload: {
|
|
|
|
|
isNewLayer: true,
|
|
|
|
|
alignment: FlexLayerAlignment.Start,
|
|
|
|
|
},
|
|
|
|
|
newWidget,
|
|
|
|
|
parentId: MAIN_CONTAINER_WIDGET_ID,
|
|
|
|
|
direction: LayoutDirection.Vertical,
|
|
|
|
|
addToBottom: true,
|
2023-04-07 13:51:35 +00:00
|
|
|
},
|
2023-11-15 12:31:54 +00:00
|
|
|
});
|
|
|
|
|
break;
|
|
|
|
|
case LayoutSystemTypes.ANVIL:
|
|
|
|
|
yield put(
|
|
|
|
|
addSuggestedWidgetAnvilAction({
|
|
|
|
|
newWidgetId: newWidget.newWidgetId,
|
|
|
|
|
rows: newWidget.rows,
|
|
|
|
|
columns: newWidget.columns,
|
|
|
|
|
type: newWidget.type,
|
|
|
|
|
...widgetConfig,
|
|
|
|
|
}),
|
|
|
|
|
);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
yield put({
|
|
|
|
|
type: WidgetReduxActionTypes.WIDGET_ADD_CHILD,
|
|
|
|
|
payload: newWidget,
|
|
|
|
|
});
|
|
|
|
|
break;
|
2023-04-07 13:51:35 +00:00
|
|
|
}
|
2020-10-15 07:21:00 +00:00
|
|
|
|
2023-02-21 13:38:16 +00:00
|
|
|
yield take(ReduxActionTypes.UPDATE_LAYOUT);
|
2020-10-15 07:21:00 +00:00
|
|
|
|
2023-07-27 13:00:23 +00:00
|
|
|
if (isSetWidgetIdForWalkthrough) {
|
|
|
|
|
localStorage.setItem(WIDGET_ID_SHOW_WALKTHROUGH, newWidget.newWidgetId);
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-21 13:38:16 +00:00
|
|
|
yield put(
|
|
|
|
|
selectWidgetInitAction(SelectionRequestType.One, [newWidget.newWidgetId]),
|
|
|
|
|
);
|
2020-10-15 07:21:00 +00:00
|
|
|
} catch (error) {
|
2021-08-20 04:13:16 +00:00
|
|
|
log.error(error);
|
2020-10-15 07:21:00 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-25 05:00:31 +00:00
|
|
|
/**
|
|
|
|
|
* saga to group selected widgets into a new container
|
|
|
|
|
*
|
|
|
|
|
* @param action
|
|
|
|
|
*/
|
|
|
|
|
export function* groupWidgetsSaga() {
|
|
|
|
|
const selectedWidgetIDs: string[] = yield select(getSelectedWidgets);
|
|
|
|
|
const isMultipleWidgetsSelected = selectedWidgetIDs.length > 1;
|
2023-06-09 08:52:27 +00:00
|
|
|
// Grouping functionality has been temporarily disabled for auto-layout canvas.
|
2023-04-28 19:31:29 +00:00
|
|
|
const isAutoLayout: boolean = yield select(getIsAutoLayout);
|
|
|
|
|
if (isAutoLayout) return;
|
2021-08-25 05:00:31 +00:00
|
|
|
if (isMultipleWidgetsSelected) {
|
|
|
|
|
try {
|
|
|
|
|
yield put({
|
|
|
|
|
type: ReduxActionTypes.PASTE_COPIED_WIDGET_INIT,
|
|
|
|
|
payload: {
|
|
|
|
|
groupWidgets: true,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
} catch (error) {
|
|
|
|
|
log.error(error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-06 05:42:35 +00:00
|
|
|
function* widgetBatchUpdatePropertySaga() {
|
|
|
|
|
/*
|
|
|
|
|
* BATCH_UPDATE_WIDGET_PROPERTY should be processed serially as
|
|
|
|
|
* it updates the state. We want the state updates from previous
|
|
|
|
|
* batch update to be flushed out to the store before processing
|
|
|
|
|
* the another batch update.
|
|
|
|
|
*/
|
2022-06-21 13:57:34 +00:00
|
|
|
const batchUpdateWidgetPropertyChannel: unknown = yield actionChannel(
|
2022-05-06 05:42:35 +00:00
|
|
|
ReduxActionTypes.BATCH_UPDATE_WIDGET_PROPERTY,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
while (true) {
|
2022-06-21 13:57:34 +00:00
|
|
|
// @ts-expect-error: Type mismatch
|
|
|
|
|
const action: unknown = yield take(batchUpdateWidgetPropertyChannel);
|
|
|
|
|
// @ts-expect-error: Type mismatch
|
2022-05-06 05:42:35 +00:00
|
|
|
yield call(batchUpdateWidgetPropertySaga, action);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-19 22:25:37 +00:00
|
|
|
export default function* widgetOperationSagas() {
|
2021-09-21 07:55:56 +00:00
|
|
|
yield fork(widgetAdditionSagas);
|
|
|
|
|
yield fork(widgetDeletionSagas);
|
2021-06-17 13:26:54 +00:00
|
|
|
yield fork(widgetSelectionSagas);
|
2022-05-06 05:42:35 +00:00
|
|
|
yield fork(widgetBatchUpdatePropertySaga);
|
2019-09-19 22:25:37 +00:00
|
|
|
yield all([
|
2021-07-26 16:44:10 +00:00
|
|
|
takeEvery(ReduxActionTypes.ADD_SUGGESTED_WIDGET, addSuggestedWidget),
|
2021-08-03 08:06:48 +00:00
|
|
|
takeLatest(WidgetReduxActionTypes.WIDGET_RESIZE, resizeSaga),
|
2019-11-06 06:35:15 +00:00
|
|
|
takeEvery(
|
|
|
|
|
ReduxActionTypes.UPDATE_WIDGET_PROPERTY_REQUEST,
|
|
|
|
|
updateWidgetPropertySaga,
|
|
|
|
|
),
|
2021-04-27 07:16:54 +00:00
|
|
|
takeEvery(
|
2021-08-03 08:06:48 +00:00
|
|
|
WidgetReduxActionTypes.WIDGET_UPDATE_PROPERTY,
|
2021-04-27 07:16:54 +00:00
|
|
|
updateWidgetPropertySaga,
|
|
|
|
|
),
|
2020-02-26 12:44:56 +00:00
|
|
|
takeEvery(
|
|
|
|
|
ReduxActionTypes.SET_WIDGET_DYNAMIC_PROPERTY,
|
|
|
|
|
setWidgetDynamicPropertySaga,
|
|
|
|
|
),
|
2023-07-26 05:38:11 +00:00
|
|
|
takeEvery(
|
|
|
|
|
ReduxActionTypes.BATCH_SET_WIDGET_DYNAMIC_PROPERTY,
|
|
|
|
|
batchUpdateWidgetDynamicPropertySaga,
|
|
|
|
|
),
|
2020-03-06 09:45:21 +00:00
|
|
|
takeEvery(
|
|
|
|
|
ReduxActionTypes.RESET_CHILDREN_WIDGET_META,
|
|
|
|
|
resetChildrenMetaSaga,
|
|
|
|
|
),
|
2021-09-21 07:55:56 +00:00
|
|
|
takeEvery(
|
|
|
|
|
ReduxActionTypes.BATCH_UPDATE_MULTIPLE_WIDGETS_PROPERTY,
|
|
|
|
|
batchUpdateMultipleWidgetsPropertiesSaga,
|
|
|
|
|
),
|
2021-01-25 08:57:26 +00:00
|
|
|
takeEvery(
|
|
|
|
|
ReduxActionTypes.DELETE_WIDGET_PROPERTY,
|
|
|
|
|
deleteWidgetPropertySaga,
|
|
|
|
|
),
|
2020-03-27 09:02:11 +00:00
|
|
|
takeLatest(ReduxActionTypes.UPDATE_CANVAS_SIZE, updateCanvasSize),
|
2020-09-16 10:28:01 +00:00
|
|
|
takeLatest(ReduxActionTypes.COPY_SELECTED_WIDGET_INIT, copyWidgetSaga),
|
2022-05-11 09:16:22 +00:00
|
|
|
takeLeading(ReduxActionTypes.PASTE_COPIED_WIDGET_INIT, pasteWidgetSaga),
|
2020-09-16 10:28:01 +00:00
|
|
|
takeEvery(ReduxActionTypes.CUT_SELECTED_WIDGET, cutWidgetSaga),
|
2021-08-25 05:00:31 +00:00
|
|
|
takeEvery(ReduxActionTypes.GROUP_WIDGETS_INIT, groupWidgetsSaga),
|
2023-11-17 07:16:18 +00:00
|
|
|
takeEvery(ReduxActionTypes.PARTIAL_IMPORT_INIT, partialImportSaga),
|
|
|
|
|
takeEvery(ReduxActionTypes.PARTIAL_EXPORT_INIT, partialExportSaga),
|
2019-09-19 22:25:37 +00:00
|
|
|
]);
|
|
|
|
|
}
|