Files
calendar/packages/eslint-plugin/src/rules/avoid-web-storage.ts
T
e29b7e83b8 feat: Round Robin groups (#22296)
* add Add Group button

* add host groups to schema

* UI for host groups

* raname groups to hostGroups

* schema update

* show groups in assignment tab

* add no group hosts to Group 1

* add dummy group for non group hosts

* fix type errors

* use two dimensional array for luckyUserPools

* fix empty array

* group RR hosts in handleNewBooking

* improve logic for grouping lucky users

* find all lucky users of all groups

* allow several RR hosts on booking

* clean up migrations

* create helper function

* group hosts for slots logic

* add group logic to loading available slots

* adding hosts to groups

* add groupId to hostSchema

* disable hosts from other groups

* handle groups in checkedTeamSelect

* fix adding hosts to groups

* remove and add groups

* show hosts if there are no groups

* fixing adding first group with existing hosts

* show groups empty groups correctly

* UI upddate fixes

* fix adding hosts to existing first host group

* small fixes + code clean up

* add availability fix with test

* create new round-robin test file

* disable reassignment

* fix losing fixed hosts

* fix updating weights and priorities

* disable load balancing with Round Robin Groups

* automatically disable load balancing in update handler

* allRRHosts should only include hosts from same group

* fix type errors

* fix type error

* fix tests

* fix type error

* remove undefined from groupId type

* type changes

* add tests for hostGroups

* add tests for host groups

* fixes

* fix type errors with undefined groupId

* remove seperate host groups prop

* fix editing weights

* remove console.log

* code clean up

* improve getAggregatedAvailability tests

* throw error when no available hosts in a group

* add fixme comment

* create constant for DEFAULT_GROUP_ID

* clean up code

* mock default_group_id for unit tests

* don't show fixed hosts in edit weights side bar

* add DEFAULT_GROUP_ID to  mock test-setup

* remove unused index variable

* code clean up

* fix updating host groups

* fix imports

* add default_group_id to mocks

* add uuid() to zod schema

* remove unused code

* fix singular translation key

* remove unnessary !!

* Revert formatting changes

* add additional tests for bookingActions

* use createMany

* import DEFAULT_GROUP_ID for mocks

* fix mocks

* clean up EventTeamAssignmentTab

* fix type errors in tests

* fix mocks

* remove constants.example.test.ts

* fix type error

* add missing groupId

* fix margin

* clean up empty host groups

* fix constants mock

* useCalback

* use reduce

* extract handlers into seperate functions

* fix handler functions

* fix border radius

* fix type error in CheckForEmptyAssignment

* fix type error

---------

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2025-08-08 12:56:13 +01:00

128 lines
4.5 KiB
TypeScript

import { ESLintUtils } from "@typescript-eslint/utils";
const createRule = ESLintUtils.RuleCreator((name) => `https://developer.cal.com/eslint/rule/${name}`);
const rule = createRule({
create(context) {
// Track imported names from @calcom/lib/webstorage
const safeImportedNames = new Set<string>();
return {
ImportDeclaration(node) {
// Check if this is an import from the safe webstorage module
if (node.source.value === "@calcom/lib/webstorage") {
node.specifiers.forEach((specifier) => {
if (specifier.type === "ImportSpecifier") {
// Track the local name used for the import
safeImportedNames.add(specifier.local.name);
}
});
}
},
CallExpression(node) {
const webStorages = ["localStorage", "sessionStorage"];
const callee = node.callee;
// Check for window.localStorage or window.sessionStorage
if (
// Can't figure out how to fix this TS issue
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
callee.object?.object?.name === "window" &&
// Can't figure out how to fix this TS issue
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
webStorages.includes(node?.callee?.object?.property?.name)
) {
return context.report({
node: node,
loc: node.loc,
messageId: "possible-issue-with-embed",
});
}
// Check for direct localStorage or sessionStorage usage
if (
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
callee.type === "MemberExpression" &&
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
callee.object?.type === "Identifier" &&
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
webStorages.includes(callee.object?.name) &&
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
!safeImportedNames.has(callee.object?.name)
) {
return context.report({
node: node,
loc: node.loc,
messageId: "possible-issue-with-embed",
});
}
},
// Also check for property access like localStorage.length
MemberExpression(node) {
const webStorages = ["localStorage", "sessionStorage"];
// Check for direct property access on localStorage/sessionStorage
if (
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
node.object?.type === "Identifier" &&
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
webStorages.includes(node.object?.name) &&
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
!safeImportedNames.has(node.object?.name)
) {
return context.report({
node: node,
loc: node.loc,
messageId: "possible-issue-with-embed",
});
}
// Check for window.localStorage/sessionStorage property access
if (
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
node.object?.type === "MemberExpression" &&
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
node.object?.object?.name === "window" &&
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
webStorages.includes(node.object?.property?.name)
) {
return context.report({
node: node,
loc: node.loc,
messageId: "possible-issue-with-embed",
});
}
},
};
},
name: "avoid-web-storage",
meta: {
fixable: "code",
docs: {
description: "Avoid deprecated imports",
recommended: "warn",
},
messages: {
"possible-issue-with-embed": `Be aware that accessing localStorage/sessionStorage throws error in Chrome Incognito mode when embed is in cross domain context. If you know what you are doing, \`import {localStorage, sessionStorage} from "@calcom/lib/webstorage"\` for safe usage. See https://github.com/calcom/cal.com/issues/2618`,
},
type: "suggestion",
schema: [],
},
defaultOptions: [],
});
export default rule;