Widget Dialog

This commit is contained in:
Sedat Öztürk 2026-02-08 22:17:06 +03:00
parent cafd4d9184
commit e4ea0171fa
2 changed files with 209 additions and 64 deletions

View file

@ -821,6 +821,54 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
}),
FormFieldsDefaultValueJson = JsonSerializer.Serialize(new FieldsDefaultValue[] {
new FieldsDefaultValue() { FieldName = "IsActive", FieldDbType = DbType.Boolean, Value = "true", CustomValueType = FieldCustomValueTypeEnum.Value }
}),
WidgetsJson = JsonSerializer.Serialize(new List<WidgetEditDto>
{
new()
{
ColGap = 3,
ColSpan = 4,
SqlQuery = @"
SELECT
'Aktif' AS ""Title"",
COUNT(""Id"") AS ""Value"",
'blue' AS ""Color"",
'Aktif Kullanıcılar' AS ""SubTitle"",
'FaUserCheck' AS ""Icon""
FROM ""AbpUsers""
WHERE ""IsActive"" = 'true'
UNION ALL
SELECT
'Pasif' AS ""Title"",
COUNT(""Id"") AS ""Value"",
'green' AS ""Color"",
'Pasif Kullanıcılar' AS ""SubTitle"",
'FaUserSlash' AS ""Icon""
FROM ""AbpUsers""
WHERE ""IsActive"" = 'false'
UNION ALL
SELECT
'Doğrulama' AS ""Title"",
COUNT(""Id"") AS ""Value"",
'purple' AS ""Color"",
'Yönetici Doğrulaması bekleyenler' AS ""SubTitle"",
'FaUserClock' AS ""Icon""
FROM ""AbpUsers""
WHERE ""IsVerified"" = 'false';
",
Title = "Title",
Value = "Value",
ValueClassName = "bg-5 text-sm",
Color = "Color",
Icon = "Icon",
SubTitle = "SubTitle",
ClassName = "mb-3",
IsActive = true
}
})
});

View file

