-
Notifications
You must be signed in to change notification settings - Fork 0
Adds cursor rule files (wip) #70
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
JWittmeyer
wants to merge
5
commits into
dev
Choose a base branch
from
cursor-files
base: dev
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
5e68453
Adds cursor rule files (wip)
JWittmeyer 3799ebf
Kern table guidelines
lumburovskalina ef4c38c
Updates files with best practices
lumburovskalina c47d1a7
PR comments
lumburovskalina 96a6bc2
Merge remote-tracking branch 'origin/dev' into cursor-files
lumburovskalina File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| --- | ||
| description: Guidelines for developing in the react-components submodule | ||
| alwaysApply: true | ||
| globs: | ||
| - "*" | ||
| --- | ||
|
|
||
| # React Components Submodule | ||
|
|
||
| This is a shared component library. Changes here affect all consuming applications. The submodules are used in the following FE repositories: cognition-ui, refinery-ui, admin-dashboard and refinery-entry. | ||
|
|
||
| ## Directory Structure | ||
|
|
||
| ``` | ||
| components/ # UI components | ||
| hooks/ # Custom React hooks | ||
| helpers/ # Component helper functions | ||
| types/ # TypeScript interfaces | ||
| assets/ # Static assets | ||
| ``` | ||
|
|
||
| ## Component Guidelines | ||
|
|
||
| ### Export Pattern | ||
|
|
||
| Use default exports for components: | ||
|
|
||
| ```typescript | ||
| export default function MyComponent(props: MyComponentProps) { ... } | ||
| ``` | ||
|
|
||
| ### Props Types | ||
|
|
||
| Define types in `types/` directory: | ||
|
|
||
| ```typescript | ||
| // types/my-component.ts | ||
| export type MyComponentProps { | ||
| required: string; | ||
| optional?: number; | ||
| } | ||
| ``` | ||
|
|
||
| ### Styling | ||
|
|
||
| - Use Tailwind CSS classes | ||
| - Use `combineClassNames` from javascript-functions for conditional classes | ||
| - Avoid inline styles | ||
|
|
||
| ## Hook Guidelines | ||
|
|
||
| - Hooks must start with `use` | ||
| - File name should match hook name | ||
| - Document return types explicitly | ||
|
|
||
| ## Dependencies | ||
|
|
||
| - `@headlessui/react` - Accessible UI primitives | ||
| - `@nextui-org/react` - Tooltip component | ||
| - `@tabler/icons-react` - Icon library | ||
|
|
||
| ## Component-Specific Guidelines | ||
|
|
||
| ### KernTable | ||
|
|
||
| See [kern-table.mdc](./kern-table.mdc) for comprehensive guidelines on using the KernTable component, including: | ||
| - Props structure and configuration | ||
| - Table data preparation patterns | ||
| - Sorting implementation | ||
| - State management with hooks | ||
| - Performance optimization | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,302 @@ | ||
| --- | ||
| description: Guidelines for using KernTable component | ||
| alwaysApply: true | ||
| globs: | ||
| - "*" | ||
| --- | ||
|
|
||
| # KernTable Component Guidelines | ||
|
|
||
| The `KernTable` component is a reusable table component that provides sorting, cell rendering, and data display functionality. | ||
|
|
||
| ## Import | ||
|
|
||
| ```typescript | ||
| import KernTable from "@/submodules/react-components/components/kern-table/KernTable"; | ||
| ``` | ||
|
|
||
| ## Props Structure | ||
|
|
||
| ### KernTableProps | ||
|
|
||
| ```typescript | ||
| { | ||
| headers: Header[]; | ||
| values?: any[][]; | ||
| config?: { | ||
| sortKeyIdx?: SortKeyIdx; | ||
| onClickSortIdx?: (idx: number) => void; | ||
| addBorder?: boolean; | ||
| noEntriesText?: string; | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ### Header Structure | ||
|
|
||
| Each header object should have: | ||
| - `column`: string - Display text for the column header | ||
| - `id`: string - Unique identifier for the column | ||
| - `hasSort?`: boolean - Whether the column is sortable | ||
| - `hasCheckboxes?`: boolean - Whether to show checkboxes in the header | ||
| - `checked?`: boolean - Checkbox checked state | ||
| - `onChange?`: function - Checkbox change handler | ||
| - `tooltip?`: string - Tooltip text for the header | ||
| - `wrapWhitespace?`: boolean - Whether to wrap whitespace in cells | ||
|
|
||
| ## Implementation Pattern | ||
|
|
||
| ### 1. Define Table Headers | ||
|
|
||
| Create a constant array of header objects: | ||
|
|
||
| ```typescript | ||
| export const TABLE_HEADERS = [ | ||
| { column: "Column Name", id: "columnId", hasSort: true }, | ||
| { column: "Date Column", id: "dateColumn", hasSort: true }, | ||
| // ... more headers | ||
| ]; | ||
| ``` | ||
|
|
||
| ### 2. Prepare Table Body Data | ||
|
|
||
| Create a preparation function that transforms raw data into table row format: | ||
|
|
||
| ```typescript | ||
| import { | ||
| toTableColumnText, | ||
| toTableColumnDate, | ||
| toTableColumnComponent | ||
| } from "@/submodules/react-components/helpers/kern-table-helper"; | ||
|
|
||
| export function prepareTableBody(data: DataType[], callback: Function) { | ||
| if (!data || data.length === 0) return []; | ||
| return data.map((item) => [ | ||
| toTableColumnText(item.text), | ||
| toTableColumnDate(item.date), | ||
| toTableColumnComponent("ComponentName", item.value, { /* props */ }) | ||
| ]); | ||
| } | ||
| ``` | ||
|
|
||
| ### 3. Define Default Sort Key | ||
|
|
||
| Create a default sort key constant: | ||
|
|
||
| ```typescript | ||
| import { SortKeyIdx } from "@/submodules/react-components/types/sort"; | ||
| import { getDefaultSortKey } from "@/src/util/helper-functions"; | ||
|
|
||
| export const DEFAULT_SORT_KEY: SortKeyIdx = getDefaultSortKey(); | ||
| ``` | ||
|
|
||
| ### 4. Component Implementation | ||
|
|
||
| Use the following pattern in your table component: | ||
|
|
||
| ```typescript | ||
| import { useCallback, useMemo, useState } from "react"; | ||
| import { useRefState } from "@/submodules/react-components/hooks/useRefState"; | ||
| import { useRefFor } from "@/submodules/react-components/hooks/useRefFor"; | ||
| import { | ||
| nextSortDirectionByIdx, | ||
| sortBySortKeyIdx, | ||
| sortPreppedArrayByIdx | ||
| } from "@/submodules/react-components/helpers/sort-functions"; | ||
| import { SortDirection, SortKeyIdx } from "@/submodules/react-components/types/sort"; | ||
|
|
||
| export default function MyTable(props: MyTableProps) { | ||
| const { state: sortKey, setState: setSortKey, ref: sortKeyRef } = | ||
| useRefState(DEFAULT_SORT_KEY); | ||
|
|
||
| const preparedValues = useMemo(() => { | ||
| const values = prepareTableBody(props.data, callback); | ||
| sortBySortKeyIdx(values, sortKeyRef.current); | ||
| return values; | ||
| }, [props.data]); | ||
|
|
||
| const preparedValuesRef = useRefFor(preparedValues); | ||
|
|
||
| const tableConfig = useMemo(() => { | ||
| function sortByPropertyIdx(idx: number) { | ||
| if (!preparedValuesRef.current || preparedValuesRef.current.length === 0) return; | ||
|
|
||
| let newSortKey: SortKeyIdx; | ||
| if (nextSortDirectionByIdx(idx, sortKey) === SortDirection.NO_SORT) { | ||
| newSortKey = { ...DEFAULT_SORT_KEY }; | ||
| if (sortKey.idx === newSortKey.idx) newSortKey.direction = SortDirection.ASC; | ||
| sortBySortKeyIdx(preparedValuesRef.current, newSortKey); | ||
| } else { | ||
| newSortKey = sortPreppedArrayByIdx(preparedValuesRef.current, idx, sortKey); | ||
| } | ||
| setSortKey(newSortKey); | ||
| } | ||
|
|
||
| return { | ||
| sortKeyIdx: sortKey, | ||
| onClickSortIdx: (idx: number) => sortByPropertyIdx(idx), | ||
| noEntriesText: "No entries available." | ||
| }; | ||
| }, [sortKey]); | ||
|
|
||
| return ( | ||
| <div className="px-4 sm:px-6 lg:px-8 md:mt-0"> | ||
| <div className="flex flex-col"> | ||
| <div className="-my-2 -mx-4 overflow-x-auto sm:-mx-6 lg:-mx-8"> | ||
| <div className="inline-block min-w-full py-2 align-middle"> | ||
| <div className="overflow-hidden border border-gray-200 rounded-b-lg"> | ||
| <KernTable | ||
| headers={TABLE_HEADERS} | ||
| values={preparedValues} | ||
| config={tableConfig} | ||
| /> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| ); | ||
| } | ||
| ``` | ||
|
|
||
| ## Helper Functions | ||
|
|
||
| Use helper functions from `kern-table-helper` to create column data: | ||
|
|
||
| - `toTableColumnText(value: string)` - For text columns | ||
| - `toTableColumnNumber(value: number)` - For numeric columns | ||
| - `toTableColumnDate(value: string, onlyDate?: boolean)` - For date columns | ||
| - `toTableColumnComponent(component: string, sortValue: any, props?: any)` - For custom cell components | ||
| - `toTableColumnCheckbox(value: boolean, valueChange?: () => void)` - For checkbox columns | ||
| - `toTableColumnInputDate(value: string, valueChange: (event) => void)` - For date input columns | ||
| - `toTableColumnDropdown(value: string, options: any[], selectedOption?: (option: any) => void, disabled?: boolean)` - For dropdown columns | ||
| - `extendEditFunction(column: any, editFunction: () => void)` - Add edit functionality to a column | ||
|
|
||
| ## Sorting | ||
|
|
||
| ### SortKeyIdx Pattern | ||
|
|
||
| Use `SortKeyIdx` (index-based sorting) for prepared table data: | ||
|
|
||
| ```typescript | ||
| type SortKeyIdx = { | ||
| idx: number; | ||
| dataType: string; | ||
| direction: SortDirection; | ||
| }; | ||
| ``` | ||
|
|
||
| ### Sort Functions | ||
|
|
||
| - `sortBySortKeyIdx(arr: any[], sortKey: SortKeyIdx)` - Sort prepared array by sort key | ||
| - `sortPreppedArrayByIdx(arr: any[][], idx: number, sortKey: SortKeyIdx)` - Sort and return new sort key | ||
| - `nextSortDirectionByIdx(idx: number, sortKey: SortKeyIdx)` - Get next sort direction | ||
|
|
||
| ### Sort Direction Cycle | ||
|
|
||
| Sorting cycles through: `ASC` → `DESC` → `NO_SORT` → `ASC` | ||
|
|
||
| When `NO_SORT` is reached, reset to default sort key. | ||
|
|
||
| ## State Management | ||
|
|
||
| ### useRefState | ||
|
|
||
| Use `useRefState` for sort key state to maintain a ref alongside state: | ||
|
|
||
| ```typescript | ||
| const { state: sortKey, setState: setSortKey, ref: sortKeyRef } = | ||
| useRefState(DEFAULT_SORT_KEY); | ||
| ``` | ||
|
|
||
| ### useRefFor | ||
|
|
||
| Use `useRefFor` to create a ref for prepared values: | ||
|
|
||
| ```typescript | ||
| const preparedValuesRef = useRefFor(preparedValues); | ||
| ``` | ||
|
|
||
| This ensures the sort function always has access to the latest prepared values. | ||
|
|
||
| ## Performance Optimization | ||
|
|
||
| - Use `useMemo` for prepared values to avoid unnecessary recalculations | ||
| - Use `useMemo` for table config to prevent recreating sort handlers | ||
| - Sort prepared values in the `useMemo` dependency on data changes | ||
|
|
||
| ## Empty State | ||
|
|
||
| ### Using config.noEntriesText (Recommended) | ||
|
|
||
| The `KernTable` component automatically uses `NoTableEntriesYet` when the values array is empty and `config.noEntriesText` is provided: | ||
|
|
||
| ```typescript | ||
| const tableConfig = useMemo(() => { | ||
| return { | ||
| sortKeyIdx: sortKey, | ||
| onClickSortIdx: (idx: number) => sortByPropertyIdx(idx), | ||
| noEntriesText: "No entries available." // This will use NoTableEntriesYet internally | ||
| }; | ||
| }, [sortKey]); | ||
|
|
||
| <KernTable | ||
| headers={TABLE_HEADERS} | ||
| values={preparedValues} | ||
| config={tableConfig} | ||
| /> | ||
| ``` | ||
|
|
||
| When `values?.length === 0` and `config.noEntriesText` is set, `KernTable` automatically renders `NoTableEntriesYet` with the provided text. | ||
|
|
||
| ### Using NoTableEntriesYet Directly | ||
|
|
||
| If you need more control over the empty state, you can use `NoTableEntriesYet` directly: | ||
|
|
||
| ```typescript | ||
| import { NoTableEntriesYet } from "@/submodules/react-components/components/NoTableEntriesYet"; | ||
|
|
||
| // In your component render: | ||
| {props.data?.length > 0 ? ( | ||
| <KernTable headers={headers} values={preparedValues} config={tableConfig} /> | ||
| ) : ( | ||
| <div className="p-5 text-sm text-gray-500">No entries available.</div> | ||
| )} | ||
| ``` | ||
|
|
||
| ### NoTableEntriesYet Props | ||
|
|
||
| ```typescript | ||
| type NoTableEntriesYetProps = { | ||
| tableColumns: number; // Required: Number of columns to span | ||
| text?: string; // Text to display (default: 'No data yet') | ||
| heightClass?: string; // Height class (default: 'h-16') | ||
| backgroundColorClass?: string; // Background color (default: 'bg-gray-50') | ||
| textColorClass?: string; // Text color (default: 'text-gray-700') | ||
| marginBottomClass?: string; // Margin bottom class (default: '') | ||
| loading?: boolean; // Show loading spinner (default: false) | ||
| loadingColorClass?: string; // Loading spinner color class | ||
| } | ||
| ``` | ||
|
|
||
| **Note**: Prefer using `config.noEntriesText` in `KernTable` config rather than manually rendering `NoTableEntriesYet`, as it's simpler and maintains consistency. | ||
|
|
||
| ## Cell Components | ||
|
|
||
| Available cell components include: | ||
| - `BadgeCell`, `IconCell`, `LinkCell`, `EmailCell` | ||
| - `DeleteCell`, `ViewCell`, `EditIntegrationCell` | ||
| - `LevelCell`, `StatusModelCell`, `TaskStateCell` | ||
| - And many more - see `CellComponents.tsx` for full list | ||
|
|
||
| Use `toTableColumnComponent` with the component name and required props. | ||
|
|
||
| ## Best Practices | ||
|
|
||
| 1. **Separate Concerns**: Keep table preparation logic in separate utility files (`util/table-preparations/`) | ||
| 2. **Consistent Naming**: Use `TABLE_HEADERS` and `prepareTableBody` naming convention | ||
| 3. **Type Safety**: Define proper TypeScript interfaces for table props | ||
| 4. **Memoization**: Always memoize prepared values and table config | ||
| 5. **Default Sort**: Always define and use a default sort key | ||
| 6. **Empty States**: Handle empty data with appropriate messaging | ||
| 7. **Ref Management**: Use refs for values accessed in callbacks to avoid stale closures |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.