Skip to content

fix: BROS-193: Follow up fixes #8057

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

Merged
merged 31 commits into from
Aug 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
f2e23ef
Make optional fields really optional, reset test connection button if…
nick-skriabin Jul 29, 2025
e2ff937
UI polishing
nick-skriabin Jul 29, 2025
71e9021
Form editing and valivation
nick-skriabin Jul 29, 2025
cd78331
Simplify field render component
nick-skriabin Jul 29, 2025
d1620a0
Display validation errors
nick-skriabin Jul 29, 2025
8e831bf
Error UI refine
nick-skriabin Jul 29, 2025
80083c4
Enable new UI for target storages
nick-skriabin Jul 29, 2025
5aa3fe5
Remove story file for ProviderGrid
nick-skriabin Jul 29, 2025
4137fe7
Remove stroy file
nick-skriabin Jul 31, 2025
49fcd4d
Do not reset the form between steps
nick-skriabin Jul 31, 2025
1815efd
Add tooltip to files to reveal full path
nick-skriabin Jul 31, 2025
50c9a7d
Merge branch 'develop' into fb-bros-193/followup
nick-skriabin Jul 31, 2025
21a99cf
Add missing permissions for files preview
nick-skriabin Jul 31, 2025
e2727f2
Refactor if-else to switch-case
nick-skriabin Jul 31, 2025
2aa55ef
Update provider forms, fix layout
nick-skriabin Aug 1, 2025
a5c8348
Compact errors display
nick-skriabin Aug 1, 2025
571e17c
Couple of refinements
nick-skriabin Aug 1, 2025
18c2bbf
Adjust preview
nick-skriabin Aug 1, 2025
8a09a99
Allow conditional fields
nick-skriabin Aug 1, 2025
ac82f5c
Add fields condition
nick-skriabin Aug 1, 2025
e5abc43
Fine tuning for export storages and preview step
nick-skriabin Aug 1, 2025
337150f
Auto-sync storages
nick-skriabin Aug 1, 2025
e3d0e02
Merge branch 'develop' into 'fb-bros-193/followup'
niklub Aug 4, 2025
bbeaad9
Fine tuning storages
nick-skriabin Aug 4, 2025
0c72b16
Validation rework
nick-skriabin Aug 4, 2025
be41cb5
Refine preview
nick-skriabin Aug 4, 2025
521df60
Allow certain field to not reset connection validation
nick-skriabin Aug 4, 2025
fe2fca5
Formatting and linter stuff
nick-skriabin Aug 4, 2025
ae933bc
Linter
nick-skriabin Aug 4, 2025
dd338c2
Remove console.log, fix formatting
nick-skriabin Aug 4, 2025
77f6561
Replace ` with "
nick-skriabin Aug 4, 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
1 change: 1 addition & 0 deletions label_studio/io_storages/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ def create(self, request, *args, **kwargs):
class ImportStorageListFilesAPI(generics.CreateAPIView):

permission_required = all_permissions.projects_change
permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES + [StoragePermission]
parser_classes = (JSONParser, FormParser, MultiPartParser)
serializer_class = None # Default serializer

Expand Down
69 changes: 36 additions & 33 deletions web/apps/labelstudio/src/components/Error/Error.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const ErrorWrapper = ({
onGoBack,
onReload,
possum = false,
minimal = false,
}) => {
const preparedStackTrace = useMemo(() => {
return (stacktrace ?? "").trim();
Expand All @@ -34,7 +35,7 @@ export const ErrorWrapper = ({

return (
<Block name="error-message">
{possum !== false && (
{!minimal && possum !== false && (
<Elem
tag="img"
name="heidi"
Expand All @@ -44,9 +45,9 @@ export const ErrorWrapper = ({
/>
)}

{title && <Elem name="title">{title}</Elem>}
{!minimal && title && <Elem name="title">{title}</Elem>}

{message && (
{!minimal && message && (
<Elem
name="detail"
dangerouslySetInnerHTML={{
Expand All @@ -55,7 +56,7 @@ export const ErrorWrapper = ({
/>
)}

{preparedStackTrace && (
{!minimal && preparedStackTrace && (
<Elem
name="stracktrace"
dangerouslySetInnerHTML={{
Expand All @@ -76,7 +77,7 @@ export const ErrorWrapper = ({
</Elem>
)}

{(version || errorId) && (
{!minimal && (version || errorId) && (
<Elem name="version">
<Space>
{version && `Version: ${version}`}
Expand All @@ -85,36 +86,38 @@ export const ErrorWrapper = ({
</Elem>
)}

<Elem name="actions">
<Space spread>
<Elem tag={Button} name="action-slack" target="_blank" icon={<IconSlack />} href={SLACK_INVITE_URL}>
Ask on Slack
</Elem>
{!minimal && (
<Elem name="actions">
<Space spread>
<Elem tag={Button} name="action-slack" target="_blank" icon={<IconSlack />} href={SLACK_INVITE_URL}>
Ask on Slack
</Elem>

<Space size="small">
{preparedStackTrace && (
<Button
disabled={copied}
onClick={copyStacktrace}
className="w-[100px]"
aria-label="Copy error stacktrace"
>
{copied ? "Copied" : "Copy Stacktrace"}
</Button>
)}
{onGoBack && (
<Button onClick={onGoBack} aria-label="Go back">
Go Back
</Button>
)}
{onReload && (
<Button onClick={onReload} aria-label="Reload page">
Reload
</Button>
)}
<Space size="small">
{preparedStackTrace && (
<Button
disabled={copied}
onClick={copyStacktrace}
className="w-[100px]"
aria-label="Copy error stacktrace"
>
{copied ? "Copied" : "Copy Stacktrace"}
</Button>
)}
{onGoBack && (
<Button onClick={onGoBack} aria-label="Go back">
Go Back
</Button>
)}
{onReload && (
<Button onClick={onReload} aria-label="Reload page">
Reload
</Button>
)}
</Space>
</Space>
</Space>
</Elem>
</Elem>
)}
</Block>
);
};
8 changes: 6 additions & 2 deletions web/apps/labelstudio/src/components/Error/InlineError.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { ApiContext } from "../../providers/ApiProvider";
import { Block } from "../../utils/bem";
import { ErrorWrapper } from "./Error";

export const InlineError = ({ children, includeValidation, className, style }) => {
export const InlineError = ({ minimal, children, includeValidation, className, style }) => {
const context = React.useContext(ApiContext);

React.useEffect(() => {
Expand All @@ -12,7 +12,11 @@ export const InlineError = ({ children, includeValidation, className, style }) =

return context.error ? (
<Block name="inline-error" mix={className} style={style}>
<ErrorWrapper possum={false} {...context.errorFormatter(context.error, { includeValidation })} />
<ErrorWrapper
possum={false}
minimal={minimal}
{...context.errorFormatter(context.error, { includeValidation })}
/>
{children}
</Block>
) : null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const StorageSet = ({ title, target, rootClass, buttonLabel }) => {
const project = useAtomValue(projectAtom);
const storageTypesQueryKey = ["storage-types", target];
const storagesQueryKey = ["storages", target, project?.id];
const useNewStorageScreen = ff.isActive(ff.FF_NEW_STORAGES) && target !== "export";
const useNewStorageScreen = ff.isActive(ff.FF_NEW_STORAGES);

const {
storageTypes,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,22 @@ export const azureProvider: ProviderConfig = {
placeholder: "my-azure-container",
schema: z.string().min(1, "Container name is required"),
},
{
name: "prefix",
type: "text",
label: "Bucket prefix",
placeholder: "path/to/files",
schema: z.string().optional().default(""),
target: "export",
},
{
name: "account_name",
type: "password",
label: "Account Name",
autoComplete: "off",
accessKey: true,
placeholder: "mystorageaccount",
schema: z.string().min(1, "Account Name is required"),
schema: z.string().optional().default(""),
},
{
name: "account_key",
Expand All @@ -32,7 +40,7 @@ export const azureProvider: ProviderConfig = {
autoComplete: "new-password",
accessKey: true,
placeholder: "Your storage account key",
schema: z.string().min(1, "Account Key is required"),
schema: z.string().optional().default(""),
},
{
name: "presign",
Expand All @@ -41,6 +49,8 @@ export const azureProvider: ProviderConfig = {
description:
"When pre-signed URLs are enabled, all data bypasses the platform and user browsers directly read data from storage",
schema: z.boolean().default(true),
target: "import",
resetConnection: false,
},
{
name: "presign_ttl",
Expand All @@ -50,19 +60,16 @@ export const azureProvider: ProviderConfig = {
max: 10080,
step: 1,
schema: z.number().min(1).max(10080).default(15),
// dependency: "presign" // Not implemented in UI yet
target: "import",
resetConnection: false,
},
],
layout: [
{
fields: ["container"],
},
{
fields: ["account_name", "account_key"],
},
{
fields: ["presign", "presign_ttl"],
},
{ fields: ["container"] },
{ fields: ["prefix"] },
{ fields: ["account_name"] },
{ fields: ["account_key"] },
{ fields: ["presign", "presign_ttl"] },
],
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@ export const gcsProvider: ProviderConfig = {
required: true,
schema: z.string().min(1, "Bucket name is required"),
},
{
name: "prefix",
type: "text",
label: "Bucket prefix",
placeholder: "path/to/files",
schema: z.string().optional().default(""),
target: "export",
},
{
name: "google_application_credentials",
type: "password",
Expand All @@ -38,6 +46,8 @@ export const gcsProvider: ProviderConfig = {
description:
"When pre-signed URLs are enabled, all data bypasses the platform and user browsers directly read data from storage",
schema: z.boolean().default(true),
target: "import",
resetConnection: false,
},
{
name: "presign_ttl",
Expand All @@ -47,22 +57,17 @@ export const gcsProvider: ProviderConfig = {
max: 10080,
step: 1,
schema: z.number().min(1).max(10080).default(15),
target: "import",
resetConnection: false,
// dependency: "presign" // Not implemented in UI yet
},
],
layout: [
{
fields: ["bucket"],
},
{
fields: ["google_application_credentials"],
},
{
fields: ["google_project_id"],
},
{
fields: ["presign", "presign_ttl"],
},
{ fields: ["bucket"] },
{ fields: ["prefix"] },
{ fields: ["google_application_credentials"] },
{ fields: ["google_project_id"] },
{ fields: ["presign", "presign_ttl"] },
],
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,16 @@ export const localFilesProvider: ProviderConfig = {
placeholder: "/data/my-folder/",
schema: z.string().min(1, "Path is required"),
},
],
layout: [
{
fields: ["path"],
name: "prefix",
type: "text",
label: "Path",
placeholder: "path/to/files",
schema: z.string().optional().default(""),
target: "export",
},
],
layout: [{ fields: ["path"] }, { fields: ["prefix"] }],
};

export default localFilesProvider;
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ export const redisProvider: ProviderConfig = {
name: "host",
type: "text",
label: "Host",
required: true,
placeholder: "redis://example.com",
schema: z.string(),
schema: z.string().min(1, "Host is required"),
},
{
name: "port",
Expand All @@ -37,12 +38,16 @@ export const redisProvider: ProviderConfig = {
placeholder: "6379",
schema: z.string().default("6379"),
},
],
layout: [
{
fields: ["host", "port", "db", "password"],
name: "prefix",
type: "text",
label: "Bucket prefix",
placeholder: "path/to/files",
schema: z.string().optional().default(""),
target: "export",
},
],
layout: [{ fields: ["host", "port", "db", "password"] }, { fields: ["prefix"] }],
};

export default redisProvider;
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,24 @@ export const s3Provider: ProviderConfig = {
name: "region_name",
type: "text",
label: "Region Name",
placeholder: "us-east-1",
placeholder: "us-east-1 (default)",
schema: z.string().optional().default(""),
},
{
name: "s3_endpoint",
type: "text",
label: "S3 Endpoint",
placeholder: "https://s3.amazonaws.com",
placeholder: "https://s3.amazonaws.com (default)",
schema: z.string().optional().default(""),
},
{
name: "prefix",
type: "text",
label: "Bucket prefix",
placeholder: "path/to/files",
schema: z.string().optional().default(""),
target: "export",
},
{
name: "aws_access_key_id",
type: "password",
Expand Down Expand Up @@ -65,6 +73,8 @@ export const s3Provider: ProviderConfig = {
description:
"When pre-signed URLs are enabled, all data bypasses the platform and user browsers directly read data from storage",
schema: z.boolean().default(true),
target: "import",
resetConnection: false,
},
{
name: "presign_ttl",
Expand All @@ -74,20 +84,18 @@ export const s3Provider: ProviderConfig = {
max: 10080,
step: 1,
schema: z.number().min(1).max(10080).default(15),
target: "import",
resetConnection: false,
},
],
layout: [
{
fields: ["bucket"],
},
{
fields: ["region_name", "s3_endpoint"],
},
{
fields: ["aws_access_key_id", "aws_secret_access_key", "aws_session_token"],
},
{
fields: ["presign", "presign_ttl"],
},
{ fields: ["bucket"] },
{ fields: ["region_name"] },
{ fields: ["s3_endpoint"] },
{ fields: ["prefix"] },
{ fields: ["aws_access_key_id"] },
{ fields: ["aws_secret_access_key"] },
{ fields: ["aws_session_token"] },
{ fields: ["presign", "presign_ttl"] },
],
};
Loading
Loading