Skip to content
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

Popover component and project management fixes #2732

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

gaspergrom
Copy link
Contributor

@gaspergrom gaspergrom commented Dec 18, 2024

Changes proposed ✍️

What

copilot:summary

copilot:poem

Why

How

copilot:walkthrough

Checklist ✅

  • Label appropriately with Feature, Improvement, or Bug.
  • Add screenshots to the PR description for relevant FE changes
  • New backend functionality has been unit-tested.
  • API documentation has been updated (if necessary) (see docs on API documentation).
  • Quality standards are met.

Summary by CodeRabbit

  • New Features

    • Enhanced button styles for improved visibility.
    • Introduced new dropdown components for managing project groups and projects.
    • Added a new popover component for better user interactions.
    • Implemented a new status pill component to display project statuses.
  • Bug Fixes

    • Updated import paths for various components to ensure correct functionality.
  • Refactor

    • Restructured component organization for better maintainability.
    • Streamlined dropdown and popover implementations.
  • Style

    • Updated styles for buttons, dropdowns, and popovers for a more cohesive look.
    • Enhanced responsiveness and visual appeal of UI components.
  • Documentation

    • Improved Storybook documentation for UI components.

@gaspergrom gaspergrom self-assigned this Dec 18, 2024
Copy link

coderabbitai bot commented Dec 18, 2024

Walkthrough

This pull request represents a significant refactoring of the frontend module structure, primarily focusing on reorganizing components from the lf/segments module to a new admin/modules/projects module. The changes involve updating import paths, renaming components, and making minor adjustments to styling and type definitions. The refactoring aims to improve the project's modularity and organization, with updates spanning multiple files across different modules.

Changes

File/Directory Change Summary
frontend/config/styles/components/button.scss Updated color variables for button styles
frontend/src/modules/admin/ New admin module with routes and components
frontend/src/modules/activity/pages/activity-list-page.vue Updated import path for sub-projects list modal
frontend/src/ui-kit/pill/ Refactored pill component with new types and styling
frontend/src/ui-kit/popover/ Added new popover component with stories and types
frontend/src/modules/lf/ Removed legacy module and components

Suggested labels

Improvement

Suggested reviewers

  • themarolt

Poem

🐰 A Rabbit's Refactoring Tale

In modules old, components were scattered wide,
But now they dance in admin's organized stride
Paths realigned, with purpose clear and bright,
A code restructure that feels just right!
Hop, hop, hooray for clean architecture's might! 🚀

Tip

CodeRabbit's docstrings feature is now available as part of our Early Access Program! Simply use the command @coderabbitai generate docstrings to have CodeRabbit automatically generate docstrings for your pull request. We would love to hear your feedback on Discord.


🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🔭 Outside diff range comments (2)
frontend/src/assets/scss/layout.scss (1)

Line range hint 84-91: Consider a more maintainable approach for autocomplete styling

The current implementation uses a very long transition duration (5000s) as a workaround for browser autocomplete styling. Consider:

  1. Using a more standard approach with form styling
  2. Letting autoprefixer handle vendor prefixes
  3. Using a shorter transition duration if the effect is still needed
 input:-webkit-autofill,
 input:-webkit-autofill:hover,
 input:-webkit-autofill:focus,
 input:-webkit-autofill:active {
-  transition: background-color 5000s ease-in-out 0s;
+  transition: background-color 0s;
+  background-color: transparent !important;
   -webkit-text-fill-color: #000 !important;
 }
frontend/src/modules/organization/components/edit/organization-add.vue (1)

Line range hint 213-238: Enhance error handling for organization creation

The error handling for organization creation could be more specific and provide better user feedback.

 OrganizationApiService.create(data, [form.subproject])
   .then((newOrg: Organization) => {
     router.push({
       name: 'organizationView',
       params: {
         id: newOrg.id,
       },
       query: {
         projectGroup: selectedProjectGroup.value?.id,
       },
     });
     isModalOpen.value = false;
     resetForm();
   })
   .catch((error: any) => {
-    if (error.response.status === 409) {
-      Message.error('Organization was not created because the identity already exists in another profile');
-    } else {
-      Errors.handle(error);
-    }
+    const errorMessages = {
+      409: 'Organization was not created because the identity already exists in another profile',
+      400: 'Invalid organization data provided',
+      403: 'You do not have permission to create organizations',
+      default: 'An error occurred while creating the organization'
+    };
+    const status = error.response?.status;
+    Message.error(errorMessages[status] || errorMessages.default);
+    Errors.handle(error);
   })
🧹 Nitpick comments (29)
frontend/src/ui-kit/pill/types/PillType.ts (1)

1-3: Consider adding JSDoc documentation.

The new semantic types would benefit from clear documentation explaining their intended usage and visual appearance.

Add documentation like this:

+/**
+ * Predefined pill types for semantic styling
+ * - primary: Main action or status
+ * - secondary: Alternative or supporting status
+ * - tertiary: Less prominent status
+ * - success: Positive or completed status
+ * - warning: Cautionary status
+ * - transparent: Subtle or background status
+ */
 export const pillType = ['primary', 'secondary', 'tertiary', 'success', 'warning', 'transparent'] as const;

+/** Type representing the available pill variants */
 export type PillType = (typeof pillType)[number]
frontend/src/assets/scss/layout.scss (1)

Line range hint 65-73: Consider standardizing spinner implementations and using design system variables

The custom spinner implementation could be improved by:

  1. Using design system color variables instead of hardcoded values
  2. Standardizing units (px vs rem)
  3. Considering consolidation with existing Element Plus spinner styles
 .custom-spinner::before {
-  @apply border-2 border-gray-100 border-b-gray-900 border-x-gray-900 rounded-full h-8 w-8 absolute;
+  @apply border-2 border-gray-100 border-b-primary border-x-primary rounded-full h-8 w-8 absolute;
   top: 10%;
   left: 10%;
   transform: translate3d(-50%, -50%, 0);
   content: "";
 }
frontend/src/ui-kit/popover/popover.scss (1)

1-6: Consider adding fallback for w-fit property

The w-fit property has limited browser support. Consider adding a fallback for older browsers:

.c-popover {
-  @apply relative w-fit flex;
+  @apply relative w-auto w-fit-content w-fit flex;
}

  &__trigger {
-    @apply w-fit;
+    @apply w-auto w-fit-content w-fit;
  }
frontend/src/ui-kit/dropdown/Dropdown.vue (1)

2-4: Consider adding an accessible trigger element.
Currently, the trigger slot may be replaced by arbitrary content, which might not always be keyboard-accessible. Adopting a button or anchor element as the trigger could improve accessibility and semantics.

frontend/src/ui-kit/popover/Popover.vue (3)

1-24: Enhance keyboard accessibility for the popover.
Currently, the template focuses on clicks and hover, but it does not address how keyboard users (e.g., pressing Enter or Escape) interact with the popover. Consider implementing keyboard navigation (e.g., close on “Esc” key) to improve accessibility.


26-45: Validate default prop values.
The default prop values such as spacing=4 might need refining in different layouts or themes. Regularly confirm that these defaults provide an optimal user experience across various devices.


61-65: Consider merging toggle logic with show/hide methods.
Instead of duplicating logic, a consolidated approach may reduce complexity and avoid future maintenance errors. For example, you can unify “togglePopover” with “showPopover”/“hidePopover” logic to handle outside click listeners more seamlessly.

frontend/src/ui-kit/popover/types/PopoverTrigger.ts (1)

1-6: Good use of literal types for 'PopoverTrigger'.
Defining an array of acceptable trigger types and using an indexed access union enforces type safety. For clarity, consider adding short docstrings describing each trigger type.

frontend/src/ui-kit/popover/types/PopoverPlacement.ts (1)

1-16: Provide fallback or boundary handling for popover placements.
While enumerating valid placements is helpful, ensure you handle or provide fallbacks for scenarios where there isn’t enough space in the chosen direction (e.g., using collision detection or boundary adjustment).

Would you like help implementing an automated fallback mechanism for limited space scenarios?

frontend/src/ui-kit/pill/Pill.vue (1)

3-6: Update component name to match new prefix

The component uses c-pill class prefix but is still named LfPill. Consider updating the component name to maintain consistency:

 export default {
-  name: 'LfPill',
+  name: 'CPill',
 };

Also applies to: 22-24

frontend/src/modules/admin/modules/projects/components/fragments/lf-project-count.vue (1)

Line range hint 20-22: Consider updating component prefix

The component name still uses the Lf prefix while the codebase seems to be moving away from this convention. Consider updating for consistency with other modernized components.

frontend/src/modules/admin/modules/projects/components/fragments/lf-status-pill.vue (1)

2-4: Add error handling for invalid status values

The fallback to 'primary' type is good, but consider logging invalid status values for debugging:

- <lf-pill :type="statusDisplay[props.status]?.type || 'primary'">
-   {{ statusDisplay[props.status]?.label }}
- </lf-pill>
+ <lf-pill :type="getStatusType(props.status)">
+   {{ getStatusLabel(props.status) }}
+ </lf-pill>

+ // Add to script section:
+ const getStatusType = (status: string) => {
+   if (!statusDisplay[status]) {
+     console.warn(`Invalid status: ${status}`);
+   }
+   return statusDisplay[status]?.type || 'primary';
+ };
+ 
+ const getStatusLabel = (status: string) => {
+   return statusDisplay[status]?.label || status;
+ };
frontend/src/modules/admin/modules/projects/components/fragments/lf-project-column.vue (1)

Line range hint 3-23: Consider enhancing popover accessibility.

The el-popover implementation could benefit from improved accessibility:

  1. Add aria-label to describe the popover content
  2. Add keyboard navigation support for users who can't use hover
 <el-popover
   placement="top"
   :width="250"
   trigger="hover"
+  aria-label="Project list"
+  :trigger="['hover', 'focus']"
 >
   <template #reference>
-    <app-lf-project-count :count="projects.length" />
+    <app-lf-project-count 
+      :count="projects.length"
+      tabindex="0"
+      role="button"
+    />
   </template>
frontend/src/modules/admin/modules/projects/components/lf-sub-projects-dropdown.vue (1)

3-13: Enhance dropdown accessibility and UX.

The icon-only button and dropdown item could benefit from accessibility improvements:

-    <lf-dropdown placement="bottom-end" width="12rem">
+    <lf-dropdown 
+      placement="bottom-end" 
+      width="12rem"
+      aria-label="Sub-project actions"
+    >
       <template #trigger>
-        <lf-button type="secondary-ghost-light" icon-only>
+        <lf-button 
+          type="secondary-ghost-light" 
+          icon-only
+          aria-label="Open sub-project actions"
+        >
           <lf-icon name="ellipsis" type="regular" />
         </lf-button>
       </template>
-      <lf-dropdown-item @click="editSubProject()">
+      <lf-dropdown-item 
+        @click="editSubProject()"
+        @keydown.enter="editSubProject()"
+      >
         <lf-icon name="pen" />
         Edit sub-project
       </lf-dropdown-item>
     </lf-dropdown>
frontend/src/ui-kit/dropdown/dropdown.scss (1)

2-2: LGTM! Consider adding focus styles for keyboard navigation

The new styling provides good visual hierarchy and consistent spacing. The use of Tailwind's utility classes is appropriate.

Consider adding focus styles for keyboard navigation:

