Fix approvers ui

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
Sacha Al Himdani
2026-02-16 16:04:20 +01:00
parent 93c7b0c2dc
commit 33dfcd26c2
10 changed files with 33 additions and 25 deletions

View File

@@ -18,12 +18,14 @@ type Props<T extends FieldValues = FieldValues> = {
label?: string;
error?: string;
selectedPeople?: Person[];
placeholder?: string;
} & ComponentProps<typeof Field>;
export function PeopleMultiSelectField<T extends FieldValues = FieldValues>({
organizationId,
control,
selectedPeople = [],
placeholder,
...props
}: Props<T>) {
return (
@@ -37,6 +39,7 @@ export function PeopleMultiSelectField<T extends FieldValues = FieldValues>({
name={props.name}
disabled={props.disabled}
selectedPeople={selectedPeople}
placeholder={placeholder}
/>
</Suspense>
</Field>
@@ -44,10 +47,10 @@ export function PeopleMultiSelectField<T extends FieldValues = FieldValues>({
}
function PeopleMultiSelectWithQuery<T extends FieldValues = FieldValues>(
props: Pick<Props<T>, "organizationId" | "control" | "name" | "disabled" | "selectedPeople">,
props: Pick<Props<T>, "organizationId" | "control" | "name" | "disabled" | "selectedPeople" | "placeholder">,
) {
const { __ } = useTranslate();
const { name, organizationId, control, selectedPeople = [] } = props;
const { name, organizationId, control, selectedPeople = [], placeholder } = props;
const people = usePeople(organizationId, { excludeContractEnded: true });
const [isOpen, setIsOpen] = useState(false);
@@ -91,7 +94,7 @@ function PeopleMultiSelectWithQuery<T extends FieldValues = FieldValues>(
disabled={props.disabled}
id={name}
variant="editor"
placeholder={__("Add attendees...")}
placeholder={placeholder ?? __("Add people...")}
onValueChange={handleAddPerson}
key={`${selectedPeopleIds.length}-${people.length}`}
className="w-full"

View File

@@ -151,6 +151,7 @@ export function CreateDocumentDialog({ trigger, connection }: Props) {
name="approverIds"
control={control}
organizationId={organizationId}
placeholder={__("Add approvers...")}
/>
</PropertyRow>
</div>

View File

@@ -177,6 +177,7 @@ export function DocumentLayoutDrawer(props: {
control={control}
organizationId={organizationId}
selectedPeople={approvers}
placeholder={__("Add approvers...")}
/>
</EditablePropertyContent>
)

View File

@@ -1,6 +1,6 @@
import { formatDate, getDocumentClassificationLabel, getDocumentTypeLabel, sprintf } from "@probo/helpers";
import { useTranslate } from "@probo/i18n";
import { ActionDropdown, Avatar, Badge, Checkbox, DropdownItem, IconTrashCan, Td, Tr, useConfirm } from "@probo/ui";
import { ActionDropdown, Badge, Checkbox, DropdownItem, IconTrashCan, Td, Tr, useConfirm } from "@probo/ui";
import { useFragment } from "react-relay";
import { type DataID, graphql } from "relay-runtime";
@@ -132,14 +132,7 @@ export function DocumentListItem(props: {
{getDocumentClassificationLabel(__, document.classification)}
</Td>
<Td className="w-60">
<div className="flex gap-2 items-center">
{document.approvers.edges.map(({ node }) => (
<div key={node.id} className="flex gap-1 items-center">
<Avatar name={node.fullName} />
{node.fullName}
</div>
))}
</div>
{document.approvers.edges.map(({ node }) => node.fullName).join(", ")}
</Td>
<Td className="w-60">{formatDate(document.updatedAt)}</Td>
<Td className="w-20">

View File

@@ -104,6 +104,7 @@ export function CreateMeetingDialog({ children, connectionId }: Props) {
control={control}
organizationId={organizationId}
label={__("Attendees")}
placeholder={__("Add attendees...")}
/>
</DialogContent>
<DialogFooter>

View File

@@ -204,7 +204,7 @@ type (
Content string
Version int
Classification Classification
Approver string
Approvers []string
Description string
PublishedAt *time.Time
Signatures []SignatureData

View File

@@ -41,7 +41,7 @@ func TestRenderHTML(t *testing.T) {
Content: "# Main Title\n\nThis is **bold** text with *italic* formatting.",
Version: 1,
Classification: ClassificationPublic,
Approver: "John Doe",
Approvers: []string{"John Doe"},
PublishedAt: &now,
Signatures: []SignatureData{
{
@@ -66,9 +66,9 @@ func TestRenderHTML(t *testing.T) {
{
name: "document with HTML characters that need escaping",
data: DocumentData{
Title: "Test & <Script> Title",
Content: "Normal markdown content",
Approver: "John <script>alert('xss')</script> Doe",
Title: "Test & <Script> Title",
Content: "Normal markdown content",
Approvers: []string{"John <script>alert('xss')</script> Doe"},
Signatures: []SignatureData{
{
SignedBy: "Alice & <Bob>",
@@ -253,8 +253,8 @@ func TestClassificationConstants(t *testing.T) {
func TestHTMLEscaping(t *testing.T) {
dangerousData := DocumentData{
Title: "<script>alert('xss')</script>",
Approver: "User & <Company>",
Title: "<script>alert('xss')</script>",
Approvers: []string{"User & <Company>"},
Signatures: []SignatureData{
{
SignedBy: "<malicious>tag",
@@ -385,7 +385,7 @@ func BenchmarkGenerateHTML(b *testing.B) {
Content: "# Title\n\nThis is **bold** text with *italic* formatting.\n\n- Item 1\n- Item 2",
Version: 1,
Classification: ClassificationPublic,
Approver: "John Doe",
Approvers: []string{"John Doe"},
PublishedAt: &now,
Signatures: []SignatureData{
{

View File

@@ -363,8 +363,18 @@
</td>
</tr>
<tr>
<td>Approver</td>
<td>{{.Approver}}</td>
<td>Approver{{- if gt (len .Approvers) 1}}s{{- end}}</td>
<td>
{{- if eq (len .Approvers) 1}}
{{index .Approvers 0}}
{{- else}}
<ul style="margin: 0; padding-left: 18px;">
{{- range .Approvers}}
<li>{{.}}</li>
{{- end}}
</ul>
{{- end}}
</td>
</tr>
<tr>
<td>Version:</td>

View File

@@ -1927,7 +1927,7 @@ func exportDocumentPDF(
Content: version.Content,
Version: version.VersionNumber,
Classification: classification,
Approver: strings.Join(approverNames, ", "),
Approvers: approverNames,
PublishedAt: version.PublishedAt,
Signatures: signatureData,
CompanyHorizontalLogoBase64: horizontalLogoBase64,

View File

@@ -18,7 +18,6 @@ import (
"context"
"fmt"
"io"
"strings"
"go.gearno.de/kit/pg"
"go.probo.inc/probo/pkg/coredata"
@@ -215,7 +214,7 @@ func (s *DocumentService) exportPDFData(
Content: version.Content,
Version: version.VersionNumber,
Classification: classification,
Approver: strings.Join(approverNames, ", "),
Approvers: approverNames,
PublishedAt: version.PublishedAt,
CompanyHorizontalLogoBase64: horizontalLogoBase64,
}