2022-07-14 07:02:35 +00:00
|
|
|
import { Colors } from "constants/Colors";
|
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 { RenderMode } from "constants/WidgetConstants";
|
|
|
|
|
import { FontStyleTypes, RenderModes } from "constants/WidgetConstants";
|
2023-02-15 11:42:46 +00:00
|
|
|
import _, { filter, isBoolean, isObject, uniq, without } from "lodash";
|
2022-07-14 07:02:35 +00:00
|
|
|
import tinycolor from "tinycolor2";
|
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 {
|
2022-07-14 07:02:35 +00:00
|
|
|
CellLayoutProperties,
|
|
|
|
|
ColumnProperties,
|
2023-03-05 14:19:44 +00:00
|
|
|
ReactTableColumnProps,
|
2023-02-15 11:42:46 +00:00
|
|
|
TableColumnProps,
|
2022-07-14 07:02:35 +00:00
|
|
|
TableStyles,
|
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 "../component/Constants";
|
|
|
|
|
import {
|
|
|
|
|
CellAlignmentTypes,
|
|
|
|
|
StickyType,
|
2022-07-14 07:02:35 +00:00
|
|
|
VerticalAlignmentTypes,
|
|
|
|
|
} from "../component/Constants";
|
|
|
|
|
import {
|
|
|
|
|
ColumnTypes,
|
|
|
|
|
DEFAULT_BUTTON_COLOR,
|
|
|
|
|
DEFAULT_COLUMN_WIDTH,
|
2023-02-15 11:42:46 +00:00
|
|
|
TABLE_COLUMN_ORDER_KEY,
|
2022-07-14 07:02:35 +00:00
|
|
|
ORIGINAL_INDEX_KEY,
|
|
|
|
|
} from "../constants";
|
|
|
|
|
import { SelectColumnOptionsValidations } from "./propertyUtils";
|
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 { TableWidgetProps } from "../constants";
|
2022-07-14 07:02:35 +00:00
|
|
|
import { get } from "lodash";
|
|
|
|
|
import { getNextEntityName } from "utils/AppsmithUtils";
|
|
|
|
|
import {
|
|
|
|
|
combineDynamicBindings,
|
|
|
|
|
getDynamicBindings,
|
|
|
|
|
} from "utils/DynamicBindingUtils";
|
|
|
|
|
import { ButtonVariantTypes } from "components/constants";
|
2022-09-29 05:26:08 +00:00
|
|
|
import { dateFormatOptions } from "widgets/constants";
|
|
|
|
|
import moment from "moment";
|
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 { Stylesheet } from "entities/AppTheming";
|
2022-12-30 10:52:11 +00:00
|
|
|
import { getKeysFromSourceDataForEventAutocomplete } from "widgets/MenuButtonWidget/widget/helper";
|
2023-02-15 11:42:46 +00:00
|
|
|
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 React from "react";
|
2022-07-14 07:02:35 +00:00
|
|
|
|
|
|
|
|
type TableData = Array<Record<string, unknown>>;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* When the table data changes we need to find the new index of the
|
|
|
|
|
* selectedRow by using the primary key
|
|
|
|
|
*/
|
|
|
|
|
export const getOriginalRowIndex = (
|
|
|
|
|
prevTableData: TableData,
|
|
|
|
|
tableData: TableData,
|
|
|
|
|
selectedRowIndex: number | undefined,
|
|
|
|
|
primaryColumnId: string,
|
|
|
|
|
) => {
|
|
|
|
|
let primaryKey = "";
|
|
|
|
|
let index = -1;
|
|
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
!_.isNil(selectedRowIndex) &&
|
|
|
|
|
prevTableData &&
|
|
|
|
|
prevTableData[selectedRowIndex]
|
|
|
|
|
) {
|
|
|
|
|
primaryKey = prevTableData[selectedRowIndex][primaryColumnId] as string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!!primaryKey && tableData) {
|
|
|
|
|
const selectedRow = tableData.find(
|
|
|
|
|
(row) => row[primaryColumnId] === primaryKey,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (selectedRow) {
|
|
|
|
|
index = selectedRow[ORIGINAL_INDEX_KEY] as number;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return index;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const getSelectRowIndex = (
|
|
|
|
|
prevTableData: TableData,
|
|
|
|
|
tableData: TableData,
|
|
|
|
|
defaultSelectedRowIndex: string | number | number[] | undefined,
|
|
|
|
|
selectedRowIndex: number | undefined,
|
|
|
|
|
primaryColumnId: string | undefined,
|
|
|
|
|
) => {
|
|
|
|
|
let index = _.isNumber(defaultSelectedRowIndex)
|
|
|
|
|
? defaultSelectedRowIndex
|
|
|
|
|
: -1;
|
|
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
selectedRowIndex !== -1 &&
|
|
|
|
|
!_.isNil(selectedRowIndex) &&
|
|
|
|
|
primaryColumnId
|
|
|
|
|
) {
|
|
|
|
|
index = getOriginalRowIndex(
|
|
|
|
|
prevTableData,
|
|
|
|
|
tableData,
|
|
|
|
|
selectedRowIndex,
|
|
|
|
|
primaryColumnId,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return index;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const getSelectRowIndices = (
|
|
|
|
|
prevTableData: TableData,
|
|
|
|
|
tableData: TableData,
|
|
|
|
|
defaultSelectedRowIndices: string | number | number[] | undefined,
|
|
|
|
|
selectedRowIndices: number[] | undefined,
|
|
|
|
|
primaryColumnId: string | undefined,
|
|
|
|
|
) => {
|
|
|
|
|
let indices: number[];
|
|
|
|
|
|
|
|
|
|
if (primaryColumnId && _.isArray(selectedRowIndices)) {
|
|
|
|
|
indices = selectedRowIndices;
|
|
|
|
|
} else if (_.isArray(defaultSelectedRowIndices)) {
|
|
|
|
|
indices = defaultSelectedRowIndices;
|
|
|
|
|
} else {
|
|
|
|
|
indices = [];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (primaryColumnId) {
|
|
|
|
|
return indices
|
|
|
|
|
.map((index: number) =>
|
|
|
|
|
getOriginalRowIndex(prevTableData, tableData, index, primaryColumnId),
|
|
|
|
|
)
|
|
|
|
|
.filter((index) => index !== -1);
|
|
|
|
|
} else {
|
|
|
|
|
return indices;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//TODO(Balaji): we shouldn't replace special characters
|
|
|
|
|
export const removeSpecialChars = (value: string, limit?: number) => {
|
|
|
|
|
const separatorRegex = /\W+/;
|
|
|
|
|
return value
|
|
|
|
|
.split(separatorRegex)
|
|
|
|
|
.join("_")
|
|
|
|
|
.slice(0, limit || 30);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Function to get list of columns from the tabledata
|
|
|
|
|
*/
|
|
|
|
|
export const getAllTableColumnKeys = (
|
|
|
|
|
tableData?: Array<Record<string, unknown>>,
|
|
|
|
|
) => {
|
|
|
|
|
const columnKeys: Set<string> = new Set();
|
|
|
|
|
|
|
|
|
|
if (_.isArray(tableData)) {
|
|
|
|
|
tableData.forEach((row) => {
|
|
|
|
|
Object.keys(row).forEach((key) => {
|
|
|
|
|
columnKeys.add(key);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Array.from(columnKeys);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export function getTableStyles(props: TableStyles) {
|
|
|
|
|
return {
|
|
|
|
|
textColor: props.textColor,
|
|
|
|
|
textSize: props.textSize,
|
|
|
|
|
fontStyle: props.fontStyle,
|
|
|
|
|
cellBackground: props.cellBackground,
|
|
|
|
|
verticalAlignment: props.verticalAlignment,
|
|
|
|
|
horizontalAlignment: props.horizontalAlignment,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function escapeString(str: string) {
|
|
|
|
|
/*
|
|
|
|
|
* Match all the unescaped `"`
|
|
|
|
|
* match `"` that follows any character except `\`. ([^\\]\")
|
|
|
|
|
*/
|
|
|
|
|
return str.replace(/[^\\]"/g, (match) => {
|
|
|
|
|
return match.substr(0, match.length - 1) + `\"`;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function getDefaultColumnProperties(
|
|
|
|
|
id: string,
|
|
|
|
|
sanitizedId: string,
|
|
|
|
|
index: number,
|
|
|
|
|
widgetName: string,
|
|
|
|
|
isDerived?: boolean,
|
2022-09-29 05:26:08 +00:00
|
|
|
columnType?: string,
|
2022-07-14 07:02:35 +00:00
|
|
|
): ColumnProperties {
|
|
|
|
|
const columnProps = {
|
|
|
|
|
allowCellWrapping: false,
|
2023-04-06 18:28:24 +00:00
|
|
|
allowSameOptionsInNewRow: true,
|
2022-07-14 07:02:35 +00:00
|
|
|
index: index,
|
|
|
|
|
width: DEFAULT_COLUMN_WIDTH,
|
|
|
|
|
originalId: id,
|
|
|
|
|
id: sanitizedId,
|
|
|
|
|
alias: id,
|
|
|
|
|
horizontalAlignment: CellAlignmentTypes.LEFT,
|
|
|
|
|
verticalAlignment: VerticalAlignmentTypes.CENTER,
|
2022-09-29 05:26:08 +00:00
|
|
|
columnType: columnType || ColumnTypes.TEXT,
|
2022-07-14 07:02:35 +00:00
|
|
|
textColor: Colors.THUNDER,
|
|
|
|
|
textSize: "0.875rem",
|
|
|
|
|
fontStyle: FontStyleTypes.REGULAR,
|
|
|
|
|
enableFilter: true,
|
|
|
|
|
enableSort: true,
|
|
|
|
|
isVisible: true,
|
|
|
|
|
isDisabled: false,
|
|
|
|
|
isCellEditable: false,
|
|
|
|
|
isEditable: false,
|
|
|
|
|
isCellVisible: true,
|
|
|
|
|
isDerived: !!isDerived,
|
|
|
|
|
label: id,
|
|
|
|
|
isSaveVisible: true,
|
|
|
|
|
isDiscardVisible: true,
|
|
|
|
|
computedValue: isDerived
|
|
|
|
|
? ""
|
|
|
|
|
: `{{${widgetName}.processedTableData.map((currentRow, currentIndex) => ( currentRow["${escapeString(
|
|
|
|
|
id,
|
|
|
|
|
)}"]))}}`,
|
2023-02-15 11:42:46 +00:00
|
|
|
sticky: StickyType.NONE,
|
2022-09-13 05:41:59 +00:00
|
|
|
validation: {},
|
2022-07-14 07:02:35 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return columnProps;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Function to extract derived columns from the primary columns
|
|
|
|
|
*/
|
|
|
|
|
export function getDerivedColumns(
|
|
|
|
|
primaryColumns: Record<string, ColumnProperties>,
|
|
|
|
|
): Record<string, ColumnProperties> {
|
|
|
|
|
const derivedColumns: Record<string, ColumnProperties> = {};
|
|
|
|
|
|
|
|
|
|
if (primaryColumns) {
|
|
|
|
|
Object.keys(primaryColumns).forEach((columnId) => {
|
|
|
|
|
if (primaryColumns[columnId] && primaryColumns[columnId].isDerived) {
|
|
|
|
|
derivedColumns[columnId] = primaryColumns[columnId];
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return derivedColumns;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export const getPropertyValue = (
|
|
|
|
|
value: any,
|
|
|
|
|
index: number,
|
|
|
|
|
preserveCase = false,
|
2022-12-30 10:52:11 +00:00
|
|
|
isSourceData = false,
|
2022-07-14 07:02:35 +00:00
|
|
|
) => {
|
|
|
|
|
if (value && isObject(value) && !Array.isArray(value)) {
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
if (value && Array.isArray(value) && value[index]) {
|
2022-12-30 10:52:11 +00:00
|
|
|
const getValueForSourceData = (value: any, index: number) => {
|
|
|
|
|
return Array.isArray(value[index]) ? value[index] : value;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return isSourceData
|
|
|
|
|
? getValueForSourceData(value, index)
|
|
|
|
|
: preserveCase
|
2022-07-14 07:02:35 +00:00
|
|
|
? value[index].toString()
|
|
|
|
|
: value[index].toString().toUpperCase();
|
|
|
|
|
} else if (value) {
|
|
|
|
|
return preserveCase ? value.toString() : value.toString().toUpperCase();
|
|
|
|
|
} else {
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
};
|
2022-12-16 04:35:51 +00:00
|
|
|
export const getBooleanPropertyValue = (value: unknown, index: number) => {
|
2022-07-14 07:02:35 +00:00
|
|
|
if (isBoolean(value)) {
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
if (Array.isArray(value) && isBoolean(value[index])) {
|
|
|
|
|
return value[index];
|
|
|
|
|
}
|
|
|
|
|
return !!value;
|
|
|
|
|
};
|
|
|
|
|
|
2022-12-16 04:35:51 +00:00
|
|
|
export const getArrayPropertyValue = (value: unknown, index: number) => {
|
|
|
|
|
if (Array.isArray(value) && value.length > 0) {
|
|
|
|
|
if (Array.isArray(value[0])) {
|
|
|
|
|
// value is array of arrays of label value
|
|
|
|
|
return value[index];
|
|
|
|
|
} else {
|
|
|
|
|
// value is array of label value
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2022-07-14 07:02:35 +00:00
|
|
|
export const getCellProperties = (
|
|
|
|
|
columnProperties: ColumnProperties,
|
|
|
|
|
rowIndex: number,
|
2023-04-06 18:28:24 +00:00
|
|
|
isAddRowInProgress = false,
|
2022-07-14 07:02:35 +00:00
|
|
|
) => {
|
|
|
|
|
if (columnProperties) {
|
|
|
|
|
return {
|
|
|
|
|
horizontalAlignment: getPropertyValue(
|
|
|
|
|
columnProperties.horizontalAlignment,
|
|
|
|
|
rowIndex,
|
|
|
|
|
),
|
|
|
|
|
verticalAlignment: getPropertyValue(
|
|
|
|
|
columnProperties.verticalAlignment,
|
|
|
|
|
rowIndex,
|
|
|
|
|
),
|
|
|
|
|
cellBackground: getPropertyValue(
|
|
|
|
|
columnProperties.cellBackground,
|
|
|
|
|
rowIndex,
|
|
|
|
|
),
|
|
|
|
|
buttonColor: getPropertyValue(columnProperties.buttonColor, rowIndex),
|
|
|
|
|
buttonLabel: getPropertyValue(
|
|
|
|
|
columnProperties.buttonLabel,
|
|
|
|
|
rowIndex,
|
|
|
|
|
true,
|
|
|
|
|
),
|
|
|
|
|
menuButtonLabel: getPropertyValue(
|
|
|
|
|
columnProperties.menuButtonLabel,
|
|
|
|
|
rowIndex,
|
|
|
|
|
true,
|
|
|
|
|
),
|
|
|
|
|
iconName: getPropertyValue(columnProperties.iconName, rowIndex, true),
|
|
|
|
|
menuButtoniconName: getPropertyValue(
|
|
|
|
|
columnProperties.menuButtoniconName,
|
|
|
|
|
rowIndex,
|
|
|
|
|
true,
|
|
|
|
|
),
|
2022-12-30 10:52:11 +00:00
|
|
|
menuItemsSource: getPropertyValue(
|
|
|
|
|
columnProperties.menuItemsSource,
|
|
|
|
|
rowIndex,
|
|
|
|
|
true,
|
|
|
|
|
),
|
|
|
|
|
sourceData: getPropertyValue(
|
|
|
|
|
columnProperties.sourceData,
|
|
|
|
|
rowIndex,
|
|
|
|
|
false,
|
|
|
|
|
true,
|
|
|
|
|
),
|
|
|
|
|
configureMenuItems: columnProperties.configureMenuItems,
|
2022-07-14 07:02:35 +00:00
|
|
|
buttonVariant: getPropertyValue(
|
|
|
|
|
columnProperties.buttonVariant,
|
|
|
|
|
rowIndex,
|
|
|
|
|
true,
|
|
|
|
|
),
|
|
|
|
|
borderRadius: getPropertyValue(
|
|
|
|
|
columnProperties.borderRadius,
|
|
|
|
|
rowIndex,
|
|
|
|
|
true,
|
|
|
|
|
),
|
|
|
|
|
boxShadow: getPropertyValue(columnProperties.boxShadow, rowIndex, true),
|
|
|
|
|
iconButtonStyle: getPropertyValue(
|
|
|
|
|
columnProperties.iconButtonStyle,
|
|
|
|
|
rowIndex,
|
|
|
|
|
true,
|
|
|
|
|
),
|
|
|
|
|
textSize: getPropertyValue(columnProperties.textSize, rowIndex),
|
|
|
|
|
textColor: getPropertyValue(columnProperties.textColor, rowIndex),
|
|
|
|
|
fontStyle: getPropertyValue(columnProperties.fontStyle, rowIndex), //Fix this
|
|
|
|
|
isVisible: getBooleanPropertyValue(columnProperties.isVisible, rowIndex),
|
|
|
|
|
isDisabled: getBooleanPropertyValue(
|
|
|
|
|
columnProperties.isDisabled,
|
|
|
|
|
rowIndex,
|
|
|
|
|
),
|
|
|
|
|
isCellVisible: getBooleanPropertyValue(
|
|
|
|
|
columnProperties.isCellVisible,
|
|
|
|
|
rowIndex,
|
|
|
|
|
),
|
|
|
|
|
displayText: getPropertyValue(
|
|
|
|
|
columnProperties.displayText,
|
|
|
|
|
rowIndex,
|
|
|
|
|
true,
|
|
|
|
|
),
|
|
|
|
|
iconAlign: getPropertyValue(columnProperties.iconAlign, rowIndex, true),
|
|
|
|
|
isCompact: getPropertyValue(columnProperties.isCompact, rowIndex),
|
|
|
|
|
menuColor: getPropertyValue(columnProperties.menuColor, rowIndex, true),
|
|
|
|
|
menuItems: getPropertyValue(columnProperties.menuItems, rowIndex),
|
|
|
|
|
menuVariant: getPropertyValue(
|
|
|
|
|
columnProperties.menuVariant,
|
|
|
|
|
rowIndex,
|
|
|
|
|
true,
|
|
|
|
|
),
|
|
|
|
|
isCellEditable: getBooleanPropertyValue(
|
|
|
|
|
columnProperties.isCellEditable,
|
|
|
|
|
rowIndex,
|
|
|
|
|
),
|
|
|
|
|
allowCellWrapping: getBooleanPropertyValue(
|
|
|
|
|
columnProperties.allowCellWrapping,
|
|
|
|
|
rowIndex,
|
|
|
|
|
),
|
|
|
|
|
// EditActions related properties
|
|
|
|
|
saveButtonVariant: getPropertyValue(
|
|
|
|
|
columnProperties.saveButtonVariant,
|
|
|
|
|
rowIndex,
|
|
|
|
|
true,
|
|
|
|
|
),
|
|
|
|
|
saveButtonColor: getPropertyValue(
|
|
|
|
|
columnProperties.saveButtonColor,
|
|
|
|
|
rowIndex,
|
|
|
|
|
true,
|
|
|
|
|
),
|
|
|
|
|
saveIconAlign: getPropertyValue(
|
|
|
|
|
columnProperties.saveIconAlign,
|
|
|
|
|
rowIndex,
|
|
|
|
|
true,
|
|
|
|
|
),
|
|
|
|
|
saveBorderRadius: getPropertyValue(
|
|
|
|
|
columnProperties.saveBorderRadius,
|
|
|
|
|
rowIndex,
|
|
|
|
|
true,
|
|
|
|
|
),
|
|
|
|
|
saveActionLabel: getPropertyValue(
|
|
|
|
|
columnProperties.saveActionLabel,
|
|
|
|
|
rowIndex,
|
|
|
|
|
true,
|
|
|
|
|
),
|
|
|
|
|
saveActionIconName: getPropertyValue(
|
|
|
|
|
columnProperties.saveActionIconName,
|
|
|
|
|
rowIndex,
|
|
|
|
|
true,
|
|
|
|
|
),
|
|
|
|
|
isSaveVisible: getBooleanPropertyValue(
|
|
|
|
|
columnProperties.isSaveVisible,
|
|
|
|
|
rowIndex,
|
|
|
|
|
),
|
|
|
|
|
isSaveDisabled: getBooleanPropertyValue(
|
|
|
|
|
columnProperties.isSaveDisabled,
|
|
|
|
|
rowIndex,
|
|
|
|
|
),
|
|
|
|
|
discardButtonVariant: getPropertyValue(
|
|
|
|
|
columnProperties.discardButtonVariant,
|
|
|
|
|
rowIndex,
|
|
|
|
|
true,
|
|
|
|
|
),
|
|
|
|
|
discardButtonColor: getPropertyValue(
|
|
|
|
|
columnProperties.discardButtonColor,
|
|
|
|
|
rowIndex,
|
|
|
|
|
true,
|
|
|
|
|
),
|
|
|
|
|
discardIconAlign: getPropertyValue(
|
|
|
|
|
columnProperties.discardIconAlign,
|
|
|
|
|
rowIndex,
|
|
|
|
|
true,
|
|
|
|
|
),
|
|
|
|
|
discardBorderRadius: getPropertyValue(
|
|
|
|
|
columnProperties.discardBorderRadius,
|
|
|
|
|
rowIndex,
|
|
|
|
|
true,
|
|
|
|
|
),
|
|
|
|
|
discardActionLabel: getPropertyValue(
|
|
|
|
|
columnProperties.discardActionLabel,
|
|
|
|
|
rowIndex,
|
|
|
|
|
true,
|
|
|
|
|
),
|
|
|
|
|
discardActionIconName: getPropertyValue(
|
|
|
|
|
columnProperties.discardActionIconName,
|
|
|
|
|
rowIndex,
|
|
|
|
|
true,
|
|
|
|
|
),
|
|
|
|
|
isDiscardVisible: getBooleanPropertyValue(
|
|
|
|
|
columnProperties.isDiscardVisible,
|
|
|
|
|
rowIndex,
|
|
|
|
|
),
|
|
|
|
|
isDiscardDisabled: getBooleanPropertyValue(
|
|
|
|
|
columnProperties.isDiscardDisabled,
|
|
|
|
|
rowIndex,
|
|
|
|
|
),
|
2022-10-14 12:21:54 +00:00
|
|
|
imageSize: getPropertyValue(columnProperties.imageSize, rowIndex, true),
|
2022-09-30 04:03:53 +00:00
|
|
|
isFilterable: getBooleanPropertyValue(
|
|
|
|
|
columnProperties.isFilterable,
|
|
|
|
|
rowIndex,
|
|
|
|
|
),
|
|
|
|
|
serverSideFiltering: getBooleanPropertyValue(
|
|
|
|
|
columnProperties.serverSideFiltering,
|
|
|
|
|
rowIndex,
|
|
|
|
|
),
|
|
|
|
|
placeholderText: getPropertyValue(
|
|
|
|
|
columnProperties.placeholderText,
|
|
|
|
|
rowIndex,
|
|
|
|
|
true,
|
|
|
|
|
),
|
2023-01-16 09:23:56 +00:00
|
|
|
resetFilterTextOnClose: getPropertyValue(
|
2022-09-30 04:03:53 +00:00
|
|
|
columnProperties.resetFilterTextOnClose,
|
|
|
|
|
rowIndex,
|
|
|
|
|
),
|
2023-01-16 09:23:56 +00:00
|
|
|
inputFormat: getPropertyValue(
|
|
|
|
|
columnProperties.inputFormat,
|
|
|
|
|
rowIndex,
|
|
|
|
|
true,
|
|
|
|
|
),
|
|
|
|
|
outputFormat: getPropertyValue(
|
|
|
|
|
columnProperties.outputFormat,
|
|
|
|
|
rowIndex,
|
|
|
|
|
true,
|
|
|
|
|
),
|
|
|
|
|
shortcuts: getBooleanPropertyValue(columnProperties.shortcuts, rowIndex),
|
2023-04-06 18:28:24 +00:00
|
|
|
selectOptions: getSelectOptions(
|
|
|
|
|
isAddRowInProgress,
|
2022-12-16 04:35:51 +00:00
|
|
|
rowIndex,
|
2023-04-06 18:28:24 +00:00
|
|
|
columnProperties,
|
2022-12-16 04:35:51 +00:00
|
|
|
),
|
2023-01-16 09:23:56 +00:00
|
|
|
timePrecision: getPropertyValue(
|
|
|
|
|
columnProperties.timePrecision,
|
|
|
|
|
rowIndex,
|
|
|
|
|
true,
|
|
|
|
|
),
|
2022-07-14 07:02:35 +00:00
|
|
|
} as CellLayoutProperties;
|
|
|
|
|
}
|
|
|
|
|
return {} as CellLayoutProperties;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const EdtiableColumnTypes: string[] = [
|
|
|
|
|
ColumnTypes.TEXT,
|
|
|
|
|
ColumnTypes.NUMBER,
|
|
|
|
|
ColumnTypes.SELECT,
|
2022-09-08 11:05:59 +00:00
|
|
|
ColumnTypes.CHECKBOX,
|
2022-09-16 04:34:11 +00:00
|
|
|
ColumnTypes.SWITCH,
|
2023-01-16 09:23:56 +00:00
|
|
|
ColumnTypes.DATE,
|
2022-07-14 07:02:35 +00:00
|
|
|
];
|
|
|
|
|
|
|
|
|
|
export function isColumnTypeEditable(columnType: string) {
|
|
|
|
|
return EdtiableColumnTypes.includes(columnType);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Nested propeties are not validated when application is refreshed
|
|
|
|
|
* TODO(Balai): Should confirm and create an issue to address this.
|
|
|
|
|
*/
|
|
|
|
|
export function getSelectColumnTypeOptions(value: unknown) {
|
|
|
|
|
const result = SelectColumnOptionsValidations(value, {}, _);
|
|
|
|
|
return result.parsed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* returns selected row bg color
|
|
|
|
|
*
|
|
|
|
|
* if the color is dark, use 80% lighter color for selected row
|
|
|
|
|
* if color is light, use 10% darker color for selected row
|
|
|
|
|
*
|
|
|
|
|
* @param accentColor
|
|
|
|
|
*/
|
|
|
|
|
export const getSelectedRowBgColor = (accentColor: string) => {
|
|
|
|
|
const tinyAccentColor = tinycolor(accentColor);
|
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 brightness = tinycolor(accentColor).greyscale().getBrightness();
|
2022-07-14 07:02:35 +00:00
|
|
|
|
|
|
|
|
const percentageBrightness = (brightness / 255) * 100;
|
|
|
|
|
let nextBrightness = 0;
|
|
|
|
|
|
|
|
|
|
switch (true) {
|
|
|
|
|
case percentageBrightness > 70:
|
|
|
|
|
nextBrightness = 10;
|
|
|
|
|
break;
|
|
|
|
|
case percentageBrightness > 50:
|
|
|
|
|
nextBrightness = 35;
|
|
|
|
|
break;
|
|
|
|
|
case percentageBrightness > 50:
|
|
|
|
|
nextBrightness = 55;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
nextBrightness = 60;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (brightness > 180) {
|
|
|
|
|
return tinyAccentColor.darken(10).toString();
|
|
|
|
|
} else {
|
|
|
|
|
return tinyAccentColor.lighten(nextBrightness).toString();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* this is a getter function to get stylesheet value of the property from the config
|
|
|
|
|
*
|
|
|
|
|
* @param props
|
|
|
|
|
* @param propertyPath
|
|
|
|
|
* @param widgetStylesheet
|
|
|
|
|
* @returns
|
|
|
|
|
*/
|
|
|
|
|
export const getStylesheetValue = (
|
|
|
|
|
props: TableWidgetProps,
|
|
|
|
|
propertyPath: string,
|
2022-11-28 04:44:31 +00:00
|
|
|
widgetStylesheet?: Stylesheet,
|
2022-07-14 07:02:35 +00:00
|
|
|
) => {
|
|
|
|
|
const propertyName = propertyPath.split(".").slice(-1)[0];
|
|
|
|
|
const columnName = propertyPath.split(".").slice(-2)[0];
|
|
|
|
|
const columnType = get(props, `primaryColumns.${columnName}.columnType`);
|
|
|
|
|
|
|
|
|
|
return get(widgetStylesheet, `childStylesheet.${columnType}.${propertyName}`);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const reorderColumns = (
|
|
|
|
|
columns: Record<string, ColumnProperties>,
|
|
|
|
|
columnOrder: string[],
|
|
|
|
|
) => {
|
|
|
|
|
const newColumnsInOrder: Record<string, ColumnProperties> = {};
|
|
|
|
|
uniq(columnOrder).forEach((id: string, index: number) => {
|
|
|
|
|
if (columns[id]) newColumnsInOrder[id] = { ...columns[id], index };
|
|
|
|
|
});
|
|
|
|
|
const remaining = without(
|
|
|
|
|
Object.keys(columns),
|
|
|
|
|
...Object.keys(newColumnsInOrder),
|
|
|
|
|
);
|
|
|
|
|
const len = Object.keys(newColumnsInOrder).length;
|
|
|
|
|
if (remaining && remaining.length > 0) {
|
|
|
|
|
remaining.forEach((id: string, index: number) => {
|
|
|
|
|
newColumnsInOrder[id] = { ...columns[id], index: len + index };
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
return newColumnsInOrder;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const getEditActionColumnProperties = () => ({
|
|
|
|
|
isSaveVisible: true,
|
|
|
|
|
isDiscardVisible: true,
|
|
|
|
|
saveIconAlign: "left",
|
|
|
|
|
discardIconAlign: "left",
|
|
|
|
|
saveActionLabel: "Save",
|
|
|
|
|
discardActionLabel: "Discard",
|
|
|
|
|
saveButtonColor: Colors.GREEN,
|
|
|
|
|
discardButtonColor: Colors.GREEN,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
export const getEditActionColumnDynamicProperties = (widgetName: string) => ({
|
|
|
|
|
isSaveDisabled: `{{${widgetName}.processedTableData.map((currentRow, currentIndex) => ( !${widgetName}.updatedRowIndices.includes(currentIndex)))}}`,
|
|
|
|
|
isDiscardDisabled: `{{${widgetName}.processedTableData.map((currentRow, currentIndex) => ( !${widgetName}.updatedRowIndices.includes(currentIndex)))}}`,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
export const createColumn = (props: TableWidgetProps, baseName: string) => {
|
|
|
|
|
const columns = props.primaryColumns || {};
|
|
|
|
|
const columnsArray = Object.values(columns);
|
|
|
|
|
const columnIds = columnsArray.map((column) => column.originalId);
|
|
|
|
|
const newColumnName = getNextEntityName(baseName, columnIds);
|
|
|
|
|
const lastItemIndex = columnsArray
|
|
|
|
|
.map((column) => column.index)
|
|
|
|
|
.sort()
|
|
|
|
|
.pop();
|
2023-02-15 11:42:46 +00:00
|
|
|
|
2022-07-14 07:02:35 +00:00
|
|
|
const nextIndex = lastItemIndex ? lastItemIndex + 1 : columnIds.length;
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
...getDefaultColumnProperties(
|
|
|
|
|
newColumnName,
|
|
|
|
|
newColumnName,
|
|
|
|
|
nextIndex,
|
|
|
|
|
props.widgetName,
|
|
|
|
|
true,
|
|
|
|
|
),
|
|
|
|
|
buttonStyle: DEFAULT_BUTTON_COLOR,
|
|
|
|
|
isDisabled: false,
|
|
|
|
|
...getTableStyles(props),
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const createEditActionColumn = (props: TableWidgetProps) => {
|
|
|
|
|
const themeProps: Record<string, string> = {};
|
|
|
|
|
|
|
|
|
|
if (props.childStylesheet[ColumnTypes.EDIT_ACTIONS]) {
|
|
|
|
|
Object.entries(props.childStylesheet[ColumnTypes.EDIT_ACTIONS]).forEach(
|
|
|
|
|
([key, value]) => {
|
|
|
|
|
const { jsSnippets, stringSegments } = getDynamicBindings(
|
|
|
|
|
value as string,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const js = combineDynamicBindings(jsSnippets, stringSegments);
|
|
|
|
|
|
|
|
|
|
themeProps[
|
|
|
|
|
key
|
|
|
|
|
] = `{{${props.widgetName}.processedTableData.map((currentRow, currentIndex) => ( ${js}))}}`;
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const column = {
|
|
|
|
|
...createColumn(props, "EditActions"),
|
|
|
|
|
...getEditActionColumnProperties(),
|
|
|
|
|
...themeProps,
|
|
|
|
|
columnType: ColumnTypes.EDIT_ACTIONS,
|
|
|
|
|
label: "Save / Discard",
|
|
|
|
|
discardButtonVariant: ButtonVariantTypes.TERTIARY,
|
|
|
|
|
discardButtonColor: Colors.DANGER_SOLID,
|
2023-02-15 11:42:46 +00:00
|
|
|
sticky: StickyType.RIGHT,
|
2022-07-14 07:02:35 +00:00
|
|
|
};
|
2023-02-15 11:42:46 +00:00
|
|
|
const columnOrder = [...(props.columnOrder || [])];
|
2022-07-14 07:02:35 +00:00
|
|
|
const editActionDynamicProperties = getEditActionColumnDynamicProperties(
|
|
|
|
|
props.widgetName,
|
|
|
|
|
);
|
|
|
|
|
|
2023-02-15 11:42:46 +00:00
|
|
|
const rightColumnIndex = columnOrder
|
|
|
|
|
.map((column) => props.primaryColumns[column])
|
|
|
|
|
.filter((col) => col.sticky !== StickyType.RIGHT).length;
|
|
|
|
|
columnOrder.splice(rightColumnIndex, 0, column.id);
|
2022-07-14 07:02:35 +00:00
|
|
|
return [
|
|
|
|
|
{
|
|
|
|
|
propertyPath: `primaryColumns.${column.id}`,
|
2022-09-21 11:35:15 +00:00
|
|
|
propertyValue: {
|
|
|
|
|
...column,
|
|
|
|
|
...editActionDynamicProperties,
|
|
|
|
|
},
|
2022-07-14 07:02:35 +00:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
propertyPath: `columnOrder`,
|
2023-02-15 11:42:46 +00:00
|
|
|
propertyValue: columnOrder,
|
2022-07-14 07:02:35 +00:00
|
|
|
},
|
|
|
|
|
...Object.entries(editActionDynamicProperties).map(([key, value]) => ({
|
|
|
|
|
propertyPath: `primaryColumns.${column.id}.${key}`,
|
|
|
|
|
propertyValue: value,
|
|
|
|
|
isDynamicPropertyPath: true,
|
|
|
|
|
})),
|
|
|
|
|
];
|
|
|
|
|
};
|
2022-09-29 05:26:08 +00:00
|
|
|
|
|
|
|
|
export const getColumnType = (
|
|
|
|
|
tableData: Array<Record<string, unknown>>,
|
|
|
|
|
columnKey: string,
|
|
|
|
|
): string => {
|
|
|
|
|
if (!_.isArray(tableData) || tableData.length === 0 || !columnKey) {
|
|
|
|
|
return ColumnTypes.TEXT;
|
|
|
|
|
}
|
|
|
|
|
let columnValue: unknown = null,
|
|
|
|
|
row = 0;
|
|
|
|
|
const maxRowsToCheck = 5;
|
|
|
|
|
/*
|
|
|
|
|
In below while loop we are trying to get a non-null value from
|
|
|
|
|
subsequent rows in case first few rows are null
|
|
|
|
|
Limited to checking upto maxRowsToCheck
|
|
|
|
|
*/
|
|
|
|
|
while (_.isNil(columnValue) && row < maxRowsToCheck) {
|
|
|
|
|
if (!_.isNil(tableData?.[row]?.[columnKey])) {
|
|
|
|
|
columnValue = tableData[row][columnKey];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
row++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_.isNil(columnValue)) {
|
|
|
|
|
return ColumnTypes.TEXT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (typeof columnValue) {
|
|
|
|
|
case "number":
|
|
|
|
|
return ColumnTypes.NUMBER;
|
|
|
|
|
case "boolean":
|
|
|
|
|
return ColumnTypes.CHECKBOX;
|
|
|
|
|
case "string":
|
|
|
|
|
return dateFormatOptions.some(({ value: format }) =>
|
|
|
|
|
moment(columnValue as string, format, true).isValid(),
|
|
|
|
|
)
|
|
|
|
|
? ColumnTypes.DATE
|
|
|
|
|
: ColumnTypes.TEXT;
|
|
|
|
|
default:
|
|
|
|
|
return ColumnTypes.TEXT;
|
|
|
|
|
}
|
|
|
|
|
};
|
2022-12-30 10:52:11 +00:00
|
|
|
|
2023-02-15 11:42:46 +00:00
|
|
|
export const generateLocalNewColumnOrderFromStickyValue = (
|
|
|
|
|
columnOrder: string[],
|
|
|
|
|
columnName: string,
|
|
|
|
|
sticky?: string,
|
|
|
|
|
leftOrder?: string[],
|
|
|
|
|
rightOrder?: string[],
|
|
|
|
|
) => {
|
|
|
|
|
let newColumnOrder = [...columnOrder];
|
|
|
|
|
newColumnOrder = without(newColumnOrder, columnName);
|
|
|
|
|
|
|
|
|
|
let columnIndex = -1;
|
|
|
|
|
if (sticky === StickyType.LEFT && leftOrder) {
|
|
|
|
|
columnIndex = leftOrder.length;
|
|
|
|
|
} else if (sticky === StickyType.RIGHT && rightOrder) {
|
|
|
|
|
columnIndex =
|
|
|
|
|
rightOrder.length !== 0
|
|
|
|
|
? columnOrder.indexOf(rightOrder[0]) - 1
|
|
|
|
|
: columnOrder.length - 1;
|
|
|
|
|
} else {
|
|
|
|
|
if (leftOrder?.includes(columnName)) {
|
|
|
|
|
columnIndex = leftOrder.length - 1;
|
|
|
|
|
} else if (rightOrder?.includes(columnName)) {
|
|
|
|
|
columnIndex =
|
|
|
|
|
rightOrder.length !== 0
|
|
|
|
|
? columnOrder.indexOf(rightOrder[0])
|
|
|
|
|
: columnOrder.length - 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
newColumnOrder.splice(columnIndex, 0, columnName);
|
|
|
|
|
return newColumnOrder;
|
|
|
|
|
};
|
|
|
|
|
/**
|
|
|
|
|
* Function to get new column order when there is a change in column's sticky value.
|
|
|
|
|
*/
|
|
|
|
|
export const generateNewColumnOrderFromStickyValue = (
|
|
|
|
|
primaryColumns: Record<string, ColumnProperties>,
|
|
|
|
|
columnOrder: string[],
|
|
|
|
|
columnName: string,
|
|
|
|
|
sticky?: string,
|
|
|
|
|
) => {
|
|
|
|
|
let newColumnOrder = [...columnOrder];
|
|
|
|
|
newColumnOrder = without(newColumnOrder, columnName);
|
|
|
|
|
|
|
|
|
|
let columnIndex;
|
|
|
|
|
if (sticky === StickyType.LEFT) {
|
|
|
|
|
columnIndex = columnOrder
|
|
|
|
|
.map((column) => primaryColumns[column])
|
|
|
|
|
.filter((column) => column.sticky === StickyType.LEFT).length;
|
|
|
|
|
} else if (sticky === StickyType.RIGHT) {
|
|
|
|
|
columnIndex =
|
|
|
|
|
columnOrder
|
|
|
|
|
.map((column) => primaryColumns[column])
|
|
|
|
|
.filter((column) => column.sticky !== StickyType.RIGHT).length - 1;
|
|
|
|
|
} else {
|
|
|
|
|
/**
|
|
|
|
|
* This block will manage the column order when column is unfrozen.
|
|
|
|
|
* Unfreezing can happen in CANVAS or PAGE mode.
|
|
|
|
|
* Logic:
|
|
|
|
|
* --> If the column is unfrozen when its on the left, then it should be unfrozen after the last left frozen column.
|
|
|
|
|
* --> If the column is unfrozen when its on the right, then it should be unfrozen before the first right frozen column.
|
|
|
|
|
*/
|
|
|
|
|
columnIndex = -1;
|
|
|
|
|
|
|
|
|
|
const staleStickyValue = primaryColumns[columnName].sticky;
|
|
|
|
|
|
|
|
|
|
if (staleStickyValue === StickyType.LEFT) {
|
|
|
|
|
columnIndex = columnOrder
|
|
|
|
|
.map((column) => primaryColumns[column])
|
|
|
|
|
.filter(
|
|
|
|
|
(column) =>
|
|
|
|
|
column.sticky === StickyType.LEFT && column.id !== columnName,
|
|
|
|
|
).length;
|
|
|
|
|
} else if (staleStickyValue === StickyType.RIGHT) {
|
|
|
|
|
columnIndex = columnOrder
|
|
|
|
|
.map((column) => primaryColumns[column])
|
|
|
|
|
.filter((column) => column.sticky !== StickyType.RIGHT).length;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
newColumnOrder.splice(columnIndex, 0, columnName);
|
|
|
|
|
return newColumnOrder;
|
|
|
|
|
};
|
|
|
|
|
|
2022-12-30 10:52:11 +00:00
|
|
|
export const getSourceDataAndCaluclateKeysForEventAutoComplete = (
|
|
|
|
|
props: TableWidgetProps,
|
|
|
|
|
): unknown => {
|
|
|
|
|
const { __evaluation__, primaryColumns } = props;
|
|
|
|
|
const primaryColumnKeys = primaryColumns ? Object.keys(primaryColumns) : [];
|
|
|
|
|
const columnName = primaryColumnKeys?.length ? primaryColumnKeys[0] : "";
|
|
|
|
|
const evaluatedColumns: any = __evaluation__?.evaluatedValues?.primaryColumns;
|
|
|
|
|
|
|
|
|
|
if (evaluatedColumns) {
|
|
|
|
|
const result = getKeysFromSourceDataForEventAutocomplete(
|
|
|
|
|
evaluatedColumns[columnName]?.sourceData || [],
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
} else {
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
};
|
2023-02-15 11:42:46 +00:00
|
|
|
|
|
|
|
|
export const deleteLocalTableColumnOrderByWidgetId = (widgetId: string) => {
|
|
|
|
|
try {
|
|
|
|
|
const localData = localStorage.getItem(TABLE_COLUMN_ORDER_KEY);
|
|
|
|
|
if (localData) {
|
|
|
|
|
const localColumnOrder = JSON.parse(localData);
|
|
|
|
|
delete localColumnOrder[widgetId];
|
|
|
|
|
localStorage.setItem(
|
|
|
|
|
TABLE_COLUMN_ORDER_KEY,
|
|
|
|
|
JSON.stringify(localColumnOrder),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
log.debug("Error in reading local data", e);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const fetchSticky = (
|
|
|
|
|
columnId: string,
|
|
|
|
|
primaryColumns: Record<string, ColumnProperties>,
|
|
|
|
|
renderMode: RenderMode,
|
|
|
|
|
widgetId?: string,
|
|
|
|
|
): StickyType | undefined => {
|
|
|
|
|
if (renderMode === RenderModes.PAGE && widgetId) {
|
|
|
|
|
const localTableColumnOrder = getColumnOrderByWidgetIdFromLS(widgetId);
|
|
|
|
|
if (localTableColumnOrder) {
|
|
|
|
|
const { leftOrder, rightOrder } = localTableColumnOrder;
|
|
|
|
|
if (leftOrder.indexOf(columnId) > -1) {
|
|
|
|
|
return StickyType.LEFT;
|
|
|
|
|
} else if (rightOrder.indexOf(columnId) > -1) {
|
|
|
|
|
return StickyType.RIGHT;
|
|
|
|
|
} else {
|
|
|
|
|
return StickyType.NONE;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
return get(primaryColumns, `${columnId}`).sticky;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (renderMode === RenderModes.CANVAS) {
|
|
|
|
|
return get(primaryColumns, `${columnId}`).sticky;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const updateAndSyncTableLocalColumnOrders = (
|
|
|
|
|
columnName: string,
|
|
|
|
|
leftOrder: string[],
|
|
|
|
|
rightOrder: string[],
|
|
|
|
|
sticky?: StickyType,
|
|
|
|
|
) => {
|
|
|
|
|
if (sticky === StickyType.LEFT) {
|
|
|
|
|
leftOrder.push(columnName);
|
|
|
|
|
if (rightOrder) {
|
|
|
|
|
rightOrder = without(rightOrder, columnName);
|
|
|
|
|
}
|
|
|
|
|
} else if (sticky === StickyType.RIGHT) {
|
|
|
|
|
rightOrder.unshift(columnName);
|
|
|
|
|
// When column is frozen to right from left. Remove the column name from leftOrder
|
|
|
|
|
if (leftOrder) {
|
|
|
|
|
leftOrder = without(leftOrder, columnName);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// remove column from both orders:
|
|
|
|
|
leftOrder = without(leftOrder, columnName);
|
|
|
|
|
rightOrder = without(rightOrder, columnName);
|
|
|
|
|
}
|
|
|
|
|
return { leftOrder, rightOrder };
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const getColumnOrderByWidgetIdFromLS = (widgetId: string) => {
|
|
|
|
|
const localTableWidgetColumnOrder = localStorage.getItem(
|
|
|
|
|
TABLE_COLUMN_ORDER_KEY,
|
|
|
|
|
);
|
|
|
|
|
if (localTableWidgetColumnOrder) {
|
|
|
|
|
try {
|
|
|
|
|
const parsedTableWidgetColumnOrder = JSON.parse(
|
|
|
|
|
localTableWidgetColumnOrder,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (parsedTableWidgetColumnOrder[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 { columnOrder, columnUpdatedAt, leftOrder, rightOrder } =
|
|
|
|
|
parsedTableWidgetColumnOrder[widgetId];
|
2023-02-15 11:42:46 +00:00
|
|
|
return {
|
|
|
|
|
columnOrder,
|
|
|
|
|
columnUpdatedAt,
|
|
|
|
|
leftOrder,
|
|
|
|
|
rightOrder,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
log.debug("Unable to parse local column order:", { e });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const getAllStickyColumnsCount = (columns: TableColumnProps[]) => {
|
|
|
|
|
return (
|
|
|
|
|
filter(columns, { sticky: StickyType.LEFT }).length +
|
|
|
|
|
filter(columns, { sticky: StickyType.RIGHT }).length
|
|
|
|
|
);
|
|
|
|
|
};
|
2023-03-05 14:19:44 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
*
|
|
|
|
|
* @param currentIndex: current dragging item index
|
|
|
|
|
* @param targetIndex: Index poistion of of header that is being hovered
|
|
|
|
|
* @returns
|
|
|
|
|
*/
|
|
|
|
|
export const getHeaderClassNameOnDragDirection = (
|
|
|
|
|
currentIndex: number,
|
|
|
|
|
targetIndex: number,
|
|
|
|
|
) => {
|
|
|
|
|
let parentClasses = "th header-reorder";
|
|
|
|
|
|
|
|
|
|
if (currentIndex !== -1) {
|
|
|
|
|
if (targetIndex > currentIndex) {
|
|
|
|
|
parentClasses += " highlight-right";
|
|
|
|
|
} else if (targetIndex < currentIndex) {
|
|
|
|
|
parentClasses += " highlight-left";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return parentClasses;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const getIndexByColumnName = (
|
|
|
|
|
columnName: string,
|
|
|
|
|
columnOrder?: string[],
|
|
|
|
|
) => {
|
|
|
|
|
let currentIndex = -1;
|
|
|
|
|
if (columnOrder) {
|
|
|
|
|
currentIndex = columnOrder.indexOf(columnName);
|
|
|
|
|
}
|
|
|
|
|
return currentIndex;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* A function to get all drag and drop handlers for HeaderCell component.
|
|
|
|
|
* @param columns: React table columns
|
|
|
|
|
* @param currentDraggedColumn: The Mutable ref object that references column being dragged
|
|
|
|
|
* @param handleReorderColumn : Function to handle column reordering.
|
|
|
|
|
* @param columnOrder
|
|
|
|
|
* @returns
|
|
|
|
|
*/
|
|
|
|
|
export const getDragHandlers = (
|
|
|
|
|
columns: ReactTableColumnProps[],
|
|
|
|
|
currentDraggedColumn: React.MutableRefObject<string>,
|
|
|
|
|
handleReorderColumn: (columnOrder: string[]) => void,
|
|
|
|
|
columnOrder?: string[],
|
|
|
|
|
) => {
|
|
|
|
|
const onDrag = (e: React.DragEvent<HTMLDivElement>) => {
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const onDragEnter = (
|
|
|
|
|
e: React.DragEvent<HTMLDivElement>,
|
|
|
|
|
targetIndex: number,
|
|
|
|
|
) => {
|
|
|
|
|
// We get the parent element(.th) so as to apply left and right highlighting
|
|
|
|
|
const targetElem = e.target as HTMLDivElement;
|
|
|
|
|
const parentTargetElem = targetElem.closest(".th.header-reorder");
|
|
|
|
|
|
|
|
|
|
const currentIndex = getIndexByColumnName(
|
|
|
|
|
currentDraggedColumn.current,
|
|
|
|
|
columnOrder,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (parentTargetElem) {
|
|
|
|
|
parentTargetElem.className = getHeaderClassNameOnDragDirection(
|
|
|
|
|
currentIndex,
|
|
|
|
|
targetIndex,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const onDragEnd = (e: React.DragEvent<HTMLDivElement>) => {
|
|
|
|
|
const targetElem = e.target as HTMLDivElement;
|
|
|
|
|
targetElem.className = targetElem.className.replace(
|
|
|
|
|
" draggable-header--dragging",
|
|
|
|
|
"",
|
|
|
|
|
);
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const onDragLeave = (e: React.DragEvent<HTMLDivElement>) => {
|
|
|
|
|
const targetElem = e.target as HTMLDivElement;
|
|
|
|
|
const parentTargetElem = targetElem.closest(".th.header-reorder");
|
|
|
|
|
|
|
|
|
|
if (parentTargetElem) {
|
|
|
|
|
parentTargetElem.className = "th header-reorder";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
};
|
|
|
|
|
const onDragOver = (
|
|
|
|
|
e: React.DragEvent<HTMLDivElement>,
|
|
|
|
|
targetIndex: number,
|
|
|
|
|
) => {
|
|
|
|
|
// We get the parent element(.th) so as to apply left and right highlighting
|
|
|
|
|
const targetElem = e.target as HTMLDivElement;
|
|
|
|
|
const parentTargetElem = targetElem.closest(".th.header-reorder");
|
|
|
|
|
|
|
|
|
|
const currentIndex = getIndexByColumnName(
|
|
|
|
|
currentDraggedColumn.current,
|
|
|
|
|
columnOrder,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (parentTargetElem) {
|
|
|
|
|
parentTargetElem.className = getHeaderClassNameOnDragDirection(
|
|
|
|
|
currentIndex,
|
|
|
|
|
targetIndex,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const onDragStart = (e: React.DragEvent<HTMLDivElement>, index: number) => {
|
|
|
|
|
currentDraggedColumn.current = columns[index].alias;
|
|
|
|
|
const targetElem = e.target as HTMLDivElement;
|
|
|
|
|
targetElem.className = targetElem.className + " draggable-header--dragging";
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const onDrop = (e: React.DragEvent<HTMLDivElement>, index: number) => {
|
|
|
|
|
const targetElem = e.target as HTMLDivElement;
|
|
|
|
|
if (currentDraggedColumn.current) {
|
|
|
|
|
const partialColumnOrder = without(
|
|
|
|
|
columnOrder,
|
|
|
|
|
currentDraggedColumn.current,
|
|
|
|
|
);
|
|
|
|
|
partialColumnOrder.splice(index, 0, currentDraggedColumn.current);
|
|
|
|
|
handleReorderColumn(partialColumnOrder);
|
|
|
|
|
}
|
|
|
|
|
targetElem.className = targetElem.className.replace(
|
|
|
|
|
" draggable-header--dragging",
|
|
|
|
|
"",
|
|
|
|
|
);
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
onDrag,
|
|
|
|
|
onDragEnd,
|
|
|
|
|
onDragEnter,
|
|
|
|
|
onDragLeave,
|
|
|
|
|
onDragOver,
|
|
|
|
|
onDragStart,
|
|
|
|
|
onDrop,
|
|
|
|
|
};
|
|
|
|
|
};
|
2023-04-06 18:28:24 +00:00
|
|
|
|
|
|
|
|
export const getSelectOptions = (
|
|
|
|
|
isNewRow: boolean,
|
|
|
|
|
rowIndex: number,
|
|
|
|
|
columnProperties: ColumnProperties,
|
|
|
|
|
) => {
|
|
|
|
|
if (isNewRow) {
|
|
|
|
|
if (
|
|
|
|
|
columnProperties.allowSameOptionsInNewRow &&
|
|
|
|
|
columnProperties?.selectOptions
|
|
|
|
|
) {
|
|
|
|
|
// Use select options from the first row
|
|
|
|
|
return getArrayPropertyValue(columnProperties.selectOptions, 0);
|
|
|
|
|
} else {
|
|
|
|
|
return columnProperties.newRowSelectOptions;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
return getArrayPropertyValue(columnProperties.selectOptions, rowIndex);
|
|
|
|
|
}
|
|
|
|
|
};
|