2022-01-07 06:08:17 +00:00
|
|
|
import { getAppsmithConfigs } from "@appsmith/configs";
|
2023-03-04 07:25:54 +00:00
|
|
|
import { ERROR_CODES } from "@appsmith/constants/ApiConstants";
|
|
|
|
|
import { createMessage, ERROR_500 } from "@appsmith/constants/messages";
|
2020-08-28 08:34:01 +00:00
|
|
|
import * as Sentry from "@sentry/react";
|
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 { Property } from "api/ActionAPI";
|
|
|
|
|
import type { AppIconName } from "design-system-old";
|
|
|
|
|
import { AppIconCollection } from "design-system-old";
|
2023-06-29 13:53:25 +00:00
|
|
|
import _, { isPlainObject } from "lodash";
|
2020-03-23 12:40:17 +00:00
|
|
|
import * as log from "loglevel";
|
2022-06-08 09:05:35 +00:00
|
|
|
import { osName } from "react-device-detect";
|
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 { ActionDataState } from "reducers/entityReducers/actionsReducer";
|
|
|
|
|
import type { JSCollectionData } from "reducers/entityReducers/jsActionsReducer";
|
2023-03-04 07:25:54 +00:00
|
|
|
import AnalyticsUtil from "./AnalyticsUtil";
|
2019-08-30 10:33:49 +00:00
|
|
|
|
2021-12-02 20:26:16 +00:00
|
|
|
export const initializeAnalyticsAndTrackers = () => {
|
|
|
|
|
const appsmithConfigs = getAppsmithConfigs();
|
2020-05-28 18:10:26 +00:00
|
|
|
|
2021-12-07 07:32:51 +00:00
|
|
|
try {
|
|
|
|
|
if (appsmithConfigs.sentry.enabled && !window.Sentry) {
|
|
|
|
|
window.Sentry = Sentry;
|
|
|
|
|
Sentry.init({
|
|
|
|
|
...appsmithConfigs.sentry,
|
2022-11-18 09:33:23 +00:00
|
|
|
beforeSend(event) {
|
|
|
|
|
if (
|
|
|
|
|
event.exception &&
|
|
|
|
|
Array.isArray(event.exception.values) &&
|
|
|
|
|
event.exception.values[0].value &&
|
|
|
|
|
event.exception.values[0].type === "ChunkLoadError"
|
|
|
|
|
) {
|
|
|
|
|
// Only log ChunkLoadErrors after the 2 retires
|
|
|
|
|
if (
|
|
|
|
|
!event.exception.values[0].value.includes(
|
|
|
|
|
"failed after 2 retries",
|
|
|
|
|
)
|
|
|
|
|
) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return event;
|
|
|
|
|
},
|
2021-12-07 07:32:51 +00:00
|
|
|
beforeBreadcrumb(breadcrumb) {
|
2020-12-09 06:20:39 +00:00
|
|
|
if (
|
2021-12-07 07:32:51 +00:00
|
|
|
breadcrumb.category === "console" &&
|
|
|
|
|
breadcrumb.level !== "error"
|
2020-12-09 06:20:39 +00:00
|
|
|
) {
|
2021-12-07 07:32:51 +00:00
|
|
|
return null;
|
2020-12-09 06:20:39 +00:00
|
|
|
}
|
2021-12-07 07:32:51 +00:00
|
|
|
if (breadcrumb.category === "sentry.transaction") {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
if (breadcrumb.category === "redux.action") {
|
|
|
|
|
if (
|
|
|
|
|
breadcrumb.data &&
|
|
|
|
|
breadcrumb.data.type === "SET_EVALUATED_TREE"
|
|
|
|
|
) {
|
|
|
|
|
breadcrumb.data = undefined;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return breadcrumb;
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
log.error(e);
|
2019-11-25 12:22:05 +00:00
|
|
|
}
|
2020-11-12 06:26:09 +00:00
|
|
|
|
2021-12-07 07:32:51 +00:00
|
|
|
try {
|
|
|
|
|
if (appsmithConfigs.smartLook.enabled && !(window as any).smartlook) {
|
|
|
|
|
const { id } = appsmithConfigs.smartLook;
|
|
|
|
|
AnalyticsUtil.initializeSmartLook(id);
|
|
|
|
|
}
|
2020-11-12 06:26:09 +00:00
|
|
|
|
2021-12-07 07:32:51 +00:00
|
|
|
if (appsmithConfigs.segment.enabled && !(window as any).analytics) {
|
|
|
|
|
if (appsmithConfigs.segment.apiKey) {
|
|
|
|
|
// This value is only enabled for Appsmith's cloud hosted version. It is not set in self-hosted environments
|
2023-01-06 14:09:38 +00:00
|
|
|
return AnalyticsUtil.initializeSegment(appsmithConfigs.segment.apiKey);
|
2021-12-07 07:32:51 +00:00
|
|
|
} else if (appsmithConfigs.segment.ceKey) {
|
|
|
|
|
// This value is set in self-hosted environments. But if the analytics are disabled, it's never used.
|
2023-01-06 14:09:38 +00:00
|
|
|
return AnalyticsUtil.initializeSegment(appsmithConfigs.segment.ceKey);
|
2021-12-07 07:32:51 +00:00
|
|
|
}
|
2020-11-05 16:51:22 +00:00
|
|
|
}
|
2021-12-07 07:32:51 +00:00
|
|
|
} catch (e) {
|
|
|
|
|
Sentry.captureException(e);
|
|
|
|
|
log.error(e);
|
2019-08-30 10:33:49 +00:00
|
|
|
}
|
2019-09-09 09:08:54 +00:00
|
|
|
};
|
2019-09-18 14:10:57 +00:00
|
|
|
|
|
|
|
|
export const mapToPropList = (map: Record<string, string>): Property[] => {
|
|
|
|
|
return _.map(map, (value, key) => {
|
|
|
|
|
return { key: key, value: value };
|
|
|
|
|
});
|
|
|
|
|
};
|
2019-10-02 18:13:04 +00:00
|
|
|
|
2022-07-14 05:00:30 +00:00
|
|
|
export const INTERACTION_ANALYTICS_EVENT = "INTERACTION_ANALYTICS_EVENT";
|
|
|
|
|
|
|
|
|
|
export type InteractionAnalyticsEventDetail = {
|
|
|
|
|
key?: string;
|
|
|
|
|
propertyName?: string;
|
|
|
|
|
propertyType?: string;
|
|
|
|
|
widgetType?: string;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const interactionAnalyticsEvent = (
|
|
|
|
|
detail: InteractionAnalyticsEventDetail = {},
|
|
|
|
|
) =>
|
|
|
|
|
new CustomEvent(INTERACTION_ANALYTICS_EVENT, {
|
|
|
|
|
bubbles: true,
|
|
|
|
|
detail,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
export function emitInteractionAnalyticsEvent<T extends HTMLElement>(
|
|
|
|
|
element: T | null,
|
|
|
|
|
args: Record<string, unknown>,
|
|
|
|
|
) {
|
|
|
|
|
element?.dispatchEvent(interactionAnalyticsEvent(args));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export const DS_EVENT = "DS_EVENT";
|
|
|
|
|
|
|
|
|
|
export enum DSEventTypes {
|
|
|
|
|
KEYPRESS = "KEYPRESS",
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type DSEventDetail = {
|
|
|
|
|
component: string;
|
|
|
|
|
event: DSEventTypes;
|
|
|
|
|
meta: Record<string, unknown>;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export function createDSEvent(detail: DSEventDetail) {
|
|
|
|
|
return new CustomEvent(DS_EVENT, {
|
|
|
|
|
bubbles: true,
|
|
|
|
|
detail,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function emitDSEvent<T extends HTMLElement>(
|
|
|
|
|
element: T | null,
|
|
|
|
|
args: DSEventDetail,
|
|
|
|
|
) {
|
|
|
|
|
element?.dispatchEvent(createDSEvent(args));
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-11 06:36:07 +00:00
|
|
|
export const getNextEntityName = (
|
|
|
|
|
prefix: string,
|
|
|
|
|
existingNames: string[],
|
|
|
|
|
startWithoutIndex?: boolean,
|
|
|
|
|
) => {
|
2019-10-03 17:06:44 +00:00
|
|
|
const regex = new RegExp(`^${prefix}(\\d+)$`);
|
2021-02-11 06:36:07 +00:00
|
|
|
|
2020-12-24 04:32:25 +00:00
|
|
|
const usedIndices: number[] = existingNames.map((name) => {
|
2020-01-24 09:54:40 +00:00
|
|
|
if (name && regex.test(name)) {
|
2019-10-03 17:06:44 +00:00
|
|
|
const matches = name.match(regex);
|
|
|
|
|
const ind =
|
|
|
|
|
matches && Array.isArray(matches) ? parseInt(matches[1], 10) : 0;
|
2019-10-02 18:13:04 +00:00
|
|
|
return Number.isNaN(ind) ? 0 : ind;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}) as number[];
|
|
|
|
|
|
2020-01-24 09:54:40 +00:00
|
|
|
const lastIndex = Math.max(...usedIndices, ...[0]);
|
2019-10-02 18:13:04 +00:00
|
|
|
|
2021-02-11 06:36:07 +00:00
|
|
|
if (startWithoutIndex && lastIndex === 0) {
|
|
|
|
|
const exactMatchFound = existingNames.some(
|
|
|
|
|
(name) => prefix && name.trim() === prefix.trim(),
|
|
|
|
|
);
|
|
|
|
|
if (!exactMatchFound) {
|
|
|
|
|
return prefix.trim();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-02 18:13:04 +00:00
|
|
|
return prefix + (lastIndex + 1);
|
|
|
|
|
};
|
2019-11-07 11:17:53 +00:00
|
|
|
|
2020-04-14 12:34:14 +00:00
|
|
|
export const getDuplicateName = (prefix: string, existingNames: string[]) => {
|
|
|
|
|
const trimmedPrefix = prefix.replace(/ /g, "");
|
|
|
|
|
const regex = new RegExp(`^${trimmedPrefix}(\\d+)$`);
|
2020-12-24 04:32:25 +00:00
|
|
|
const usedIndices: number[] = existingNames.map((name) => {
|
2020-04-14 12:34:14 +00:00
|
|
|
if (name && regex.test(name)) {
|
|
|
|
|
const matches = name.match(regex);
|
|
|
|
|
const ind =
|
|
|
|
|
matches && Array.isArray(matches) ? parseInt(matches[1], 10) : 0;
|
|
|
|
|
return Number.isNaN(ind) ? 0 : ind;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}) as number[];
|
|
|
|
|
|
|
|
|
|
const lastIndex = Math.max(...usedIndices, ...[0]);
|
|
|
|
|
|
|
|
|
|
return trimmedPrefix + `_${lastIndex + 1}`;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const createNewApiName = (actions: ActionDataState, pageId: string) => {
|
|
|
|
|
const pageApiNames = actions
|
2020-12-24 04:32:25 +00:00
|
|
|
.filter((a) => a.config.pageId === pageId)
|
|
|
|
|
.map((a) => a.config.name);
|
2020-04-14 12:34:14 +00:00
|
|
|
return getNextEntityName("Api", pageApiNames);
|
|
|
|
|
};
|
|
|
|
|
|
2021-09-08 17:32:22 +00:00
|
|
|
export const createNewJSFunctionName = (
|
2022-06-21 13:57:34 +00:00
|
|
|
jsActions: JSCollectionData[],
|
2021-09-08 17:32:22 +00:00
|
|
|
pageId: string,
|
|
|
|
|
) => {
|
|
|
|
|
const pageJsFunctionNames = jsActions
|
|
|
|
|
.filter((a) => a.config.pageId === pageId)
|
|
|
|
|
.map((a) => a.config.name);
|
|
|
|
|
return getNextEntityName("JSObject", pageJsFunctionNames);
|
|
|
|
|
};
|
|
|
|
|
|
2019-12-16 08:49:10 +00:00
|
|
|
export const noop = () => {
|
2021-07-05 05:49:43 +00:00
|
|
|
log.debug("noop");
|
2019-12-16 08:49:10 +00:00
|
|
|
};
|
2020-03-16 07:59:07 +00:00
|
|
|
|
2021-05-18 18:29:39 +00:00
|
|
|
export const stopEventPropagation = (e: any) => {
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
};
|
|
|
|
|
|
2020-05-05 07:50:30 +00:00
|
|
|
export const createNewQueryName = (
|
|
|
|
|
queries: ActionDataState,
|
|
|
|
|
pageId: string,
|
2023-06-01 17:26:05 +00:00
|
|
|
prefix = "Query",
|
2020-05-05 07:50:30 +00:00
|
|
|
) => {
|
|
|
|
|
const pageApiNames = queries
|
2020-12-24 04:32:25 +00:00
|
|
|
.filter((a) => a.config.pageId === pageId)
|
|
|
|
|
.map((a) => a.config.name);
|
2023-06-01 17:26:05 +00:00
|
|
|
|
|
|
|
|
return getNextEntityName(prefix, pageApiNames);
|
2020-05-05 07:50:30 +00:00
|
|
|
};
|
|
|
|
|
|
2020-03-16 07:59:07 +00:00
|
|
|
export const convertToString = (value: any): string => {
|
|
|
|
|
if (_.isUndefined(value)) {
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
if (_.isObject(value)) {
|
|
|
|
|
return JSON.stringify(value, null, 2);
|
|
|
|
|
}
|
|
|
|
|
if (_.isString(value)) return value;
|
|
|
|
|
return value.toString();
|
|
|
|
|
};
|
2020-03-27 12:46:29 +00:00
|
|
|
|
2023-05-19 18:37:06 +00:00
|
|
|
export const getInitialsFromName = (fullName: string) => {
|
|
|
|
|
let inits = "";
|
|
|
|
|
// if name contains space. eg: "Full Name"
|
|
|
|
|
if (fullName && fullName.includes(" ")) {
|
|
|
|
|
const namesArr = fullName.split(" ");
|
|
|
|
|
let initials = namesArr
|
|
|
|
|
.map((name: string) => name.charAt(0))
|
|
|
|
|
.join("")
|
|
|
|
|
.toUpperCase();
|
|
|
|
|
initials = initials;
|
|
|
|
|
inits = initials.slice(0, 2);
|
|
|
|
|
} else {
|
|
|
|
|
// handle for camelCase
|
|
|
|
|
const str = fullName ? fullName.replace(/([a-z])([A-Z])/g, "$1 $2") : "";
|
|
|
|
|
const namesArr = str.split(" ");
|
|
|
|
|
const initials = namesArr
|
|
|
|
|
.map((name: string) => name.charAt(0))
|
|
|
|
|
.join("")
|
|
|
|
|
.toUpperCase();
|
|
|
|
|
inits = initials.slice(0, 2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return inits;
|
|
|
|
|
};
|
|
|
|
|
|
2020-09-16 11:50:47 +00:00
|
|
|
export const getInitialsAndColorCode = (
|
2023-05-19 18:37:06 +00:00
|
|
|
fullName = "",
|
2020-09-16 11:50:47 +00:00
|
|
|
colorPalette: string[],
|
|
|
|
|
): string[] => {
|
2023-05-19 18:37:06 +00:00
|
|
|
const initials = getInitialsFromName(fullName);
|
|
|
|
|
const colorCode = getColorCode(initials, colorPalette);
|
|
|
|
|
return [initials, colorCode];
|
|
|
|
|
};
|
|
|
|
|
export const getInitials = (
|
|
|
|
|
fullName: any,
|
|
|
|
|
// colorPalette: string[],
|
|
|
|
|
): string => {
|
2020-04-28 10:47:59 +00:00
|
|
|
let inits = "";
|
|
|
|
|
// if name contains space. eg: "Full Name"
|
2021-06-16 18:36:34 +00:00
|
|
|
if (fullName && fullName.includes(" ")) {
|
2020-04-28 10:47:59 +00:00
|
|
|
const namesArr = fullName.split(" ");
|
|
|
|
|
let initials = namesArr.map((name: string) => name.charAt(0));
|
|
|
|
|
initials = initials.join("").toUpperCase();
|
|
|
|
|
inits = initials.slice(0, 2);
|
|
|
|
|
} else {
|
|
|
|
|
// handle for camelCase
|
2021-06-16 18:36:34 +00:00
|
|
|
const str = fullName ? fullName.replace(/([a-z])([A-Z])/g, "$1 $2") : "";
|
2020-04-28 10:47:59 +00:00
|
|
|
const namesArr = str.split(" ");
|
|
|
|
|
let initials = namesArr.map((name: string) => name.charAt(0));
|
|
|
|
|
initials = initials.join("").toUpperCase();
|
|
|
|
|
inits = initials.slice(0, 2);
|
|
|
|
|
}
|
2023-05-19 18:37:06 +00:00
|
|
|
// const colorCode = getColorCode(inits, colorPalette);
|
|
|
|
|
return inits;
|
2020-04-28 10:47:59 +00:00
|
|
|
};
|
2020-09-16 11:50:47 +00:00
|
|
|
export const getColorCode = (
|
|
|
|
|
initials: string,
|
|
|
|
|
colorPalette: string[],
|
|
|
|
|
): string => {
|
2020-04-28 10:47:59 +00:00
|
|
|
let asciiSum = 0;
|
|
|
|
|
for (let i = 0; i < initials.length; i++) {
|
|
|
|
|
asciiSum += initials[i].charCodeAt(0);
|
|
|
|
|
}
|
2020-09-16 11:50:47 +00:00
|
|
|
return colorPalette[asciiSum % colorPalette.length];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const getApplicationIcon = (initials: string): AppIconName => {
|
|
|
|
|
let asciiSum = 0;
|
|
|
|
|
for (let i = 0; i < initials.length; i++) {
|
|
|
|
|
asciiSum += initials[i].charCodeAt(0);
|
|
|
|
|
}
|
|
|
|
|
return AppIconCollection[asciiSum % AppIconCollection.length];
|
2020-04-28 10:47:59 +00:00
|
|
|
};
|
2020-05-28 18:10:26 +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
|
|
|
export function hexToRgb(hex: string): {
|
2020-05-28 18:10:26 +00:00
|
|
|
r: number;
|
|
|
|
|
g: number;
|
|
|
|
|
b: number;
|
|
|
|
|
} {
|
|
|
|
|
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
|
|
|
|
return result
|
|
|
|
|
? {
|
|
|
|
|
r: parseInt(result[1], 16),
|
|
|
|
|
g: parseInt(result[2], 16),
|
|
|
|
|
b: parseInt(result[3], 16),
|
|
|
|
|
}
|
|
|
|
|
: {
|
|
|
|
|
r: -1,
|
|
|
|
|
g: -1,
|
|
|
|
|
b: -1,
|
|
|
|
|
};
|
|
|
|
|
}
|
2020-08-19 09:21:32 +00:00
|
|
|
|
2020-09-15 06:59:58 +00:00
|
|
|
export const retryPromise = (
|
2020-11-03 13:05:40 +00:00
|
|
|
fn: () => Promise<any>,
|
2020-09-15 06:59:58 +00:00
|
|
|
retriesLeft = 5,
|
|
|
|
|
interval = 1000,
|
|
|
|
|
): Promise<any> => {
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
fn()
|
|
|
|
|
.then(resolve)
|
2020-12-17 07:03:59 +00:00
|
|
|
.catch(() => {
|
2020-09-15 06:59:58 +00:00
|
|
|
setTimeout(() => {
|
|
|
|
|
if (retriesLeft === 1) {
|
2020-12-17 07:03:59 +00:00
|
|
|
return Promise.reject({
|
|
|
|
|
code: ERROR_CODES.SERVER_ERROR,
|
2021-03-13 14:24:45 +00:00
|
|
|
message: createMessage(ERROR_500),
|
2020-12-17 07:03:59 +00:00
|
|
|
show: false,
|
|
|
|
|
});
|
2020-09-15 06:59:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Passing on "reject" is the important part
|
|
|
|
|
retryPromise(fn, retriesLeft - 1, interval).then(resolve, reject);
|
|
|
|
|
}, interval);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
};
|
2020-12-07 06:51:13 +00:00
|
|
|
|
|
|
|
|
export const getRandomPaletteColor = (colorPalette: string[]) => {
|
|
|
|
|
return colorPalette[Math.floor(Math.random() * colorPalette.length)];
|
|
|
|
|
};
|
2021-08-24 03:38:57 +00:00
|
|
|
|
|
|
|
|
export const isBlobUrl = (url: string) => {
|
|
|
|
|
return typeof url === "string" && url.startsWith("blob:");
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
*
|
|
|
|
|
* @param data string file data
|
|
|
|
|
* @param type string file type
|
|
|
|
|
* @returns string containing blob id and type
|
|
|
|
|
*/
|
2022-06-21 13:57:34 +00:00
|
|
|
export const createBlobUrl = (data: Blob | MediaSource, type: string) => {
|
2021-08-24 03:38:57 +00:00
|
|
|
let url = URL.createObjectURL(data);
|
2023-04-19 18:29:56 +00:00
|
|
|
url = url.replace(`${window.location.origin}/`, "");
|
2021-08-24 03:38:57 +00:00
|
|
|
|
|
|
|
|
return `${url}?type=${type}`;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
*
|
|
|
|
|
* @param blobId string blob id along with type.
|
|
|
|
|
* @returns [string,string] [blobUrl, type]
|
|
|
|
|
*/
|
|
|
|
|
export const parseBlobUrl = (blobId: string) => {
|
2023-04-19 18:29:56 +00:00
|
|
|
const url = `blob:${window.location.origin}/${blobId.substring(5)}`;
|
2021-08-24 03:38:57 +00:00
|
|
|
return url.split("?type=");
|
|
|
|
|
};
|
2021-11-23 08:01:46 +00:00
|
|
|
|
|
|
|
|
/**
|
2021-12-09 12:02:47 +00:00
|
|
|
* Convert a string into camelCase
|
|
|
|
|
* @param sourceString input string
|
|
|
|
|
* @returns camelCase string
|
|
|
|
|
*/
|
|
|
|
|
export const getCamelCaseString = (sourceString: string) => {
|
|
|
|
|
let out = "";
|
|
|
|
|
// Split the input string to separate words using RegEx
|
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 regEx =
|
|
|
|
|
/[A-Z\xC0-\xD6\xD8-\xDE]?[a-z\xDF-\xF6\xF8-\xFF]+|[A-Z\xC0-\xD6\xD8-\xDE]+(?![a-z\xDF-\xF6\xF8-\xFF])|\d+/g;
|
2021-12-09 12:02:47 +00:00
|
|
|
const words = sourceString.match(regEx);
|
|
|
|
|
if (words) {
|
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
|
|
|
words.forEach(function (el, idx) {
|
2021-12-09 12:02:47 +00:00
|
|
|
const add = el.toLowerCase();
|
|
|
|
|
out += idx === 0 ? add : add[0].toUpperCase() + add.slice(1);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return out;
|
|
|
|
|
};
|
|
|
|
|
|
feat: camera widget (#8069)
* feat: Camera Widget
-- Scaffold the basic structure of the widget
* feat: Camera Widget
-- Prototype a feature, taking picture
* feat: Camera Widget
-- Add types for MediaRecorder
-- Define media capture status and action types
-- Prototype basic video recording, playing features
* feat: Camera Widget
-- Implement video player
-- Add timer for recording and playing video
-- Add permission and error handling logic
-- Add device selectors
* feat: Camera Widget
-- Place control buttons above device inputs layer
-- Make the widget fully responsive
* feat: Camera Widget
-- Change the color of caret-down icon to white
-- Remove overlaying of web cam and video player
-- Add some padding for device inputs
* feat: Camera Widget
-- Add black background to the container of the widget
* feat: Camera Widget
-- Change the widget icon
* feat: Camera Widget
-- Implement the mute feature of a mic or a camera
* feat: Camera Widget
-- Check media device permissions before getting started
* feat: Camera Widget
-- Add a fullscreen control
* feat: Camera Widget
-- Set error text color to white
-- Change the layout of control panel
* feat: Camera Widget
-- Apply layout change for control panel according to app layout change
* feat: Camera Widget
-- Add a new derived property, videoURL
* feat: Switch Group Widget
-- Adopt theme changes
* feat: Camera Widget
-- Make background grey in case of both error and disabled status
* feat: Camera Widget
-- Update npm dependencies
* feat: Camera Widget
-- Fix on #8788, using muted property
* feat: Camera Widget
-- Show off the microphone setting icon only if the current mode is video
-- Set isMirrored property to true by default
* feat: Camera Widget
-- Add photo viewer
* feat: Camera Widget
-- Add onImageCapture, onRecordingStart, onRecordingStop actions instead of onMediaCapture
* feat: Camera Widget
-- Expose meta properties for the widget
* feat: Camera Widget
-- Fix on responsiveness issue
* feat: Camera Widget
-- Add type definitions for MediaStream recording
* feat: Camera Widget
-- Hide isMirroed property for video mode
* feat: Camera Widget
-- Wrap all the controls with TooltipComponent
* feat: Camera Widget
-- Implement enter, exit full screen feature
* feat: Camera Widget
-- Add a widget icon for entity explorer
* feat: Camera Widget
-- Fix on the typo for the label of onRecordingStop property
* feat: Camera Widget
-- Enable/disable media tracks
* feat: Camera Widget
-- Set the video's height to 100% in fullscreen mode
* feat: Camera Widget
-- Add overlayers on Webcam
* feat: Camera Widget
-- Set position to relative on fullscreen wrapper div
-- Set the photo viewer's height to 100%
* feat: Camera Widget
-- Add image, mediaCaptureStatus, timer meta properties to keep UI states when the widget is dragged
* feat: Camera Widget
-- Refactor code base, eliminating commented code blocks
* feat: Camera Widget
-- Revert all the changes needed for keeping status when the widget is dragged
-- Set mirroed property to false for video mode
2021-12-24 14:06:59 +00:00
|
|
|
/**
|
|
|
|
|
* Convert Base64 string to Blob
|
|
|
|
|
* @param base64Data
|
|
|
|
|
* @param contentType
|
|
|
|
|
* @param sliceSize
|
|
|
|
|
* @returns
|
|
|
|
|
*/
|
|
|
|
|
export const base64ToBlob = (
|
|
|
|
|
base64Data: string,
|
|
|
|
|
contentType = "",
|
|
|
|
|
sliceSize = 512,
|
|
|
|
|
) => {
|
|
|
|
|
const byteCharacters = atob(base64Data);
|
|
|
|
|
const byteArrays = [];
|
|
|
|
|
|
|
|
|
|
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
|
|
|
|
|
const slice = byteCharacters.slice(offset, offset + sliceSize);
|
|
|
|
|
|
|
|
|
|
const byteNumbers = new Array(slice.length);
|
|
|
|
|
for (let i = 0; i < slice.length; i++) {
|
|
|
|
|
byteNumbers[i] = slice.charCodeAt(i);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const byteArray = new Uint8Array(byteNumbers);
|
|
|
|
|
byteArrays.push(byteArray);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const blob = new Blob(byteArrays, { type: contentType });
|
|
|
|
|
return blob;
|
|
|
|
|
};
|
2022-06-08 09:05:35 +00:00
|
|
|
|
|
|
|
|
// util function to detect current os is Mac
|
|
|
|
|
export const isMacOs = () => {
|
|
|
|
|
return osName === "Mac OS";
|
|
|
|
|
};
|
2022-08-19 10:10:36 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* checks if array of strings are equal regardless of order
|
|
|
|
|
* @param arr1
|
|
|
|
|
* @param arr2
|
|
|
|
|
* @returns
|
|
|
|
|
*/
|
|
|
|
|
export function areArraysEqual(arr1: string[], arr2: string[]) {
|
|
|
|
|
if (arr1.length !== arr2.length) return false;
|
2023-03-04 07:25:54 +00:00
|
|
|
// Because the array is frozen in strict mode, you'll need to copy the array before sorting it
|
|
|
|
|
if ([...arr1].sort().join(",") === [...arr2].sort().join(",")) return true;
|
2022-08-19 10:10:36 +00:00
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2023-06-29 13:53:25 +00:00
|
|
|
|
|
|
|
|
export enum DataType {
|
|
|
|
|
OBJECT = "OBJECT",
|
|
|
|
|
NUMBER = "NUMBER",
|
|
|
|
|
ARRAY = "ARRAY",
|
|
|
|
|
BOOLEAN = "BOOLEAN",
|
|
|
|
|
STRING = "STRING",
|
|
|
|
|
NULL = "NULL",
|
|
|
|
|
UNDEFINED = "UNDEFINED",
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function getDatatype(value: unknown) {
|
|
|
|
|
if (typeof value === "string") {
|
|
|
|
|
return DataType.STRING;
|
|
|
|
|
} else if (typeof value === "number") {
|
|
|
|
|
return DataType.NUMBER;
|
|
|
|
|
} else if (typeof value === "boolean") {
|
|
|
|
|
return DataType.BOOLEAN;
|
|
|
|
|
} else if (isPlainObject(value)) {
|
|
|
|
|
return DataType.OBJECT;
|
|
|
|
|
} else if (Array.isArray(value)) {
|
|
|
|
|
return DataType.ARRAY;
|
|
|
|
|
} else if (value === null) {
|
|
|
|
|
return DataType.NULL;
|
|
|
|
|
} else if (value === undefined) {
|
|
|
|
|
return DataType.UNDEFINED;
|
|
|
|
|
}
|
|
|
|
|
}
|