Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 5 additions & 12 deletions app/components/assessment/editor/MentionDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,8 @@

import { useLayoutEffect, useState } from "react";
import { createPortal } from "react-dom";
import { DocumentFileIcon, ImageIcon } from "@/app/components/icons";
import type {
MentionDropdownProps,
PromptFieldType,
} from "@/app/lib/types/assessment";

const TYPE_ICONS: Record<PromptFieldType, React.ReactNode> = {
text: <span className="font-sans text-[11px] font-semibold">Aa</span>,
image: <ImageIcon className="h-3.5 w-3.5" />,
pdf: <DocumentFileIcon className="h-3.5 w-3.5" />,
};
import RenderFieldType from "./RenderFieldType";
import type { MentionDropdownProps } from "@/app/lib/types/assessment";

const rowBase =
"flex w-full cursor-pointer items-center gap-2 px-3 py-2 text-left text-sm";
Expand Down Expand Up @@ -78,7 +69,9 @@ export default function MentionDropdown({
<OptionRow
key={option.type}
active={index === activeIndex}
badge={TYPE_ICONS[option.type]}
badge={
<RenderFieldType type={option.type} className="h-3.5 w-3.5" />
}
label={option.label}
isCurrent={option.isCurrent}
onPick={() => onPickType(option.type)}
Expand Down
17 changes: 6 additions & 11 deletions app/components/assessment/editor/PreviewPane.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
"use client";

import {
DocumentFileIcon,
ImageIcon,
LockClosedIcon,
} from "@/app/components/icons";
import { LockClosedIcon } from "@/app/components/icons";
import RenderFieldType from "./RenderFieldType";
import {
buildPreviewBlocks,
fieldTypeOf,
Expand Down Expand Up @@ -115,14 +112,12 @@ function SegmentView({
if (segment.kind === "plain") return <>{segment.text}</>;

if (segment.kind === "attachment" && segment.name) {
const isImage = fieldTypeOf(fieldTypes, segment.name) === "image";
return (
<span className="mx-0.5 inline-flex items-center gap-1 rounded-md border border-status-warning-border bg-status-warning-bg px-2 py-px align-baseline text-xs font-medium text-status-warning-text">
{isImage ? (
<ImageIcon className="h-3 w-3" />
) : (
<DocumentFileIcon className="h-3 w-3" />
)}
<RenderFieldType
type={fieldTypeOf(fieldTypes, segment.name)}
className="h-3 w-3"
/>
{segment.name}
</span>
);
Expand Down
21 changes: 21 additions & 0 deletions app/components/assessment/editor/RenderFieldType.tsx

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

keep its name a bit like RenderFieldType etc. something like that, right now it sounds like an icon component here, and an icon component should be in the icons folder instead of here, but here it's rendering an icon based on the type, so please change the component name.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Renamed to RenderFieldType in 1f9693f (app/components/assessment/editor/RenderFieldType.tsx). The plain VideoIcon stays in app/components/icons/common/.

Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { DocumentFileIcon, ImageIcon, VideoIcon } from "@/app/components/icons";
import type { PromptFieldType } from "@/app/lib/types/assessment";

export default function RenderFieldType({
type,
className,
textLabel = "Aa",
}: {
type: PromptFieldType;
className: string;
textLabel?: string;
}) {
if (type === "text") {
return (
<span className="font-sans text-[11px] font-semibold">{textLabel}</span>
);
}
if (type === "image") return <ImageIcon className={className} />;
if (type === "video") return <VideoIcon className={className} />;
return <DocumentFileIcon className={className} />;
}
14 changes: 6 additions & 8 deletions app/components/assessment/wizard/ReviewSaveModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { useState } from "react";
import { Button, Field, Modal } from "@/app/components/ui";
import { DocumentFileIcon, ImageIcon } from "@/app/components/icons";
import RenderFieldType from "@/app/components/assessment/editor/RenderFieldType";
import {
fieldTypeOf,
TOKEN_RE,
Expand Down Expand Up @@ -61,13 +61,11 @@ export default function ReviewSaveModal({
key={column}
className="inline-flex items-center gap-1.5 rounded-full border border-border bg-bg-secondary px-2.5 py-1 font-mono text-[11px] text-text-primary"
>
{type === "text" ? (
"@"
) : type === "image" ? (
<ImageIcon className="h-3 w-3" />
) : (
<DocumentFileIcon className="h-3 w-3" />
)}
<RenderFieldType
type={type}
className="h-3 w-3"
textLabel="@"
/>
{column}
<span className="font-sans text-[10px] text-text-secondary">
{type}
Expand Down
24 changes: 24 additions & 0 deletions app/components/icons/common/VideoIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
interface IconProps {
className?: string;
style?: React.CSSProperties;
}

export default function VideoIcon({ className, style }: IconProps) {
return (
<svg
className={className}
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
strokeWidth={2}
style={style}
>
<rect x="3" y="6" width="13" height="12" rx="2" />
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M16 10l5-3v10l-5-3"
/>
</svg>
);
}
1 change: 1 addition & 0 deletions app/components/icons/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export { default as ErrorCircleIcon } from "./common/ErrorCircleIcon";
export { default as DownloadIcon } from "./common/DownloadIcon";
export { default as HomeIcon } from "./common/HomeIcon";
export { default as ImageIcon } from "./common/ImageIcon";
export { default as VideoIcon } from "./common/VideoIcon";
export { default as LockClosedIcon } from "./common/LockClosedIcon";

// Evaluations Icons
Expand Down
2 changes: 1 addition & 1 deletion app/hooks/usePromptMentions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import type {
UsePromptMentionsResult,
} from "@/app/lib/types/assessment";

const TYPE_ORDER: PromptFieldType[] = ["text", "image", "pdf"];
const TYPE_ORDER: PromptFieldType[] = ["text", "image", "pdf", "video"];

const HOVER_CLOSE_DELAY_MS = 200;

Expand Down
4 changes: 2 additions & 2 deletions app/lib/assessment/configBlob.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ function attachmentsFrom(
.filter(([, column]) => column.type !== "text")
.map(([name, column]) => ({
column: name,
type: column.type as "image" | "pdf",
type: column.type,
format: column.format ?? "url",
}));
}
Expand Down Expand Up @@ -156,7 +156,7 @@ function inputSchema(
names.map((name) => {
const attachment = byColumn.get(name);
const column: AssessmentBlobInputColumn =
attachment && attachment.type !== "mixed"
attachment && attachment.type !== "text"
? { type: attachment.type, format: attachment.format ?? "url" }
: { type: "text", format: null };
return [name, strict.has(name) ? { ...column, strict: true } : column];
Expand Down
7 changes: 4 additions & 3 deletions app/lib/assessment/promptTokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export const PROMPT_FIELD_TYPE_LABELS: Record<PromptFieldType, string> = {
text: "Text",
image: "Image (link)",
pdf: "PDF (link)",
video: "Video (link)",
};

export function tokenName(raw: string): string {
Expand Down Expand Up @@ -165,7 +166,7 @@ export function fromWireTemplate(
return template.replace(TOKEN_RE, (raw) => {
const name = tokenName(raw);
const type = byColumn.get(name);
return type && type !== "mixed" ? `<${name}>` : `@${name}`;
return type && type !== "text" ? `<${name}>` : `@${name}`;
});
}

Expand All @@ -174,7 +175,7 @@ export function fieldTypesFromAttachments(
): Record<string, PromptFieldType> {
return Object.fromEntries(
attachments
.filter((item) => item.type !== "mixed")
.map((item) => [item.column, item.type as PromptFieldType]),
.filter((item) => item.type !== "text")
.map((item) => [item.column, item.type]),
);
}
3 changes: 2 additions & 1 deletion app/lib/types/assessment/core.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { ChangeEvent, DragEvent, RefObject } from "react";
import type { PromptFieldType } from "./prompt";

export type ValueSetter<T> = (value: T) => void;
export type SampleRow = Record<string, string>;
Expand Down Expand Up @@ -126,7 +127,7 @@ export interface AssessmentResultsPayload {

export interface Attachment {
column: string;
type: "image" | "pdf" | "mixed";
type: PromptFieldType;
format: "url" | "base64";
type_column?: string | null;
type_value_map?: Record<string, string> | null;
Expand Down
2 changes: 1 addition & 1 deletion app/lib/types/assessment/prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { ProviderType } from "@/app/lib/types/configs";
import type { SchemaProperty } from "./core";
import type { AssessorModelSelection, AssessorVersionDetail } from "./assessor";

export type PromptFieldType = "text" | "image" | "pdf";
export type PromptFieldType = "text" | "image" | "pdf" | "video";

export type PromptZoneId = "instructions" | "submission";

Expand Down
Loading