Repository: campudus/tableaux-frontend
Pull request #468: GRUD_DEV-1140/fix multiple links in cell
Author: login: smnhgn
Created: 2025-04-24T15:50:51Z | Merged: 2025-05-08T22:28:11Z

# Submit a pull request

## Please make sure the following is true:

- [x] I gave the PR a meaningful name
- [x] I checked that the correct target branch is selected
- [x] I rebased the branch on the target branch and it can be merged
- [x] I ran the linter and it did pass
- [x] I checked for unused code / dead code / debug code
- [x] I checked that variables/functions have meaningful names
- [x] I checked that the behaviour is as the documentation/task describes and I tested it
- [x] I updated the docs / specifications if possible
- [x] I could explain all that code when someone wakes me up at 3am
- [x] I checked that the code considers failures and not just the happy path
- [x] There are no new dependencies OR I listed them and explained them below
- [x] PR introduces no breaking changes OR I listed them and described them below
- [x] I added/updated tests for new/modified unit-testable functions/helpers
- [x] I ran the tests and they did pass



Diff:
diff --git a/src/app/components/cells/Cell.jsx b/src/app/components/cells/Cell.jsx
index f0dce898a..3a7f4c677 100644
--- a/src/app/components/cells/Cell.jsx
+++ b/src/app/components/cells/Cell.jsx
@@ -80,7 +80,7 @@ class Cell extends React.Component {
     ]);
 
     return (
-      (this.props.cell.kind === ColumnKinds.link &&
+      (f.contains(cell.kind, [ColumnKinds.link, ColumnKinds.attachment]) &&
         this.props.width !== nextProps.width) ||
       this.props.langtag !== nextProps.langtag ||
       cell.id !== nextCell.id ||
diff --git a/src/app/components/cells/attachment/AttachmentCell.jsx b/src/app/components/cells/attachment/AttachmentCell.jsx
index 50bf3ce85..912ab19d6 100644
--- a/src/app/components/cells/attachment/AttachmentCell.jsx
+++ b/src/app/components/cells/attachment/AttachmentCell.jsx
@@ -1,4 +1,4 @@
-import React from "react";
+import React, { useMemo } from "react";
 import PropTypes from "prop-types";
 import AttachmentLabelCell from "./AttachmentLabelCell.jsx";
 import * as f from "lodash/fp";
@@ -10,6 +10,7 @@ import { maybe } from "../../../helpers/functools";
 import { retrieveTranslation } from "../../../helpers/multiLanguage";
 import apiUrl from "../../../helpers/apiUrl";
 import { canUserChangeCell } from "../../../helpers/accessManagementHelper";
+import { getVisibleLinkCount } from "../link/getVisibleLinkCount";
 
 const AttachmentCell = props => {
   const {
@@ -18,12 +19,19 @@ const AttachmentCell = props => {
     editing,
     selected,
     cell: { value },
-    langtag
+    langtag,
+    width
   } = props;
   const cellClass = classNames("cell-content", {
     editing: editing,
     selected: selected
   });
+  const previewAttachmentCount = useMemo(() => {
+    const currentLangDisplayValues = f.map(f.get(["title", langtag]), value);
+    return getVisibleLinkCount(currentLangDisplayValues, width);
+  }, [width]);
+
+  const tooManyAttachments = f.size(value) > previewAttachmentCount;
 
   const viewAttachment = attachment =>
     f.flow(
@@ -60,9 +68,9 @@ const AttachmentCell = props => {
     });
   };
 
-  const attachments = (editing && selected
+  const attachments = (editing || selected
     ? value
-    : f.take(3)(value)
+    : f.take(previewAttachmentCount)(value)
   ).map((element, idx) => (
     <AttachmentLabelCell
       key={idx}
@@ -73,7 +81,7 @@ const AttachmentCell = props => {
       selected={selected}
       cell={cell}
       editing={editing}
-      handleClick={handleAttachmentLabelClick}
+      handleClick={editing || selected ? handleAttachmentLabelClick : f.noop}
     />
   ));
 
@@ -87,7 +95,11 @@ const AttachmentCell = props => {
   };
 
   const handleClick = e => {
-    if (editing && selected) {
+    if (
+      !isLocked(cell.row) &&
+      canUserChangeCell(cell, langtag) &&
+      (editing || selected)
+    ) {
       if (allAttachmentsHaveSameFolderId(value)) {
         openOverlay(e, f.get("folder", f.head(value)));
       } else {
@@ -99,16 +111,16 @@ const AttachmentCell = props => {
   return (
     <>
       <div className={cellClass} onClick={handleClick}>
-        {f.size(attachments) === f.size(value)
-          ? attachments
-          : [
+        {tooManyAttachments && !selected && !editing
+          ? [
               ...attachments,
               <span key={"more"} className="more">
                 &hellip;
               </span>
-            ]}
+            ]
+          : attachments}
       </div>
-      {editing && selected ? (
+      {editing || selected ? (
         <button key={"add-btn"} className="edit" onClick={handleClick}>
           <span className="fa fa-pencil" />
         </button>
diff --git a/src/app/components/cells/link/getVisibleLinkCount.js b/src/app/components/cells/link/getVisibleLinkCount.js
index d88de59b0..ee69c61c3 100644
--- a/src/app/components/cells/link/getVisibleLinkCount.js
+++ b/src/app/components/cells/link/getVisibleLinkCount.js
@@ -1,5 +1,5 @@
 // TODO: Keep in sync with link label spacings/font
-const gapWidthInPx = 8;
+const gapWidthInPx = 6;
 const linkLabelStyle = {
   padding: "6px 8px",
   fontFammily: "Roboto",
@@ -7,6 +7,8 @@ const linkLabelStyle = {
   fontWeight: "normal",
   position: "absolute"
 };
+const cellPaddingInPx = 10;
+const ellipsisWidthInPx = 8;
 
 const { max } = Math;
 
@@ -24,11 +26,17 @@ const measureLinkWidth = displayValue => {
   return width;
 };
 
-export const getVisibleLinkCount = (values, availableWidth, n = 0) => {
+export const getVisibleLinkCount = (
+  values,
+  fullWidth,
+  n = 0,
+  reservedWidth = 2 * cellPaddingInPx + ellipsisWidthInPx
+) => {
+  const availableWidth = max(0, fullWidth - reservedWidth);
   if (n >= values.length) return max(n, 1);
   const nextVal = values[n];
   const vWidth = measureLinkWidth(nextVal);
   return vWidth >= availableWidth
     ? max(n, 1)
-    : getVisibleLinkCount(values, availableWidth - vWidth, n + 1);
+    : getVisibleLinkCount(values, availableWidth - vWidth, n + 1, 0);
 };
diff --git a/src/scss/cells/cell.scss b/src/scss/cells/cell.scss
index 5bac119f8..240fcae19 100644
--- a/src/scss/cells/cell.scss
+++ b/src/scss/cells/cell.scss
@@ -151,6 +151,36 @@
   &.selected {
     border: 1px solid $color-primary;
 
+    &.cell-link,
+    &.cell-text,
+    &.cell-attachment,
+    &.cell-richtext,
+    &.cell-currency {
+      border: 0;
+      padding: 0;
+      align-items: flex-start;
+
+      .annotation-bar {
+        padding: 0 10px;
+        top: 2px;
+        z-index: 2;
+      }
+
+      .cell-content {
+        @include box-sizing(border-box);
+        padding: 9px;
+        height: auto;
+        min-height: $space-height-cell;
+        background-color: $color-selected-row;
+        border: 1px solid $color-primary;
+        z-index: 1;
+        width: 100%;
+        max-height: 170px;
+        overflow-y: visible;
+        overflow-x: hidden;
+      }
+    }
+
     &.cell-link,
     &.cell-attachment {
       .cell-content {
diff --git a/src/scss/cells/link.scss b/src/scss/cells/link.scss
index 619af779c..d873827a9 100644
--- a/src/scss/cells/link.scss
+++ b/src/scss/cells/link.scss
@@ -36,4 +36,16 @@
       }
     }
   }
+
+  &.selected,
+  &.editing {
+    .cell-content {
+      flex-flow: row wrap;
+      padding-bottom: 3px;
+
+      .link-label {
+        margin-bottom: 6px;
+      }
+    }
+  }
 }


Reviews:
user: login: McHunkyTrunk
body: Wenn man die Spalte vergrößert, aktualisiert sich die Anzeige erst beim nächsten Rerender (sodass der Platz gefüllt wird). Können wir es anpassen?

![image](https://github.com/user-attachments/assets/4540b042-51c2-49f1-a2b4-0e26f8f5aaba)

state: CHANGES_REQUESTED
author_association: COLLABORATOR
submitted_at: 2025-05-05T11:49:19Z
user: login: hermann-p
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-08T06:14:27Z
user: login: smnhgn
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-08T07:04:38Z
user: login: hermann-p
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-08T12:37:21Z
user: login: McHunkyTrunk
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-05-08T22:28:05Z

Review comments:
diff_hunk: @@ -1,12 +1,14 @@
 // TODO: Keep in sync with link label spacings/font
-const gapWidthInPx = 8;
+const gapWidthInPx = 6;
 const linkLabelStyle = {
   padding: "6px 8px",
   fontFammily: "Roboto",
   fontSize: "1.3rem",
   fontWeight: "normal",
   position: "absolute"
 };
+const cellPaddingInPx = 10;
path: src/app/components/cells/link/getVisibleLinkCount.js
user: login: hermann-p
body: Könnte man die beiden Style-Werte evtl. noch mit dem CSS verknüpfen? Wenn das nur an 1-2 Stellen vorkommt wäre das sicher nicht schlecht; wenn man dafür allerdings Unmengen CSS-Files anfassen muss lohnt es sich wohl kaum.
created_at: 2025-05-08T06:14:27Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,12 +1,14 @@
 // TODO: Keep in sync with link label spacings/font
-const gapWidthInPx = 8;
+const gapWidthInPx = 6;
 const linkLabelStyle = {
   padding: "6px 8px",
   fontFammily: "Roboto",
   fontSize: "1.3rem",
   fontWeight: "normal",
   position: "absolute"
 };
+const cellPaddingInPx = 10;
path: src/app/components/cells/link/getVisibleLinkCount.js
user: login: smnhgn
body: Was meinst du genau mit `mit dem CSS verknüpfen`?
created_at: 2025-05-08T07:04:37Z
author_association: MEMBER
diff_hunk: @@ -1,12 +1,14 @@
 // TODO: Keep in sync with link label spacings/font
-const gapWidthInPx = 8;
+const gapWidthInPx = 6;
 const linkLabelStyle = {
   padding: "6px 8px",
   fontFammily: "Roboto",
   fontSize: "1.3rem",
   fontWeight: "normal",
   position: "absolute"
 };
+const cellPaddingInPx = 10;
path: src/app/components/cells/link/getVisibleLinkCount.js
user: login: hermann-p
body: Wie besprochen ist das out of scope :)
created_at: 2025-05-08T12:37:21Z
author_association: CONTRIBUTOR

PR comments:
user: login: smnhgn
created_at: 2025-05-05T14:12:41Z
body: Kann ich mir noch anschauen. Ich glaube ich habe da was ähnliches für die Badges in der Annotationbar gebaut.
Vllt. kann ich das ja wiederverwenden.
author_association: MEMBER
user: login: smnhgn
created_at: 2025-05-07T11:58:51Z
body: @McHunkyTrunk War letztendlich ein Bug, dass die AttachmentCell nach dem ColumnResize nicht geupdated wurde.  
Habe das im letzten Commit gefixt.
author_association: MEMBER