@ -10,6 +10,7 @@ import {
toast,
Tooltip,
} from '@/components/ui'
import SqlEditor from '@/views/sqlQueryManager/components/SqlEditor'
import { ListFormJsonRowDto } from '@/proxy/admin/list-form/models'
import { SelectBoxOption } from '@/types/shared'
import { useStoreActions, useStoreState } from '@/store'
@ -89,16 +90,17 @@ function JsonRowOpDialogWidget({
data.widgetValues ?? {
colGap: 3,
colSpan: 3,
sqlQuery: '',
sqlQuery:
"SELECT 'Total Records' as title, COUNT(*) as value, 'blue' as color, 'FaChartBar' as icon, 'Active records' as subTitle FROM YourTable WHERE IsActive = 1",
className: 'mb-3',
valueClassName: 'bg-5 text-sm',
title: 'Title',
value: 'Value',
color: 'Color',
icon: 'Icon',
subTitle: 'SubTitle',
title: 'title',
value: 'value',
color: 'color',
icon: 'icon',
subTitle: 'subTitle',
onClick: '',
isActive: false,
isActive: true,
}
}
validationSchema={schema}
@ -135,11 +137,11 @@ function JsonRowOpDialogWidget({
}
}}
>
{({ touched, errors, values, isSubmitting }) => (
{({ touched, errors, values, isSubmitting, setFieldValue }) => (
<Form>
<FormContainer size="sm">
<div className="h-full overflow-y-auto p-2">
<div className="grid grid-cols-3 gap-4">
<div className="h-full overflow-y-auto p-1">
<div className="grid grid-cols-5 gap-4">
<FormItem
label="Column Gap (Sütun Boşluğu)"
invalid={errors.colGap && touched.colGap}
@ -175,6 +177,52 @@ function JsonRowOpDialogWidget({
</Field>
</FormItem>
<Tooltip
title={
<div className="text-xs">
<div className="font-semibold mb-1">Widget Container CSS Classes</div>
<div>Examples: mb-3, mt-2, p-4, rounded-lg, shadow-md</div>
</div>
}
>
<FormItem
label="Class Name"
invalid={errors.className && touched.className}
errorMessage={errors.className}
>
<Field
type="text"
autoComplete="off"
name="className"
placeholder="Tailwind CSS classes: mb-3, mt-2, p-4..."
component={Input}
/>
</FormItem>
</Tooltip>
<Tooltip
title={
<div className="text-xs">
<div className="font-semibold mb-1">Value Display CSS Classes</div>
<div>Examples: text-3xl, text-2xl, font-bold, text-sm, text-center</div>
</div>
}
>
<FormItem
label="Value Class Name"
invalid={errors.valueClassName && touched.valueClassName}
errorMessage={errors.valueClassName}
>
<Field
type="text"
autoComplete="off"
name="valueClassName"
placeholder="Tailwind CSS classes: text-3xl, font-bold..."
component={Input}
/>
</FormItem>
</Tooltip>
<FormItem
label="IsActive"
invalid={errors.isActive && touched.isActive}
@ -189,25 +237,46 @@ function JsonRowOpDialogWidget({
</FormItem>
</div>
<Tooltip
title={
<div className="text-xs max-h-96 overflow-y-auto">
<div className="font-semibold mb-2">SQL Query Examples:</div>
<div className="space-y-3">
<div>
<code className="text-xs bg-gray-800 p-1 rounded block mt-1">
SELECT 'Aktif' as title, COUNT(Id) as value,
<br />
&nbsp;&nbsp;'blue' as color, 'FaChartBar' as icon,
<br />
&nbsp;&nbsp;'Aktif kayıtlar' as subTitle
<br />
FROM YourTable WHERE IsActive = 1
</code>
</div>
</div>
</div>
}
>
Sql Query
</Tooltip>
<FormItem
label="Sql Query"
invalid={errors.sqlQuery && touched.sqlQuery}
errorMessage={errors.sqlQuery}
>
<Field
type="text"
autoComplete="off"
name="sqlQuery"
placeholder="Sql Query"
component={Input}
textArea={true}
<div
className="border rounded-lg overflow-hidden"
style={{ height: '200px' }}
>
<SqlEditor
value={values.sqlQuery || ''}
onChange={(value) => setFieldValue('sqlQuery', value || '')}
height="200px"
/>
</div>
</FormItem>
<div className="bg-gray-100 p-1 rounded-md pb-2">
<span className="text-gray-500 font-bold">SQL Query Fields</span>
</div>
<div className="grid grid-cols-6 gap-2">
<div className="grid grid-cols-5 gap-2">
<FormItem
label="Title Field"
invalid={errors.title && touched.title}
@ -217,7 +286,7 @@ function JsonRowOpDialogWidget({
type="text"
autoComplete="off"
name="title"
placeholder="Title Field"
placeholder="Column name from SQL query e.g., 'title'"
component={Input}
/>
</FormItem>
@ -231,12 +300,30 @@ function JsonRowOpDialogWidget({
type="text"
autoComplete="off"
name="value"
placeholder="Value Field"
placeholder="Column name from SQL query e.g., 'value'"
component={Input}
/>
</FormItem>
<Tooltip title={'blue, green, purple, gray, red, yellow, pink, indigo, teal'}>
<Tooltip
title={
<div className="text-xs">
<div className="font-semibold mb-1">Available Colors:</div>
<div className="grid grid-cols-2 gap-1">
<div> blue</div>
<div> green</div>
<div> purple</div>
<div> gray</div>
<div> red</div>
<div> yellow</div>
<div> pink</div>
<div> indigo</div>
<div> teal</div>
<div> orange</div>
</div>
</div>
}
>
<FormItem
label="Color Field"
invalid={errors.color && touched.color}
@ -246,7 +333,7 @@ function JsonRowOpDialogWidget({
type="text"
autoComplete="off"
name="color"
placeholder="Color"
placeholder="blue, green, purple, gray, red..."
component={Input}
/>
</FormItem>
@ -254,7 +341,45 @@ function JsonRowOpDialogWidget({
<Tooltip
title={
'FaHome, FaUser, FaSearch, FaCog, FaBell etc. (react-icons/fa icons)'
<div className="text-xs max-h-64 overflow-y-auto">
<div className="font-semibold mb-2">Popular Icon Examples:</div>
<div className="space-y-1">
<div>
📊 <strong>Charts:</strong> FaChartBar, FaChartLine, FaChartPie,
FaChartArea
</div>
<div>
💰 <strong>Finance:</strong> FaDollarSign, FaMoneyBill, FaWallet,
FaCreditCard
</div>
<div>
👥 <strong>Users:</strong> FaUser, FaUsers, FaUserCircle, FaUserTie
</div>
<div>
📦 <strong>Business:</strong> FaShoppingCart, FaBoxes, FaWarehouse,
FaTruck
</div>
<div>
📈 <strong>Analytics:</strong> FaArrowUp, FaArrowDown,
FaArrowTrendUp
</div>
<div>
<strong>Settings:</strong> FaCog, FaTools, FaWrench
</div>
<div>
🔔 <strong>Alerts:</strong> FaBell, FaExclamation, FaInfoCircle
</div>
<div>
📁 <strong>Files:</strong> FaFile, FaFolder, FaFileAlt, FaDownload
</div>
<div>
🏠 <strong>Other:</strong> FaHome, FaBuilding, FaGlobe, FaHeart
</div>
</div>
<div className="mt-2 pt-2 border-t">
All icons from <strong>react-icons/fa</strong> (Font Awesome)
</div>
</div>
}
>
<FormItem
@ -266,7 +391,7 @@ function JsonRowOpDialogWidget({
type="text"
autoComplete="off"
name="icon"
placeholder="Icon"
placeholder="FaChartBar, FaUsers, FaShoppingCart..."
component={Input}
/>
</FormItem>
@ -281,10 +406,11 @@ function JsonRowOpDialogWidget({
type="text"
autoComplete="off"
name="subTitle"
placeholder="Sub Title"
placeholder="Column name from SQL query e.g., 'subTitle'"
component={Input}
/>
</FormItem>
</div>
<FormItem
label="On Click"
@ -295,41 +421,12 @@ function JsonRowOpDialogWidget({
type="text"
autoComplete="off"
name="onClick"
placeholder="On Click"
placeholder="JavaScript function: () => alert('Clicked')"
component={Input}
/>
</FormItem>
</div>
<FormItem
label="Class Name"
invalid={errors.className && touched.className}
errorMessage={errors.className}
>
<Field
type="text"
autoComplete="off"
name="className"
placeholder="Class Name"
component={Input}
/>
</FormItem>
<FormItem
label="Value Class Name"
invalid={errors.valueClassName && touched.valueClassName}
errorMessage={errors.valueClassName}
>
<Field
type="text"
autoComplete="off"
name="valueClassName"
placeholder="Value Class Name"
component={Input}
/>
</FormItem>
</div>
<div className="text-right mt-4">
<div className="text-right mt-2">
<Button className="ltr:mr-2 rtl:ml-2" variant="plain" onClick={handleClose}>
Cancel
</Button>