[Workplace Search] Misc tech debt (#108767)

* Remove TODOs

Removes 2 todos:
- in index.tsx, the access is handled somewhere else and visiting any org page as a non-admin results in an error message. No further action needed
- error_state.tsx - this had been completed by Constance in a separate PR but the comment was missed.

* Remove a bunch of unused components

These were left over from the user migration project and mainly have to do with users displayed in the groups section, which is no longer a feature.

* This commit needs no explanition

This was missed in this commit:
19ccd27e04

Refacotred and somehow renaming resulted in this monstrosity 🤦🏼‍♂️

* Remove source descriptions

Since this commit, these are no longer displayed in the UI

16d089acfd (diff-a4761afc86544a299d0129b749e3001625f5b194b95ebc31303824f8f95f4381L173)
This commit is contained in:
Scotty Bollinger 2021-08-16 17:02:37 -05:00 committed by GitHub
parent ed7c0825b7
commit ec120a2cc1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 5 additions and 1005 deletions

View file

@ -1,8 +0,0 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
export { TableHeader } from './table_header';

View file

@ -1,32 +0,0 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import React from 'react';
import { shallow } from 'enzyme';
import { EuiTableHeader, EuiTableHeaderCell } from '@elastic/eui';
import { TableHeader } from './table_header';
const headerItems = ['foo', 'bar', 'baz'];
describe('TableHeader', () => {
it('renders', () => {
const wrapper = shallow(<TableHeader headerItems={headerItems} />);
expect(wrapper.find(EuiTableHeader)).toHaveLength(1);
expect(wrapper.find(EuiTableHeaderCell)).toHaveLength(3);
});
it('renders extra cell', () => {
const wrapper = shallow(<TableHeader headerItems={headerItems} extraCell />);
expect(wrapper.find(EuiTableHeader)).toHaveLength(1);
expect(wrapper.find(EuiTableHeaderCell)).toHaveLength(4);
});
});

View file

@ -1,24 +0,0 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import React from 'react';
import { EuiTableHeader, EuiTableHeaderCell } from '@elastic/eui';
interface TableHeaderProps {
headerItems: string[];
extraCell?: boolean;
}
export const TableHeader: React.FC<TableHeaderProps> = ({ headerItems, extraCell }) => (
<EuiTableHeader>
{headerItems.map((item, i) => (
<EuiTableHeaderCell key={i}>{item}</EuiTableHeaderCell>
))}
{extraCell && <EuiTableHeaderCell />}
</EuiTableHeader>
);

View file

@ -66,7 +66,7 @@ export const WorkplaceSearchConfigured: React.FC<InitialAppData> = (props) => {
* EX: http://localhost:5601/app/enterprise_search/workplace_search/p/sources
*/
const isOrganization = !useRouteMatch(PERSONAL_PATH); // TODO: Once auth is figured out, we need to have a check for the equivalent of `isAdmin`.
const isOrganization = !useRouteMatch(PERSONAL_PATH);
setContext(isOrganization);

View file

@ -80,8 +80,6 @@ export interface SourceDataItem {
connected?: boolean;
features?: Features;
objTypes?: string[];
sourceDescription: string;
connectStepDescription: string;
addPath: string;
editPath: string;
accountContextOnly: boolean;

View file

@ -57,15 +57,9 @@ export const AddSource: React.FC<AddSourceProps> = (props) => {
newCustomSource,
} = useValues(AddSourceLogic);
const {
serviceType,
configuration,
features,
objTypes,
sourceDescription,
connectStepDescription,
addPath,
} = staticSourceData[props.sourceIndex] as SourceDataItem;
const { serviceType, configuration, features, objTypes, addPath } = staticSourceData[
props.sourceIndex
] as SourceDataItem;
const { isOrganization } = useValues(AppLogic);
@ -132,8 +126,6 @@ export const AddSource: React.FC<AddSourceProps> = (props) => {
configuration={configuration}
features={features}
objTypes={objTypes}
sourceDescription={sourceDescription}
connectStepDescription={connectStepDescription}
needsPermissions={!!needsPermissions}
onFormCreated={goToFormSourceCreated}
header={header}

View file

@ -55,8 +55,6 @@ interface ConnectInstanceProps {
objTypes?: string[];
name: string;
serviceType: string;
sourceDescription: string;
connectStepDescription: string;
needsPermissions: boolean;
onFormCreated(name: string): void;
}

View file

@ -65,24 +65,6 @@ import {
} from '../../routes';
import { FeatureIds, SourceDataItem } from '../../types';
const connectStepDescription = {
attachments: i18n.translate(
'xpack.enterpriseSearch.workplaceSearch.sources.connectStepDescription.attachments',
{
defaultMessage:
'Content found within Attachments (PDFs, Microsoft Office Files, and other popular textual file formats) will be automatically indexed and searchable.',
}
),
files: i18n.translate(
'xpack.enterpriseSearch.workplaceSearch.sources.connectStepDescription.files',
{
defaultMessage:
'Content found within PDFs, Microsoft Office Files, and other popular textual file formats will be automatically indexed and searchable.',
}
),
empty: '',
};
export const staticSourceData = [
{
name: SOURCE_NAMES.BOX,
@ -96,15 +78,6 @@ export const staticSourceData = [
documentationUrl: BOX_DOCS_URL,
applicationPortalUrl: 'https://app.box.com/developers/console',
},
sourceDescription: i18n.translate(
'xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.box',
{
defaultMessage:
'{sourceName} is a cloud-based storage service for organizations of all sizes. Create, store, share and automatically synchronize documents across your desktop and web.',
values: { sourceName: SOURCE_NAMES.BOX },
}
),
connectStepDescription: connectStepDescription.files,
objTypes: [SOURCE_OBJ_TYPES.FOLDERS, SOURCE_OBJ_TYPES.ALL_FILES],
features: {
basicOrgContext: [
@ -134,15 +107,6 @@ export const staticSourceData = [
documentationUrl: CONFLUENCE_DOCS_URL,
applicationPortalUrl: 'https://developer.atlassian.com/apps/',
},
sourceDescription: i18n.translate(
'xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.confluence',
{
defaultMessage:
'{sourceName} is a team workspace, where knowledge and collaboration meet. Often used as an organizational wiki and intranet, it usually houses valuable information for staff across multiple areas of your business.',
values: { sourceName: SOURCE_NAMES.CONFLUENCE },
}
),
connectStepDescription: connectStepDescription.attachments,
objTypes: [
SOURCE_OBJ_TYPES.PAGES,
SOURCE_OBJ_TYPES.ATTACHMENTS,
@ -176,15 +140,6 @@ export const staticSourceData = [
needsBaseUrl: false,
documentationUrl: CONFLUENCE_SERVER_DOCS_URL,
},
sourceDescription: i18n.translate(
'xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.confluenceServer',
{
defaultMessage:
'{sourceName} is a team workspace, where knowledge and collaboration meet. Often used as an organizational wiki and intranet, it usually houses valuable information for staff across multiple areas of your business.',
values: { sourceName: SOURCE_NAMES.CONFLUENCE },
}
),
connectStepDescription: connectStepDescription.attachments,
objTypes: [
SOURCE_OBJ_TYPES.PAGES,
SOURCE_OBJ_TYPES.ATTACHMENTS,
@ -218,15 +173,6 @@ export const staticSourceData = [
documentationUrl: DROPBOX_DOCS_URL,
applicationPortalUrl: 'https://www.dropbox.com/developers/apps',
},
sourceDescription: i18n.translate(
'xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.dropbox',
{
defaultMessage:
'{sourceName} is a cloud-based storage service for organizations of all sizes. Create, store, share and automatically synchronize documents across your desktop and web.',
values: { sourceName: SOURCE_NAMES.DROPBOX },
}
),
connectStepDescription: connectStepDescription.files,
objTypes: [SOURCE_OBJ_TYPES.FOLDERS, SOURCE_OBJ_TYPES.ALL_FILES],
features: {
basicOrgContext: [
@ -257,15 +203,6 @@ export const staticSourceData = [
applicationPortalUrl: 'https://github.com/settings/developers',
applicationLinkTitle: GITHUB_LINK_TITLE,
},
sourceDescription: i18n.translate(
'xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.github',
{
defaultMessage:
'{sourceName} is a development platform, version control and collaboration platform for teams of all sizes. From open source to business, you can host and review code, manage projects, and build software across departments and continents.',
values: { sourceName: SOURCE_NAMES.GITHUB },
}
),
connectStepDescription: connectStepDescription.empty,
objTypes: [
SOURCE_OBJ_TYPES.ISSUES,
SOURCE_OBJ_TYPES.PULL_REQUESTS,
@ -306,15 +243,6 @@ export const staticSourceData = [
applicationPortalUrl: 'https://github.com/settings/developers',
applicationLinkTitle: GITHUB_LINK_TITLE,
},
sourceDescription: i18n.translate(
'xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.githubEnterprise',
{
defaultMessage:
'{sourceName} is a development platform, version control and collaboration platform for teams of all sizes. From open source to business, you can host and review code, manage projects, and build software across departments and continents.',
values: { sourceName: SOURCE_NAMES.GITHUB_ENTERPRISE },
}
),
connectStepDescription: connectStepDescription.empty,
objTypes: [
SOURCE_OBJ_TYPES.ISSUES,
SOURCE_OBJ_TYPES.PULL_REQUESTS,
@ -347,15 +275,6 @@ export const staticSourceData = [
documentationUrl: GMAIL_DOCS_URL,
applicationPortalUrl: 'https://console.developers.google.com/',
},
sourceDescription: i18n.translate(
'xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.gmail',
{
defaultMessage:
'{sourceName} is a free email service developed by Google. It is fast, reliable, and trusted by millions of people and organizations around the world. Workplace Search brings all of your Gmail content into one relevant and ease-to-use search experience.',
values: { sourceName: SOURCE_NAMES.GMAIL },
}
),
connectStepDescription: connectStepDescription.empty,
objTypes: [SOURCE_OBJ_TYPES.EMAILS],
features: {
platinumPrivateContext: [FeatureIds.Remote, FeatureIds.Private, FeatureIds.SearchableContent],
@ -374,15 +293,6 @@ export const staticSourceData = [
documentationUrl: GOOGLE_DRIVE_DOCS_URL,
applicationPortalUrl: 'https://console.developers.google.com/',
},
sourceDescription: i18n.translate(
'xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.googleDrive',
{
defaultMessage:
'{sourceName} is a cloud-based storage and collaboration service for organizations of all sizes, with a focus on G Suite document (Google Docs, Sheets, Slides, etc) storage and collaboration. Create, store, share and automatically synchronize documents across your desktop and web.',
values: { sourceName: SOURCE_NAMES.GOOGLE_DRIVE },
}
),
connectStepDescription: connectStepDescription.files,
objTypes: [
SOURCE_OBJ_TYPES.FOLDERS,
SOURCE_OBJ_TYPES.G_SUITE_FILES,
@ -416,15 +326,6 @@ export const staticSourceData = [
documentationUrl: JIRA_DOCS_URL,
applicationPortalUrl: '',
},
sourceDescription: i18n.translate(
'xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.jira',
{
defaultMessage:
'{sourceName} is an issue tracking product that provides bug tracking, workflow automation, and agile project management tools for teams of all sizes. ',
values: { sourceName: SOURCE_NAMES.JIRA },
}
),
connectStepDescription: connectStepDescription.files,
objTypes: [
SOURCE_OBJ_TYPES.EPICS,
SOURCE_OBJ_TYPES.PROJECTS,
@ -461,15 +362,6 @@ export const staticSourceData = [
documentationUrl: JIRA_SERVER_DOCS_URL,
applicationPortalUrl: '',
},
sourceDescription: i18n.translate(
'xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.jiraServer',
{
defaultMessage:
'{sourceName} is an issue tracking product that provides bug tracking, workflow automation, and agile project management tools for teams of all sizes. ',
values: { sourceName: SOURCE_NAMES.JIRA_SERVER },
}
),
connectStepDescription: connectStepDescription.files,
objTypes: [
SOURCE_OBJ_TYPES.EPICS,
SOURCE_OBJ_TYPES.PROJECTS,
@ -505,15 +397,6 @@ export const staticSourceData = [
documentationUrl: ONEDRIVE_DOCS_URL,
applicationPortalUrl: 'https://portal.azure.com/',
},
sourceDescription: i18n.translate(
'xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.oneDrive',
{
defaultMessage:
'{sourceName} is a cloud-based storage service for organizations of all sizes, with a focus on Office 365 document storage and collaboration. Create, store, share and automatically synchronize documents across your organization.',
values: { sourceName: SOURCE_NAMES.ONEDRIVE },
}
),
connectStepDescription: connectStepDescription.files,
objTypes: [SOURCE_OBJ_TYPES.FOLDERS, SOURCE_OBJ_TYPES.ALL_FILES],
features: {
basicOrgContext: [
@ -543,15 +426,6 @@ export const staticSourceData = [
documentationUrl: SALESFORCE_DOCS_URL,
applicationPortalUrl: 'https://salesforce.com/',
},
sourceDescription: i18n.translate(
'xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.salesforce',
{
defaultMessage:
'{sourceName} is a cloud-based customer relationship management (CRM) platform with a focus on customer service, marketing automation, analytics, and sales operation tooling.',
values: { sourceName: SOURCE_NAMES.SALESFORCE },
}
),
connectStepDescription: connectStepDescription.attachments,
objTypes: [
SOURCE_OBJ_TYPES.CONTACTS,
SOURCE_OBJ_TYPES.OPPORTUNITIES,
@ -586,15 +460,6 @@ export const staticSourceData = [
documentationUrl: SALESFORCE_DOCS_URL,
applicationPortalUrl: 'https://test.salesforce.com/',
},
sourceDescription: i18n.translate(
'xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.salesforceSandbox',
{
defaultMessage:
'{sourceName} is a cloud-based customer relationship management (CRM) platform with a focus on customer service, marketing automation, analytics, and sales operation tooling.',
values: { sourceName: SOURCE_NAMES.SALESFORCE_SANDBOX },
}
),
connectStepDescription: connectStepDescription.attachments,
objTypes: [
SOURCE_OBJ_TYPES.CONTACTS,
SOURCE_OBJ_TYPES.OPPORTUNITIES,
@ -629,15 +494,6 @@ export const staticSourceData = [
documentationUrl: SERVICENOW_DOCS_URL,
applicationPortalUrl: 'https://www.servicenow.com/my-account/sign-in.html',
},
sourceDescription: i18n.translate(
'xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.serviceNow',
{
defaultMessage:
'{sourceName} is a cloud-based IT Service Management (ITSM) platform focusing on workflow automation and internal organizational support.',
values: { sourceName: SOURCE_NAMES.SERVICENOW },
}
),
connectStepDescription: connectStepDescription.empty,
objTypes: [
SOURCE_OBJ_TYPES.USERS,
SOURCE_OBJ_TYPES.INCIDENTS,
@ -671,15 +527,6 @@ export const staticSourceData = [
documentationUrl: SHAREPOINT_DOCS_URL,
applicationPortalUrl: 'https://portal.azure.com/',
},
sourceDescription: i18n.translate(
'xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.sharePoint',
{
defaultMessage:
'{sourceName} is a cloud-based collaboration, knowledge management and storage platform for organizations of all sizes. Often used as a centralized content management system (CMS), SharePoint Online stores a wealth of information across departments and teams.',
values: { sourceName: SOURCE_NAMES.SHAREPOINT },
}
),
connectStepDescription: connectStepDescription.files,
objTypes: [SOURCE_OBJ_TYPES.FOLDERS, SOURCE_OBJ_TYPES.SITES, SOURCE_OBJ_TYPES.ALL_FILES],
features: {
basicOrgContext: [
@ -709,15 +556,6 @@ export const staticSourceData = [
documentationUrl: SLACK_DOCS_URL,
applicationPortalUrl: 'https://api.slack.com/apps/',
},
sourceDescription: i18n.translate(
'xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.slack',
{
defaultMessage:
'{sourceName} is a communication tool that enables real-time collaboration and decision making. With {sourceName}, keep track of the work happening across teams, engage directly with your coworkers on ongoing projects and communicate with other organizations.',
values: { sourceName: SOURCE_NAMES.SLACK },
}
),
connectStepDescription: connectStepDescription.empty,
objTypes: [
SOURCE_OBJ_TYPES.PUBLIC_MESSAGES,
SOURCE_OBJ_TYPES.PRIVATE_MESSAGES,
@ -741,15 +579,6 @@ export const staticSourceData = [
documentationUrl: ZENDESK_DOCS_URL,
applicationPortalUrl: 'https://www.zendesk.com/login/',
},
sourceDescription: i18n.translate(
'xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.zendesk',
{
defaultMessage:
'{sourceName} is cloud-based customer relationship management and customer support platform that provides tools for tracking, prioritizing, and solving customer support tickets.',
values: { sourceName: SOURCE_NAMES.ZENDESK },
}
),
connectStepDescription: connectStepDescription.empty,
objTypes: [SOURCE_OBJ_TYPES.TICKETS],
features: {
basicOrgContext: [
@ -782,8 +611,6 @@ export const staticSourceData = [
documentationUrl: CUSTOM_SOURCE_DOCS_URL,
applicationPortalUrl: '',
},
sourceDescription: '',
connectStepDescription: connectStepDescription.empty,
accountContextOnly: false,
},
] as SourceDataItem[];

View file

@ -5,8 +5,6 @@
* 2.0.
*/
// TODO: Remove EuiPage & EuiPageBody before exposing full app
import React from 'react';
import { KibanaPageTemplate } from '../../../../../../../../src/plugins/kibana_react/public';

View file

@ -1,121 +0,0 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { users } from '../../../__mocks__/users.mock';
import React from 'react';
import { shallow } from 'enzyme';
import { EuiFieldSearch, EuiFilterSelectItem, EuiCard, EuiPopoverTitle } from '@elastic/eui';
import { User } from '../../../types';
import { FilterableUsersList } from './filterable_users_list';
const mockSetState = jest.fn();
const useStateMock: any = (initState: any) => [initState, mockSetState];
const addFilteredUser = jest.fn();
const removeFilteredUser = jest.fn();
const props = {
users,
addFilteredUser,
removeFilteredUser,
};
describe('FilterableUsersList', () => {
afterEach(() => {
jest.clearAllMocks();
});
it('renders', () => {
const wrapper = shallow(<FilterableUsersList {...props} />);
expect(wrapper.find(EuiFieldSearch)).toHaveLength(1);
expect(wrapper.find(EuiCard)).toHaveLength(0);
});
it('updates the input value and renders zero users card', () => {
jest.spyOn(React, 'useState').mockImplementation(useStateMock);
const _users = [
users[0],
{
...users[0],
id: 'asdfa',
email: 'user@example.co',
name: null,
},
];
const wrapper = shallow(<FilterableUsersList {...props} users={_users} />);
const input = wrapper.find(EuiFieldSearch);
input.simulate('change', { target: { value: 'bar' } });
expect(wrapper.find(EuiCard)).toHaveLength(1);
expect(wrapper.find(EuiFilterSelectItem)).toHaveLength(0);
});
it('handles adding and removing users', () => {
const _users = [
users[0],
{
...users[0],
id: 'asdfa',
},
];
const wrapper = shallow(
<FilterableUsersList {...props} users={_users} itemsClickable selectedOptions={['1z1z']} />
);
const firstItem = wrapper.find(EuiFilterSelectItem).first();
firstItem.simulate('click');
expect(removeFilteredUser).toHaveBeenCalled();
expect(addFilteredUser).not.toHaveBeenCalled();
const secondItem = wrapper.find(EuiFilterSelectItem).last();
secondItem.simulate('click');
expect(addFilteredUser).toHaveBeenCalled();
});
it('renders loading when no users', () => {
const wrapper = shallow(
<FilterableUsersList {...props} users={[]} allGroupUsersLoading={<>loading</>} />
);
const card = wrapper.find(EuiCard);
expect((card.prop('description') as any).props.children).toEqual('loading');
});
it('handles hidden users when count is higher than 20', () => {
const _users = [] as User[];
const NUM_TOTAL_USERS = 30;
const NUM_VISIBLE_USERS = 20;
[...Array(NUM_TOTAL_USERS)].forEach((_, i) => {
_users.push({
...users[0],
id: i.toString(),
});
});
const wrapper = shallow(<FilterableUsersList itemsClickable {...props} users={_users} />);
expect(wrapper.find(EuiFilterSelectItem)).toHaveLength(NUM_VISIBLE_USERS);
});
it('renders elements wrapped when popover', () => {
const wrapper = shallow(<FilterableUsersList isPopover {...props} />);
expect(wrapper.find(EuiPopoverTitle)).toHaveLength(1);
expect(wrapper.find('.euiFilterSelect__items')).toHaveLength(1);
});
});

View file

@ -1,134 +0,0 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import React, { useState } from 'react';
import {
EuiCard,
EuiFieldSearch,
EuiFilterSelectItem,
EuiIcon,
EuiPopoverTitle,
EuiSpacer,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { User } from '../../../types';
import { UserOptionItem } from './user_option_item';
const MAX_VISIBLE_USERS = 20;
const FILTER_USERS_PLACEHOLDER = i18n.translate(
'xpack.enterpriseSearch.workplaceSearch.groups.filterUsers.placeholder',
{
defaultMessage: 'Filter users...',
}
);
const NO_USERS_FOUND = i18n.translate(
'xpack.enterpriseSearch.workplaceSearch.groups.noUsersFound',
{
defaultMessage: 'No users found',
}
);
interface FilterableUsersListProps {
users: User[];
selectedOptions?: string[];
itemsClickable?: boolean;
isPopover?: boolean;
allGroupUsersLoading?: React.ReactElement;
addFilteredUser(userId: string): void;
removeFilteredUser(userId: string): void;
}
export const FilterableUsersList: React.FC<FilterableUsersListProps> = ({
users,
selectedOptions = [],
itemsClickable,
isPopover,
addFilteredUser,
allGroupUsersLoading,
removeFilteredUser,
}) => {
const [filterValue, updateValue] = useState('');
const filterUsers = (userId: string): boolean => {
if (!filterValue) return true;
const filterUser = users.find(({ id }) => id === userId) as User;
const filteredName = filterUser.name || filterUser.email;
return filteredName.toLowerCase().indexOf(filterValue.toLowerCase()) > -1;
};
// Only show the first 20 users in the dropdown.
const availableUsers = users.map(({ id }) => id).filter(filterUsers);
const hiddenUsers = [...availableUsers];
const visibleUsers = hiddenUsers.splice(0, MAX_VISIBLE_USERS);
const getOptionEl = (userId: string, index: number): React.ReactElement => {
const checked = selectedOptions.indexOf(userId) > -1 ? 'on' : undefined;
const handleClick = () => (checked ? removeFilteredUser(userId) : addFilteredUser(userId));
const user = users.filter(({ id }) => id === userId)[0];
const option = <UserOptionItem user={user} />;
return itemsClickable ? (
<EuiFilterSelectItem key={index} checked={checked} onClick={handleClick}>
{option}
</EuiFilterSelectItem>
) : (
<div key={index} className="euiFilterSelectItem user-group__item">
{option}
</div>
);
};
const filterUsersBar = (
<EuiFieldSearch
value={filterValue}
placeholder={FILTER_USERS_PLACEHOLDER}
onChange={(e) => updateValue(e.target.value)}
/>
);
const noResults = (
<>
<EuiIcon type="minusInCircle" /> <span>{NO_USERS_FOUND}</span>
</>
);
const options =
visibleUsers.length > 0 ? (
visibleUsers.map((userId, index) => getOptionEl(userId, index))
) : (
<EuiCard
title={<EuiSpacer size="xs" />}
description={!!allGroupUsersLoading ? allGroupUsersLoading : noResults}
/>
);
const usersList = (
<>
{hiddenUsers.length > 0 && (
<div className="euiFilterSelectItem">
<small>
{i18n.translate('xpack.enterpriseSearch.workplaceSearch.groups.userListCount', {
defaultMessage: 'Showing {maxVisibleUsers} of {numUsers} users.',
values: { maxVisibleUsers: MAX_VISIBLE_USERS, numUsers: availableUsers.length },
})}
</small>
</div>
)}
{options}
</>
);
return (
<>
{isPopover ? <EuiPopoverTitle>{filterUsersBar}</EuiPopoverTitle> : filterUsersBar}
{isPopover ? <div className="euiFilterSelect__items">{usersList}</div> : usersList}
</>
);
};

View file

@ -1,45 +0,0 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { setMockActions } from '../../../../__mocks__/kea_logic';
import { users } from '../../../__mocks__/users.mock';
import React from 'react';
import { shallow } from 'enzyme';
import { EuiFilterGroup, EuiPopover } from '@elastic/eui';
import { FilterableUsersList } from './filterable_users_list';
import { FilterableUsersPopover } from './filterable_users_popover';
const closePopover = jest.fn();
const addFilteredUser = jest.fn();
const removeFilteredUser = jest.fn();
const props = {
users,
closePopover,
isPopoverOpen: false,
button: <></>,
};
describe('FilterableUsersPopover', () => {
beforeEach(() => {
setMockActions({
addFilteredUser,
removeFilteredUser,
});
});
it('renders', () => {
const wrapper = shallow(<FilterableUsersPopover {...props} />);
expect(wrapper.find(EuiFilterGroup)).toHaveLength(1);
expect(wrapper.find(EuiPopover)).toHaveLength(1);
expect(wrapper.find(FilterableUsersList)).toHaveLength(1);
});
});

View file

@ -1,62 +0,0 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import React from 'react';
import { useActions } from 'kea';
import { EuiFilterGroup, EuiPopover } from '@elastic/eui';
import { User } from '../../../types';
import { GroupsLogic } from '../groups_logic';
import { FilterableUsersList } from './filterable_users_list';
interface FilterableUsersPopoverProps {
users: User[];
selectedOptions?: string[];
itemsClickable?: boolean;
isPopoverOpen: boolean;
allGroupUsersLoading?: React.ReactElement;
className?: string;
button: React.ReactElement;
closePopover(): void;
}
export const FilterableUsersPopover: React.FC<FilterableUsersPopoverProps> = ({
users,
selectedOptions = [],
itemsClickable,
isPopoverOpen,
allGroupUsersLoading,
className,
button,
closePopover,
}) => {
const { addFilteredUser, removeFilteredUser } = useActions(GroupsLogic);
return (
<EuiFilterGroup className={className}>
<EuiPopover
ownFocus
button={button}
isOpen={isPopoverOpen}
closePopover={closePopover}
panelPaddingSize="none"
>
<FilterableUsersList
users={users}
selectedOptions={selectedOptions}
itemsClickable={itemsClickable}
addFilteredUser={addFilteredUser}
allGroupUsersLoading={allGroupUsersLoading}
removeFilteredUser={removeFilteredUser}
isPopover
/>
</EuiPopover>
</EuiFilterGroup>
);
};

View file

@ -1,66 +0,0 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { setMockActions, setMockValues } from '../../../../__mocks__/kea_logic';
import { users } from '../../../__mocks__/users.mock';
import React from 'react';
import { shallow, mount } from 'enzyme';
import { EuiLoadingContent, EuiButtonEmpty } from '@elastic/eui';
import { FilterableUsersPopover } from './filterable_users_popover';
import { GroupRowUsersDropdown } from './group_row_users_dropdown';
const fetchGroupUsers = jest.fn();
const onButtonClick = jest.fn();
const closePopover = jest.fn();
const props = {
isPopoverOpen: true,
numOptions: 1,
groupId: '123',
onButtonClick,
closePopover,
};
describe('GroupRowUsersDropdown', () => {
beforeEach(() => {
setMockActions({ fetchGroupUsers });
setMockValues({
allGroupUsers: users,
allGroupUsersLoading: false,
});
});
it('renders', () => {
const wrapper = shallow(<GroupRowUsersDropdown {...props} />);
expect(wrapper.find(FilterableUsersPopover)).toHaveLength(1);
});
it('handles toggle click', () => {
const wrapper = mount(<GroupRowUsersDropdown {...props} />);
const button = wrapper.find(EuiButtonEmpty);
button.simulate('click');
expect(fetchGroupUsers).toHaveBeenCalledWith('123');
expect(onButtonClick).toHaveBeenCalled();
});
it('handles loading state', () => {
setMockValues({
allGroupUsers: users,
allGroupUsersLoading: true,
});
const wrapper = shallow(<GroupRowUsersDropdown {...props} />);
const popover = wrapper.find(FilterableUsersPopover);
expect(popover.prop('allGroupUsersLoading')).toEqual(<EuiLoadingContent lines={6} />);
});
});

View file

@ -1,57 +0,0 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import React from 'react';
import { useActions, useValues } from 'kea';
import { EuiLoadingContent, EuiButtonEmpty } from '@elastic/eui';
import { GroupsLogic } from '../groups_logic';
import { FilterableUsersPopover } from './filterable_users_popover';
interface GroupRowUsersDropdownProps {
isPopoverOpen: boolean;
numOptions: number;
groupId: string;
onButtonClick(): void;
closePopover(): void;
}
export const GroupRowUsersDropdown: React.FC<GroupRowUsersDropdownProps> = ({
isPopoverOpen,
numOptions,
groupId,
onButtonClick,
closePopover,
}) => {
const { fetchGroupUsers } = useActions(GroupsLogic);
const { allGroupUsersLoading, allGroupUsers } = useValues(GroupsLogic);
const handleLinkClick = () => {
fetchGroupUsers(groupId);
onButtonClick();
};
const toggleLink = (
<EuiButtonEmpty className="user-group-source--additional" onClick={handleLinkClick}>
+ {numOptions}
</EuiButtonEmpty>
);
return (
<FilterableUsersPopover
users={allGroupUsers}
isPopoverOpen={isPopoverOpen}
allGroupUsersLoading={allGroupUsersLoading ? <EuiLoadingContent lines={6} /> : undefined}
className="user-group-source--additional__wrap"
button={toggleLink}
closePopover={closePopover}
/>
);
};

View file

@ -1,52 +0,0 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { users } from '../../../__mocks__/users.mock';
import React from 'react';
import { shallow } from 'enzyme';
import { UserIcon } from '../../../components/shared/user_icon';
import { User } from '../../../types';
import { GroupRowUsersDropdown } from './group_row_users_dropdown';
import { GroupUsers } from './group_users';
const props = {
groupUsers: users,
usersCount: 1,
groupId: '123',
};
describe('GroupUsers', () => {
it('renders', () => {
const wrapper = shallow(<GroupUsers {...props} />);
expect(wrapper.find(UserIcon)).toHaveLength(1);
});
it('handles hidden users when count is higher than 20', () => {
const _users = [] as User[];
const NUM_TOTAL_USERS = 20;
[...Array(NUM_TOTAL_USERS)].forEach((_, i) => {
_users.push({
...users[0],
id: i.toString(),
});
});
const wrapper = shallow(<GroupUsers {...props} groupUsers={_users} />);
// These were needed for 100% test coverage.
wrapper.find(GroupRowUsersDropdown).invoke('onButtonClick')();
wrapper.find(GroupRowUsersDropdown).invoke('closePopover')();
expect(wrapper.find(GroupRowUsersDropdown)).toHaveLength(1);
});
});

View file

@ -1,45 +0,0 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import React, { useState } from 'react';
import { UserIcon } from '../../../components/shared/user_icon';
import { MAX_TABLE_ROW_ICONS } from '../../../constants';
import { User } from '../../../types';
import { GroupRowUsersDropdown } from './group_row_users_dropdown';
interface GroupUsersProps {
groupUsers: User[];
usersCount: number;
groupId: string;
}
export const GroupUsers: React.FC<GroupUsersProps> = ({ groupUsers, usersCount, groupId }) => {
const [popoverOpen, setPopoverOpen] = useState(false);
const closePopover = () => setPopoverOpen(false);
const togglePopover = () => setPopoverOpen(!popoverOpen);
const hiddenUsers = [...groupUsers];
const visibleUsers = hiddenUsers.splice(0, MAX_TABLE_ROW_ICONS);
return (
<>
{visibleUsers.map((user, index) => (
<UserIcon {...user} key={index} />
))}
{hiddenUsers.length > 0 && (
<GroupRowUsersDropdown
isPopoverOpen={popoverOpen}
numOptions={usersCount - MAX_TABLE_ROW_ICONS}
groupId={groupId}
onButtonClick={togglePopover}
closePopover={closePopover}
/>
)}
</>
);
};

View file

@ -1,55 +0,0 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { setMockValues } from '../../../../__mocks__/kea_logic';
import { groups } from '../../../__mocks__/groups.mock';
import React from 'react';
import { shallow } from 'enzyme';
import { EuiTable, EuiTablePagination } from '@elastic/eui';
import { TableHeader } from '../../../../shared/table_header';
import { User } from '../../../types';
import { GroupUsersTable } from './group_users_table';
const group = groups[0];
describe('GroupUsersTable', () => {
it('renders', () => {
setMockValues({ group });
const wrapper = shallow(<GroupUsersTable />);
expect(wrapper.find(EuiTable)).toHaveLength(1);
expect(wrapper.find(TableHeader).prop('headerItems')).toHaveLength(2);
});
it('renders pagination', () => {
const users = [] as User[];
const NUM_TOTAL_USERS = 20;
[...Array(NUM_TOTAL_USERS)].forEach((_, i) => {
users.push({
...group.users[0],
id: i.toString(),
});
});
setMockValues({ group: { users } });
const wrapper = shallow(<GroupUsersTable />);
const pagination = wrapper.find(EuiTablePagination);
// This was needed for 100% test coverage. The tests pass and 100% coverage
// is achieved with this line, but TypeScript complains anyway, so ignoring line.
// @ts-ignore
pagination.invoke('onChangePage')(1);
expect(pagination).toHaveLength(1);
});
});

View file

@ -1,66 +0,0 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import React, { useState } from 'react';
import { useValues } from 'kea';
import { EuiTable, EuiTableBody, EuiTablePagination } from '@elastic/eui';
import { Pager } from '@elastic/eui';
import { USERNAME_LABEL, EMAIL_LABEL } from '../../../../shared/constants';
import { TableHeader } from '../../../../shared/table_header';
import { UserRow } from '../../../components/shared/user_row';
import { User } from '../../../types';
import { GroupLogic } from '../group_logic';
const USERS_PER_PAGE = 10;
export const GroupUsersTable: React.FC = () => {
const {
group: { users },
} = useValues(GroupLogic);
const headerItems = [USERNAME_LABEL, EMAIL_LABEL];
const [firstItem, setFirstItem] = useState(0);
const [lastItem, setLastItem] = useState(USERS_PER_PAGE - 1);
const [currentPage, setCurrentPage] = useState(0);
const numUsers = users.length;
const pager = new Pager(numUsers, USERS_PER_PAGE);
const onChangePage = (pageIndex: number) => {
pager.goToPageIndex(pageIndex);
setFirstItem(pager.firstItemIndex);
setLastItem(pager.lastItemIndex);
setCurrentPage(pager.getCurrentPageIndex());
};
const pagination = (
<EuiTablePagination
activePage={currentPage}
itemsPerPage={USERS_PER_PAGE}
pageCount={pager.getTotalPages()}
onChangePage={onChangePage}
hidePerPageOptions
/>
);
return (
<>
<EuiTable>
<TableHeader headerItems={headerItems} />
<EuiTableBody>
{users.slice(firstItem, lastItem + 1).map((user: User) => (
<UserRow key={user.id} showEmail user={user} />
))}
</EuiTableBody>
</EuiTable>
{numUsers > USERS_PER_PAGE && pagination}
</>
);
};

View file

@ -81,7 +81,7 @@ export const BrandingSection: React.FC<Props> = ({
const resetConfirmModal = (
<EuiConfirmModal
title={isLogo ? RESET_IMAGE_TITLE : RESET_IMAGE_TITLE}
title={RESET_IMAGE_TITLE}
onCancel={closeDeleteModal}
onConfirm={() => {
resetImage();

View file

@ -8972,7 +8972,6 @@
"xpack.enterpriseSearch.workplaceSearch.groups.description": "共有コンテンツソースとユーザーをグループに割り当て、さまざまな内部チーム向けに関連する検索エクスペリエンスを作成します。",
"xpack.enterpriseSearch.workplaceSearch.groups.filterGroups.placeholder": "名前でグループをフィルター...",
"xpack.enterpriseSearch.workplaceSearch.groups.filterSources.buttonText": "ソース",
"xpack.enterpriseSearch.workplaceSearch.groups.filterUsers.placeholder": "ユーザーをフィルター...",
"xpack.enterpriseSearch.workplaceSearch.groups.groupDeleted": "グループ「{groupName}」が正常に削除されました。",
"xpack.enterpriseSearch.workplaceSearch.groups.groupManagerHeaderTitle": "{label}を管理",
"xpack.enterpriseSearch.workplaceSearch.groups.groupManagerSelectAllToggle": "{action}すべて",
@ -8991,8 +8990,6 @@
"xpack.enterpriseSearch.workplaceSearch.groups.newGroup.action": "グループを管理",
"xpack.enterpriseSearch.workplaceSearch.groups.newGroupSavedSuccess": "{groupName}が正常に作成されました",
"xpack.enterpriseSearch.workplaceSearch.groups.noSourcesMessage": "共有コンテンツソースがありません",
"xpack.enterpriseSearch.workplaceSearch.groups.noUsersFound": "ユーザーが見つかりません",
"xpack.enterpriseSearch.workplaceSearch.groups.noUsersMessage": "ユーザーがありません",
"xpack.enterpriseSearch.workplaceSearch.groups.overview.confirmRemoveButtonText": "{name}を削除",
"xpack.enterpriseSearch.workplaceSearch.groups.overview.confirmRemoveDescription": "グループはWorkplace Searchから削除されます。{name}を削除してよろしいですか?",
"xpack.enterpriseSearch.workplaceSearch.groups.overview.confirmTitleText": "確認",
@ -9018,7 +9015,6 @@
"xpack.enterpriseSearch.workplaceSearch.groups.sourceProioritization.zeroStateTitle": "ソースはこのグループと共有されていません",
"xpack.enterpriseSearch.workplaceSearch.groups.sourcesModalLabel": "共有コンテンツソース",
"xpack.enterpriseSearch.workplaceSearch.groups.sourcesModalTitle": "{groupName}と共有するコンテンツソースを選択",
"xpack.enterpriseSearch.workplaceSearch.groups.userListCount": "{maxVisibleUsers}/{numUsers}ユーザーを表示しています。",
"xpack.enterpriseSearch.workplaceSearch.keepEditing.button": "編集を続行",
"xpack.enterpriseSearch.workplaceSearch.name.label": "名前",
"xpack.enterpriseSearch.workplaceSearch.nav.addSource": "ソースの追加",
@ -9137,8 +9133,6 @@
"xpack.enterpriseSearch.workplaceSearch.sources.config.link": "コンテンツソースコネクター設定を編集",
"xpack.enterpriseSearch.workplaceSearch.sources.config.title": "コンテンツソース構成",
"xpack.enterpriseSearch.workplaceSearch.sources.configuration.title": "構成",
"xpack.enterpriseSearch.workplaceSearch.sources.connectStepDescription.attachments": "添付ファイル (PDF、Microsoft Officeファイル、別の一般的なテキストファイル形式) 内で検出されたコンテンツは、自動的にインデックスが作成され、検索可能になります。",
"xpack.enterpriseSearch.workplaceSearch.sources.connectStepDescription.files": "PDF、Microsoft Officeファイル、別の一般的なテキストファイル形式内で検出されたコンテンツは、自動的にインデックスが作成され、検索可能になります。",
"xpack.enterpriseSearch.workplaceSearch.sources.contentLoading.text": "コンテンツを読み込んでいます...",
"xpack.enterpriseSearch.workplaceSearch.sources.contentSummary.title": "コンテンツ概要",
"xpack.enterpriseSearch.workplaceSearch.sources.contentType.header": "コンテンツタイプ",
@ -9230,23 +9224,6 @@
"xpack.enterpriseSearch.workplaceSearch.sources.shared.empty.title": "コンテンツソースがありません",
"xpack.enterpriseSearch.workplaceSearch.sources.sourceContent.searchBar.placeholder": "{prefix}コンテンツ...",
"xpack.enterpriseSearch.workplaceSearch.sources.sourceContent.title": "ソースコンテンツ",
"xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.box": "{sourceName}は、あらゆる規模の組織にあったクラウドストレージサービスです。デスクトップとWeb全体でドキュメントを作成、共有し、自動的に同期します。",
"xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.confluence": "{sourceName}はチームワークスペースであり、知識やコラボレーションが結集しています。一般的に、組織wikiやイントラネットで使用されます。通常は、ビジネスの複数の領域で従業員にとって価値のある情報が格納されます。",
"xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.confluenceServer": "{sourceName}はチームワークスペースであり、知識やコラボレーションが結集しています。一般的に、組織wikiやイントラネットで使用されます。通常は、ビジネスの複数の領域で従業員にとって価値のある情報が格納されます。",
"xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.dropbox": "{sourceName}は、あらゆる規模の組織にあったクラウドストレージサービスです。デスクトップとWeb全体でドキュメントを作成、共有し、自動的に同期します。",
"xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.github": "{sourceName}は、あらゆる規模のサイズに合った開発プラットフォームであり、バージョン管理・コラボレーションプラットフォームです。オープンソースからビジネスまで、部署や国全体でコードのホスティングとレビュー、プロジェクトの管理、ソフトウェアの構築が可能です。",
"xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.githubEnterprise": "{sourceName}は、あらゆる規模のサイズに合った開発プラットフォームであり、バージョン管理・コラボレーションプラットフォームです。オープンソースからビジネスまで、部署や国全体でコードのホスティングとレビュー、プロジェクトの管理、ソフトウェアの構築が可能です。",
"xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.gmail": "{sourceName}はGoogleが開発した無料の電子メールサービスです。世界中で億単位のユーザーや組織が信頼している、高速で信頼できるサービスです。Workplace SearchはすべてのGmailコンテンツを1つの関連する使いやすい検索エクスペリエンスに統合します。",
"xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.googleDrive": "{sourceName}はあらゆる規模の組織に合ったクラウドストレージ・コラボレーションサービスです。G Suiteドキュメント (Googleドキュメント、Googleスプレッドシート、Googleスライドなど) の保存とコラボレーションに特化しています。デスクトップとWeb全体でドキュメントを作成、共有し、自動的に同期します。",
"xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.jira": "{sourceName}は問題追跡製品であり、あらゆる規模のチームに合った不具合追跡、ワークフロー自動化、アジャイルプロジェクト管理ツールを提供します。",
"xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.jiraServer": "{sourceName}は問題追跡製品であり、あらゆる規模のチームに合った不具合追跡、ワークフロー自動化、アジャイルプロジェクト管理ツールを提供します。",
"xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.oneDrive": "{sourceName}はあらゆる規模の組織に合ったクラウドストレージサービスです。Office 365ドキュメントの保存とコラボレーションに特化しています。組織全体でドキュメントを作成、共有し、自動的に同期します。",
"xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.salesforce": "{sourceName}はクラウドベースの顧客関係管理 (CRM) プラットフォームであり、カスタマーサービス、マーケティング自動化、分析、営業活動ツールに特化しています。",
"xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.salesforceSandbox": "{sourceName}はクラウドベースの顧客関係管理 (CRM) プラットフォームであり、カスタマーサービス、マーケティング自動化、分析、営業活動ツールに特化しています。",
"xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.serviceNow": "{sourceName}はクラウドITサービス管理 (ITSM) プラットフォームで、ワークフロー自動化と内部組織サポートに特化しています。",
"xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.sharePoint": "{sourceName}はあらゆる規模の組織に合ったクラウドコラボレーション、ナレッジ管理、ストレージプラットフォームです。SharePoint Onlineは、多くの場合、集中管理されたコンテンツ管理システム (CMS) として使用され、さまざまな部署やチーム全体における豊富な情報を格納します。",
"xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.slack": "{sourceName}はコミュニケーションツールであり、リアルタイムのコラボレーションと意思決定を実現します。{sourceName}では、複数のチーム全体の作業を追跡したり、継続中のプロジェクトで同僚と直接連携したり、他の組織とコミュニケーションを取ったりすることができます。",
"xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.zendesk": "{sourceName}はクラウドベースの顧客関係管理・カスタマーサポートプラットフォームであり、カスタマーサポートチケットの追跡、優先度決定、解決のためのツールを提供します。",
"xpack.enterpriseSearch.workplaceSearch.sources.sourceDisabled.button": "プラチナライセンスの詳細",
"xpack.enterpriseSearch.workplaceSearch.sources.sourceDisabled.description": "組織のライセンスレベルが変更されました。データは安全ですが、ドキュメントレベルのアクセス権はサポートされなくなり、このソースの検索は無効になっています。このソースを再有効化するには、プラチナライセンスにアップグレードしてください。",
"xpack.enterpriseSearch.workplaceSearch.sources.sourceDisabled.title": "コンテンツソースが無効です",

View file

@ -9220,7 +9220,6 @@
"xpack.enterpriseSearch.workplaceSearch.groups.description": "将共享内容源和用户分配到组,以便为各种内部团队打造相关搜索体验。",
"xpack.enterpriseSearch.workplaceSearch.groups.filterGroups.placeholder": "按名称筛选组......",
"xpack.enterpriseSearch.workplaceSearch.groups.filterSources.buttonText": "源",
"xpack.enterpriseSearch.workplaceSearch.groups.filterUsers.placeholder": "筛选用户......",
"xpack.enterpriseSearch.workplaceSearch.groups.groupDeleted": "组“{groupName}”已成功删除。",
"xpack.enterpriseSearch.workplaceSearch.groups.groupManagerHeaderTitle": "管理 {label}",
"xpack.enterpriseSearch.workplaceSearch.groups.groupManagerSelectAllToggle": "全部{action}",
@ -9239,8 +9238,6 @@
"xpack.enterpriseSearch.workplaceSearch.groups.newGroup.action": "管理组",
"xpack.enterpriseSearch.workplaceSearch.groups.newGroupSavedSuccess": "已成功创建 {groupName}",
"xpack.enterpriseSearch.workplaceSearch.groups.noSourcesMessage": "无共享内容源",
"xpack.enterpriseSearch.workplaceSearch.groups.noUsersFound": "找不到用户",
"xpack.enterpriseSearch.workplaceSearch.groups.noUsersMessage": "无用户",
"xpack.enterpriseSearch.workplaceSearch.groups.overview.confirmRemoveButtonText": "删除 {name}",
"xpack.enterpriseSearch.workplaceSearch.groups.overview.confirmRemoveDescription": "您的组将从 Workplace Search 中删除。确定要移除 {name}",
"xpack.enterpriseSearch.workplaceSearch.groups.overview.confirmTitleText": "确认",
@ -9266,7 +9263,6 @@
"xpack.enterpriseSearch.workplaceSearch.groups.sourceProioritization.zeroStateTitle": "未与此组共享任何源",
"xpack.enterpriseSearch.workplaceSearch.groups.sourcesModalLabel": "共享内容源",
"xpack.enterpriseSearch.workplaceSearch.groups.sourcesModalTitle": "选择要与 {groupName} 共享的内容源",
"xpack.enterpriseSearch.workplaceSearch.groups.userListCount": "正在显示 {numUsers} 个用户中的 {maxVisibleUsers} 个。",
"xpack.enterpriseSearch.workplaceSearch.keepEditing.button": "继续编辑",
"xpack.enterpriseSearch.workplaceSearch.name.label": "名称",
"xpack.enterpriseSearch.workplaceSearch.nav.addSource": "添加源",
@ -9385,8 +9381,6 @@
"xpack.enterpriseSearch.workplaceSearch.sources.config.link": "编辑内容源连接器设置",
"xpack.enterpriseSearch.workplaceSearch.sources.config.title": "内容源配置",
"xpack.enterpriseSearch.workplaceSearch.sources.configuration.title": "配置",
"xpack.enterpriseSearch.workplaceSearch.sources.connectStepDescription.attachments": "附件内找到的内容PDF、Microsoft Office 文件和其他常见文本文件格式)将自动索引并可搜索。",
"xpack.enterpriseSearch.workplaceSearch.sources.connectStepDescription.files": "PDF、Microsoft Office 文件和其他常见文本文件格式内找到的内容将自动索引并可搜索。",
"xpack.enterpriseSearch.workplaceSearch.sources.contentLoading.text": "正在加载内容......",
"xpack.enterpriseSearch.workplaceSearch.sources.contentSummary.title": "内容摘要",
"xpack.enterpriseSearch.workplaceSearch.sources.contentType.header": "内容类型",
@ -9479,23 +9473,6 @@
"xpack.enterpriseSearch.workplaceSearch.sources.shared.empty.title": "没有可用的内容源",
"xpack.enterpriseSearch.workplaceSearch.sources.sourceContent.searchBar.placeholder": "{prefix} 内容......",
"xpack.enterpriseSearch.workplaceSearch.sources.sourceContent.title": "源内容",
"xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.box": "{sourceName} 是基于云的存储服务,适合所有规模的组织。创建、存储、共享文档并在您的桌面和 Web 之间同步文档。",
"xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.confluence": "{sourceName} 是团队工作区,用于知识分享和协作。常用作组织 wiki 和 Intranet通常存放有价值的信息供企业多个领域的员工使用。",
"xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.confluenceServer": "{sourceName} 是团队工作区,用于知识分享和协作。常用作组织 wiki 和 Intranet通常存放有价值的信息供企业多个领域的员工使用。",
"xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.dropbox": "{sourceName} 是基于云的存储服务,适合所有规模的组织。创建、存储、共享文档并在您的桌面和 Web 之间同步文档。",
"xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.github": "{sourceName} 是适用于各种团队规模的开发平台以及版本控制和协作平台。无论是开源还是公司,您都可以跨部门跨洲托管并查看代码、管理项目以及构建软件。",
"xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.githubEnterprise": "{sourceName} 是适用于各种团队规模的开发平台以及版本控制和协作平台。无论是开源还是公司,您都可以跨部门跨洲托管并查看代码、管理项目以及构建软件。",
"xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.gmail": "{sourceName} 是 Google 开发的免费电子邮件服务。其快速、可靠并为全球数以百万计的人和组织所信任。Workplace Search 使您的所有 Gmail 内容变成一种相关的且易用的搜索体验。",
"xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.googleDrive": "{sourceName} 是基于云的存储和协作服务,适用于所有规模的组织,专注于 G Suite 文档Google 文档、表格和幻灯片等)存储和协作。创建、存储、共享文档并在您的桌面和 Web 之间同步文档。",
"xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.jira": "{sourceName} 是问题跟踪产品,为各种规模的团队提供错误跟踪、工作流自动化以及敏捷项目管理工具。",
"xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.jiraServer": "{sourceName} 是问题跟踪产品,为各种规模的团队提供错误跟踪、工作流自动化以及敏捷项目管理工具。",
"xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.oneDrive": "{sourceName} 是基于云的存储服务适用于所有规模的组织专注于Office 365 文档存储和协作。在您的组织中创建、存储、共享和同步文档。",
"xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.salesforce": "{sourceName} 是基于云的客户关系管理 (CRM) 平台,专注于提供适用于客户服务、营销自动化、分析和销售的操作工具。",
"xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.salesforceSandbox": "{sourceName} 是基于云的客户关系管理 (CRM) 平台,专注于提供适用于客户服务、营销自动化、分析和销售的操作工具。",
"xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.serviceNow": "{sourceName} 是基于云的 IT 服务管理 (ITSM) 平台,专注于工作流自动化和内部组织支持。",
"xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.sharePoint": "{sourceName} 是基于云的协作、知识管理和存储平台,适用于各种规模的组织。经常用作集中化内容管理系统 (CMS)SharePoint Online 存储部门和团队的丰富信息。",
"xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.slack": "{sourceName} 是通讯工具,用于实时协作和决策。使用 {sourceName},跟踪跨团队进行的工作,与您的同事直接交流正在进行的项目以及与其他组织通讯。",
"xpack.enterpriseSearch.workplaceSearch.sources.sourceDescriptions.zendesk": "{sourceName} 是基于云的客户关系管理和客户支持平台,提供用于跟踪、优先级和解决客户支持工单的工具。",
"xpack.enterpriseSearch.workplaceSearch.sources.sourceDisabled.button": "了解白金级许可证",
"xpack.enterpriseSearch.workplaceSearch.sources.sourceDisabled.description": "您的组织的许可证级别已更改。您的数据是安全的,但不再支持文档级别权限,且已禁止搜索此源。升级到白金级许可证,以重新启用此源。",
"xpack.enterpriseSearch.workplaceSearch.sources.sourceDisabled.title": "内容源已禁用",