.c-dropdown {
  @apply border border-gray-100 shadow-md p-2 flex flex-col gap-1 rounded-xl bg-white;
+ &:focus-visible {
+   @apply outline-none ring-2 ring-primary-500;
+ }
frontend/src/modules/admin/modules/projects/components/lf-projects-dropdown.vue (3)

38-43: Add TypeScript type annotations

Consider adding TypeScript type annotations for better type safety and developer experience.

defineProps({
  id: {
    type: String,
-   default: null,
+   default: null,
+   required: false,
  },
} as const);

+ type Events = {
+   onEditProject: [] // no payload
+   onAddSubProject: [] // no payload
+ }
- const emit = defineEmits(['onEditProject', 'onAddSubProject']);
+ const emit = defineEmits<Events>();

45-45: Consider using kebab-case for event names

Vue's style guide recommends using kebab-case for event names.

- const emit = defineEmits(['onEditProject', 'onAddSubProject']);
+ const emit = defineEmits(['edit-project', 'add-sub-project']);

49-55: Consider adding error handling for emit actions

The event handlers could benefit from try-catch blocks to handle potential errors.

const editProject = () => {
+ try {
    emit('onEditProject');
+ } catch (error) {
+   console.error('Failed to emit edit project event:', error);
+ }
};

const addSubProject = () => {
+ try {
    emit('onAddSubProject');
+ } catch (error) {
+   console.error('Failed to emit add sub-project event:', error);
+ }
};
frontend/src/ui-kit/popover/Popover.stories.ts (1)

51-72: Consider enhancing the default story with more examples.

While the current example is good, consider adding more stories to showcase different:

  • Placements (top, bottom, left, right)
  • Trigger events (hover, click)
  • Content variations

Example addition:

export const Placements = {
  args: {
    ...Default.args,
  },
  render: () => ({
    components: { LfPopover, LfButton },
    template: `
      <div class="flex gap-4">
        <lf-popover v-for="placement in popoverPlacements" :placement="placement">
          <template #trigger>
            <lf-button>{{ placement }}</lf-button>
          </template>
          <div class="p-4">Popover content</div>
        </lf-popover>
      </div>
    `,
  }),
};
frontend/src/modules/admin/modules/projects/components/lf-project-groups-dropdown.vue (1)

9-35: Consider simplifying complex permission conditions.

The nested permission checks in the template make it harder to maintain. Consider extracting these into computed properties.

Example refactor:

+ const canEdit = computed(() => 
+   hasPermission(LfPermission.projectGroupEdit) && 
+   hasAccessToSegmentId(id)
+ );
+ 
+ const canCreate = computed(() => 
+   hasPermission(LfPermission.projectCreate) && 
+   hasAccessToSegmentId(id) && 
+   !showEditOnly
+ );

- v-if="hasPermission(LfPermission.projectGroupEdit) && hasAccessToSegmentId(id)"
+ v-if="canEdit"

- v-if="hasPermission(LfPermission.projectCreate) && hasAccessToSegmentId(id) && !showEditOnly"
+ v-if="canCreate"
frontend/src/modules/activity/pages/activity-list-page.vue (1)

Line range hint 96-100: Consider using an enum for drawer states

The current implementation uses string literals for drawer states. Consider using an enum to improve type safety and maintainability.

+enum DrawerState {
+  ADD_ACTIVITY = 'add-activity',
+  ACTIVITY_TYPES = 'activity-types',
+}

-const drawer = ref<string | undefined>();
+const drawer = ref<DrawerState | undefined>();

-if (drawer.value === 'add-activity') {
+if (drawer.value === DrawerState.ADD_ACTIVITY) {
   isActivityDrawerOpen.value = true;
-} else if (drawer.value === 'activity-types') {
+} else if (drawer.value === DrawerState.ACTIVITY_TYPES) {
   isActivityTypeDrawerOpen.value = true;
}
frontend/src/modules/admin/modules/projects/components/view/lf-projects-table.vue (2)

13-16: Consider extracting permission check to computed property

The template contains a complex permission check that could be moved to a computed property for better maintainability and reusability.

+const canAddSubProject = computed(() => 
+  hasPermission(LfPermission.subProjectCreate) && 
+  hasAccessToSegmentId(project.id)
+);

 <lf-button
-  v-if="
-    hasPermission(LfPermission.subProjectCreate)
-      && hasAccessToSegmentId(project.id)
-  "
+  v-if="canAddSubProject"
   type="secondary-ghost-light"
   icon-only
   @click="emit('onAddSubProject', project)"
>

116-168: Consider using CSS custom properties for repeated values

The styling section contains repeated color and spacing values that could be extracted into CSS custom properties.

<style lang="scss">
+:root {
+  --projects-table-border-color: #e5e7eb;
+  --projects-table-padding-x: 1rem;
+  --projects-table-padding-y: 1rem;
+}

#projects-table {
-  @apply rounded-lg shadow-sm border border-solid border-gray-200;
+  @apply rounded-lg shadow-sm border border-solid;
+  border-color: var(--projects-table-border-color);

  thead .table-columns {
-    @apply align-middle h-auto px-2 py-4;
+    @apply align-middle h-auto;
+    padding: var(--projects-table-padding-y) var(--projects-table-padding-x);
frontend/src/modules/admin/modules/projects/pages/project-groups-list.page.vue (1)

Line range hint 192-194: Consider adding retry logic for image loading

The image error handling is basic and could be enhanced with retry logic or fallback URLs.

+const MAX_RETRY_ATTEMPTS = 3;
+const imageRetryCount = reactive({});

 const handleImageError = (id, e) => {
+  const currentRetry = imageRetryCount[id] || 0;
+  if (currentRetry < MAX_RETRY_ATTEMPTS) {
+    imageRetryCount[id] = currentRetry + 1;
+    // Retry with timestamp to bypass cache
+    e.target.src = `${projectGroup.url}?retry=${Date.now()}`;
+  } else {
     imageErrors[id] = true;
+  }
 };
frontend/src/modules/organization/components/edit/organization-add.vue (1)

Line range hint 134-157: Consider using a type-safe approach for form validation rules

The validation rules could benefit from stronger typing to catch potential issues at compile time.

+type ValidationRules = {
+  subproject: { required: true };
+  name: { required: true };
+  website: { required: true };
+  identities: {
+    required: (value: OrganizationAddIdentity[]) => boolean;
+  };
+};

-const rules = {
+const rules: ValidationRules = {
   subproject: {
     required,
   },
   name: {
     required,
   },
   website: {
     required,
   },
   identities: {
     required: (value: OrganizationAddIdentity[]) => value.some((i) => i.value.length),
   },
 };
frontend/src/modules/organization/pages/organization-form-page.vue (4)

Line range hint 441-507: Consider refactoring the form submission logic for better maintainability.

The onSubmit function handles both creation and update scenarios with complex error handling. Consider splitting this into separate methods for better maintainability and testing.

- async function onSubmit() {
+ async function handleOrganizationUpdate(payload) {
+   trackEvent({
+     key: FeatureEventKey.EDIT_ORGANIZATION,
+     type: EventType.FEATURE,
+     properties: {
+       ...payload.values,
+     },
+   });
+
+   try {
+     await OrganizationService.update(payload.id, payload.values);
+     Message.success(i18n('entities.organization.update.success'));
+     return true;
+   } catch (error) {
+     if (error.response.status === 409) {
+       Message.error(
+         h(
+           'div',
+           { class: 'flex flex-col gap-2' },
+           [
+             h(
+               'el-button',
+               {
+                 class: 'btn btn--xs btn--secondary !h-6 !w-fit',
+                 onClick: () => {
+                   organizationsStore.addToMergeOrganizations(payload.id, error.response.data);
+                   Message.closeAll();
+                 },
+               },
+               'Merge organizations',
+             ),
+           ],
+         ),
+         {
+           title: 'Organization was not updated because the website already exists in another organization.',
+         },
+       );
+     } else {
+       Errors.handle(error);
+     }
+     return false;
+   }
+ }
+
+ async function handleOrganizationCreate(payload) {
+   trackEvent({
+     key: FeatureEventKey.ADD_ORGANIZATION,
+     type: EventType.FEATURE,
+     properties: {
+       ...payload,
+     },
+   });
+
+   try {
+     await OrganizationService.create(payload);
+     Message.success(i18n('entities.organization.create.success'));
+     return true;
+   } catch (error) {
+     Message.error(i18n('entities.organization.create.error'));
+     Errors.handle(error);
+     return false;
+   }
+ }
+
+ async function onSubmit() {
    isFormSubmitting.value = true;

    const { emails, ...rest } = formModel.value;
    const name = isEditPage.value === false ? formModel.value.displayName : undefined;

    const data = {
      manuallyCreated: true,
      ...rest,
      attributes: {
        name: {
          default: name,
          custom: [name],
        },
      },
    };

    const payload = isEditPage.value
      ? {
        id: props.id,
        values: data,
        segments: segments.value,
      }
      : {
        ...data,
        segments: segments.value,
      };

-   // Edit
-   if (isEditPage.value) {
-     trackEvent({...})
-     try {...} catch (error) {...}
-   } else {
-     trackEvent({...})
-     try {...} catch (error) {...}
-   }
+   const success = isEditPage.value
+     ? await handleOrganizationUpdate(payload)
+     : await handleOrganizationCreate(payload);

    isFormSubmitting.value = false;
-   wasFormSubmittedSuccessfully.value = true;
+   wasFormSubmittedSuccessfully.value = success;
  }

Line range hint 508-516: Consider extracting route query handling logic.

The onChange function directly manipulates route query parameters. Consider extracting this logic into a dedicated composable for better reusability and testing.

+ function useRouteQueryManager() {
+   const router = useRouter();
+   
+   const updateSubprojectQuery = (subprojectId) => {
+     router.replace({
+       name: 'organizationCreate',
+       query: {
+         subprojectId,
+       },
+     });
+   };
+   
+   return {
+     updateSubprojectQuery,
+   };
+ }
+
- const onChange = ({ subprojectId }) => {
-   router.replace({
-     name: 'organizationCreate',
-     query: {
-       subprojectId,
-     },
-   });
- };
+ const { updateSubprojectQuery } = useRouteQueryManager();
+ const onChange = ({ subprojectId }) => {
+   updateSubprojectQuery(subprojectId);
+ };

Line range hint 471-486: Enhance error messages for better user experience.

The error handling for organization conflicts provides good user feedback, but other error scenarios could be more specific to help users understand and resolve issues.

  } catch (error) {
    if (error.response.status === 409) {
      Message.error(
        h(
          'div',
          { class: 'flex flex-col gap-2' },
          [
            h(
              'el-button',
              {
                class: 'btn btn--xs btn--secondary !h-6 !w-fit',
                onClick: () => {
                  organizationsStore.addToMergeOrganizations(payload.id, error.response.data);
                  Message.closeAll();
                },
              },
              'Merge organizations',
            ),
          ],
        ),
        {
          title: 'Organization was not updated because the website already exists in another organization.',
        },
      );
+   } else if (error.response.status === 400) {
+     Message.error(i18n('entities.organization.update.validationError'), {
+       title: 'Validation Error',
+       description: error.response.data.message || 'Please check your input and try again.',
+     });
+   } else if (error.response.status === 403) {
+     Message.error(i18n('entities.organization.update.permissionError'), {
+       title: 'Permission Error',
+       description: 'You do not have permission to update this organization.',
+     });
    } else {
      Errors.handle(error);
    }

Line range hint 529-559: Consider using CSS custom properties for better maintainability.

The SCSS styles could be more maintainable by using CSS custom properties for common values and leveraging Element Plus's built-in customization options.

  <style lang="scss">
+ :root {
+   --organization-form-spacing: 1.5rem;
+   --organization-form-btn-gap: 0.25rem;
+ }
+
  .organization-form-page {
    .el-button [class*="el-icon"] + span {
-     @apply ml-1;
+     margin-left: var(--organization-form-btn-gap);
    }

    .el-main {
-     @apply max-h-fit;
+     max-height: fit-content;
    }

    // Personal Details form
    .organization-details-form {
      & .el-form-item {
-       @apply mb-6;
+       margin-bottom: var(--organization-form-spacing);
      }
    }

    .identities-form .el-form-item,
    .custom-attributes-form .el-form-item {
-     @apply mb-0;
+     margin-bottom: 0;
    }

    .el-form .el-form-item__content,
    .el-form--default.el-form--label-top,
    .custom-attributes-form,
    .el-form-item__content {
-     @apply flex mb-0;
+     display: flex;
+     margin-bottom: 0;
    }
  }
  </style>
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b66d2c1 and 0b3e6e0.

📒 Files selected for processing (41)
  • frontend/config/styles/components/button.scss (1 hunks)
  • frontend/src/assets/scss/layout.scss (1 hunks)
  • frontend/src/modules/activity/pages/activity-list-page.vue (1 hunks)
  • frontend/src/modules/admin/admin.module.ts (1 hunks)
  • frontend/src/modules/admin/admin.routes.ts (1 hunks)
  • frontend/src/modules/admin/modules/projects/components/fragments/lf-project-column.vue (1 hunks)
  • frontend/src/modules/admin/modules/projects/components/fragments/lf-project-count.vue (1 hunks)
  • frontend/src/modules/admin/modules/projects/components/fragments/lf-status-pill.vue (1 hunks)
  • frontend/src/modules/admin/modules/projects/components/lf-project-groups-dropdown.vue (1 hunks)
  • frontend/src/modules/admin/modules/projects/components/lf-projects-dropdown.vue (1 hunks)
  • frontend/src/modules/admin/modules/projects/components/lf-sub-projects-dropdown.vue (1 hunks)
  • frontend/src/modules/admin/modules/projects/components/view/lf-project-groups-table.vue (2 hunks)
  • frontend/src/modules/admin/modules/projects/components/view/lf-projects-table.vue (1 hunks)
  • frontend/src/modules/admin/modules/projects/pages/project-groups-list.page.vue (1 hunks)
  • frontend/src/modules/admin/modules/projects/pages/project-groups.page.vue (1 hunks)
  • frontend/src/modules/admin/modules/projects/pages/projects.page.vue (2 hunks)
  • frontend/src/modules/admin/pages/admin-panel.page.vue (2 hunks)
  • frontend/src/modules/contributor/components/edit/contributor-add.vue (1 hunks)
  • frontend/src/modules/dashboard/components/dashboard-project-group-drawer.vue (1 hunks)
  • frontend/src/modules/index.ts (2 hunks)
  • frontend/src/modules/lf/config/status.js (2 hunks)
  • frontend/src/modules/lf/lf-modules.js (0 hunks)
  • frontend/src/modules/lf/segments/components/fragments/lf-status-pill.vue (0 hunks)
  • frontend/src/modules/lf/segments/components/lf-project-groups-dropdown.vue (0 hunks)
  • frontend/src/modules/lf/segments/components/lf-projects-dropdown.vue (0 hunks)
  • frontend/src/modules/lf/segments/components/view/lf-projects-table.vue (0 hunks)
  • frontend/src/modules/organization/components/edit/organization-add.vue (1 hunks)
  • frontend/src/modules/organization/pages/organization-form-page.vue (1 hunks)
  • frontend/src/ui-kit/dropdown/Dropdown.vue (1 hunks)
  • frontend/src/ui-kit/dropdown/dropdown.scss (1 hunks)
  • frontend/src/ui-kit/index.scss (1 hunks)
  • frontend/src/ui-kit/pill/Pill.stories.ts (2 hunks)
  • frontend/src/ui-kit/pill/Pill.vue (1 hunks)
  • frontend/src/ui-kit/pill/pill.scss (1 hunks)
  • frontend/src/ui-kit/pill/types/PillColor.ts (0 hunks)
  • frontend/src/ui-kit/pill/types/PillType.ts (1 hunks)
  • frontend/src/ui-kit/popover/Popover.stories.ts (1 hunks)
  • frontend/src/ui-kit/popover/Popover.vue (1 hunks)
  • frontend/src/ui-kit/popover/popover.scss (1 hunks)
  • frontend/src/ui-kit/popover/types/PopoverPlacement.ts (1 hunks)
  • frontend/src/ui-kit/popover/types/PopoverTrigger.ts (1 hunks)
💤 Files with no reviewable changes (6)
  • frontend/src/modules/lf/lf-modules.js
  • frontend/src/ui-kit/pill/types/PillColor.ts
  • frontend/src/modules/lf/segments/components/fragments/lf-status-pill.vue
  • frontend/src/modules/lf/segments/components/lf-projects-dropdown.vue
  • frontend/src/modules/lf/segments/components/lf-project-groups-dropdown.vue
  • frontend/src/modules/lf/segments/components/view/lf-projects-table.vue
✅ Files skipped from review due to trivial changes (3)
  • frontend/src/ui-kit/index.scss
  • frontend/src/modules/contributor/components/edit/contributor-add.vue
  • frontend/src/modules/admin/admin.module.ts
🔇 Additional comments (29)
frontend/src/ui-kit/pill/types/PillType.ts (1)

1-1: Verify the impact of type changes across the codebase.

The change from style-based types ('solid', 'bordered') to semantic types is a good improvement for maintainability. However, this is a breaking change that requires careful migration.

Let's verify the usage and potential impact:

frontend/src/assets/scss/layout.scss (1)

5-7: Verify the impact of overflow-hidden on the root element

Adding overflow-hidden to the HTML element could prevent scrolling throughout the application. This might cause issues with:

  • Long content becoming inaccessible
  • Modal/popover content being cut off
  • Mobile responsiveness

Please ensure this change doesn't negatively impact the user experience.

✅ Verification successful

The overflow-hidden on HTML is intentional and works with the app's scroll architecture

The overflow-hidden on the HTML element is part of a deliberate scrolling architecture where:

  • The HTML root is locked to prevent double scrollbars
  • Scrolling is managed through dedicated components (ScrollControll and ScrollBodyControll)
  • The main content area (el-main) is constrained with max-height: 100vh
  • Proper scroll event handling is implemented for infinite scrolling and content overflow

This is a common pattern for single-page applications to have better control over scrolling behavior and prevent scroll issues.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for potential scroll-dependent components that might be affected
rg -l "overflow-y|overflow-x|scroll|modal|drawer|popover" --type html --type vue

Length of output: 110


Script:

#!/bin/bash
# Search for potential scroll-dependent components with broader file types
rg -l "overflow-y|overflow-x|scroll|modal|drawer|popover" --type-add 'web:*.{vue,html,js,jsx,ts,tsx}'  --type web

# Also check for any CSS/SCSS files that might have scroll-related styles
rg -l "overflow|scroll|modal|drawer|popover" --type css

Length of output: 15827


Script:

#!/bin/bash
# Check the specific content of key layout and component files to understand scroll handling
cat frontend/src/assets/scss/layout.scss
cat frontend/src/ui-kit/scrollcontroll/ScrollControll.vue
cat frontend/src/ui-kit/scrollcontroll/ScrollBodyControll.vue

Length of output: 3241

frontend/src/ui-kit/popover/popover.scss (1)

11-71: 🛠️ Refactor suggestion

Add documentation and handle edge cases

The placement logic is comprehensive but could benefit from some improvements:

  1. Add documentation for CSS variables:
// Add at the top of the file:
/*
 * CSS Variables used:
 * --lf-popover-trigger-left: Left position of trigger element
 * --lf-popover-trigger-right: Right position of trigger element
 * --lf-popover-trigger-top: Top position of trigger element
 * --lf-popover-trigger-bottom: Bottom position of trigger element
 * --lf-popover-trigger-width: Width of trigger element
 * --lf-popover-trigger-height: Height of trigger element
 * --lf-popover-content-width: Width of popover content
 * --lf-popover-content-height: Height of popover content
 * --lf-popover-spacing: Spacing between trigger and content
 */
  1. Consider adding viewport boundary detection:

The popover might overflow the viewport in certain positions. Consider implementing a JavaScript-based position adjustment system that can detect viewport boundaries and switch to an alternative placement when needed.

  1. Add RTL support:

If RTL support is needed, consider using logical properties:

-        left: var(--lf-popover-trigger-left);
+        inset-inline-start: var(--lf-popover-trigger-left);
frontend/src/ui-kit/dropdown/Dropdown.vue (2)

6-15: Verify whether clicking inside the dropdown should immediately close it.
You are calling "close" on any click within the dropdown container, which may prevent users from interacting with elements inside it. If this behavior is unintentional, consider removing the click handler or delegating closure to a specific button or action within the slot.


20-20: Confirm that 'LfPopover' is correctly registered or globally available.
Ensure that 'LfPopover' is either globally registered in your app or imported wherever you intend to use this dropdown component.

frontend/src/ui-kit/pill/Pill.vue (1)

13-19: Props API improvement looks good

The simplification of props by removing the color prop in favor of type improves the component's API. The default value of 'primary' aligns well with common UI patterns.

Let's verify the impact of this change:

✅ Verification successful

Props API change is safe and properly implemented

The change from color to type prop is well-implemented with no remaining usages of the old color prop in the codebase. The new type prop is properly typed with PillType, which includes all necessary variants ('primary', 'secondary', 'tertiary', 'success', 'warning', 'transparent'). The Storybook examples demonstrate correct usage of the new API across all supported types.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any remaining usage of the color prop
rg -g '*.{vue,ts,js}' "color.*?['\"](solid|transparent)" 

Length of output: 161


Script:

#!/bin/bash
# Let's check for any usage of the Pill component with color prop
rg -g '*.{vue,ts,js}' '<Pill.*?color=' -A 2

# Also check for any imports or references to PillType
rg -g '*.{vue,ts,js}' 'PillType'

Length of output: 411


Script:

#!/bin/bash
# Let's check the content of PillType.ts to understand the type definition
cat frontend/src/ui-kit/pill/types/PillType.ts

# Let's also check the stories file to see the component usage examples
cat frontend/src/ui-kit/pill/Pill.stories.ts

Length of output: 1282

frontend/src/modules/lf/config/status.js (1)

Line range hint 3-24: Status class names are more semantic now

The change from color-based classes (green, yellow, gray) to semantic classes (success, warning, secondary) improves maintainability and accessibility.

Consider aligning color values with semantic names

While class names are now semantic, the color values still use direct color names. Consider updating these for consistency:

 {
   class: 'success',
-  color: 'bg-green-500',
+  color: 'bg-success-500',
   label: 'Active',
   value: 'active',
 },

Let's check for similar patterns:

frontend/src/ui-kit/pill/pill.scss (2)

Line range hint 4-30: LGTM! Well-structured modifier system

The modifier system follows good practices:

  • Consistent naming convention aligned with semantic meanings (success, warning)
  • Clear visual hierarchy with primary/secondary/tertiary variants
  • Proper use of Tailwind's color system

1-2: Consider handling overflow scenarios

The change from max-height to fixed height (h-5) might cause content overflow issues. Consider adding overflow handling or allowing height flexibility for longer content.

frontend/src/modules/index.ts (1)

13-13: Verify the module transition impact

The removal of the lf module and addition of the admin module represents a significant structural change. Please ensure all routes and components have been properly migrated.

Also applies to: 30-30

✅ Verification successful

No remaining references to lf module in active use

Based on the search results, while there are references to the lf module in the codebase, they are all within the old module directory frontend/src/modules/lf/ which is being removed. The new admin module is properly referenced in multiple files showing successful migration. No active imports or usage of the old lf module were found outside its own directory.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for any remaining references to the old lf module
echo "Checking for remaining references to lf module..."
rg -l "from ['\"]\@\/modules\/lf\/" --type vue --type ts

# Check for any components still using old paths
echo "Checking for components using old paths..."
rg -l "import.*from ['\"]\@\/modules\/lf\/segments\/" --type vue --type ts

Length of output: 573


Script:

#!/bin/bash
# Check for any remaining references to the old lf module, escaping @ properly
echo "Checking for remaining references to lf module..."
rg -l "from ['\"]@/modules/lf/" --type vue --type ts

# Check for any components still using old paths
echo "Checking for components using old paths..."
rg -l "import.*from ['\"]@/modules/lf/segments/" --type vue --type ts

# Check for any other references to lf module
echo "Checking for other lf module references..."
rg -l "/modules/lf" --type vue --type ts

# Check for admin module usage to verify migration
echo "Checking admin module usage..."
rg -l "from ['\"]@/modules/admin/" --type vue --type ts

Length of output: 713


Script:

#!/bin/bash
# Check for any remaining references to the old lf module
echo "Checking for remaining references to lf module..."
rg -l "modules/lf"

# Check for admin module usage to verify migration
echo "Checking admin module usage..."
rg -l "modules/admin"

# List all .vue and .ts files to verify file type support
echo "Listing Vue and TypeScript files..."
fd "\.(vue|ts)$"

Length of output: 69017

frontend/src/ui-kit/pill/Pill.stories.ts (2)

12-12: LGTM: Type prop default value change aligns with common UI patterns.

The change from 'default' to 'primary' as the default value follows standard UI component library patterns where 'primary' represents the main variant.


27-64: LGTM: Story renaming improves semantic meaning.

The renaming of stories from color-based names (Green, Yellow, etc.) to semantic names (Primary, Secondary, etc.) is a good improvement that:

  • Makes the component's purpose clearer
  • Aligns with common UI component patterns
  • Makes the stories more maintainable
frontend/src/modules/admin/modules/projects/components/fragments/lf-project-column.vue (1)

30-30: LGTM: Import path updated to use absolute path.

The change from relative to absolute import path improves maintainability and aligns with the module restructuring.

frontend/src/modules/admin/modules/projects/components/lf-sub-projects-dropdown.vue (1)

21-23: LGTM: Custom UI kit components imported.

The addition of custom dropdown components from the UI kit improves consistency across the application.

frontend/src/modules/admin/admin.routes.ts (1)

7-7: LGTM! Import paths correctly updated

The component imports have been properly relocated to the new admin module structure, maintaining the existing route configuration and permission guards.

Also applies to: 11-11, 15-15

frontend/src/ui-kit/popover/Popover.stories.ts (1)

6-49: LGTM! Well-structured Storybook configuration.

The story configuration follows best practices with:

  • Clear component title and autodocs tag
  • Comprehensive prop documentation with descriptions and controls
  • Well-defined slot documentation
frontend/src/modules/admin/modules/projects/components/lf-project-groups-dropdown.vue (1)

40-75: LGTM! Clean script setup implementation.

The component follows Vue 3 Composition API best practices with:

  • Clear prop definitions
  • Event emitters
  • Clean separation of concerns
frontend/src/modules/admin/modules/projects/components/view/lf-project-groups-table.vue (2)

74-74: LGTM! Import path update aligns with module reorganization.

The import path update correctly reflects the new location of the dropdown component in the admin module.


21-21: Verify the impact of fixed width on status pill.

Adding w-20 class makes the status pill width fixed. Ensure this doesn't cause text overflow issues with longer status texts.

✅ Verification successful

Based on the search results, I can now provide a definitive response about the status pill width concern:

Fixed width of 5rem (w-20) is appropriate for all possible status values.

The LfStatusPill component is used to display project group statuses which can only be one of these values:

  • "Active" (6 chars)
  • "Formation" (9 chars)
  • "Prospect" (8 chars)
  • "Archived" (8 chars)

The Tailwind w-20 class provides 5rem (80px) width, which is sufficient to accommodate all these status labels without text overflow, considering:

  • The longest status text is "Formation" with 9 characters
  • The component uses standard font sizes
  • The status labels are predefined and cannot be customized
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for all possible status values to verify they fit within w-20 (5rem/80px)
rg -A 1 "status.*=.*['\"].*['\"].*" --type vue

Length of output: 80


Script:

#!/bin/bash
# Search for status-related code in all files
rg -g '!{dist,build}/*' -A 3 'status.*=.*["\'].*["\']' 

# Search for the status pill component definition
fd -e vue -e js -e ts "lf-status-pill" --exec cat {}

Length of output: 116


Script:

#!/bin/bash
# Search for status-related code in all files
rg -g "!{dist,build}/*" -A 3 "status.*=.*['\"].*['\"]"

# Search for the status pill component definition
fd "lf-status-pill" -e vue -e js -e ts -x cat {}

Length of output: 35954

frontend/src/modules/admin/pages/admin-panel.page.vue (2)

37-56: LGTM! Template structure improvements

The consolidation of tab content under a single div with v-else-if conditions improves code maintainability and reduces DOM elements while maintaining the same functionality.


70-70: LGTM! Import path update

The import path update aligns with the project's restructuring efforts, moving project-related components to the admin/modules/projects directory.

frontend/src/modules/admin/modules/projects/pages/project-groups.page.vue (1)

76-79: LGTM! Consistent import path updates

The import paths have been updated to reflect the new project structure, moving project-related components to a dedicated projects module. This improves code organization and maintainability.

frontend/src/modules/activity/pages/activity-list-page.vue (1)

90-90: LGTM! Consistent import path update

The import path update aligns with the project's restructuring efforts.

frontend/src/modules/admin/modules/projects/pages/project-groups-list.page.vue (1)

125-125: LGTM: Import path updated correctly

The import path has been updated to reflect the new module structure.

frontend/src/modules/organization/components/edit/organization-add.vue (1)

120-120: LGTM: Import path updated correctly

The import path has been updated to reflect the new module structure.

frontend/src/modules/dashboard/components/dashboard-project-group-drawer.vue (1)

158-158: LGTM: Import path updated correctly.

The import path for AppLfSearchInput has been updated to reflect the new module structure.

frontend/config/styles/components/button.scss (1)

139-139: LGTM: Improved text contrast for better accessibility.

The text colors for the secondary ghost light button variant have been updated to use darker shades, which improves readability and accessibility:

  • Normal state: Changed from gray-400 to gray-500
  • Hover state: Changed from gray-500 to gray-600
  • Active state: Changed from gray-500 to gray-600

Also applies to: 144-144, 148-148

frontend/src/modules/admin/modules/projects/pages/projects.page.vue (1)

156-160: LGTM: Import paths updated consistently.

All component imports have been correctly updated to reflect the new module structure, moving from lf/segments to admin/modules/projects. The changes are consistent with the broader refactoring effort seen across the PR.

Also applies to: 169-171

frontend/src/modules/organization/pages/organization-form-page.vue (1)

166-166: Verify the component's new location and its impact.

The import path change aligns with the module restructuring effort. However, we should ensure this change is consistent across the codebase.

✅ Verification successful

Let me check the imports in the other files to ensure consistency.


Import path change is consistent across the codebase

The component exists at the new location frontend/src/modules/admin/modules/projects/components/lf-sub-projects-list-dropdown.vue, and all files that use this component are already using the new import path @/modules/admin/modules/projects/components/lf-sub-projects-list-dropdown.vue. The change is properly aligned with the codebase.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if the old import path is still being used elsewhere
rg -l "@/modules/lf/segments/components/lf-sub-projects-list-dropdown.vue"

# Verify the new component location exists
fd "lf-sub-projects-list-dropdown.vue" "frontend/src/modules/admin/modules/projects/components"

# Find all other imports of this component to ensure consistency
rg -l "lf-sub-projects-list-dropdown.vue"

Length of output: 592


Script:

#!/bin/bash
# Check import statements in files that use the component
rg -A 1 -B 1 "lf-sub-projects-list-dropdown" frontend/src/modules/organization/components/edit/organization-add.vue frontend/src/modules/contributor/components/edit/contributor-add.vue frontend/src/modules/admin/modules/projects/components/lf-sub-projects-list-modal.vue

Length of output: 2451

Comment on lines +8 to +10
&__content {
@apply absolute z-50 w-max transition-all overflow-visible;

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Optimize transitions and z-index management

A few suggestions to improve performance and maintainability:

  1. Replace transition-all with specific transitions to improve performance:
-    @apply absolute z-50 w-max transition-all overflow-visible;
+    @apply absolute z-50 w-max overflow-visible;
+    transition: transform 0.2s ease-in-out, opacity 0.2s ease-in-out;
  1. Consider using CSS custom properties for z-index to maintain a consistent stacking context across the application:
-    @apply absolute z-50 w-max transition-all overflow-visible;
+    @apply absolute w-max transition-all overflow-visible;
+    z-index: var(--lf-z-index-popover, 50);

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +3 to +6
<lf-badge type="secondary" class="!flex items-center gap-1 w-full !rounded-full !px-2.5">
<lf-icon-old name="stack-line" />
{{ pluralize('project', props.count, true) }}
</lf-pill>
</lf-badge>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Review utility class overrides

The use of multiple ! important flags in utility classes suggests potential style conflicts:

class="!flex items-center gap-1 w-full !rounded-full !px-2.5"

Consider addressing the root cause of these style conflicts instead of using important flags.

Comment on lines 11 to 14
import pluralize from 'pluralize';
import LfPill from '@/ui-kit/pill/Pill.vue';
import LfIconOld from '@/ui-kit/icon/IconOld.vue';
import LfBadge from '@/ui-kit/badge/Badge.vue';

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

One remaining LfPill component needs to be migrated

The UI modernization effort to replace LfPill with LfBadge is incomplete. There is still one component using the old LfPill:

  • frontend/src/modules/admin/modules/projects/components/fragments/lf-status-pill.vue

This component should also be updated to use LfBadge for consistency with the UI modernization efforts.

🔗 Analysis chain

Component imports and replacement look good

The replacement of LfPill with LfBadge aligns with the UI modernization efforts seen across the codebase.

Let's verify no orphaned pill components remain:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for remaining LfPill usage
rg -g '*.vue' "import.*LfPill.*from"

Length of output: 167


Script:

#!/bin/bash
# Let's check if LfPill is still being used in lf-status-pill.vue
cat frontend/src/modules/admin/modules/projects/components/fragments/lf-status-pill.vue

Length of output: 753

Comment on lines +14 to +31
const statusDisplay: Record<string, any> = {
active: {
type: 'success',
label: 'Active',
},
formation: {
type: 'primary',
label: 'Formation',
},
prospect: {
type: 'warning',
label: 'Prospect',
},
archived: {
type: 'secondary',
label: 'Archived',
},
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve type safety of status mapping

The current Record<string, any> type is too permissive. Consider creating proper interfaces:

interface StatusConfig {
  type: 'success' | 'primary' | 'warning' | 'secondary';
  label: string;
}

const statusDisplay: Record<string, StatusConfig> = {
  active: {
    type: 'success',
    label: 'Active',
  },
  // ... rest of the mapping
};

Comment on lines +3 to +4
v-if="(hasPermission(LfPermission.subProjectCreate) && hasAccessToSegmentId(id))
|| (hasPermission(LfPermission.projectEdit) && hasAccessToSegmentId(id))"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Simplify permission checks

The permission check logic is duplicated and could be simplified into a computed property.

+ const canShowDropdown = computed(() => {
+   return (hasPermission(LfPermission.subProjectCreate) || hasPermission(LfPermission.projectEdit)) 
+          && hasAccessToSegmentId(id);
+ });

- v-if="(hasPermission(LfPermission.subProjectCreate) && hasAccessToSegmentId(id))
-   || (hasPermission(LfPermission.projectEdit) && hasAccessToSegmentId(id))"
+ v-if="canShowDropdown"

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +31 to +68
<article
v-for="subproject of props.project.subprojects"
:key="subproject.id"
class="border-t border-gray-200 px-4 py-3 flex items-center justify-between"
>
<div class="flex items-center gap-4">
<lf-project-status-pill :status="subproject.status" class="w-20" />
<p class="text-medium">
{{ subproject.name }}
</p>
<app-lf-project-integration-column
:segment-id="subproject.id"
:integrations="subproject.integrations"
:progress="props.progress"
:progress-error="progressError"
/>
</div>
<div class="flex items-center gap-2">
<router-link
:to="{
name: 'integration',
params: {
id: subproject.id,
grandparentId: route.params.id,
},
}"
>
<lf-button type="primary-ghost">
<lf-icon name="grid-round-2-plus" :size="16" type="regular" />
Integrations
</lf-button>
</router-link>
<app-lf-sub-projects-dropdown
:id="subproject.id"
@on-edit-sub-project="emit('onEditSubProject', subproject.id)"
/>
</div>
</article>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add key accessibility attributes to interactive elements

The subprojects section contains interactive elements that should have proper accessibility attributes.

 <article
   v-for="subproject of props.project.subprojects"
   :key="subproject.id"
   class="border-t border-gray-200 px-4 py-3 flex items-center justify-between"
 >
   <div class="flex items-center gap-4">
-    <lf-project-status-pill :status="subproject.status" class="w-20" />
+    <lf-project-status-pill 
+      :status="subproject.status" 
+      class="w-20"
+      :aria-label="`Status: ${subproject.status}`"
+    />
     <p class="text-medium">
       {{ subproject.name }}
     </p>
   </div>
   <div class="flex items-center gap-2">
     <router-link
       :to="{
         name: 'integration',
         params: {
           id: subproject.id,
           grandparentId: route.params.id,
         },
       }"
+      :aria-label="`View integrations for ${subproject.name}`"
     >

Committable suggestion skipped: line range outside the PR's diff.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants