mirror of
https://github.com/elastic/kibana.git
synced 2025-06-28 11:05:39 -04:00
`100.0.0` ⏩ `101.0.1` [Questions? Please see our Kibana upgrade FAQ.](https://github.com/elastic/eui/blob/main/wiki/eui-team-processes/upgrading-kibana.md#faq-for-kibana-teams) ## Package updates ### `@elastic/eui` [`v101.0.1`](https://github.com/elastic/eui/releases/v101.0.1) - Updated `EuiProvider` and `EuiThemeProvider` with a new `highContrastMode` ([#8444](https://github.com/elastic/eui/pull/8444)) - This prop allows toggling a higher contrast visual style that primarily affects borders and shadows - On `EuiProvider`, if the `highContrastMode` prop is not passed, this setting will inherit from the user's OS/system settings - If the user is using a forced colors mode (e.g. Windows' high contrast themes), this system setting will take precedence over any `highContrastMode` or `colorMode` props passed - Added `highContrastModeStyles` and `preventForcedColors` styling utils ([#8444](https://github.com/elastic/eui/pull/8444)) - Updated `EuiRangeTooltip` to be easier to see in dark mode ([#8444](https://github.com/elastic/eui/pull/8444)) - Updated some deprecated color token usages that have direct substitutes ([#8444](https://github.com/elastic/eui/pull/8444)) - `text` -> `textParagraph` - `title` -> `textHeading` - `subduedText` -> `textSubdued` - `disabledText` -> `textDisabled` - `accentText` -> `textAccent` - `dangerText` -> `textDanger` - `warningText` -> `textWarning` - `useEuiShadow()` now accepts a second `options` argument ([#8234](https://github.com/elastic/eui/pull/8234)) - `useEuiShadowFlat()` now accepts an `options` object instead of only a color ([#8234](https://github.com/elastic/eui/pull/8234)) - Updated `EuiPopover` and `EuiToolTip` to be easier to see in dark mode. ([#8174](https://github.com/elastic/eui/pull/8174)) **Bug fixes** - Fixed a visual bug where a transparent border would create visible empty space (`LIGHT` mode only) for the components: ([#8427](https://github.com/elastic/eui/pull/8427)) - `EuiPanel` - `EuiPopover` - `EuiToolTip` - `EuiToast` - `EuiTour` --- ### `@elastic/eui-theme-common` [`v0.1.0`](https://github.com/elastic/eui/releases/v0.1.0) - Removed type `EuiShadowCustomColor` ([#8444](https://github.com/elastic/eui/pull/8444)) - Added types: ([#8444](https://github.com/elastic/eui/pull/8444)) - `EuiShadowOptions` - `EuiThemeHighContrastModeProp` - `EuiThemeHighContrastMode` - Updated shadow utils to accepts a second `options` argument and return borders in high contrast mode: ([#8444](https://github.com/elastic/eui/pull/8444)) - `euiShadow` - `euiShadowXSmall` - `euiShadowSmall` - `euiShadowMedium` - `euiShadowLarge` - `euiSlightShadowHover` - `euiShadowFlat` --- ### `@elastic/eui-theme-borealis` [`v0.1.0`](https://github.com/elastic/eui/releases/v0.1.0) - Added new component level tokens: ([#8444](https://github.com/elastic/eui/pull/8444)) - `buttonGroupBackgroundDisabledSelected` - `overlayMaskBackground` - `overlayMaskBackgroundHighContrast` - `skeletonBackgroundSkeletonMiddleHighContrast` ## Additional changes The latest `@elastic/eui` package introduces high contrast mode support. This PR sets all usages of `EuiProvider` to use `highContrastMode={false}` to introduce it in disabled state (this reflects the current functionality in Kibana). This is because the UI for the high contrast mode functionality (and style adjustments) need to first be implemented on Kibana side (by shared-ux). ## QA Adding high contrast mode in disabled state should result in no visual changes in Kibana. Please ensure your product view remain unchanged. --------- Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
192 lines
5.7 KiB
TypeScript
192 lines
5.7 KiB
TypeScript
/*
|
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
* or more contributor license agreements. Licensed under the "Elastic License
|
|
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
|
|
* Public License v 1"; you may not use this file except in compliance with, at
|
|
* your election, the "Elastic License 2.0", the "GNU Affero General Public
|
|
* License v3.0 only", or the "Server Side Public License, v 1".
|
|
*/
|
|
|
|
import React, { useState } from 'react';
|
|
import { useQuery } from '@tanstack/react-query';
|
|
import type { FileJSON } from '@kbn/files-plugin/common';
|
|
import type { FilesClientResponses } from '@kbn/files-plugin/public';
|
|
|
|
import {
|
|
EuiProvider,
|
|
EuiPageTemplate,
|
|
EuiInMemoryTable,
|
|
EuiInMemoryTableProps,
|
|
EuiButton,
|
|
EuiIcon,
|
|
EuiButtonIcon,
|
|
EuiLink,
|
|
} from '@elastic/eui';
|
|
|
|
import { CoreStart } from '@kbn/core/public';
|
|
import { MyFilePicker } from './file_picker';
|
|
import type { MyImageMetadata } from '../../common';
|
|
import type { FileClients } from '../types';
|
|
import { DetailsFlyout } from './details_flyout';
|
|
import { ConfirmButtonIcon } from './confirm_button';
|
|
import { Modal } from './modal';
|
|
|
|
interface FilesExampleAppDeps {
|
|
files: FileClients;
|
|
notifications: CoreStart['notifications'];
|
|
}
|
|
|
|
type ListResponse = FilesClientResponses<MyImageMetadata>['list'];
|
|
|
|
export const FilesExampleApp = ({ files, notifications }: FilesExampleAppDeps) => {
|
|
const { data, isLoading, error, refetch } = useQuery<ListResponse>(
|
|
['files'],
|
|
() => files.example.list(),
|
|
{ refetchOnWindowFocus: false }
|
|
);
|
|
const [showUploadModal, setShowUploadModal] = useState(false);
|
|
const [showFilePickerModal, setShowFilePickerModal] = useState(false);
|
|
const [isDeletingFile, setIsDeletingFile] = useState(false);
|
|
const [selectedItem, setSelectedItem] = useState<undefined | FileJSON<MyImageMetadata>>();
|
|
|
|
const renderToolsRight = () => {
|
|
return [
|
|
<EuiButton
|
|
onClick={() => setShowFilePickerModal(true)}
|
|
isDisabled={isLoading || isDeletingFile}
|
|
iconType="eye"
|
|
>
|
|
Select a file
|
|
</EuiButton>,
|
|
<EuiButton
|
|
onClick={() => setShowUploadModal(true)}
|
|
isDisabled={isLoading || isDeletingFile}
|
|
iconType="exportAction"
|
|
>
|
|
Upload image
|
|
</EuiButton>,
|
|
];
|
|
};
|
|
|
|
const items = [...(data?.files ?? [])].reverse();
|
|
|
|
const columns: EuiInMemoryTableProps<FileJSON<MyImageMetadata>>['columns'] = [
|
|
{
|
|
field: 'name',
|
|
name: 'Name',
|
|
render: (name, item) => (
|
|
<EuiLink disabled={isDeletingFile} onClick={() => setSelectedItem(item)}>
|
|
{name}
|
|
</EuiLink>
|
|
),
|
|
},
|
|
{
|
|
field: 'status',
|
|
name: 'Status',
|
|
render: (status: FileJSON['status']) =>
|
|
status === 'READY' ? (
|
|
<EuiIcon color="success" type="checkInCircleFilled" aria-label={status} />
|
|
) : status === 'AWAITING_UPLOAD' ? (
|
|
<EuiIcon type="clock" aria-label={status} />
|
|
) : (
|
|
<EuiIcon color="danger" type="warning" arial-label={status} />
|
|
),
|
|
},
|
|
{
|
|
name: 'Actions',
|
|
actions: [
|
|
{
|
|
name: 'View',
|
|
description: 'View file',
|
|
isPrimary: true,
|
|
render: (item) => (
|
|
<EuiButtonIcon
|
|
disabled={isDeletingFile}
|
|
aria-label="View file details"
|
|
iconType="eye"
|
|
onClick={() => setSelectedItem(item)}
|
|
/>
|
|
),
|
|
},
|
|
{
|
|
name: 'Delete',
|
|
description: 'Delete this file',
|
|
render: (item) => (
|
|
<ConfirmButtonIcon
|
|
disabled={isDeletingFile}
|
|
label="Delete this file"
|
|
confirmationText="Are you sure you want to delete this file?"
|
|
onConfirm={async () => {
|
|
try {
|
|
setIsDeletingFile(true);
|
|
await files.example.delete({ id: item.id });
|
|
await refetch();
|
|
} finally {
|
|
setIsDeletingFile(false);
|
|
}
|
|
}}
|
|
/>
|
|
),
|
|
},
|
|
],
|
|
},
|
|
];
|
|
|
|
return (
|
|
<EuiProvider highContrastMode={false}>
|
|
<EuiPageTemplate restrictWidth>
|
|
<EuiPageTemplate.Header pageTitle="Files example" />
|
|
<EuiPageTemplate.Section>
|
|
<EuiInMemoryTable
|
|
columns={columns}
|
|
items={items}
|
|
itemId="id"
|
|
loading={isLoading || isDeletingFile}
|
|
error={error ? JSON.stringify(error) : undefined}
|
|
sorting
|
|
search={{
|
|
toolsRight: renderToolsRight(),
|
|
}}
|
|
pagination
|
|
/>
|
|
</EuiPageTemplate.Section>
|
|
</EuiPageTemplate>
|
|
{selectedItem && (
|
|
<DetailsFlyout
|
|
files={files}
|
|
file={selectedItem}
|
|
onDismiss={() => setSelectedItem(undefined)}
|
|
/>
|
|
)}
|
|
{showUploadModal && (
|
|
<Modal
|
|
client={files.unscoped}
|
|
onDismiss={() => setShowUploadModal(false)}
|
|
onUploaded={() => {
|
|
notifications.toasts.addSuccess('Uploaded file!');
|
|
refetch();
|
|
setShowUploadModal(false);
|
|
}}
|
|
/>
|
|
)}
|
|
{showFilePickerModal && (
|
|
<MyFilePicker
|
|
onClose={() => setShowFilePickerModal(false)}
|
|
onUpload={() => {
|
|
notifications.toasts.addSuccess({
|
|
title: 'Uploaded files',
|
|
});
|
|
refetch();
|
|
}}
|
|
onDone={(ids) => {
|
|
notifications.toasts.addSuccess({
|
|
title: 'Selected files!',
|
|
text: 'IDS:' + JSON.stringify(ids, null, 2),
|
|
});
|
|
setShowFilePickerModal(false);
|
|
}}
|
|
/>
|
|
)}
|
|
</EuiProvider>
|
|
);
|
|
};
|