@scality/data-browser-library 1.0.0-preview.15 → 1.0.0-preview.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,26 +2,11 @@ import React from 'react';
2
2
  import type { DataBrowserUIProps } from '../config/types';
3
3
  /**
4
4
  * DataBrowserUI component - Main UI component for data browser.
5
- * Must be wrapped with DataBrowserProvider for S3 client and theme context,
5
+ * Must be wrapped with DataBrowserProvider for S3 configuration context,
6
6
  * and a BrowserRouter for routing.
7
7
  *
8
- * Uses relative routing for route definitions, but absolute paths for navigation.
9
- * Pass basePath to DataBrowserUI to specify where the UI is mounted.
10
- *
11
- * @example
12
- * ```tsx
13
- * <BrowserRouter>
14
- * <DataBrowserProvider
15
- * getS3Config={getS3Config}
16
- * theme={theme}
17
- * >
18
- * <Routes>
19
- * <Route path="/accounts/:accountName/buckets/*" element={
20
- * <DataBrowserUI basePath="/accounts/my-account" />
21
- * } />
22
- * </Routes>
23
- * </DataBrowserProvider>
24
- * </BrowserRouter>
25
- * ```
8
+ * Uses relative routing for route definitions. The `basePath` prop is used internally
9
+ * by `useDataBrowserNavigate()` to prefix all navigation paths, allowing the UI to be
10
+ * mounted at any route within your application.
26
11
  */
27
12
  export declare const DataBrowserUI: React.FC<DataBrowserUIProps>;
@@ -5,11 +5,11 @@ import { BucketDetails } from "../buckets/BucketDetails.js";
5
5
  import { applyBucketMocks, createTestWrapper } from "../../test/testUtils.js";
6
6
  import { useGetBucketAcl, useGetBucketCors, useGetBucketLifecycle, useGetBucketLocation, useGetBucketObjectLockConfiguration, useGetBucketPolicy, useGetBucketReplication, useGetBucketTagging, useGetBucketVersioning } from "../../hooks/index.js";
7
7
  import { useISVBucketStatus } from "../../hooks/useISVBucketDetection.js";
8
- import { useFeatures } from "../../utils/useFeatures.js";
8
+ import { useFeatures } from "../../hooks/useFeatures.js";
9
9
  import * as __WEBPACK_EXTERNAL_MODULE__contexts_DataBrowserUICustomizationContext_js_f267b01c__ from "../../contexts/DataBrowserUICustomizationContext.js";
10
10
  jest.mock('../../hooks');
11
11
  jest.mock('../../hooks/useISVBucketDetection');
12
- jest.mock('../../utils/useFeatures');
12
+ jest.mock('../../hooks/useFeatures');
13
13
  const mockUseParams = jest.fn();
14
14
  const mockUseNavigate = jest.fn();
