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

feat: DIA-2044: Add label config to "import sample data" #7227

Open
wants to merge 33 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
bbce2de
Adding sample select block
nick-skriabin Mar 7, 2025
d53cf37
Merge branch 'develop' into fb-dia-1924/sample-imports
nick-skriabin Mar 10, 2025
307a3ad
Merge remote-tracking branch 'origin/develop' into fb-dia-1924/sample…
matt-bernstein Mar 10, 2025
e28abfe
Merge remote-tracking branch 'origin/develop' into fb-dia-1924/sample…
matt-bernstein Mar 11, 2025
e524a31
Uploading data samples
nick-skriabin Mar 11, 2025
b539c7d
Format
nick-skriabin Mar 12, 2025
866cc83
Add sample import to import dialog within the project
nick-skriabin Mar 12, 2025
974b50f
feat: OPTIC-1746: Improve global error message handling by showing to…
bmartel Mar 11, 2025
cc617d3
fix: DIA-2028: [BE] Membership API call for organization with ID=2574…
nick-skriabin Mar 11, 2025
d2afd79
fix: DIA-2028: [BE] Membership API call for organization with ID=2574…
nick-skriabin Mar 11, 2025
8b826a7
feat: OPTIC-1265: Improve error pages (#7196)
mcanu Mar 11, 2025
13afe5b
fix: DIA-2026: allow annotators/reviewers to view jwt settings (#7208)
pakelley Mar 11, 2025
20008e0
fix: OPTIC-1749: Limit only sentry_force error logs to go to Sentry (…
mcanu Mar 11, 2025
4425120
Merge remote-tracking branch 'origin/develop' into fb-dia-1924/sample…
matt-bernstein Mar 12, 2025
96926ba
remove redundant sample
matt-bernstein Mar 12, 2025
45d07f4
turn ff off by default for safety
matt-bernstein Mar 13, 2025
b5d8f7a
Select styles
nick-skriabin Mar 14, 2025
e421f23
upload samples
matt-bernstein Mar 14, 2025
ff267ec
feat: DIA-2044: Add label config to "import sample data"
matt-bernstein Mar 14, 2025
4014976
add warning message to samples dropdown
matt-bernstein Mar 14, 2025
0ed24ba
add label config to samples
matt-bernstein Mar 14, 2025
abccd04
update label config on saving sample
matt-bernstein Mar 14, 2025
813be08
fix trash icon
matt-bernstein Mar 14, 2025
c5c5d6e
Merge remote-tracking branch 'origin/develop' into fb-dia-2044
matt-bernstein Mar 19, 2025
f2f730a
move warning to the right of the dropdown
matt-bernstein Mar 19, 2025
d9032e0
biome
matt-bernstein Mar 19, 2025
63fd114
Merge remote-tracking branch 'origin/develop' into fb-dia-2044
matt-bernstein Mar 24, 2025
8911eef
Organize imports
nick-skriabin Mar 25, 2025
8e7c6f5
Remove excess
nick-skriabin Mar 25, 2025
1e8f41a
Formatting
nick-skriabin Mar 25, 2025
3f1cc5c
Remove excess function
nick-skriabin Mar 25, 2025
f8c6802
Use correct FF check
nick-skriabin Mar 25, 2025
e2c0b2d
Organize imports
nick-skriabin Mar 25, 2025
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
24 changes: 16 additions & 8 deletions web/apps/labelstudio/src/pages/CreateProject/CreateProject.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,21 @@ import { EnterpriseBadge } from "@humansignal/ui";
import React from "react";
import { useHistory } from "react-router";
import { Button, ToggleItems } from "../../components";
import { Caption } from "../../components/Caption/Caption";
import { Input, Select, TextArea } from "../../components/Form";
import { HeidiTips } from "../../components/HeidiTips/HeidiTips";
import { createURL } from "../../components/HeidiTips/utils";
import { Modal } from "../../components/Modal/Modal";
import { Space } from "../../components/Space/Space";
import { HeidiTips } from "../../components/HeidiTips/HeidiTips";
import { useAPI } from "../../providers/ApiProvider";
import { cn } from "../../utils/bem";
import { FF_LSDV_E_297, isFF } from "../../utils/feature-flags";
import { ConfigPage } from "./Config/Config";
import { EMPTY_CONFIG } from "./Config/Template";
import "./CreateProject.scss";
import { ImportPage } from "./Import/Import";
import { useImportPage } from "./Import/useImportPage";
import { useDraftProject } from "./utils/useDraftProject";
import { Input, Select, TextArea } from "../../components/Form";
import { Caption } from "../../components/Caption/Caption";
import { FF_LSDV_E_297, isFF } from "../../utils/feature-flags";
import { createURL } from "../../components/HeidiTips/utils";

const ProjectName = ({ name, setName, onSaveName, onSubmit, error, description, setDescription, show = true }) =>
!show ? null : (
Expand Down Expand Up @@ -89,6 +90,7 @@ export const CreateProject = ({ onClose, redirect = true }) => {
const [name, setName] = React.useState("");
const [error, setError] = React.useState();
const [description, setDescription] = React.useState("");
const [config, setConfig] = React.useState(EMPTY_CONFIG);
const [sample, setSample] = React.useState(null);

const setStep = React.useCallback((step) => {
Expand Down Expand Up @@ -123,9 +125,9 @@ export const CreateProject = ({ onClose, redirect = true }) => {
() => ({
title: name,
description,
label_config: project?.label_config ?? "<View></View>",
label_config: sample && sample.label_config ? sample.label_config : project?.label_config ?? EMPTY_CONFIG,
}),
[name, description, project?.label_config],
[name, description, project?.label_config, sample],
);

const onCreate = React.useCallback(async () => {
Expand Down Expand Up @@ -218,8 +220,14 @@ export const CreateProject = ({ onClose, redirect = true }) => {
project={project}
show={step === "import"}
sample={sample}
onSampleDatasetSelect={setSample}
onSampleDatasetSelect={(selectedSample) => {
setSample(selectedSample);
if (selectedSample?.label_config) {
setConfig(selectedSample.label_config);
}
}}
openLabelingConfig={() => setStep("config")}
hasLabelConfig={config && config !== EMPTY_CONFIG}
{...pageProps}
/>
<ConfigPage
Expand Down
13 changes: 12 additions & 1 deletion web/apps/labelstudio/src/pages/CreateProject/Import/Import.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { Modal } from "../../../components/Modal/Modal";
import { useAPI } from "../../../providers/ApiProvider";
import { cn } from "../../../utils/bem";
import { unique } from "../../../utils/helpers";
import { EMPTY_CONFIG } from "../Config/Template";
import { sampleDatasetAtom } from "../utils/atoms";
import "./Import.scss";
import samples from "./samples.json";
Expand Down Expand Up @@ -167,6 +168,7 @@ export const ImportPage = ({
csvHandling,
setCsvHandling,
addColumns,
hasLabelConfig,
openLabelingConfig,
}) => {
const [loading, setLoading] = useState(false);
Expand Down Expand Up @@ -367,7 +369,16 @@ export const ImportPage = ({
Upload {files.uploaded.length ? "More " : ""}Files
</Button>
{ff.isActive(ff.FF_SAMPLE_DATASETS) && (
<SampleDatasetSelect samples={samples} sample={sample} onSampleApplied={onSampleDatasetSelect} />
<SampleDatasetSelect
samples={samples}
sample={sample}
onSampleApplied={onSampleDatasetSelect}
warningMessage={
hasLabelConfig || (project?.label_config && project.label_config !== EMPTY_CONFIG)
? "Selecting a sample dataset will overwrite your current labeling configuration."
: undefined
}
/>
)}
<div
className={importClass.elem("csv-handling").mod({ highlighted: highlightCsvHandling, hidden: !csvHandling })}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const Inner = () => {
const [sample, setSample] = useState(null);
const api = useAPI();

const { uploading, uploadDisabled, finishUpload, fileIds, pageProps, uploadSample } = useImportPage(project);
const { uploading, uploadDisabled, finishUpload, fileIds, pageProps, uploadSample } = useImportPage(project, sample);

const backToDM = useCallback(() => {
const path = location.pathname.replace(ImportModal.path, "");
Expand Down Expand Up @@ -56,8 +56,21 @@ export const Inner = () => {
const imported = await finishUpload();

if (!imported) return;

// If we have a sample with a label_config, update the project's label config
if (sample && sample.label_config) {
await api.callApi("updateProject", {
params: {
pk: project.id,
},
body: {
label_config: sample.label_config,
},
});
}

backToDM();
}, [backToDM, finishUpload, sample]);
}, [backToDM, finishUpload, sample, api, project.id]);

return (
<Modal
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
{
"title": "COCO 2017 Images",
"description": "A 100-image subset of the COCO image segmentation benchmark dataset.",
"url": "https://hs-sandbox-pub.s3.us-east-1.amazonaws.com/sample_data/coco_2017_val_100tasks.json"
"url": "https://hs-sandbox-pub.s3.us-east-1.amazonaws.com/sample_data/coco_2017_val_100tasks.json",
"label_config": "<View><Image name=\"image\" value=\"$image\"/><Text name=\"text\" value=\"$text\"/><View name=\"label\"/></View>"
},
{
"title": "CoNLL 2012 NER",
"description": "The CoNLL dataset of 13k sentences for Named Entity Recognition.",
"url": "https://hs-sandbox-pub.s3.us-east-1.amazonaws.com/sample_data/conll_2012.json"
"url": "https://hs-sandbox-pub.s3.us-east-1.amazonaws.com/sample_data/conll_2012.json",
"label_config": "<View> <Labels name=\"label\" toName=\"text\"> <Label value=\"PER\" background=\"red\"/> <Label value=\"ORG\" background=\"darkorange\"/> <Label value=\"LOC\" background=\"orange\"/> <Label value=\"MISC\" background=\"green\"/> </Labels> <Text name=\"text\" value=\"$text\"/></View>"
}
]
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export const useImportPage = (project, sample) => {
setCsvHandling,
onFileListUpdate: setFileIds,
dontCommitToProject: true,
sample,
};

return { columns, uploading, uploadDisabled, finishUpload, fileIds, pageProps, uploadSample };
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
import { Select, SelectContent, SelectItem, SelectTrigger } from "@humansignal/shad/components/ui/select";
import { useCallback, useMemo } from "react";
import { IconWarning } from "@humansignal/ui/assets/icons";

type Sample = {
title: string;
url: string;
description: string;
label_config?: string;
};

export function SampleDatasetSelect({
samples,
sample,
onSampleApplied,
warningMessage,
}: {
samples: Sample[];
sample?: Sample;
onSampleApplied: (sample?: Sample) => void;
warningMessage?: string;
}) {
const title = useMemo(() => {
return sample?.title ?? "Select sample";
Expand All @@ -28,21 +32,30 @@ export function SampleDatasetSelect({
);

return (
<div className="flex gap-3 items-center">
<span className="text-lsNeutralContentSubtler">or use a sample dataset</span>
<Select value={sample?.url ?? undefined} onValueChange={onSelect}>
<SelectTrigger className="h-10 min-w-52 rounded-sm border-lsNeutralBorderBold data-[placeholder]:text-[#000] text-[16px] [&_svg]:stroke-[#000]">
{title}
</SelectTrigger>
<SelectContent className="z-99999 min-w-90">
{samples.map((sample) => (
<SelectItem value={sample.url} key={sample.url}>
<div className=" font-bold">{sample.title}</div>
<div className="mt-2">{sample.description}</div>
</SelectItem>
))}
</SelectContent>
</Select>
<div className="flex flex-row items-start gap-4">
<div className="flex gap-3 items-center">
<span className="text-lsNeutralContentSubtler">or use a sample dataset</span>
<Select value={sample?.url ?? undefined} onValueChange={onSelect}>
<SelectTrigger className="h-10 min-w-52 rounded-sm border-lsNeutralBorderBold data-[placeholder]:text-[#000] text-[16px] [&_svg]:stroke-[#000]">
{title}
</SelectTrigger>
<SelectContent className="z-99999 min-w-90">
{samples.map((sample) => (
<SelectItem value={sample.url} key={sample.url}>
<div className=" font-bold">{sample.title}</div>
<div className="mt-2">{sample.description}</div>
</SelectItem>
))}
</SelectContent>
</Select>
</div>

{warningMessage && (
<div className="flex items-start gap-2 p-2 text-red-600 bg-red-50 border border-red-200 rounded-sm max-w-xs">
<IconWarning className="w-5 h-5 fill-red-600 flex-shrink-0 mt-0.5" />
<span className="text-sm leading-tight">{warningMessage}</span>
</div>
)}
</div>
);
}
4 changes: 3 additions & 1 deletion web/libs/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
"version": "0.0.0",
"license": "MIT",
"private": true,
"dependencies": {},
"dependencies": {
"@radix-ui/react-select": "^2.1.6"
},
"main": "src/index.ts",
"files": ["src/tailwind.css", "src/shad/components", "src/ui/assets", "src/ui/typography"]
}
Loading