FormDevExpress Buton yapısı değiştirildi
This commit is contained in:
parent
59ec8950a3
commit
9b9ef9c100
7 changed files with 334 additions and 215 deletions
8
.github/instructions/ai.instructions.md
vendored
8
.github/instructions/ai.instructions.md
vendored
|
|
@ -294,7 +294,7 @@ the Wizard's `Custom` path.
|
|||
per-command Form permissions (`selectPermission`, `insertPermission`, `updatePermission`,
|
||||
`deletePermission`). In `Otomatik` mode the base is the read permission the Wizard created for
|
||||
the component and the commands get `''` / `.Create` / `.Update` / `.Delete` suffixes.
|
||||
- List screen permissions: `App.DeveloperKit.CustomComponents{,.Create,.Update,.Delete}`.
|
||||
- List screen permissions: `App.DeveloperKit.CustomComponents{,.Create,.Update,.Delete,.Export,.Import}`.
|
||||
- Every save/delete is mirrored into `configs/seeds/{scope}/data/App.DeveloperKit.CustomComponents.json`; the endpoints it uses are
|
||||
referenced through `crud/{Entity}.json`. A component that is not seed-backed is not done.
|
||||
|
||||
|
|
@ -657,10 +657,12 @@ a deploy. AI must learn and teach implementation flow primarily from these asset
|
|||
- LanguagesData.json
|
||||
- WizardDataSeeder.cs / CrudDataSeeder.cs — the seeders that read
|
||||
surface B below
|
||||
- ListFormSeedDataApplier (Domain/Data/) — applies `data/{ListFormCode}.json` after every
|
||||
contributor has run
|
||||
|
||||
**B. Runtime seeds (written by the running application)** — `configs/seeds/`, resolved through
|
||||
`SeedPathResolver`. The Wizard, the Custom Components screen / Visual Designer and the CRUD
|
||||
Endpoint Manager write here; the
|
||||
`SeedPathResolver`. The Wizard, the Custom Components screen / Visual Designer, the CRUD
|
||||
Endpoint Manager and every ListForm screen with a `SeedFilePath` write here; the
|
||||
seeders above restore them when the database is recreated. Scope folders mirror the CDN layout:
|
||||
|
||||
```
|
||||
|
|
|
|||
13
.github/instructions/lowcode.instructions.md
vendored
13
.github/instructions/lowcode.instructions.md
vendored
|
|
@ -1490,6 +1490,9 @@ Kurallar:
|
|||
- `AuthName` boş bırakılırsa buton **herkese görünür**. Süreç butonlarında bu alanı boş bırakma:
|
||||
yetki kontrolünden geçmeyen buton hiç çizilmez, gizlemenin tek doğru yolu budur.
|
||||
- `Text` ve `Hint` dil anahtarıdır; çeviri `::` öneki eklenerek çözülür. Düz metin yazma.
|
||||
- `Icon` bir **DevExtreme ikon adıdır** (`check`, `trash`, `doc`, `preferences` …); tema CSS'i
|
||||
`dx-icon-<ad>` sınıfıyla çizer. Komut diyalogundaki alan hazır ikon listesini önerir, listede
|
||||
olmayan bir ad da yazılabilir. Form ekranının araç çubuğu da aynı ikon adlarını kullanır.
|
||||
- Toolbar butonu **seçili satırlarla** çalışır; `SelectionJson` uygun modda (`single`/`multiple`)
|
||||
olmalıdır. İş akışı varsa wizard bunu zaten `single` yapar.
|
||||
- Satır bazlı aksiyon istiyorsan `ButtonPosition: 0` kullan; buton komut sütununda görünür.
|
||||
|
|
@ -2356,7 +2359,7 @@ Form düğümünün `id`'si) ve Save/Delete üzerinden geri yazar. Olaylar: `onL
|
|||
- `Özel` mod: yetki adı elle yazılır.
|
||||
- Boş bırakılan komut serbesttir.
|
||||
|
||||
Liste ekranı yetkileri: `App.DeveloperKit.CustomComponents{,.Create,.Update,.Delete}`.
|
||||
Liste ekranı yetkileri: `App.DeveloperKit.CustomComponents{,.Create,.Update,.Delete,.Export,.Import}`.
|
||||
|
||||
### 7.6 Bileşeni menüye bağlama
|
||||
|
||||
|
|
@ -2892,9 +2895,11 @@ Endpoint **tanımlarını** düzenleme yetkileri ListForm ekranının
|
|||
`App.DeveloperKit.CustomEndpoints{,.Create,.Update,.Delete}` yetkileridir — çağırma
|
||||
yetkilerinden (`.Get/.Post/.Put/.Remove` + `PermissionsJson`) ayrıdır.
|
||||
|
||||
**Seed:** ekrandan girilen kayıt yalnızca veritabanında yaşar. Proje teslimi için kaydı
|
||||
`sql/execute/{Ad}.sql` upsert prosedürüyle geri getirilebilir yap (§9.14 uyarısı); platform
|
||||
varsayılanı ise çekirdeğin `Seeds/TenantData.json` → `CustomEndpoints` bloğundadır.
|
||||
**Seed:** platform varsayılanları `configs/seeds/{kapsam}/data/App.DeveloperKit.CustomEndpoints.json`
|
||||
dosyasından gelir; ekranın `SeedSyncInsert/Update/Delete` bayrakları **kapalıdır**, yani ekrandan
|
||||
girilen kayıt dosyaya yansımaz ve yalnızca veritabanında yaşar. Proje teslimi için kaydı ya bu
|
||||
dosyaya elle ekle ya da `sql/execute/{Ad}.sql` upsert prosedürüyle geri getirilebilir yap
|
||||
(§9.14 uyarısı).
|
||||
|
||||
**Ne zaman CRUD, ne zaman Custom Endpoint?** Tek tabloya standart CRUD gerekiyorsa CRUD Endpoint
|
||||
(otomatik üretilir, `crud/{Entity}.json` ile seed'lenir, filtre sözleşmesi hazırdır).
|
||||
|
|
|
|||
12
README.md
12
README.md
|
|
@ -632,8 +632,8 @@ Teknik kullanıcılar için `/admin/developerkit` altında toplanan araçlar:
|
|||
| **Custom Endpoint** | `/admin/list/App.DeveloperKit.CustomEndpoints` | SQL veya servis tanımından REST endpoint üretimi; GET/POST/PUT/DELETE için ayrı yetki kapıları (`App.DeveloperKit.CustomEndpoints.*`) ve kullanıcı/rol/global erişim kuralları. |
|
||||
| **CRUD Endpoint** | SQL Query Manager içinde | Tablo tanımından tam CRUD endpoint kümesi üretimi. Ayrı ekranı yoktur; bkz. aşağıdaki not. |
|
||||
| **Dynamic Service** | `/admin/list/App.DeveloperKit.DynamicServices` | Liste bir ListForm ekranıdır (KPI şeridi, Swagger butonu, kart/ızgara görünümü); kod yazma listeden açılan `DynamicServiceEditor` diyalogundadır: Monaco editörü, Roslyn ile derleme (`TestCompile`), yayınlama (`Publish`) ve çalışan uygulamaya controller olarak kaydetme. Yetkiler: Create/Edit/Delete/Manage/TestCompile/Publish/ViewCode. |
|
||||
| **Custom Component** | `/admin/list/App.DeveloperKit.CustomComponents` | React bileşenini veritabanında saklama; `@babel/standalone` ile tarayıcıda derleyip route'a bağlama. Liste bir ListForm ekranıdır (KPI şeridi, ızgara/kart görünümü, grid'in kendi ekleme/düzenleme formu); satırdaki **Design** butonu `/admin/developerkit/components/design/{id}` tasarımcısını, **Open URL** butonu bileşenin `RoutePath`'ini açar. Kayıtlar `configs/seeds/host/data/App.DeveloperKit.CustomComponents.json` dosyasına senkronlanır. Yetkiler `App.DeveloperKit.CustomComponents{,.Create,.Update,.Delete}`. |
|
||||
| **Visual Designer** | Component editörü içinde | Sürükle-bırak kanvas ile bileşen üretimi ve kod üretimi (`visualDesigner/codeGenerator.ts`). |
|
||||
| **Custom Component** | `/admin/list/App.DeveloperKit.CustomComponents` | React bileşenini veritabanında saklama; `@babel/standalone` ile tarayıcıda derleyip route'a bağlama. Liste bir ListForm ekranıdır (KPI şeridi, ızgara/kart görünümü, grid'in kendi ekleme/düzenleme formu); satırdaki **Design** butonu `/admin/developerkit/components/design/{id}` tasarımcısını, **Open URL** butonu bileşenin `RoutePath`'ini açar. Kayıtlar `configs/seeds/host/data/App.DeveloperKit.CustomComponents.json` dosyasına senkronlanır. Yetkiler `App.DeveloperKit.CustomComponents{,.Create,.Update,.Delete,.Export,.Import}`. |
|
||||
| **Visual Designer** | `/admin/developerkit/components/design/:id` | Custom Component listesindeki **Design** butonundan açılır; sürükle-bırak kanvas ile bileşen üretimi ve kod üretimi (`visualDesigner/codeGenerator.ts`). |
|
||||
| **ListForm** | `/admin/list/App.Listforms.Listform` | Var olan ekranların ham tanım listesi; buradan `/admin/listform/edit/{kod}` sekmeli editörüne geçilir. |
|
||||
| **Wizard Manager** | `/admin/listform/wizardManager` | Üretilmiş wizard seed dosyalarının listesi/kartı, düzenleme, silme, DB migrate, export/import. Yetki `App.Listforms.Wizard{,.Create,.Update,.Delete,.Export,.Import}`. |
|
||||
|
||||
|
|
@ -783,7 +783,7 @@ içindedir; oradaki kontroller yalnızca butonları gizler, asıl kontrol AppSer
|
|||
| Grup | Alt yetkiler |
|
||||
| --- | --- |
|
||||
| `App.Listforms.Wizard` | `.Create`, `.Update`, `.Delete`, `.Export`, `.Import` |
|
||||
| `App.DeveloperKit.CustomComponents` | `.Create`, `.Update`, `.Delete` |
|
||||
| `App.DeveloperKit.CustomComponents` | `.Create`, `.Update`, `.Delete`, `.Export`, `.Import` |
|
||||
| `App.DeveloperKit.CustomEndpoints` | `.Get`, `.Post`, `.Put`, `.Remove` (dispatcher üzerinden çağrı kapısı; endpoint bazlı User/Role/Global kuralları bunun üstünde denetlenir) |
|
||||
| `App.DeveloperKit.DynamicServices` | `.Create`, `.Edit`, `.Delete`, `.Manage`, `.TestCompile`, `.Publish`, `.ViewCode` |
|
||||
| `App.SqlQueryManager` | `.CrudEndpoints` |
|
||||
|
|
@ -1197,9 +1197,12 @@ derlenip yayınlanır. Yeni bir modülün nasıl kurulacağını öğrenmek içi
|
|||
- `LanguagesData.json` — dil anahtarları (EN/TR)
|
||||
- `WizardDataSeeder.cs`, `CrudDataSeeder.cs` — aşağıdaki
|
||||
runtime seed dosyalarını okuyup uygulayan seeder'lar
|
||||
- `ListFormSeedDataApplier` (`Domain/Data/`) — bütün contributor'lar bittikten sonra
|
||||
`data/{ListFormCode}.json` dosyalarını uygular
|
||||
|
||||
**2. Runtime'da üretilen seed'ler** — `configs/seeds/`. Wizard, Custom Components ekranı/Visual
|
||||
Designer ve CRUD Endpoint Manager çalışma zamanında burayı yazar; veritabanı silinip yeniden oluşturulduğunda aynı dosyalar
|
||||
Designer, CRUD Endpoint Manager ve `SeedFilePath` tanımlı ListForm ekranları çalışma zamanında
|
||||
burayı yazar; veritabanı silinip yeniden oluşturulduğunda aynı dosyalar
|
||||
geri yüklenir. Kapsam klasörü CDN düzeniyle aynıdır ve `SeedPathResolver` üzerinden çözülür:
|
||||
|
||||
```
|
||||
|
|
@ -1207,6 +1210,7 @@ configs/seeds/
|
|||
├── host/ # host kapsamı
|
||||
│ ├── wizard/ # {Ad}.json → WizardDataSeeder
|
||||
│ ├── crud/ # {EntityName}.json → CrudDataSeeder
|
||||
│ ├── data/ # {ListFormCode}.json → ListFormSeedDataApplier
|
||||
│ ├── sql/{object,execute}/ # .sql (SQL Server)
|
||||
│ └── postgres/{object,execute}/
|
||||
├── tenants/{tenantId}/… # aynı düzen, tenant kapsamı
|
||||
|
|
|
|||
|
|
@ -18,9 +18,10 @@ import { SelectBoxOption } from '@/types/shared'
|
|||
import { useStoreActions, useStoreState } from '@/store'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
import { Field, FieldProps, Form, Formik } from 'formik'
|
||||
import CreatableSelect from 'react-select/creatable'
|
||||
import { Dispatch, SetStateAction, useEffect, useState } from 'react'
|
||||
import { number, object, string } from 'yup'
|
||||
import { commandButtonPositionTypeOptions, urlOptions } from '../options'
|
||||
import { commandButtonIconOptions, commandButtonPositionTypeOptions, urlOptions } from '../options'
|
||||
import { JsonRowDialogData } from './types'
|
||||
import {
|
||||
deleteListFormJsonRow,
|
||||
|
|
@ -248,13 +249,34 @@ function JsonRowOpDialogCommand({
|
|||
invalid={errors.icon && touched.icon}
|
||||
errorMessage={errors.icon}
|
||||
>
|
||||
<Field
|
||||
type="text"
|
||||
autoComplete="off"
|
||||
name="icon"
|
||||
<Field type="text" autoComplete="off" name="icon" placeholder="Icon">
|
||||
{({ field, form }: FieldProps<string>) => (
|
||||
<Select
|
||||
field={field}
|
||||
form={form}
|
||||
isClearable={true}
|
||||
componentAs={CreatableSelect}
|
||||
placeholder="Icon"
|
||||
component={Input}
|
||||
options={commandButtonIconOptions}
|
||||
value={
|
||||
values.icon
|
||||
? (commandButtonIconOptions.find(
|
||||
(option) => option.value === values.icon,
|
||||
) ?? { value: values.icon, label: values.icon })
|
||||
: null
|
||||
}
|
||||
formatOptionLabel={(option: SelectBoxOption) => (
|
||||
<span className="flex items-center gap-2">
|
||||
<i className={`dx-icon dx-icon-${option.value}`} />
|
||||
{option.label}
|
||||
</span>
|
||||
)}
|
||||
onChange={(option: SelectBoxOption | null) =>
|
||||
form.setFieldValue(field.name, option?.value ?? '')
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
</FormItem>
|
||||
<FormItem
|
||||
label="Is Visible"
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import {
|
|||
} from '../../../../proxy/admin/list-form-field/models'
|
||||
import { enumToList } from '../../../../utils/enumUtils'
|
||||
import { PREFIX } from '@/constants/theme.constant'
|
||||
import { SelectBoxOption } from '@/types/shared'
|
||||
|
||||
export enum WidgetColorEnum {
|
||||
'Blue' = 'blue',
|
||||
|
|
@ -696,3 +697,112 @@ export const styleMapOptions = enumToList<string>(StyleEnum).map((opt) => ({
|
|||
...opt,
|
||||
color: styleColorMap[opt.value],
|
||||
}))
|
||||
|
||||
/**
|
||||
* Grid/Toolbar komut butonlarının ikon seçenekleri. Değerler DevExtreme ikon
|
||||
* adlarıdır (`dx-icon-<ad>`); butonlar ikonu doğrudan bu adla çizer.
|
||||
*/
|
||||
export const commandButtonIconOptions: SelectBoxOption[] = [
|
||||
'add',
|
||||
'plus',
|
||||
'minus',
|
||||
'remove',
|
||||
'trash',
|
||||
'edit',
|
||||
'save',
|
||||
'undo',
|
||||
'revert',
|
||||
'refresh',
|
||||
'clear',
|
||||
'close',
|
||||
'check',
|
||||
'apply',
|
||||
'checklist',
|
||||
'copy',
|
||||
'paste',
|
||||
'cut',
|
||||
'search',
|
||||
'find',
|
||||
'filter',
|
||||
'sorted',
|
||||
'columnchooser',
|
||||
'fields',
|
||||
'preferences',
|
||||
'card',
|
||||
'detailslayout',
|
||||
'contentlayout',
|
||||
'menu',
|
||||
'more',
|
||||
'overflow',
|
||||
'export',
|
||||
'exportpdf',
|
||||
'exportxlsx',
|
||||
'exportselected',
|
||||
'import',
|
||||
'upload',
|
||||
'download',
|
||||
'doc',
|
||||
'docfile',
|
||||
'docxfile',
|
||||
'pdffile',
|
||||
'xlsfile',
|
||||
'xlsxfile',
|
||||
'csv',
|
||||
'file',
|
||||
'folder',
|
||||
'print',
|
||||
'email',
|
||||
'message',
|
||||
'comment',
|
||||
'bell',
|
||||
'share',
|
||||
'link',
|
||||
'globe',
|
||||
'home',
|
||||
'user',
|
||||
'group',
|
||||
'key',
|
||||
'lock',
|
||||
'unlock',
|
||||
'verticalaligntop',
|
||||
'chart',
|
||||
'datapie',
|
||||
'datausage',
|
||||
'money',
|
||||
'cart',
|
||||
'product',
|
||||
'box',
|
||||
'photo',
|
||||
'image',
|
||||
'video',
|
||||
'attach',
|
||||
'clock',
|
||||
'event',
|
||||
'todo',
|
||||
'runner',
|
||||
'repeat',
|
||||
'info',
|
||||
'help',
|
||||
'warning',
|
||||
'errorcircle',
|
||||
'checkmarkcircle',
|
||||
'favorites',
|
||||
'like',
|
||||
'pin',
|
||||
'map',
|
||||
'tel',
|
||||
'back',
|
||||
'chevronleft',
|
||||
'chevronright',
|
||||
'chevrondown',
|
||||
'chevronup',
|
||||
'arrowleft',
|
||||
'arrowright',
|
||||
'arrowup',
|
||||
'arrowdown',
|
||||
'expand',
|
||||
'collapse',
|
||||
'fullscreen',
|
||||
'hierarchy',
|
||||
'floppy',
|
||||
].map((icon) => ({ value: icon, label: icon }))
|
||||
|
|
|
|||
|
|
@ -1,21 +1,13 @@
|
|||
import { Badge, Button, Dialog, Notification, toast } from '@/components/ui'
|
||||
import { useNavigationIcons } from '@/proxy/menus/navigation-icon.config'
|
||||
import { Button, Dialog, Notification, toast } from '@/components/ui'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
import CustomStore from 'devextreme/data/custom_store'
|
||||
import Toolbar from 'devextreme-react/toolbar'
|
||||
import type { dxToolbarItem as DxToolbarItem } from 'devextreme/ui/toolbar'
|
||||
import { useState } from 'react'
|
||||
import {
|
||||
FaChevronLeft,
|
||||
FaTrashAlt,
|
||||
FaPlusCircle,
|
||||
FaPencilAlt,
|
||||
FaEye,
|
||||
FaSave,
|
||||
FaCog,
|
||||
FaSistrix,
|
||||
} from 'react-icons/fa'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { GridColumnData } from '../list/GridColumnData'
|
||||
import { isWorkflowToolbarItemDisabled, useToolbar } from '../list/useToolbar'
|
||||
import { orderListToolbarItems } from '../list/toolbarOrder'
|
||||
import { PermissionResults, RowMode } from './types'
|
||||
import { GridDto } from '@/proxy/form/models'
|
||||
import { ROUTES_ENUM } from '@/routes/route.constant'
|
||||
|
|
@ -162,99 +154,82 @@ const FormButtons = (props: {
|
|||
}
|
||||
}
|
||||
|
||||
const navigationIcon = useNavigationIcons()
|
||||
|
||||
const toolbarExcludedNames = ['deleteAllRecords', 'deleteSelectedRecords', 'refreshButton']
|
||||
const hasVisibleToolbarButtons = toolbarData?.some(isToolbarButtonVisible)
|
||||
|
||||
const commandExcludedNames = ['edit', 'delete', 'detail']
|
||||
const hasVisibleCommandButtons = commandColumnData?.buttons?.some(isCommandButtonVisible)
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="flex flex-row items-center gap-1">
|
||||
{toolbarData
|
||||
?.filter(isToolbarButtonVisible)
|
||||
.map((item, i) => {
|
||||
const IconComp = navigationIcon[item.options?.icon]
|
||||
const hasValidIcon =
|
||||
IconComp &&
|
||||
(typeof IconComp === 'function' ||
|
||||
(typeof IconComp === 'object' && 'render' in IconComp))
|
||||
/** Grid toolbar sozlesmesiyle ayni bicimde bir dxButton ogesi uretir. */
|
||||
const buildButtonItem = (
|
||||
icon: string,
|
||||
text: string,
|
||||
onClick: (e: any) => void,
|
||||
disabled = false,
|
||||
): DxToolbarItem => ({
|
||||
location: 'after',
|
||||
widget: 'dxButton',
|
||||
locateInMenu: 'auto',
|
||||
showText: 'always',
|
||||
options: { icon, text, hint: text, disabled, onClick },
|
||||
})
|
||||
|
||||
return (
|
||||
<Button
|
||||
key={'toolbarButton-' + i}
|
||||
variant="default"
|
||||
size="sm"
|
||||
icon={hasValidIcon ? <IconComp className="text-gray-400" /> : null}
|
||||
disabled={isToolbarButtonDisabled(item)}
|
||||
onClick={(e) => item.options?.onClick?.({ ...e, ...rowEvent })}
|
||||
>
|
||||
{item.options?.text}
|
||||
</Button>
|
||||
)
|
||||
})}
|
||||
const toolbarItems: DxToolbarItem[] = [
|
||||
// Liste toolbar'indan gelen ozel butonlar; grid ile ayni sirayi korur.
|
||||
...orderListToolbarItems(toolbarData?.filter(isToolbarButtonVisible) ?? []).map(
|
||||
(item): DxToolbarItem => ({
|
||||
location: 'after',
|
||||
widget: 'dxButton',
|
||||
locateInMenu: 'auto',
|
||||
showText: 'always',
|
||||
options: {
|
||||
...item.options,
|
||||
// Gorunurluk zaten filtrelendi; DX'e fonksiyon gecilmemeli.
|
||||
visible: true,
|
||||
disabled: isToolbarButtonDisabled(item),
|
||||
onClick: (e: any) => item.options?.onClick?.({ ...e, ...rowEvent }),
|
||||
},
|
||||
}),
|
||||
),
|
||||
|
||||
{hasVisibleToolbarButtons && <Badge innerClass="bg-blue-500" />}
|
||||
// Komut kolonundan toolbar'a tasinan butonlar.
|
||||
...(commandColumnData?.buttons?.filter(isCommandButtonVisible) ?? []).map(
|
||||
(item: any): DxToolbarItem => ({
|
||||
location: 'after',
|
||||
widget: 'dxButton',
|
||||
locateInMenu: 'auto',
|
||||
showText: 'always',
|
||||
options: {
|
||||
icon: item.icon,
|
||||
text: item.text,
|
||||
hint: item.hint ?? item.text,
|
||||
onClick: (e: any) => item.onClick?.({ ...e, ...rowEvent }),
|
||||
},
|
||||
}),
|
||||
),
|
||||
]
|
||||
|
||||
{commandColumnData?.buttons
|
||||
?.filter(isCommandButtonVisible)
|
||||
.map((item: any, i) => {
|
||||
return (
|
||||
<Button
|
||||
key={'commandColumnButton-' + i}
|
||||
variant="default"
|
||||
size="sm"
|
||||
title={item.hint}
|
||||
onClick={(e: any) => {
|
||||
if (item.onClick) {
|
||||
item.onClick({ ...e, ...rowEvent })
|
||||
}
|
||||
}}
|
||||
>
|
||||
{item.text}
|
||||
</Button>
|
||||
)
|
||||
})}
|
||||
|
||||
{hasVisibleCommandButtons && <Badge innerClass="bg-blue-500" />}
|
||||
|
||||
{!isSubForm && (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="default"
|
||||
icon={<FaChevronLeft />}
|
||||
title={translate('::App.Platform.Cancel')}
|
||||
onClick={() => {
|
||||
if (!isSubForm) {
|
||||
toolbarItems.push(
|
||||
buildButtonItem('back', translate('::App.Platform.Cancel'), () => {
|
||||
if (onActionView && id) {
|
||||
onActionView()
|
||||
} else {
|
||||
navigate(-1)
|
||||
}
|
||||
}}
|
||||
></Button>
|
||||
)}
|
||||
{mode != 'new' && (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="solid"
|
||||
icon={<FaTrashAlt />}
|
||||
title={translate('::App.Platform.Delete')}
|
||||
onClick={() => {
|
||||
setDeleteRowId(id)
|
||||
}}
|
||||
{...(permissions.d ? {} : { disabled: true })}
|
||||
></Button>
|
||||
)}
|
||||
{mode != 'new' && (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="solid"
|
||||
color='blue-500'
|
||||
icon={<FaPlusCircle />}
|
||||
title={translate('::App.Platform.AddNew')}
|
||||
onClick={() => {
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
if (mode !== 'new') {
|
||||
toolbarItems.push(
|
||||
buildButtonItem(
|
||||
'trash',
|
||||
translate('::App.Platform.Delete'),
|
||||
() => setDeleteRowId(id),
|
||||
!permissions.d,
|
||||
),
|
||||
buildButtonItem(
|
||||
'add',
|
||||
translate('::App.Platform.AddNew'),
|
||||
() => {
|
||||
if (onActionNew) {
|
||||
onActionNew()
|
||||
} else {
|
||||
|
|
@ -265,18 +240,18 @@ const FormButtons = (props: {
|
|||
),
|
||||
)
|
||||
}
|
||||
}}
|
||||
{...(permissions.c ? {} : { disabled: true })}
|
||||
></Button>
|
||||
)}
|
||||
{mode == 'view' && (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="solid"
|
||||
color="green-600"
|
||||
icon={<FaPencilAlt />}
|
||||
title={translate('::App.Platform.Edit')}
|
||||
onClick={() => {
|
||||
},
|
||||
!permissions.c,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
if (mode === 'view') {
|
||||
toolbarItems.push(
|
||||
buildButtonItem(
|
||||
'edit',
|
||||
translate('::App.Platform.Edit'),
|
||||
() => {
|
||||
if (onActionEdit) {
|
||||
onActionEdit()
|
||||
} else {
|
||||
|
|
@ -286,18 +261,18 @@ const FormButtons = (props: {
|
|||
.replace(':id', encodeURIComponent(id!)),
|
||||
)
|
||||
}
|
||||
}}
|
||||
{...(permissions.u ? {} : { disabled: true })}
|
||||
></Button>
|
||||
)}
|
||||
{(mode == 'edit' || (onActionView && mode == 'new')) && (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="solid"
|
||||
color="gray-500"
|
||||
icon={<FaEye />}
|
||||
title={translate('::App.Platform.Detail')}
|
||||
onClick={() => {
|
||||
},
|
||||
!permissions.u,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
if (mode === 'edit' || (onActionView && mode === 'new')) {
|
||||
toolbarItems.push(
|
||||
buildButtonItem(
|
||||
'eyeopen',
|
||||
translate('::App.Platform.Detail'),
|
||||
() => {
|
||||
if (onActionView) {
|
||||
onActionView()
|
||||
} else {
|
||||
|
|
@ -307,38 +282,36 @@ const FormButtons = (props: {
|
|||
.replace(':id', encodeURIComponent(id!)),
|
||||
)
|
||||
}
|
||||
}}
|
||||
{...(permissions.r ? {} : { disabled: true })}
|
||||
></Button>
|
||||
)}
|
||||
{(mode == 'edit' || mode == 'new') && (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="solid"
|
||||
icon={<FaSave />}
|
||||
title={translate('::App.Platform.Save')}
|
||||
onClick={handleSubmit}
|
||||
{...(permissions.c || permissions.u ? {} : { disabled: true })}
|
||||
></Button>
|
||||
)}
|
||||
{id && !isSubForm && (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="solid"
|
||||
color="purple-500"
|
||||
icon={<FaSistrix />}
|
||||
title={translate('::App.Reports.Form')}
|
||||
onClick={openDynamicGridReport}
|
||||
></Button>
|
||||
)}
|
||||
{checkPermission('App.Listforms.Listform.Update') && !isSubForm && (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="solid"
|
||||
icon={<FaCog />}
|
||||
color="green-500"
|
||||
title={translate('::App.Platform.Manage')}
|
||||
onClick={() => {
|
||||
},
|
||||
!permissions.r,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
if (mode === 'edit' || mode === 'new') {
|
||||
toolbarItems.push(
|
||||
buildButtonItem(
|
||||
'save',
|
||||
translate('::App.Platform.Save'),
|
||||
handleSubmit,
|
||||
!(permissions.c || permissions.u),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
if (id && !isSubForm) {
|
||||
toolbarItems.push(
|
||||
buildButtonItem(
|
||||
'doc',
|
||||
translate('::App.Reports.Form'),
|
||||
openDynamicGridReport,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
if (checkPermission('App.Listforms.Listform.Update') && !isSubForm) {
|
||||
toolbarItems.push(
|
||||
buildButtonItem('preferences', translate('::App.Platform.Manage'), () => {
|
||||
window.open(
|
||||
ROUTES_ENUM.protected.saas.listFormManagement.edit.replace(
|
||||
':listFormCode',
|
||||
|
|
@ -346,10 +319,13 @@ const FormButtons = (props: {
|
|||
),
|
||||
isPwaMode ? '_self' : '_blank',
|
||||
)
|
||||
}}
|
||||
></Button>
|
||||
)}
|
||||
</div>
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Toolbar className="list-view-toolbar-host flex-1" items={toolbarItems} />
|
||||
<Dialog
|
||||
isOpen={toolbarModalData?.open || false}
|
||||
onClose={() => setToolbarModalData(undefined)}
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ const Blog: React.FC = () => {
|
|||
value={searchQuery}
|
||||
placeholder={translateLabel(translate, 'App.PublicBlog.SearchPlaceholder')}
|
||||
aria-label={translate('::App.Platform.Search3')}
|
||||
className="w-full rounded-lg border border-gray-300 bg-white py-2 pl-10 text-gray-900 placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-blue-500 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-100 dark:placeholder-gray-400"
|
||||
className="rounded-lg border border-gray-300 bg-white py-2 pl-10 text-gray-900 placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-blue-500 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-100 dark:placeholder-gray-400"
|
||||
onChange={(event) => setSearchQuery(event.target.value)}
|
||||
/>
|
||||
<FaSearch className="absolute left-3 top-2.5 h-5 w-5 text-gray-400" />
|
||||
|
|
|
|||
Loading…
Reference in a new issue