15
15
  jest.mock('react-router', ()=>({
@@ -5,10 +5,10 @@ import { MemoryRouter } from "react-router";
5
5
  import { useGetBucketAcl, useGetBucketCors, useGetBucketLocation, useGetBucketObjectLockConfiguration, useGetBucketPolicy, useGetBucketTagging, useGetBucketVersioning, useISVBucketStatus } from "../../hooks/index.js";
6
6
  import { applyBucketMocks, createTestWrapper } from "../../test/testUtils.js";
7
7
  import { BucketOverview, useBucketOverviewContext } from "../buckets/BucketOverview.js";
8
- import { useFeatures } from "../../utils/useFeatures.js";
8
+ import { useFeatures } from "../../hooks/useFeatures.js";
9
9
  import * as __WEBPACK_EXTERNAL_MODULE__contexts_DataBrowserUICustomizationContext_js_f267b01c__ from "../../contexts/DataBrowserUICustomizationContext.js";
10
10
  jest.mock('../../hooks');
11
- jest.mock('../../utils/useFeatures');
11
+ jest.mock('../../hooks/useFeatures');
12
12
  const mockUseGetBucketVersioning = jest.mocked(useGetBucketVersioning);
13
13
  const mockUseGetBucketAcl = jest.mocked(useGetBucketAcl);
14
14
  const mockUseGetBucketLocation = jest.mocked(useGetBucketLocation);
@@ -5,7 +5,7 @@ import { createTestWrapper, mockOffsetSize, setupMswServer } from "../../test/te
5
5
  import { useListObjectVersions, useListObjects } from "../../hooks/index.js";
6
6
  import { ObjectList } from "../objects/ObjectList.js";
7
7
  import { DataBrowserUICustomizationProvider } from "../../contexts/DataBrowserUICustomizationContext.js";
8
- import * as __WEBPACK_EXTERNAL_MODULE__utils_useFeatures_js_1facdd0d__ from "../../utils/useFeatures.js";
8
+ import * as __WEBPACK_EXTERNAL_MODULE__hooks_useFeatures_js_a6a84786__ from "../../hooks/useFeatures.js";
9
9
  setupMswServer();
10
10
  const renderObjectList = (props = {}, customization)=>{
11
11
  const Wrapper = createTestWrapper();
@@ -32,7 +32,7 @@ describe('ObjectList', ()=>{
32
32
  beforeEach(()=>{
33
33
  jest.clearAllMocks();
34
34
  mockOffsetSize(800, 600);
35
- jest.spyOn(__WEBPACK_EXTERNAL_MODULE__utils_useFeatures_js_1facdd0d__, 'useFeatures').mockReturnValue(false);
35
+ jest.spyOn(__WEBPACK_EXTERNAL_MODULE__hooks_useFeatures_js_a6a84786__, 'useFeatures').mockReturnValue(false);
36
36
  });
37
37
  afterEach(()=>{
38
38
  jest.restoreAllMocks();
@@ -284,7 +284,7 @@ describe('ObjectList', ()=>{
284
284
  });
285
285
  describe('Search Features', ()=>{
286
286
  it('renders table search when metadata-search feature is disabled', async ()=>{
287
- jest.spyOn(__WEBPACK_EXTERNAL_MODULE__utils_useFeatures_js_1facdd0d__, 'useFeatures').mockReturnValue(false);
287
+ jest.spyOn(__WEBPACK_EXTERNAL_MODULE__hooks_useFeatures_js_a6a84786__, 'useFeatures').mockReturnValue(false);
288
288
  renderObjectList();
289
289
  await waitFor(()=>{
290
290
  expect(screen.getByRole('grid')).toBeInTheDocument();
@@ -292,7 +292,7 @@ describe('ObjectList', ()=>{
292
292
  expect(screen.queryByPlaceholderText(/Metadata Search/i)).not.toBeInTheDocument();
293
293
  });
294
294
  it('renders MetadataSearch component when metadata-search feature is enabled', async ()=>{
295
- jest.spyOn(__WEBPACK_EXTERNAL_MODULE__utils_useFeatures_js_1facdd0d__, 'useFeatures').mockReturnValue(true);
295
+ jest.spyOn(__WEBPACK_EXTERNAL_MODULE__hooks_useFeatures_js_a6a84786__, 'useFeatures').mockReturnValue(true);
296
296
  renderObjectList();
297
297
  await waitFor(()=>{
298
298
  expect(screen.getByRole('grid')).toBeInTheDocument();
@@ -6,7 +6,7 @@ import { useDataBrowserUICustomization } from "../../contexts/DataBrowserUICusto
6
6
  import { useGetBucketAcl, useGetBucketCors, useGetBucketObjectLockConfiguration, useGetBucketPolicy, useGetBucketVersioning } from "../../hooks/index.js";
7
7
  import { isNotFoundError } from "../../utils/errorHandling.js";
8
8
  import { EditRetentionButton } from "../objects/ObjectLock/EditRetentionButton.js";
9
- import { useDataBrowserContext } from "../providers/DataBrowserProvider.js";
9
+ import { useDataBrowserConfig } from "../providers/DataBrowserProvider.js";
10
10
  import { Body, Group, GroupContent, GroupName, GroupValues, Key, Row, Table, TableContainer, Value } from "../ui/Table.elements.js";
11
11
  import { BucketLocation } from "./BucketLocation.js";
12
12
  import { BucketPolicyButton } from "./BucketPolicyButton.js";
@@ -401,8 +401,7 @@ DataProtectionSection.displayName = 'BucketOverview.DataProtectionSection';
401
401
  const PermissionsSection = /*#__PURE__*/ memo(({ onEditPolicy, ownerField, aclField, corsField, publicField, bucketPolicyField, renderOwner, renderAcl, renderCors, renderPublic, renderBucketPolicy })=>{
402
402
  const { bucketName } = useBucketOverviewContext();
403
403
  const { extraBucketOverviewPermissions } = useDataBrowserUICustomization();
404
- const { getS3Config } = useDataBrowserContext();
405
- const config = getS3Config();
404
+ const config = useDataBrowserConfig();
406
405
  const { data: aclData, status: aclStatus } = useGetBucketAcl({
407
406
  Bucket: bucketName
408
407
  });
@@ -4,7 +4,7 @@ import { useCallback, useMemo } from "react";
4
4
  import { Controller, useFormContext } from "react-hook-form";
5
5
  import { getFilteredEventGroups } from "./events.js";
6
6
  import { Box } from "@scality/core-ui/dist/next";
7
- import { useSupportedNotificationEvents } from "../../../utils/useSupportedNotificationEvents.js";
7
+ import { useSupportedNotificationEvents } from "../../../hooks/useSupportedNotificationEvents.js";
8
8
  function EventsSection() {
9
9
  const { control, formState: { errors } } = useFormContext();
10
10
  const supportedEvents = useSupportedNotificationEvents();
@@ -18,6 +18,7 @@ export { ObjectLockSettings } from './objects/ObjectLock/ObjectLockSettings';
18
18
  export { EditRetentionButton } from './objects/ObjectLock/EditRetentionButton';
19
19
  export { MetadataSearch } from './search/MetadataSearch';
20
20
  export { ArrayFieldActions } from './ui/ArrayFieldActions';
21
- export { DataBrowserProvider, useDataBrowserContext, useDataBrowserTheme, } from './providers/DataBrowserProvider';
21
+ export { DataBrowserProvider, useDataBrowserContext, useDataBrowserConfig, useInvalidateQueries, } from './providers/DataBrowserProvider';
22
+ export { QueryProvider } from './providers/QueryProvider';
22
23
  export { useDataBrowserNavigate } from '../hooks/useDataBrowserNavigate';
23
24
  export { DataBrowserUI } from './DataBrowserUI';
@@ -18,7 +18,8 @@ import { ObjectLockSettings } from "./objects/ObjectLock/ObjectLockSettings.js";
18
18
  import { EditRetentionButton } from "./objects/ObjectLock/EditRetentionButton.js";
19
19
  import { MetadataSearch } from "./search/MetadataSearch.js";
20
20
  import { ArrayFieldActions } from "./ui/ArrayFieldActions.js";
21
- import { DataBrowserProvider, useDataBrowserContext, useDataBrowserTheme } from "./providers/DataBrowserProvider.js";
21
+ import { DataBrowserProvider, useDataBrowserConfig, useDataBrowserContext, useInvalidateQueries } from "./providers/DataBrowserProvider.js";
22
+ import { QueryProvider } from "./providers/QueryProvider.js";
22
23
  import { useDataBrowserNavigate } from "../hooks/useDataBrowserNavigate.js";
23
24
  import { DataBrowserUI } from "./DataBrowserUI.js";
24
- export { ArrayFieldActions, BucketCreate, BucketLifecycleFormPage, BucketList, BucketNotificationCreatePage, BucketOverview, BucketOverviewField, BucketOverviewSection, BucketPage, BucketPolicyPage, BucketReplicationFormPage, BucketVersioning, CreateFolderButton, DataBrowserProvider, DataBrowserUI, DeleteBucketButton, EditRetentionButton, EmptyBucketButton, MetadataSearch, ObjectDetails, ObjectList, ObjectLockSettings, ObjectPage, UploadButton, baseBucketCreateSchema, bucketErrorMessage, bucketNameValidationSchema, useBucketOverviewContext, useDataBrowserContext, useDataBrowserNavigate, useDataBrowserTheme };
25
+ export { ArrayFieldActions, BucketCreate, BucketLifecycleFormPage, BucketList, BucketNotificationCreatePage, BucketOverview, BucketOverviewField, BucketOverviewSection, BucketPage, BucketPolicyPage, BucketReplicationFormPage, BucketVersioning, CreateFolderButton, DataBrowserProvider, DataBrowserUI, DeleteBucketButton, EditRetentionButton, EmptyBucketButton, MetadataSearch, ObjectDetails, ObjectList, ObjectLockSettings, ObjectPage, QueryProvider, UploadButton, baseBucketCreateSchema, bucketErrorMessage, bucketNameValidationSchema, useBucketOverviewContext, useDataBrowserConfig, useDataBrowserContext, useDataBrowserNavigate, useInvalidateQueries };
@@ -8,7 +8,7 @@ import { useSearchObjects, useSearchObjectsVersions } from "../../hooks/index.js
8
8
  import { useGetPresignedDownload } from "../../hooks/presignedOperations.js";
9
9
  import { useBatchObjectLegalHold } from "../../hooks/useBatchObjectLegalHold.js";
10
10
  import { useQueryParams } from "../../utils/hooks.js";
11
- import { useFeatures } from "../../utils/useFeatures.js";
11
+ import { useFeatures } from "../../hooks/useFeatures.js";
12
12
  import CreateFolderButton from "./CreateFolderButton.js";
13
13
  import MetadataSearch from "../search/MetadataSearch.js";
14
14
  import UploadButton from "./UploadButton.js";
@@ -1,23 +1,24 @@
1
1
  import React from 'react';
2
2
  import { QueryClient, InvalidateQueryFilters, QueryKey } from '@tanstack/react-query';
3
3
  import { GetConfigFunction } from '../../types';
4
- import { CoreUITheme } from '@scality/core-ui/dist/style/theme';
4
+ import { CoreUITheme } from '@scality/core-ui/dist/next';
5
5
  export interface DataBrowserContextValue {
6
- getS3Config: GetConfigFunction;
7
- theme: CoreUITheme;
6
+ getS3Config: GetConfigFunction | null;
8
7
  s3ConfigIdentifier: string;
9
8
  }
10
- export declare const DataBrowserContext: React.Context<DataBrowserContextValue | null>;
9
+ export declare const DataBrowserContext: React.Context<DataBrowserContextValue>;
11
10
  export declare const useDataBrowserContext: () => DataBrowserContextValue;
12
- export declare const useDataBrowserTheme: () => CoreUITheme;
13
- interface DataBrowserProviderProps {
11
+ export interface DataBrowserProviderProps {
14
12
  children: React.ReactNode;
15
- queryClient?: QueryClient;
16
- enableDevtools?: boolean;
17
13
  getS3Config?: GetConfigFunction;
14
+ queryClient?: QueryClient;
18
15
  theme?: CoreUITheme;
16
+ enableDevtools?: boolean;
19
17
  }
20
18
  export declare const DataBrowserProvider: React.FC<DataBrowserProviderProps>;
19
+ export declare const useDataBrowserConfig: () => import("../../types").S3BrowserConfig & {
20
+ credentials: import("../../types").S3Credentials;
21
+ };
21
22
  /**
22
23
  * Hook to invalidate queries with automatic S3 config identifier prefixing.
23
24
  *
@@ -28,4 +29,3 @@ export declare const DataBrowserProvider: React.FC<DataBrowserProviderProps>;
28
29
  export declare const useInvalidateQueries: () => (filters: Omit<InvalidateQueryFilters, "queryKey"> & {
29
30
  queryKey: QueryKey;
30
31
  }) => Promise<void>;
31
- export {};
@@ -1,49 +1,49 @@
1
- import { jsx, jsxs } from "react/jsx-runtime";
2
- import { createContext, useCallback, useContext } from "react";
3
- import { QueryClient, QueryClientProvider, useQueryClient } from "@tanstack/react-query";
4
- import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { createContext, useCallback, useContext, useMemo } from "react";
3
+ import { useQueryClient } from "@tanstack/react-query";
5
4
  import { ANONYMOUS_S3_CONFIG_IDENTIFIER, computeS3ConfigIdentifier } from "../../utils/s3ConfigIdentifier.js";
6
- const DataBrowserContext = /*#__PURE__*/ createContext(null);
7
- const useDataBrowserContext = ()=>{
8
- const context = useContext(DataBrowserContext);
9
- if (!context) throw new Error('useDataBrowserContext must be used within a DataBrowserProvider component');
10
- return context;
5
+ import { QueryProvider } from "./QueryProvider.js";
6
+ import { CoreUiThemeProvider } from "@scality/core-ui/dist/next";
7
+ import { coreUIAvailableThemes } from "@scality/core-ui/dist/style/theme";
8
+ const DEFAULT_CONTEXT_VALUE = {
9
+ getS3Config: null,
10
+ s3ConfigIdentifier: ANONYMOUS_S3_CONFIG_IDENTIFIER
11
11
  };
12
- const useDataBrowserTheme = ()=>{
13
- const { theme } = useDataBrowserContext();
14
- return theme;
15
- };
16
- const defaultQueryClient = new QueryClient({
17
- defaultOptions: {
18
- queries: {
19
- staleTime: 300000,
20
- retry: 2
21
- }
22
- }
23
- });
24
- const DataBrowserProvider = ({ children, queryClient = defaultQueryClient, enableDevtools = 'development' === process.env.NODE_ENV, getS3Config, theme })=>{
25
- const config = getS3Config?.();
26
- const s3ConfigIdentifier = config ? computeS3ConfigIdentifier(config) : ANONYMOUS_S3_CONFIG_IDENTIFIER;
27
- const content = /*#__PURE__*/ jsxs(QueryClientProvider, {
28
- client: queryClient,
29
- children: [
30
- children,
31
- enableDevtools && /*#__PURE__*/ jsx(ReactQueryDevtools, {
32
- initialIsOpen: false
33
- })
34
- ]
35
- });
36
- if (!getS3Config || !theme) return content;
37
- const contextValue = {
12
+ const DataBrowserContext = /*#__PURE__*/ createContext(DEFAULT_CONTEXT_VALUE);
13
+ const useDataBrowserContext = ()=>useContext(DataBrowserContext);
14
+ const DataBrowserProvider = ({ children, queryClient, theme, enableDevtools, getS3Config })=>{
15
+ const currentConfig = getS3Config?.();
16
+ const s3ConfigIdentifier = useMemo(()=>currentConfig ? computeS3ConfigIdentifier(currentConfig) : ANONYMOUS_S3_CONFIG_IDENTIFIER, [
17
+ currentConfig?.credentials?.accessKeyId,
18
+ currentConfig?.credentials?.roleArn,
19
+ currentConfig?.credentials?.sessionToken,
20
+ currentConfig?.region,
21
+ currentConfig?.endpoint
22
+ ]);
23
+ const contextValue = useMemo(()=>({
24
+ getS3Config: getS3Config ?? null,
25
+ s3ConfigIdentifier
26
+ }), [
38
27
  getS3Config,
39
- theme,
40
28
  s3ConfigIdentifier
41
- };
42
- return /*#__PURE__*/ jsx(DataBrowserContext.Provider, {
43
- value: contextValue,
44
- children: content
29
+ ]);
30
+ return /*#__PURE__*/ jsx(CoreUiThemeProvider, {
31
+ theme: theme ?? coreUIAvailableThemes.darkRebrand,
32
+ children: /*#__PURE__*/ jsx(QueryProvider, {
33
+ queryClient: queryClient,
34
+ enableDevtools: enableDevtools,
35
+ children: /*#__PURE__*/ jsx(DataBrowserContext.Provider, {
36
+ value: contextValue,
37
+ children: children
38
+ })
39
+ })
45
40
  });
46
41
  };
42
+ const useDataBrowserConfig = ()=>{
43
+ const { getS3Config } = useDataBrowserContext();
44
+ if (!getS3Config) throw new Error("useDataBrowserConfig: S3 config not available. Ensure DataBrowserProvider has getS3Config prop set.");
45
+ return getS3Config();
46
+ };
47
47
  const useInvalidateQueries = ()=>{
48
48
  const { s3ConfigIdentifier } = useDataBrowserContext();
49
49
  const queryClient = useQueryClient();
@@ -61,4 +61,4 @@ const useInvalidateQueries = ()=>{
61
61
  s3ConfigIdentifier
62
62
  ]);
63
63
  };
64
- export { DataBrowserContext, DataBrowserProvider, useDataBrowserContext, useDataBrowserTheme, useInvalidateQueries };
64
+ export { DataBrowserContext, DataBrowserProvider, useDataBrowserConfig, useDataBrowserContext, useInvalidateQueries };
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ import { QueryClient } from '@tanstack/react-query';
3
+ export interface QueryProviderProps {
4
+ children: React.ReactNode;
5
+ queryClient?: QueryClient;
6
+ enableDevtools?: boolean;
7
+ }
8
+ export declare const defaultQueryClient: QueryClient;
9
+ export declare const QueryProvider: React.FC<QueryProviderProps>;
@@ -0,0 +1,22 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import "react";
3
+ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
4
+ import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
5
+ const defaultQueryClient = new QueryClient({
6
+ defaultOptions: {
7
+ queries: {
8
+ staleTime: 300000,
9
+ retry: 2
10
+ }
11
+ }
12
+ });
13
+ const QueryProvider = ({ children, queryClient = defaultQueryClient, enableDevtools = 'development' === process.env.NODE_ENV })=>/*#__PURE__*/ jsxs(QueryClientProvider, {
14
+ client: queryClient,
15
+ children: [
16
+ children,
17
+ enableDevtools && /*#__PURE__*/ jsx(ReactQueryDevtools, {
18
+ initialIsOpen: false
19
+ })
20
+ ]
21
+ });
22
+ export { QueryProvider, defaultQueryClient };
@@ -1,11 +1,11 @@
1
1
  import { renderHook } from "@testing-library/react";
2
2
  import { useISVBucketStatus } from "../useISVBucketDetection.js";
3
3
  import { useGetBucketTagging } from "../bucketConfiguration.js";
4
- import { useFeatures } from "../../utils/useFeatures.js";
4
+ import { useFeatures } from "../useFeatures.js";
5
5
  import { BUCKET_TAG_APPLICATION, BUCKET_TAG_VEEAM_APPLICATION, COMMVAULT_APPLICATION, VEEAM_BACKUP_REPLICATION, VEEAM_OFFICE_365, VEEAM_OFFICE_365_V8, VEEAM_VBO_APPLICATION } from "../../utils/constants.js";
6
6
  import { createTestWrapper } from "../../test/testUtils.js";
7
7
  jest.mock('../bucketConfiguration');
8
- jest.mock('../../utils/useFeatures');
8
+ jest.mock('../useFeatures');
9
9
  const mockUseGetBucketTagging = useGetBucketTagging;
10
10
  const mockUseFeatures = useFeatures;
11
11
  describe('useISVBucketStatus', ()=>{
@@ -8,6 +8,8 @@ export { useDeleteBucketConfigRule } from './useDeleteBucketConfigRule';
8
8
  export { useTableRowSelection } from './useTableRowSelection';
9
9
  export { useISVBucketStatus } from './useISVBucketDetection';
10
10
  export { useBatchObjectLegalHold } from './useBatchObjectLegalHold';
11
+ export { useFeatures } from './useFeatures';
12
+ export { useSupportedNotificationEvents } from './useSupportedNotificationEvents';
11
13
  export { useBuckets, useGetBucketLocation, useCreateBucket, useDeleteBucket, } from './bucketOperations';
12
14
  export { useGetBucketAcl, useSetBucketAcl, useGetBucketPolicy, useSetBucketPolicy, useDeleteBucketPolicy, useGetBucketVersioning, useSetBucketVersioning, useGetBucketCors, useSetBucketCors, useDeleteBucketCors, useGetBucketLifecycle, useSetBucketLifecycle, useDeleteBucketLifecycle, useGetBucketNotification, useSetBucketNotification, useGetBucketEncryption, useSetBucketEncryption, useGetBucketTagging, useSetBucketTagging, useDeleteBucketTagging, useGetBucketObjectLockConfiguration, useSetBucketObjectLockConfiguration, useGetBucketReplication, useSetBucketReplication, useDeleteBucketReplication, } from './bucketConfiguration';
13
15
  export { useListObjects, useListObjectVersions, useObjectMetadata, useObjectRetention, useGetObject, usePutObject, useCreateFolder, useUploadObjects, useDeleteObject, useDeleteObjects, useCopyObject, useSetObjectRetention, useObjectLegalHold, useSetObjectLegalHold, useObjectTagging, useSetObjectTagging, useDeleteObjectTagging, useObjectAcl, useSetObjectAcl, useGetObjectAttributes, useGetObjectTorrent, useRestoreObject, useSelectObjectContent, useListMultipartUploads, useSearchObjects, useSearchObjectsVersions, } from './objectOperations';
@@ -7,8 +7,10 @@ import { useDeleteBucketConfigRule } from "./useDeleteBucketConfigRule.js";
7
7
  import { useTableRowSelection } from "./useTableRowSelection.js";
8
8
  import { useISVBucketStatus } from "./useISVBucketDetection.js";
9
9
  import { useBatchObjectLegalHold } from "./useBatchObjectLegalHold.js";
10
+ import { useFeatures } from "./useFeatures.js";
11
+ import { useSupportedNotificationEvents } from "./useSupportedNotificationEvents.js";
10
12
  import { useBuckets, useCreateBucket, useDeleteBucket, useGetBucketLocation } from "./bucketOperations.js";
11
13
  import { useDeleteBucketCors, useDeleteBucketLifecycle, useDeleteBucketPolicy, useDeleteBucketReplication, useDeleteBucketTagging, useGetBucketAcl, useGetBucketCors, useGetBucketEncryption, useGetBucketLifecycle, useGetBucketNotification, useGetBucketObjectLockConfiguration, useGetBucketPolicy, useGetBucketReplication, useGetBucketTagging, useGetBucketVersioning, useSetBucketAcl, useSetBucketCors, useSetBucketEncryption, useSetBucketLifecycle, useSetBucketNotification, useSetBucketObjectLockConfiguration, useSetBucketPolicy, useSetBucketReplication, useSetBucketTagging, useSetBucketVersioning } from "./bucketConfiguration.js";
12
14
  import { useCopyObject, useCreateFolder, useDeleteObject, useDeleteObjectTagging, useDeleteObjects, useGetObject, useGetObjectAttributes, useGetObjectTorrent, useListMultipartUploads, useListObjectVersions, useListObjects, useObjectAcl, useObjectLegalHold, useObjectMetadata, useObjectRetention, useObjectTagging, usePutObject, useRestoreObject, useSearchObjects, useSearchObjectsVersions, useSelectObjectContent, useSetObjectAcl, useSetObjectLegalHold, useSetObjectRetention, useSetObjectTagging, useUploadObjects } from "./objectOperations.js";
13
15
  import { useGetPresignedDownload, useGetPresignedPost, useGetPresignedUpload } from "./presignedOperations.js";
14
- export { useBatchObjectLegalHold, useBuckets, useCopyObject, useCreateBucket, useCreateFolder, useDeleteBucket, useDeleteBucketConfigRule, useDeleteBucketCors, useDeleteBucketLifecycle, useDeleteBucketPolicy, useDeleteBucketReplication, useDeleteBucketTagging, useDeleteObject, useDeleteObjectTagging, useDeleteObjects, useEmptyBucket, useGetBucketAcl, useGetBucketCors, useGetBucketEncryption, useGetBucketLifecycle, useGetBucketLocation, useGetBucketNotification, useGetBucketObjectLockConfiguration, useGetBucketPolicy, useGetBucketReplication, useGetBucketTagging, useGetBucketVersioning, useGetObject, useGetObjectAttributes, useGetObjectTorrent, useGetPresignedDownload, useGetPresignedPost, useGetPresignedUpload, useISVBucketStatus, useIsBucketEmpty, useListMultipartUploads, useListObjectVersions, useListObjects, useLoginMutation, useObjectAcl, useObjectLegalHold, useObjectMetadata, useObjectRetention, useObjectTagging, usePutObject, useRestoreObject, useS3Client, useS3ConfigSwitch, useSearchObjects, useSearchObjectsVersions, useSelectObjectContent, useSetBucketAcl, useSetBucketCors, useSetBucketEncryption, useSetBucketLifecycle, useSetBucketNotification, useSetBucketObjectLockConfiguration, useSetBucketPolicy, useSetBucketReplication, useSetBucketTagging, useSetBucketVersioning, useSetObjectAcl, useSetObjectLegalHold, useSetObjectRetention, useSetObjectTagging, useTableRowSelection, useUploadObjects };
16
+ export { useBatchObjectLegalHold, useBuckets, useCopyObject, useCreateBucket, useCreateFolder, useDeleteBucket, useDeleteBucketConfigRule, useDeleteBucketCors, useDeleteBucketLifecycle, useDeleteBucketPolicy, useDeleteBucketReplication, useDeleteBucketTagging, useDeleteObject, useDeleteObjectTagging, useDeleteObjects, useEmptyBucket, useFeatures, useGetBucketAcl, useGetBucketCors, useGetBucketEncryption, useGetBucketLifecycle, useGetBucketLocation, useGetBucketNotification, useGetBucketObjectLockConfiguration, useGetBucketPolicy, useGetBucketReplication, useGetBucketTagging, useGetBucketVersioning, useGetObject, useGetObjectAttributes, useGetObjectTorrent, useGetPresignedDownload, useGetPresignedPost, useGetPresignedUpload, useISVBucketStatus, useIsBucketEmpty, useListMultipartUploads, useListObjectVersions, useListObjects, useLoginMutation, useObjectAcl, useObjectLegalHold, useObjectMetadata, useObjectRetention, useObjectTagging, usePutObject, useRestoreObject, useS3Client, useS3ConfigSwitch, useSearchObjects, useSearchObjectsVersions, useSelectObjectContent, useSetBucketAcl, useSetBucketCors, useSetBucketEncryption, useSetBucketLifecycle, useSetBucketNotification, useSetBucketObjectLockConfiguration, useSetBucketPolicy, useSetBucketReplication, useSetBucketTagging, useSetBucketVersioning, useSetObjectAcl, useSetObjectLegalHold, useSetObjectRetention, useSetObjectTagging, useSupportedNotificationEvents, useTableRowSelection, useUploadObjects };
@@ -1,14 +1,28 @@
1
1
  import { NavigateOptions } from 'react-router';
2
+ /**
3
+ * Normalizes a path by prefixing it with the basePath.
4
+ * Handles edge cases like missing slashes, relative paths, and root paths.
5
+ *
6
+ * @param basePath - The base path prefix (e.g., "/accounts/my-account/buckets")
7
+ * @param to - The target path (e.g., "/my-bucket")
8
+ * @returns The normalized absolute path (e.g., "/accounts/my-account/buckets/my-bucket")
9
+ */
2
10
  export declare const normalizePath: (basePath: string, to: string) => string;
3
11
  /**
4
12
  * Hook for navigation with automatic basePath prefixing.
5
13
  * Must be used within DataBrowserUI component.
6
14
  *
15
+ * This hook wraps react-router's useNavigate and automatically prefixes all
16
+ * navigation paths with the basePath configured in DataBrowserUI props.
17
+ * This allows internal navigation to work correctly when DataBrowserUI is
18
+ * mounted at any route within the application.
19
+ *
7
20
  * @example
8
21
  * ```tsx
22
+ * // If DataBrowserUI has basePath="/accounts/my-account/buckets"
9
23
  * const navigate = useDataBrowserNavigate();
10
- * navigate('/buckets/my-bucket'); // Will be prefixed with basePath
11
- * navigate(-1); // History navigation works as normal
24
+ * navigate('/my-bucket'); // Navigates to "/accounts/my-account/buckets/my-bucket"
25
+ * navigate(-1); // History navigation works as normal (no prefixing)
12
26
  * ```
13
27
  */
14
28
  export declare const useDataBrowserNavigate: () => (to: string | number, options?: NavigateOptions) => void;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Hook to check if a feature is enabled in the S3 configuration.
3
+ *
4
+ * @param feature - The feature name to check
5
+ * @returns true if enabled, false if disabled, undefined if config not available
6
+ */
7
+ export declare function useFeatures(feature: string): boolean | undefined;
@@ -0,0 +1,8 @@
1
+ import { useDataBrowserContext } from "../components/providers/DataBrowserProvider.js";
2
+ function useFeatures(feature) {
3
+ const { getS3Config } = useDataBrowserContext();
4
+ if (!getS3Config) return;
5
+ const config = getS3Config();
6
+ return config.features?.includes(feature) ?? false;
7
+ }
8
+ export { useFeatures };
@@ -1,12 +1,12 @@
1
1
  import { useGetBucketTagging } from "./bucketConfiguration.js";
2
- import { useFeatures } from "../utils/useFeatures.js";
2
+ import { useFeatures } from "./useFeatures.js";
3
3
  import { BUCKET_TAG_APPLICATION, BUCKET_TAG_VEEAM_APPLICATION, COMMVAULT_APPLICATION, VEEAM_BACKUP_REPLICATION, VEEAM_OFFICE_365, VEEAM_OFFICE_365_V8, VEEAM_VBO_APPLICATION } from "../utils/constants.js";
4
4
  const useISVBucketStatus = (bucketName)=>{
5
5
  const isISVFeatureEnabled = useFeatures('ISV');
6
6
  const { data: bucketTags, status: bucketTagsStatus } = useGetBucketTagging({
7
7
  Bucket: bucketName
8
8
  }, {
9
- enabled: isISVFeatureEnabled
9
+ enabled: true === isISVFeatureEnabled
10
10
  });
11
11
  const veeamTagApplication = bucketTags?.TagSet?.find((tag)=>tag.Key === BUCKET_TAG_VEEAM_APPLICATION)?.Value;
12
12
  const ISVApplicationTag = bucketTags?.TagSet?.find((tag)=>tag.Key === BUCKET_TAG_APPLICATION)?.Value;
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * Hook to get the S3 client instance.
3
3
  *
4
- * Recreates client when getS3Config or s3ConfigIdentifier changes.
4
+ * Recreates client only when s3ConfigIdentifier changes.
5
+ * The client is memoized to avoid unnecessary recreations.
5
6
  */
6
7
  export declare const useS3Client: () => import("@aws-sdk/client-s3").S3Client;
@@ -2,12 +2,12 @@ import { useMemo } from "react";
2
2
  import { useDataBrowserContext } from "../components/providers/DataBrowserProvider.js";
3
3
  import { createS3Client } from "../utils/s3Client.js";
4
4
  const useS3Client = ()=>{
5
- const { getS3Config, s3ConfigIdentifier } = useDataBrowserContext();
5
+ const { s3ConfigIdentifier, getS3Config } = useDataBrowserContext();
6
+ if (!getS3Config) throw new Error('useS3Client: S3 config not available. Ensure DataBrowserProvider has getS3Config prop set.');
6
7
  return useMemo(()=>{
7
8
  const config = getS3Config();
8
9
  return createS3Client(config);
9
10
  }, [
10
- getS3Config,
11
11
  s3ConfigIdentifier
12
12
  ]);
13
13
  };
@@ -1,6 +1,6 @@
1
1
  import type { S3EventType } from '../config/types';
2
2
  /**
3
- * Hook to get supported notification events from the S3 configuration
3
+ * Hook to get supported notification events from the DataBrowser configuration
4
4
  * If no supported events are configured, returns undefined (meaning all events are supported)
5
5
  */
6
6
  export declare function useSupportedNotificationEvents(): S3EventType[] | undefined;
@@ -1,6 +1,7 @@
1
- import { useDataBrowserContext } from "../components/index.js";
1
+ import { useDataBrowserContext } from "../components/providers/DataBrowserProvider.js";
2
2
  function useSupportedNotificationEvents() {
3
3
  const { getS3Config } = useDataBrowserContext();
4
+ if (!getS3Config) return;
4
5
  const config = getS3Config();
5
6
  return config?.supportedNotificationEvents;
6
7
  }
@@ -4,7 +4,6 @@ import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
4
4
  import { QueryClient } from "@tanstack/react-query";
5
5
  import { fireEvent, renderHook, screen, waitFor } from "@testing-library/react";
6
6
  import { coreUIAvailableThemes } from "@scality/core-ui/dist/style/theme";
7
- import { CoreUiThemeProvider } from "@scality/core-ui/dist/next";
8
7
  import { ToastProvider } from "@scality/core-ui";
9
8
  import { DataBrowserProvider } from "../components/providers/DataBrowserProvider.js";
10
9
  import { DataBrowserUICustomizationProvider } from "../contexts/DataBrowserUICustomizationContext.js";
@@ -125,11 +124,8 @@ const createTestWrapper = (config = testConfig, credentials = testCredentials)=>
125
124
  config: {
126
125
  basePath: ''
127
126
  },
128
- children: /*#__PURE__*/ jsx(CoreUiThemeProvider, {
129
- theme: theme,
130
- children: /*#__PURE__*/ jsx(ToastProvider, {
131
- children: children
132
- })
127
+ children: /*#__PURE__*/ jsx(ToastProvider, {
128
+ children: children
133
129
  })
134
130
  })
135
131
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scality/data-browser-library",
3
- "version": "1.0.0-preview.15",
3
+ "version": "1.0.0-preview.16",
4
4
  "description": "A modular React component library for browsing S3 buckets and objects",
5
5
  "type": "module",
6
6
  "types": "./dist/index.d.ts",
@@ -1 +0,0 @@
1
- export declare function useFeatures(feature: string): boolean | undefined;
@@ -1,7 +0,0 @@
1
- import { useDataBrowserContext } from "../components/index.js";
2
- function useFeatures(feature) {
3
- const { getS3Config } = useDataBrowserContext();
4
- const config = getS3Config();
5
- return config?.features?.includes(feature);
6
- }
7
- export { useFeatures };