mirror of https://github.com/buster-so/buster.git
fix scroll area border
This commit is contained in:
parent
d4962aa406
commit
ed93eb1c19
|
@ -1,3 +1,2 @@
|
|||
export * from './interfaces';
|
||||
export * from './requests';
|
||||
export * from './queryRequests';
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
import type { BusterChartConfigProps } from '@/api/asset_interfaces/metric';
|
||||
import type { VerificationStatus } from '@/api/asset_interfaces/share';
|
||||
|
||||
export interface GetMetricParams {
|
||||
id: string;
|
||||
password?: string;
|
||||
version_number?: number; //api will default to latest if not provided
|
||||
}
|
||||
|
||||
/**
|
||||
* Request payload for updating metric properties
|
||||
*/
|
||||
export type UpdateMetricParams = {
|
||||
/** The unique identifier of the metric to update */
|
||||
id: string;
|
||||
/** New title for the metric */
|
||||
name?: string;
|
||||
/** SQL query associated with the metric */
|
||||
sql?: string;
|
||||
chart_config?: BusterChartConfigProps;
|
||||
/** Flag to save the current draft state */
|
||||
save_draft?: boolean;
|
||||
/** Admin only: verification status update */
|
||||
status?: VerificationStatus;
|
||||
/** file in yaml format to update */
|
||||
file?: string;
|
||||
};
|
|
@ -14,7 +14,6 @@ import {
|
|||
unshareMetric,
|
||||
updateMetricShare
|
||||
} from './requests';
|
||||
import type { GetMetricParams } from './interfaces';
|
||||
import { prepareMetricUpdateMetric, upgradeMetricToIMetric } from '@/lib/metrics';
|
||||
import { metricsQueryKeys } from '@/api/query_keys/metric';
|
||||
import { collectionQueryKeys } from '@/api/query_keys/collection';
|
||||
|
@ -60,7 +59,10 @@ export const useGetMetric = <TData = IBusterMetric>(
|
|||
});
|
||||
};
|
||||
|
||||
export const prefetchGetMetric = async (params: GetMetricParams, queryClientProp?: QueryClient) => {
|
||||
export const prefetchGetMetric = async (
|
||||
params: Parameters<typeof getMetric_server>[0],
|
||||
queryClientProp?: QueryClient
|
||||
) => {
|
||||
const queryClient = queryClientProp || new QueryClient();
|
||||
await queryClient.prefetchQuery({
|
||||
...metricsQueryKeys.metricsGetMetric(params.id),
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { mainApi } from '../instances';
|
||||
import { serverFetch } from '@/api/createServerInstance';
|
||||
import type { GetMetricParams, UpdateMetricParams } from './interfaces';
|
||||
import type {
|
||||
BusterChartConfigProps,
|
||||
BusterMetric,
|
||||
BusterMetricData,
|
||||
BusterMetricListItem
|
||||
|
@ -13,7 +13,15 @@ import type {
|
|||
} from '@/api/asset_interfaces/shared_interfaces';
|
||||
import { VerificationStatus } from '@/api/asset_interfaces/share';
|
||||
|
||||
export const getMetric = async ({ id, password, version_number }: GetMetricParams) => {
|
||||
export const getMetric = async ({
|
||||
id,
|
||||
password,
|
||||
version_number
|
||||
}: {
|
||||
id: string;
|
||||
password?: string;
|
||||
version_number?: number; //api will default to latest if not provided
|
||||
}) => {
|
||||
return mainApi
|
||||
.get<BusterMetric>(`/metrics/${id}`, {
|
||||
params: { password, version_number }
|
||||
|
@ -21,7 +29,7 @@ export const getMetric = async ({ id, password, version_number }: GetMetricParam
|
|||
.then((res) => res.data);
|
||||
};
|
||||
|
||||
export const getMetric_server = async ({ id, password }: GetMetricParams) => {
|
||||
export const getMetric_server = async ({ id, password }: Parameters<typeof getMetric>[0]) => {
|
||||
return await serverFetch<BusterMetric>(`/metrics/${id}`, {
|
||||
params: { ...(password && { password }) }
|
||||
});
|
||||
|
@ -54,7 +62,21 @@ export const listMetrics_server = async (params: Parameters<typeof listMetrics>[
|
|||
return await serverFetch<BusterMetricListItem[]>('/metrics', { params });
|
||||
};
|
||||
|
||||
export const updateMetric = async (params: UpdateMetricParams) => {
|
||||
export const updateMetric = async (params: {
|
||||
/** The unique identifier of the metric to update */
|
||||
id: string;
|
||||
/** New title for the metric */
|
||||
name?: string;
|
||||
/** SQL query associated with the metric */
|
||||
sql?: string;
|
||||
chart_config?: BusterChartConfigProps;
|
||||
/** Flag to save the current draft state */
|
||||
save_draft?: boolean;
|
||||
/** Admin only: verification status update */
|
||||
status?: VerificationStatus;
|
||||
/** file in yaml format to update */
|
||||
file?: string;
|
||||
}) => {
|
||||
return mainApi.put<BusterMetric>(`/metrics/${params.id}`, params).then((res) => res.data);
|
||||
};
|
||||
|
||||
|
|
|
@ -11,29 +11,17 @@ import { cn } from '@/lib/classMerge';
|
|||
type DropdownValue = ShareRole | 'remove' | 'notShared';
|
||||
|
||||
export const AccessDropdown: React.FC<{
|
||||
groupShare?: boolean;
|
||||
className?: string;
|
||||
showRemove?: boolean;
|
||||
shareLevel?: ShareRole | null;
|
||||
onChangeShareLevel?: (level: ShareRole | null) => void;
|
||||
}> = ({
|
||||
shareLevel,
|
||||
showRemove = true,
|
||||
groupShare = false,
|
||||
className = '',
|
||||
onChangeShareLevel
|
||||
}) => {
|
||||
}> = ({ shareLevel, showRemove = true, className = '', onChangeShareLevel }) => {
|
||||
const disabled = useMemo(() => canEdit(shareLevel), [shareLevel]);
|
||||
|
||||
const items = useMemo(() => {
|
||||
const baseItems: DropdownItem<DropdownValue>[] = standardItems;
|
||||
const baseItems: DropdownItem<DropdownValue>[] = [...standardItems];
|
||||
|
||||
if (groupShare) {
|
||||
baseItems.push({
|
||||
label: <DropdownLabel title="Not shared" subtitle="Does not have access." />,
|
||||
value: 'notShared'
|
||||
});
|
||||
} else if (showRemove) {
|
||||
if (showRemove) {
|
||||
baseItems.push({
|
||||
label: 'Remove',
|
||||
value: 'remove'
|
||||
|
@ -44,7 +32,7 @@ export const AccessDropdown: React.FC<{
|
|||
...item,
|
||||
selected: item.value === shareLevel
|
||||
}));
|
||||
}, [groupShare, showRemove, shareLevel]);
|
||||
}, [showRemove, shareLevel]);
|
||||
|
||||
const selectedLabel = useMemo(() => {
|
||||
const selectedItem = items.find((item) => item.selected) || OWNER_ITEM;
|
||||
|
|
|
@ -174,7 +174,6 @@ const ShareMenuContentShare: React.FC<ShareMenuContentBodyProps> = React.memo(
|
|||
{inputValue && (
|
||||
<AccessDropdown
|
||||
showRemove={false}
|
||||
groupShare={false}
|
||||
className="absolute top-[50%] right-[10px] -translate-y-1/2"
|
||||
shareLevel={defaultPermissionLevel}
|
||||
onChangeShareLevel={onChangeAccessDropdown}
|
||||
|
|
|
@ -45,7 +45,9 @@ export const AppPageLayout: React.FC<
|
|||
</AppPageLayoutHeader>
|
||||
)}
|
||||
|
||||
<AppPageLayoutContent className="scroll-shadow-container" scrollable={scrollable}>
|
||||
<AppPageLayoutContent
|
||||
className={cn(headerBorderVariant === 'ghost' && 'scroll-shadow-container')}
|
||||
scrollable={scrollable}>
|
||||
{header && scrollable && headerBorderVariant === 'ghost' && (
|
||||
<div className="scroll-header"></div>
|
||||
)}
|
||||
|
|
|
@ -3,7 +3,7 @@ import React from 'react';
|
|||
import { cva, type VariantProps } from 'class-variance-authority';
|
||||
|
||||
const headerVariants = cva(
|
||||
'bg-page-background flex max-h-[38px] min-h-[38px] items-center justify-between gap-x-2.5 relative',
|
||||
'bg-page-background flex max-h-[38px] min-h-[38px] items-center z-10 justify-between gap-x-2.5 relative',
|
||||
{
|
||||
variants: {
|
||||
sizeVariant: {
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import { ScrollArea } from './ScrollArea';
|
||||
|
||||
const meta = {
|
||||
title: 'UI/ScrollArea/ScrollArea',
|
||||
component: ScrollArea,
|
||||
parameters: {
|
||||
layout: 'centered'
|
||||
},
|
||||
tags: ['autodocs']
|
||||
} satisfies Meta<typeof ScrollArea>;
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
export const Default: Story = {
|
||||
render: () => (
|
||||
<ScrollArea className="h-[200px] w-[350px] rounded-md border p-4">
|
||||
<div>
|
||||
<p className="mb-4">
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam auctor, nisl eget
|
||||
ultricies tincidunt, nisl nisl aliquam nisl, eget ultricies nisl nisl eget nisl.
|
||||
</p>
|
||||
<p className="mb-4">
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque
|
||||
laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi
|
||||
architecto beatae vitae dicta sunt explicabo.
|
||||
</p>
|
||||
<p className="mb-4">
|
||||
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia
|
||||
consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.
|
||||
</p>
|
||||
<p className="mb-4">
|
||||
Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci
|
||||
velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam
|
||||
quaerat voluptatem.
|
||||
</p>
|
||||
<p>
|
||||
Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam,
|
||||
nisi ut aliquid ex ea commodi consequatur.
|
||||
</p>
|
||||
</div>
|
||||
</ScrollArea>
|
||||
)
|
||||
};
|
||||
|
||||
export const TallContent: Story = {
|
||||
render: () => (
|
||||
<ScrollArea className="h-[200px] w-[350px] rounded-md border p-4">
|
||||
<div>
|
||||
{Array.from({ length: 50 }).map((_, i) => (
|
||||
<div key={i} className="mb-2">
|
||||
Row {i + 1}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</ScrollArea>
|
||||
)
|
||||
};
|
||||
|
||||
export const WideContent: Story = {
|
||||
render: () => (
|
||||
<ScrollArea className="h-[200px] w-[350px] rounded-md border p-4">
|
||||
<div className="w-[500px]">
|
||||
<p className="mb-4">
|
||||
This content is intentionally wider than the container to demonstrate horizontal
|
||||
scrolling. The ScrollArea component will automatically add scrollbars as needed.
|
||||
</p>
|
||||
<div className="flex space-x-4">
|
||||
{Array.from({ length: 10 }).map((_, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="flex h-20 w-20 flex-shrink-0 items-center justify-center rounded-md bg-gray-200">
|
||||
{i + 1}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</ScrollArea>
|
||||
)
|
||||
};
|
||||
|
||||
export const CustomHeight: Story = {
|
||||
render: () => (
|
||||
<ScrollArea className="h-[400px] w-[350px] rounded-md border p-4">
|
||||
<div>
|
||||
<p className="mb-4 text-lg font-semibold">Taller Scroll Area</p>
|
||||
{Array.from({ length: 20 }).map((_, i) => (
|
||||
<p key={i} className="mb-4">
|
||||
Paragraph {i + 1}: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
</ScrollArea>
|
||||
)
|
||||
};
|
||||
|
||||
export const NestedContent: Story = {
|
||||
render: () => (
|
||||
<ScrollArea className="h-[300px] w-[400px] rounded-md border p-4">
|
||||
<div>
|
||||
<h3 className="mb-4 text-lg font-semibold">Nested Content Example</h3>
|
||||
<div className="mb-4">
|
||||
<p className="mb-2">Main content area with some text.</p>
|
||||
<div className="rounded-md border p-2">
|
||||
<h4 className="mb-2 font-medium">Nested Section</h4>
|
||||
<p>This is nested content inside the scroll area.</p>
|
||||
</div>
|
||||
</div>
|
||||
{Array.from({ length: 10 }).map((_, i) => (
|
||||
<div key={i} className="mb-4">
|
||||
<h4 className="mb-1 font-medium">Section {i + 1}</h4>
|
||||
<p>Additional content for demonstrating scrolling behavior.</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</ScrollArea>
|
||||
)
|
||||
};
|
|
@ -16,7 +16,7 @@ import type {
|
|||
PieChartAxis,
|
||||
ScatterAxis
|
||||
} from '@/api/asset_interfaces/metric/charts';
|
||||
import { UpdateMetricParams } from '@/api/buster_rest/metrics';
|
||||
import { type updateMetric } from '@/api/buster_rest/metrics';
|
||||
|
||||
const DEFAULT_COLUMN_SETTINGS_ENTRIES = Object.entries(DEFAULT_COLUMN_SETTINGS);
|
||||
const DEFAULT_COLUMN_LABEL_FORMATS_ENTRIES = Object.entries(DEFAULT_COLUMN_LABEL_FORMAT);
|
||||
|
@ -120,11 +120,11 @@ const getChangesFromDefaultChartConfig = (newMetric: IBusterMetric) => {
|
|||
export const prepareMetricUpdateMetric = (
|
||||
newMetric: IBusterMetric,
|
||||
oldMetric: IBusterMetric
|
||||
): UpdateMetricParams | null => {
|
||||
): Parameters<typeof updateMetric>[0] | null => {
|
||||
const changedTopLevelValues = getChangedTopLevelMessageValues(
|
||||
newMetric,
|
||||
oldMetric
|
||||
) as unknown as UpdateMetricParams;
|
||||
) as unknown as Parameters<typeof updateMetric>[0];
|
||||
|
||||
const changedChartConfig = getChangesFromDefaultChartConfig(newMetric);
|
||||
|
||||
|
|
|
@ -7,22 +7,23 @@
|
|||
}
|
||||
|
||||
.scroll-shadow-container {
|
||||
@apply relative;
|
||||
@apply relative overflow-y-auto;
|
||||
scroll-timeline-name: --scrollShadowContainer;
|
||||
|
||||
.scroll-header {
|
||||
@apply fixed top-[30px] right-0 left-0 h-2 w-full;
|
||||
animation: shadowAnimation linear;
|
||||
animation-range: 0px 125px;
|
||||
animation-timeline: scroll(block start);
|
||||
animation-range: 0px 100px;
|
||||
animation-timeline: --scrollShadowContainer;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
|
||||
@keyframes shadowAnimation {
|
||||
from {
|
||||
box-shadow: 0 0 0 rgba(0, 0, 0, 0);
|
||||
box-shadow: 0px 0px 0px 0px var(--color-border) !important;
|
||||
}
|
||||
to {
|
||||
box-shadow: 0px 1px 8px 0px #00000029;
|
||||
box-shadow: 0px 0px 0px 0.5px var(--color-border) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue