mirror of
https://github.com/makeplane/plane.git
synced 2026-07-13 05:49:40 +02:00
* feat: page comments * chore: added node id * chore: changed reverse relation * chore: added resolve comment endpoint * fix: build errors * fix: basic comment decoration added * fix: add marks * fix: operations * fix: to ditch decorations approach! * fix: move dev-wiki into apps * fix: new approach with some more types * fix: link view container * fix: editor ee packages updated * fix: basic threads implementation added * fix: comments scroll and filtering * fix scrolling * chore: added total count for comments * fix: seperate the comments store * fix: comments removal * feat: multi comment on same mark * fix: mark fixed and styles of comments fixed! * feat: added better animations * fix: better styles and animations for comments * fix: ee seperation * fix: threads api fix * fix: new comment store attached * fix: resolve and delete * fix: remove framer motion * fix: add comment ordering * fix: delete extension * fix: web * fix: context aware comments * fix: new working comment store * fix: getting changes to web * fix: ui of comments * fix: comment mark resolution fixed * fix: move changes to store * temp fix: project pages * fix: comments using lite text editor * fix: rerendering infinitely * fix: comment box and reference * chore: updated the migration file * fix: move things to ee * chore: un commented the feature flag logic * chore: removed an extra line in feature flag * fix: editor types * fix: scrolling of thread items * fix: scrolling of thread items * fix: type errors * fix: comment creation * fix: page comments * fix: page comments * fix: remove utils * fix: added feature flagging * fix:loading json content * fix: upload items * fix: upload items * fix: ui chanegs * fix: comment box * fix: better spacing * Fix spacing and removing the divs not needed anymore * fix: comments storing json * Add comment thread management hooks * Replace use-new-comment hook with use-scroll-manager Remove useNewComment hook and related logic. Add useScrollManager hook for managing scroll behavior in the comments sidebar. Refactor threads-sidebar to use scroll manager for thread and comment box navigation. Add cancel button to new comment box. * Remove hover and click effects for resolved comment marks * Auto-scroll new comments in sidebar after order sync Adds highlight and scroll-to behavior for newly created comments. Sidebar now scrolls to the new thread after comments order updates. * Add granular page comment permissions and UI checks Introduce canCurrentUserCommentOnPage permission for pages. Update comment UI to respect user comment permissions. Refactor comment creation logic into useNewComment hook. Hide comment/reply UI for users without permission. * Refactor comments components and imports for clarity and type safety * Refactor comments components to use local types and remove unused files - Move type definitions from shared types file into local components - Remove unused comment-reactions component and types/index.ts - Update imports to use local hooks and types - Minor code cleanup and formatting * Refactor comments feature flag and clean up comments components - Replace isPageCommentsEnabled with isCommentsEnabled in page stores - Remove unused types, utils, and reactions components from comments - Move and rename comments components for consistency - Update editor flagging to use new comments feature flag logic - Simplify comments sidebar and thread item structure - Remove redundant exports and props from comments modules * Refactor comments extension to use workspace feature flag - Pass storeType to navigation pane extensions - Check isCommentsEnabled with workspaceSlug before rendering comments - Update canComment logic to use canCurrentUserCommentOnPage - Remove console.log and unused code - Fix types for extension props * Add canCurrentUserCommentOnPage to TeamspacePage * Refactor TCommentConfig type and move EditorSideEffects - Move TCommentConfig to ce/types/editor.ts and ee * fix: ce sync * fix: prosemirror-model fixed * chore: removed the extra migration * chore: added page comments serializer * fix: comments * refactor: comments * fix: ce/ee seperation * chore: changed the page serialization * fix: page comments refactored * fix: remove ce changes * fix: restoration for nested pages fixed * fix: less ce changes * fix: imports * fix: better refactoring of page root and editor body * fix: renaming files * fix: editor sideeffects * fix: add comments json field * fix: page comments types * fix: lint warnings * fix: props name change * fix: props name * fix: comment mark * fix: import type * fix: review changes * fix: extra checks * fix: type changes * fix: remove editor ref current * fix: renaming * fix: renaming files * fix: comments extension revamp * fix: declaring better types * fix: better types * fix: hooks seperated * fix: edit box * fix: html validation * fix: agents md * fix: naming convention * fix: update names and service methods * fix: more fixes * fix: attributs * fix: dev wiki sync --------- Co-authored-by: Palanikannan M <akashmalinimurugu@gmail.com> Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>
120 lines
3.6 KiB
TypeScript
120 lines
3.6 KiB
TypeScript
import isEmpty from "lodash/isEmpty";
|
|
import { IIssueLabel, IIssueLabelTree } from "@plane/types";
|
|
|
|
export const groupBy = (array: any[], key: string) => {
|
|
const innerKey = key.split("."); // split the key by dot
|
|
return array.reduce((result, currentValue) => {
|
|
const key = innerKey.reduce((obj, i) => obj?.[i], currentValue) ?? "None"; // get the value of the inner key
|
|
(result[key] = result[key] || []).push(currentValue);
|
|
return result;
|
|
}, {});
|
|
};
|
|
|
|
export const orderArrayBy = (orgArray: any[], key: string, ordering: "ascending" | "descending" = "ascending") => {
|
|
if (!orgArray || !Array.isArray(orgArray) || orgArray.length === 0) return [];
|
|
|
|
const array = [...orgArray];
|
|
|
|
if (key[0] === "-") {
|
|
ordering = "descending";
|
|
key = key.slice(1);
|
|
}
|
|
|
|
const innerKey = key.split("."); // split the key by dot
|
|
|
|
return array.sort((a, b) => {
|
|
const keyA = innerKey.reduce((obj, i) => obj[i], a); // get the value of the inner key
|
|
const keyB = innerKey.reduce((obj, i) => obj[i], b); // get the value of the inner key
|
|
if (keyA < keyB) {
|
|
return ordering === "ascending" ? -1 : 1;
|
|
}
|
|
if (keyA > keyB) {
|
|
return ordering === "ascending" ? 1 : -1;
|
|
}
|
|
return 0;
|
|
});
|
|
};
|
|
|
|
export const checkDuplicates = (array: any[]) => new Set(array).size !== array.length;
|
|
|
|
export const findStringWithMostCharacters = (strings: string[]): string => {
|
|
if (!strings || strings.length === 0) return "";
|
|
|
|
return strings.reduce((longestString, currentString) =>
|
|
currentString.length > longestString.length ? currentString : longestString
|
|
);
|
|
};
|
|
|
|
export const checkIfArraysHaveSameElements = (arr1: any[] | null, arr2: any[] | null): boolean => {
|
|
if (!arr1 || !arr2) return false;
|
|
if (!Array.isArray(arr1) || !Array.isArray(arr2)) return false;
|
|
if (arr1.length === 0 && arr2.length === 0) return true;
|
|
|
|
return arr1.length === arr2.length && arr1.every((e) => arr2.includes(e));
|
|
};
|
|
|
|
type GroupedItems<T> = { [key: string]: T[] };
|
|
|
|
export const groupByField = <T>(array: T[], field: keyof T): GroupedItems<T> =>
|
|
array.reduce((grouped: GroupedItems<T>, item: T) => {
|
|
const key = String(item[field]);
|
|
grouped[key] = (grouped[key] || []).concat(item);
|
|
return grouped;
|
|
}, {});
|
|
|
|
export const sortByField = (array: any[], field: string): any[] =>
|
|
array.sort((a, b) => (a[field] < b[field] ? -1 : a[field] > b[field] ? 1 : 0));
|
|
|
|
export const orderGroupedDataByField = <T>(groupedData: GroupedItems<T>, orderBy: keyof T): GroupedItems<T> => {
|
|
for (const key in groupedData) {
|
|
if (groupedData.hasOwnProperty(key)) {
|
|
groupedData[key] = groupedData[key].sort((a, b) => {
|
|
if (a[orderBy] < b[orderBy]) return -1;
|
|
if (a[orderBy] > b[orderBy]) return 1;
|
|
return 0;
|
|
});
|
|
}
|
|
}
|
|
return groupedData;
|
|
};
|
|
|
|
export const buildTree = (array: IIssueLabel[], parent = null) => {
|
|
const tree: IIssueLabelTree[] = [];
|
|
|
|
array.forEach((item: any) => {
|
|
if (item.parent === parent) {
|
|
const children = buildTree(array, item.id);
|
|
item.children = children;
|
|
tree.push(item);
|
|
}
|
|
});
|
|
|
|
return tree;
|
|
};
|
|
|
|
/**
|
|
* Returns Valid keys from object whose value is not falsy
|
|
* @param obj
|
|
* @returns
|
|
*/
|
|
export const getValidKeysFromObject = (obj: any) => {
|
|
if (!obj || isEmpty(obj) || typeof obj !== "object" || Array.isArray(obj)) return [];
|
|
|
|
return Object.keys(obj).filter((key) => !!obj[key]);
|
|
};
|
|
|
|
/**
|
|
* Convert an array into an object of keys and boolean strue
|
|
* @param arrayStrings
|
|
* @returns
|
|
*/
|
|
export const convertStringArrayToBooleanObject = (arrayStrings: string[]) => {
|
|
const obj: { [key: string]: boolean } = {};
|
|
|
|
for (const arrayString of arrayStrings) {
|
|
obj[arrayString] = true;
|
|
}
|
|
|
|
return obj;
|
|
};
|