mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-28 14:03:48 +03:00
AdminX copy updates (#18092)
refs. https://github.com/TryGhost/Product/issues/3349 - couple of copy had to be updated in AdminX
This commit is contained in:
parent
dbe1c0fa2e
commit
be32b23295
@ -47,7 +47,7 @@ const List: React.FC<ListProps> = ({
|
||||
<>
|
||||
{pageTitle && <Heading>{pageTitle}</Heading>}
|
||||
<section className={listClasses}>
|
||||
<ListHeading actions={actions} title={title} titleSeparator={!pageTitle && titleSeparator && !borderTop} titleSize={titleSize} />
|
||||
{title && <ListHeading actions={actions} title={title} titleSeparator={!pageTitle && titleSeparator && !borderTop} titleSize={titleSize} />}
|
||||
<div className='flex flex-col'>
|
||||
{children}
|
||||
</div>
|
||||
|
@ -48,7 +48,7 @@ const Sidebar: React.FC = () => {
|
||||
<SettingNavItem navid='facebook' title="Facebook card" onClick={handleSectionClick} />
|
||||
<SettingNavItem navid='social-accounts' title="Social accounts" onClick={handleSectionClick} />
|
||||
<SettingNavItem navid='locksite' title="Make this site private" onClick={handleSectionClick} />
|
||||
<SettingNavItem navid='users' title="Users and permissions" onClick={handleSectionClick} />
|
||||
<SettingNavItem navid='users' title="Staff" onClick={handleSectionClick} />
|
||||
</SettingNavSection>
|
||||
|
||||
<SettingNavSection title="Site">
|
||||
@ -68,7 +68,7 @@ const Sidebar: React.FC = () => {
|
||||
<SettingNavItem navid='analytics' title="Analytics" onClick={handleSectionClick} />
|
||||
</SettingNavSection>
|
||||
|
||||
<SettingNavSection title="Email newsletters">
|
||||
<SettingNavSection title="Email newsletter">
|
||||
<SettingNavItem navid='enable-newsletters' title="Newsletter sending" onClick={handleSectionClick} />
|
||||
{newslettersEnabled !== 'disabled' && (
|
||||
<>
|
||||
|
@ -4,6 +4,7 @@ import Icon from '../../../admin-x-ds/global/Icon';
|
||||
import List from '../../../admin-x-ds/global/List';
|
||||
import ListItem from '../../../admin-x-ds/global/ListItem';
|
||||
import NiceModal from '@ebay/nice-modal-react';
|
||||
import NoValueLabel from '../../../admin-x-ds/global/NoValueLabel';
|
||||
import React, {useState} from 'react';
|
||||
import SettingGroup from '../../../admin-x-ds/settings/SettingGroup';
|
||||
import TabView from '../../../admin-x-ds/global/TabView';
|
||||
@ -138,39 +139,45 @@ const CustomIntegrations: React.FC<{integrations: Integration[]}> = ({integratio
|
||||
const {updateRoute} = useRouting();
|
||||
const {mutateAsync: deleteIntegration} = useDeleteIntegration();
|
||||
|
||||
return (
|
||||
<List>
|
||||
{integrations.map(integration => (
|
||||
<IntegrationItem
|
||||
action={() => updateRoute({route: `integrations/show/${integration.id}`})}
|
||||
detail={integration.description || 'No description'}
|
||||
icon={
|
||||
integration.icon_image ?
|
||||
<img className='h-8 w-8 object-cover' role='presentation' src={integration.icon_image} /> :
|
||||
<Icon className='w-8' name='integration' />
|
||||
}
|
||||
title={integration.name}
|
||||
custom
|
||||
onDelete={() => {
|
||||
NiceModal.show(ConfirmationModal, {
|
||||
title: 'Are you sure?',
|
||||
prompt: 'Deleting this integration will remove all webhooks and api keys associated with it.',
|
||||
okColor: 'red',
|
||||
okLabel: 'Delete Integration',
|
||||
onOk: async (confirmModal) => {
|
||||
await deleteIntegration(integration.id);
|
||||
confirmModal?.remove();
|
||||
showToast({
|
||||
message: 'Integration deleted',
|
||||
type: 'success'
|
||||
});
|
||||
}
|
||||
});
|
||||
}}
|
||||
/>)
|
||||
)}
|
||||
</List>
|
||||
);
|
||||
if (integrations.length) {
|
||||
return (
|
||||
<List borderTop={false}>
|
||||
{integrations.map(integration => (
|
||||
<IntegrationItem
|
||||
action={() => updateRoute({route: `integrations/show/${integration.id}`})}
|
||||
detail={integration.description || 'No description'}
|
||||
icon={
|
||||
integration.icon_image ?
|
||||
<img className='h-8 w-8 object-cover' role='presentation' src={integration.icon_image} /> :
|
||||
<Icon className='w-8' name='integration' />
|
||||
}
|
||||
title={integration.name}
|
||||
custom
|
||||
onDelete={() => {
|
||||
NiceModal.show(ConfirmationModal, {
|
||||
title: 'Are you sure?',
|
||||
prompt: 'Deleting this integration will remove all webhooks and api keys associated with it.',
|
||||
okColor: 'red',
|
||||
okLabel: 'Delete Integration',
|
||||
onOk: async (confirmModal) => {
|
||||
await deleteIntegration(integration.id);
|
||||
confirmModal?.remove();
|
||||
showToast({
|
||||
message: 'Integration deleted',
|
||||
type: 'success'
|
||||
});
|
||||
}
|
||||
});
|
||||
}}
|
||||
/>)
|
||||
)}
|
||||
</List>
|
||||
);
|
||||
} else {
|
||||
return <NoValueLabel icon='integration'>
|
||||
No custom integration.
|
||||
</NoValueLabel>;
|
||||
}
|
||||
};
|
||||
|
||||
const Integrations: React.FC<{ keywords: string[] }> = ({keywords}) => {
|
||||
|
@ -112,7 +112,7 @@ const WebhookModal: React.FC<WebhookModalProps> = ({webhook, integrationId}) =>
|
||||
onKeyDown={() => clearError('target_url')}
|
||||
/>
|
||||
<TextField
|
||||
placeholder='Psst...'
|
||||
placeholder='https://example.com'
|
||||
title='Secret'
|
||||
value={formState.secret || undefined}
|
||||
onChange={e => updateForm(state => ({...state, secret: e.target.value}))}
|
||||
|
@ -172,7 +172,7 @@ const DefaultRecipients: React.FC<{ keywords: string[] }> = ({keywords}) => {
|
||||
{(selectedOption === 'segment') && (
|
||||
<MultiSelect
|
||||
options={segmentOptionGroups.filter(group => group.options.length > 0)}
|
||||
title='Select tiers'
|
||||
title='Filter'
|
||||
values={selectedSegments}
|
||||
clearBg
|
||||
onChange={setSelectedSegments}
|
||||
|
@ -106,7 +106,7 @@ const Metadata: React.FC<{ keywords: string[] }> = ({keywords}) => {
|
||||
navid='metadata'
|
||||
saveState={saveState}
|
||||
testId='metadata'
|
||||
title='Metadata'
|
||||
title='Meta data'
|
||||
onCancel={handleCancel}
|
||||
onEditingChange={handleEditingChange}
|
||||
onSave={handleSave}
|
||||
|
@ -432,8 +432,8 @@ const Password: React.FC<UserDetailProps> = ({user}) => {
|
||||
|
||||
const UserMenuTrigger = () => (
|
||||
<button className='flex h-8 cursor-pointer items-center justify-center rounded bg-[rgba(0,0,0,0.75)] px-3 opacity-80 hover:opacity-100' type='button'>
|
||||
<Icon colorClass='text-white' name='ellipsis' size='md' />
|
||||
<span className='sr-only'>Actions</span>
|
||||
<Icon colorClass='text-white' name='ellipsis' size='md' />
|
||||
</button>
|
||||
);
|
||||
|
||||
|
@ -20,6 +20,7 @@ interface OwnerProps {
|
||||
|
||||
interface UsersListProps {
|
||||
users: User[];
|
||||
groupname?: string;
|
||||
updateUser?: (user: User) => void;
|
||||
}
|
||||
|
||||
@ -43,14 +44,14 @@ const Owner: React.FC<OwnerProps> = ({user}) => {
|
||||
<div className='group flex gap-3 hover:cursor-pointer' data-testid='owner-user' onClick={showDetailModal}>
|
||||
<Avatar bgColor={generateAvatarColor((user.name ? user.name : user.email))} image={user.profile_image} label={getInitials(user.name)} labelColor='white' size='lg' />
|
||||
<div className='flex flex-col'>
|
||||
<span>{user.name} — <strong>Owner</strong> <button className='ml-2 inline-block text-sm font-bold text-green group-hover:visible md:invisible' type='button'>Edit</button></span>
|
||||
<span>{user.name} — <strong>Owner</strong> <button className='ml-2 inline-block text-sm font-bold text-green group-hover:visible md:invisible' type='button'>View profile</button></span>
|
||||
<span className='text-xs text-grey-700'>{user.email}</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const UsersList: React.FC<UsersListProps> = ({users}) => {
|
||||
const UsersList: React.FC<UsersListProps> = ({users, groupname}) => {
|
||||
const {updateRoute} = useRouting();
|
||||
|
||||
const showDetailModal = (user: User) => {
|
||||
@ -60,7 +61,7 @@ const UsersList: React.FC<UsersListProps> = ({users}) => {
|
||||
if (!users || !users.length) {
|
||||
return (
|
||||
<NoValueLabel icon='single-user-block'>
|
||||
No users found.
|
||||
No {groupname} found.
|
||||
</NoValueLabel>
|
||||
);
|
||||
}
|
||||
@ -149,7 +150,7 @@ const InvitesUserList: React.FC<InviteListProps> = ({users}) => {
|
||||
if (!users || !users.length) {
|
||||
return (
|
||||
<NoValueLabel icon='single-user-block'>
|
||||
No users found.
|
||||
No invitations found.
|
||||
</NoValueLabel>
|
||||
);
|
||||
}
|
||||
@ -196,7 +197,7 @@ const Users: React.FC<{ keywords: string[] }> = ({keywords}) => {
|
||||
};
|
||||
|
||||
const buttons = (
|
||||
<Button color='green' label='Invite users' link={true} onClick={() => {
|
||||
<Button color='green' label='Invite people' link={true} onClick={() => {
|
||||
showInviteModal();
|
||||
}} />
|
||||
);
|
||||
@ -207,22 +208,22 @@ const Users: React.FC<{ keywords: string[] }> = ({keywords}) => {
|
||||
{
|
||||
id: 'users-admins',
|
||||
title: 'Administrators',
|
||||
contents: (<UsersList users={adminUsers} />)
|
||||
contents: (<UsersList groupname='administrators' users={adminUsers} />)
|
||||
},
|
||||
{
|
||||
id: 'users-editors',
|
||||
title: 'Editors',
|
||||
contents: (<UsersList users={editorUsers} />)
|
||||
contents: (<UsersList groupname='editors' users={editorUsers} />)
|
||||
},
|
||||
{
|
||||
id: 'users-authors',
|
||||
title: 'Authors',
|
||||
contents: (<UsersList users={authorUsers} />)
|
||||
contents: (<UsersList groupname='authors' users={authorUsers} />)
|
||||
},
|
||||
{
|
||||
id: 'users-contributors',
|
||||
title: 'Contributors',
|
||||
contents: (<UsersList users={contributorUsers} />)
|
||||
contents: (<UsersList groupname='contributors' users={contributorUsers} />)
|
||||
},
|
||||
{
|
||||
id: 'users-invited',
|
||||
@ -237,7 +238,7 @@ const Users: React.FC<{ keywords: string[] }> = ({keywords}) => {
|
||||
keywords={keywords}
|
||||
navid='users'
|
||||
testId='users'
|
||||
title='Users and permissions'
|
||||
title='Staff'
|
||||
>
|
||||
<Owner user={ownerUser} />
|
||||
<TabView selectedTab={selectedTab} tabs={tabs} onTabChange={setSelectedTab} />
|
||||
|
@ -80,7 +80,7 @@ test.describe('Default recipient settings', async () => {
|
||||
await section.getByRole('button', {name: 'Edit'}).click();
|
||||
|
||||
await section.getByLabel('Default newsletter recipients').selectOption({label: 'Specific people'});
|
||||
await section.getByLabel('Select tiers').click();
|
||||
await section.getByLabel('Filter').click();
|
||||
|
||||
await section.locator('[data-testid="multiselect-option"]', {hasText: 'Basic Supporter'}).click();
|
||||
await section.locator('[data-testid="multiselect-option"]', {hasText: 'first-label'}).click();
|
||||
|
@ -31,7 +31,7 @@ test.describe('User invitations', async () => {
|
||||
|
||||
const section = page.getByTestId('users');
|
||||
|
||||
await section.getByRole('button', {name: 'Invite users'}).click();
|
||||
await section.getByRole('button', {name: 'Invite people'}).click();
|
||||
|
||||
const modal = page.getByTestId('invite-user-modal');
|
||||
await modal.getByLabel('Email address').fill('newuser@test.com');
|
||||
@ -144,7 +144,7 @@ test.describe('User invitations', async () => {
|
||||
|
||||
const section = page.getByTestId('users');
|
||||
|
||||
await section.getByRole('button', {name: 'Invite users'}).click();
|
||||
await section.getByRole('button', {name: 'Invite people'}).click();
|
||||
|
||||
const modal = page.getByTestId('invite-user-modal');
|
||||
|
||||
|
@ -126,7 +126,7 @@ test.describe('User profile', async () => {
|
||||
|
||||
const wrapper = section.getByTestId('owner-user');
|
||||
await wrapper.hover();
|
||||
await wrapper.getByRole('button', {name: 'Edit'}).click();
|
||||
await wrapper.getByRole('button', {name: 'View profile'}).click();
|
||||
|
||||
// Upload profile picture
|
||||
|
||||
|
@ -72,7 +72,7 @@ test.describe('User roles', async () => {
|
||||
|
||||
await expect(modal.getByRole('button', {name: 'Saved'})).toBeVisible();
|
||||
|
||||
await expect(activeTab).toHaveText(/No users found/);
|
||||
await expect(activeTab).toHaveText(/No authors found./);
|
||||
|
||||
await section.getByRole('tab', {name: 'Editors'}).click();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user