ui: fixed card and tag removal, alert buttons, kai input disable state

This commit is contained in:
nick-delirium 2025-05-30 10:34:04 +02:00
parent 75230d72ec
commit 0d9c8d70c8
No known key found for this signature in database
GPG key ID: 93ABD695DF5FDBA0
7 changed files with 96 additions and 82 deletions

View file

@ -1,10 +1,10 @@
import React from 'react';
import { Button, Form, Input, Space, Modal } from 'antd';
import { Button, Form, Input, Space } from 'antd';
import { Trash } from 'UI/Icons';
import { useStore } from '@/mstore';
import { useModal } from 'Components/ModalContext';
import { useTranslation } from 'react-i18next';
import { confirm } from 'UI';
interface Props {
tag: any;
projectId: number;
@ -23,14 +23,16 @@ function TagForm(props: Props) {
};
const onDelete = async () => {
Modal.confirm({
title: t('Tag'),
content: t('Are you sure you want to remove?'),
onOk: async () => {
await tagWatchStore.deleteTag(tag.tagId, projectId);
closeModal();
},
});
if (
await confirm({
header: t('Remove Tag'),
confirmButton: t('Remove'),
confirmation: t('Are you sure you want to remove this tag?'),
})
) {
await tagWatchStore.deleteTag(tag.tagId, projectId);
closeModal();
}
};
const onSave = async () => {

View file

@ -23,6 +23,7 @@ function BottomButtons({
<Button
loading={loading}
type="primary"
htmlType="submit"
disabled={loading || !instance.validate()}
id="submit-button"
>

View file

@ -90,6 +90,7 @@ function Condition({
<label className="w-1/6 flex-shrink-0 font-normal">{t('is')}</label>
<div className="w-2/6 flex items-center">
<Select
popupMatchSelectWidth={false}
placeholder={t('Select Condition')}
options={localizedConditions}
name="operator"

View file

@ -7,19 +7,18 @@ import {
Button,
Dropdown,
Modal as AntdModal,
Avatar, TableColumnType, Spin
Avatar,
TableColumnType,
Spin,
} from 'antd';
import {
EditOutlined,
DeleteOutlined,
} from '@ant-design/icons';
import { EditOutlined, DeleteOutlined } from '@ant-design/icons';
import { EllipsisVertical } from 'lucide-react';
import { TablePaginationConfig, SorterResult } from 'antd/lib/table/interface';
import { useStore } from 'App/mstore';
import { toast } from 'react-toastify';
import { useHistory } from 'react-router';
import { withSiteId } from 'App/routes';
import { Icon } from 'UI';
import { Icon, confirm } from 'UI';
import cn from 'classnames';
import { TYPE_ICONS, TYPE_NAMES } from 'App/constants/card';
import Widget from 'App/mstore/types/widget';
@ -45,7 +44,7 @@ const ListView: React.FC<Props> = ({
toggleSelection,
disableSelection = false,
inLibrary = false,
loading = false
loading = false,
}) => {
const { t } = useTranslation();
const [editingMetricId, setEditingMetricId] = useState<number | null>(null);
@ -63,7 +62,7 @@ const ListView: React.FC<Props> = ({
<Text strong>
{Math.min(
(metricStore.pageSize || 10) * (metricStore.page || 1),
list.length
list.length,
)}
</Text>{' '}
{t('of')}&nbsp;<Text strong>{list.length}</Text>&nbsp;{t('cards')}
@ -124,15 +123,17 @@ const ListView: React.FC<Props> = ({
const onMenuClick = async (metric: Widget, { key }: { key: string }) => {
if (key === 'delete') {
AntdModal.confirm({
title: t('Confirm'),
content: t('Are you sure you want to permanently delete this card?'),
okText: t('Yes, delete'),
cancelText: t('No'),
onOk: async () => {
await metricStore.delete(metric);
}
});
if (
await confirm({
header: t('Delete Card'),
confirmButton: t('Delete'),
confirmation: t(
'Are you sure you want to permanently delete this card? This action cannot be undone.',
),
})
) {
await metricStore.delete(metric);
}
}
if (key === 'rename') {
setEditingMetricId(metric.metricId);
@ -155,7 +156,7 @@ const ListView: React.FC<Props> = ({
const menuItems = [
{ key: 'rename', icon: <EditOutlined />, label: t('Rename') },
{ key: 'delete', icon: <DeleteOutlined />, label: t('Delete') }
{ key: 'delete', icon: <DeleteOutlined />, label: t('Delete') },
];
const renderTitle = (_text: string, metric: Widget) => (
@ -201,9 +202,10 @@ const ListView: React.FC<Props> = ({
key: 'title',
className: 'cap-first pl-4',
sorter: true,
sortOrder: metricStore.sort.field === 'name' ? metricStore.sort.order : undefined,
sortOrder:
metricStore.sort.field === 'name' ? metricStore.sort.order : undefined,
width: inLibrary ? '31%' : '25%',
render: renderTitle
render: renderTitle,
},
{
title: t('Owner'),
@ -211,19 +213,25 @@ const ListView: React.FC<Props> = ({
key: 'owner',
className: 'capitalize',
sorter: true,
sortOrder: metricStore.sort.field === 'owner_email' ? metricStore.sort.order : undefined,
sortOrder:
metricStore.sort.field === 'owner_email'
? metricStore.sort.order
: undefined,
width: inLibrary ? '31%' : '25%',
render: renderOwner
render: renderOwner,
},
{
title: t('Last Modified'),
dataIndex: 'edited_at',
key: 'lastModified',
sorter: true,
sortOrder: metricStore.sort.field === 'edited_at' ? metricStore.sort.order : undefined,
sortOrder:
metricStore.sort.field === 'edited_at'
? metricStore.sort.order
: undefined,
width: inLibrary ? '31%' : '25%',
render: renderLastModified
}
render: renderLastModified,
},
];
if (!inLibrary) {
@ -232,14 +240,14 @@ const ListView: React.FC<Props> = ({
key: 'options',
className: 'text-right',
width: '5%',
render: renderOptions
render: renderOptions,
});
}
const handleTableChange = (
pag: TablePaginationConfig,
_filters: Record<string, (string | number | boolean)[] | null>,
sorterParam: SorterResult<Widget> | SorterResult<Widget>[]
sorterParam: SorterResult<Widget> | SorterResult<Widget>[],
) => {
const sorter = Array.isArray(sorterParam) ? sorterParam[0] : sorterParam;
let order = sorter.order;
@ -268,19 +276,19 @@ const ListView: React.FC<Props> = ({
onRow={
inLibrary
? (record) => ({
onClick: () => {
if (!disableSelection) toggleSelection?.(record?.metricId);
}
})
onClick: () => {
if (!disableSelection) toggleSelection?.(record?.metricId);
},
})
: undefined
}
rowSelection={
!disableSelection
? {
selectedRowKeys: selectedList,
onChange: (keys) => toggleSelection && toggleSelection(keys),
columnWidth: 16
}
selectedRowKeys: selectedList,
onChange: (keys) => toggleSelection && toggleSelection(keys),
columnWidth: 16,
}
: undefined
}
pagination={{
@ -292,7 +300,7 @@ const ListView: React.FC<Props> = ({
showLessItems: true,
showTotal: () => totalMessage,
size: 'small',
simple: true
simple: true,
}}
/>
<AntdModal

View file

@ -10,10 +10,10 @@ import AddCardSection from '../AddCardSection/AddCardSection';
import { useTranslation } from 'react-i18next';
function MetricsList({
siteId,
onSelectionChange,
inLibrary
}: {
siteId,
onSelectionChange,
inLibrary,
}: {
siteId: string;
onSelectionChange?: (selected: any[]) => void;
inLibrary?: boolean;
@ -26,16 +26,16 @@ function MetricsList({
const dashboard = dashboardStore.selectedDashboard;
const existingCardIds = useMemo(
() => dashboard?.widgets?.map((i) => parseInt(i.metricId)),
[dashboard]
[dashboard],
);
const cards = useMemo(
() =>
onSelectionChange
? metricStore.filteredCards.filter(
(i) => !existingCardIds?.includes(parseInt(i.metricId))
)
(i) => !existingCardIds?.includes(parseInt(i.metricId)),
)
: metricStore.filteredCards,
[metricStore.filteredCards, existingCardIds, onSelectionChange]
[metricStore.filteredCards, existingCardIds, onSelectionChange],
);
const loading = metricStore.isLoading;
@ -66,7 +66,8 @@ function MetricsList({
metricStore.updateKey('sessionsPage', 1);
}, [metricStore]);
const isFiltered = metricStore.filter.query !== '' || metricStore.filter.type !== '';
const isFiltered =
metricStore.filter.query !== '' || metricStore.filter.type !== '';
const searchImageDimensions = { width: 60, height: 'auto' };
const defaultImageDimensions = { width: 600, height: 'auto' };
@ -93,7 +94,9 @@ function MetricsList({
) : (
<div className="flex flex-col items-center">
<div>
{t('Create and customize cards to analyze trends and user behavior effectively.')}
{t(
'Create and customize cards to analyze trends and user behavior effectively.',
)}
</div>
<Popover
arrow={false}

View file

@ -1,7 +1,7 @@
import { useHistory } from 'react-router';
import { useStore } from 'App/mstore';
import { observer } from 'mobx-react-lite';
import { Button, Dropdown, MenuProps, Modal } from 'antd';
import { Button, Dropdown, MenuProps } from 'antd';
import {
BellIcon,
EllipsisVertical,
@ -14,6 +14,7 @@ import { useModal } from 'Components/ModalContext';
import AlertFormModal from 'Components/Alerts/AlertFormModal/AlertFormModal';
import { showAddToDashboardModal } from 'Components/Dashboard/components/AddToDashboardButton';
import { useTranslation } from 'react-i18next';
import { confirm } from 'UI';
function CardViewMenu() {
const { t } = useTranslation();
@ -51,29 +52,25 @@ function CardViewMenu() {
label: t('Delete'),
icon: <TrashIcon size={15} />,
disabled: !widget.exists(),
onClick: () => {
Modal.confirm({
title: t('Confirm Card Deletion'),
icon: null,
content:
t('Are you sure you want to remove this card? This action is permanent and cannot be undone.'),
footer: (_, { OkBtn, CancelBtn }) => (
<>
<CancelBtn />
<OkBtn />
</>
),
onOk: () => {
metricStore
.delete(widget)
.then(() => {
history.goBack();
})
.catch(() => {
toast.error(t('Failed to remove card'));
});
},
});
onClick: async () => {
if (
await confirm({
header: t('Remove Card'),
confirmButton: t('Remove'),
confirmation: t(
'Are you sure you want to remove this card? This action is permanent and cannot be undone.',
),
})
) {
metricStore
.delete(widget)
.then(() => {
history.goBack();
})
.catch(() => {
toast.error(t('Failed to remove card'));
});
}
},
},
];

View file

@ -25,7 +25,9 @@ function ChatInput({
kaiStore.setQueryText(text);
};
const submit = () => {
const submit = (e: any) => {
e.preventDefault();
e.stopPropagation();
if (limited) {
return;
}
@ -80,7 +82,7 @@ function ChatInput({
);
}
return (
<div className="relative">
<div className="relative bg-white">
<Input
onPressEnter={submit}
onKeyDown={(e) => {