Skip to content

Commit fb62d85

Browse files
fix media-manager
1 parent 1264db2 commit fb62d85

11 files changed

Lines changed: 91 additions & 23 deletions

File tree

fixture/adminizerConfig.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -525,7 +525,8 @@ const config: AdminpanelConfig = {
525525
options: {
526526
id: "default",
527527
group: 'form_global_images',
528-
accept: ['image/jpeg, image/png']
528+
initTab: "table-application",
529+
accept: ["application/pdf", "application/msword"]
529530
},
530531
value: null
531532
},

src/assets/js/components/field-renderer.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,10 @@ const FieldRenderer: FC<{
8989
}, [onChange, field.name])
9090

9191
const handleMediaChange = useCallback((mediaList: Media[]) => {
92-
const transformedData = mediaList.map(media => ({ id: media.id, url: media.url }))
92+
const transformedData = mediaList.map(media => (
93+
{
94+
id: media.id, url: media.url, mimeType: media.mimeType, filename: media.filename
95+
}))
9396
onChange(field.name, transformedData)
9497
}, [onChange, field.name])
9598

@@ -232,7 +235,8 @@ const FieldRenderer: FC<{
232235
if (field.options?.name === 'jsoneditor') {
233236
return (
234237
<JsonEditorLazy content={value as Content} name={`${field.type}-${field.name}`}
235-
onChange={handleJSONChange} {...field.options?.config} disabled={processing || field.disabled}
238+
onChange={handleJSONChange} {...field.options?.config}
239+
disabled={processing || field.disabled}
236240
/>
237241
)
238242
} else {
@@ -274,7 +278,8 @@ const FieldRenderer: FC<{
274278
}
275279
case 'mediamanager':
276280
return (
277-
<MediaLazy layout={Layout.Grid} value={value as Media[]} onChange={handleMediaChange} config={{...field.options}}/>
281+
<MediaLazy layout={Layout.Grid} value={value as Media[]} onChange={handleMediaChange}
282+
config={{...field.options}}/>
278283
)
279284
default:
280285
return (

src/assets/js/components/media-manager/Item.tsx

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,19 @@ export interface Props extends Omit<HTMLAttributes<HTMLButtonElement>, 'id'> {
2323
id: UniqueIdentifier;
2424
index?: number;
2525
url: string;
26+
fileName: string
27+
mimeType: string
2628
layout: Layout;
2729

2830
onRemove?(): void;
2931
}
3032

3133
export const Item = forwardRef<HTMLLIElement, Props>(function Page(
32-
{id, index, active, clone, insertPosition, layout, onRemove, style, url, ...props},
34+
{id, index, active, clone, insertPosition, layout, onRemove, style, url, mimeType, fileName, ...props},
3335
ref
3436
) {
37+
const isImage = mimeType?.startsWith('image/');
38+
3539
return (
3640
<li
3741
className={cn(
@@ -46,8 +50,16 @@ export const Item = forwardRef<HTMLLIElement, Props>(function Page(
4650
ref={ref}
4751
>
4852
<button className={`${styles.Page} after:bg-black dark:after:bg-gray-300`} data-id={id.toString()} {...props}>
49-
<img src={url} alt="" className="absolute top-0 left-0 w-full h-full object-cover overflow-hidden rounded-[5px]"/>
53+
<img src={url} alt="" className="absolute top-0 left-0 w-full h-full object-cover overflow-hidden rounded-[5px]" />
54+
55+
{/* Показываем имя файла, если это НЕ изображение */}
56+
{!isImage && (
57+
<div className="absolute inset-x-0 bottom-0 break-words text-white text-sm font-medium bg-black/75 h-[40%] rounded-b-[5px] p-2">
58+
{fileName}
59+
</div>
60+
)}
5061
</button>
62+
5163
{!active && onRemove ? (
5264
<button className={styles.Remove} onClick={onRemove}>
5365
{removeIcon}

src/assets/js/components/media-manager/components/DropZone.tsx

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,25 +18,52 @@ const DropZone: FC<DropZoneProps> = ({callback, messages}) => {
1818
const {uploadUrl, group, accept} = useContext(MediaManagerContext);
1919

2020
const handleClose = () => {
21-
setAlert('')
22-
}
21+
setAlert('');
22+
};
23+
24+
// Проверка, разрешён ли тип файла
25+
const isFileAllowed = (file: File): boolean => {
26+
const fileType = file.type;
27+
const fileName = file.name;
28+
29+
// Проверяем по MIME-типу или расширению
30+
return accept.some(type => {
31+
if (type.startsWith('.')) {
32+
return fileName.toLowerCase().endsWith(type.toLowerCase());
33+
} else if (type.endsWith('/*')) {
34+
const mainType = type.slice(0, -1); // 'image/*' -> 'image'
35+
return fileType.startsWith(mainType);
36+
} else {
37+
return fileType === type;
38+
}
39+
});
40+
};
2341

2442
const onDrop = async (e: React.DragEvent<HTMLDivElement>) => {
2543
e.preventDefault();
2644
e.stopPropagation();
2745
setLoading(true);
2846

29-
if (e.dataTransfer.files) {
30-
for (const file of e.dataTransfer.files) {
31-
await upload(file);
47+
const files = Array.from(e.dataTransfer.files);
48+
for (const file of files) {
49+
if (!isFileAllowed(file)) {
50+
setLoading(false);
51+
setAlert(messages[`File type not allowed`] || `File type not allowed: ${file.name}`);
52+
return; // Останавливаем загрузку
3253
}
54+
await upload(file);
3355
}
3456
};
3557

3658
const onLoad = async (e: React.ChangeEvent<HTMLInputElement>) => {
3759
e.stopPropagation();
3860
if (e.target.files) {
39-
for (const file of e.target.files) {
61+
const files = Array.from(e.target.files);
62+
for (const file of files) {
63+
if (!isFileAllowed(file)) {
64+
setAlert(`${messages[`File type are not supported`]} .${file.name.split('.').pop()?.toLowerCase()}`);
65+
return; // Останавливаем загрузку
66+
}
4067
setLoading(true);
4168
await upload(file);
4269
}

src/assets/js/components/media-manager/media-manager.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ const MediaManager = ({layout, config, onChange, value}: Props) => {
141141
}, []);
142142

143143
const addMediaWithCallback = useCallback((newMedia: Media) => {
144+
console.log(newMedia)
144145
setItems((prev) => {
145146
const newItems = [...prev, newMedia];
146147
if (onChange) onChange(newItems);
@@ -238,6 +239,8 @@ const MediaManager = ({layout, config, onChange, value}: Props) => {
238239
key={media.id}
239240
index={index}
240241
url={contextValue.imageUrl(media)}
242+
fileName={media.filename ?? ''}
243+
mimeType={media.mimeType ?? ''}
241244
layout={layout}
242245
activeIndex={activeIndex}
243246
onRemove={() => {
@@ -262,6 +265,8 @@ const MediaManager = ({layout, config, onChange, value}: Props) => {
262265
layout={layout}
263266
items={items}
264267
url={activeMedia ? contextValue.imageUrl(activeMedia) : ''}
268+
fileName={activeMedia?.filename ? activeMedia.filename ?? '' : ''}
269+
mimeType={activeMedia?.mimeType ? activeMedia.mimeType ?? '' : ''}
265270
/>
266271
) : null}
267272
</DragOverlay>

src/controllers/media-manager/mediaManagerAdapter.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,8 @@ export class MediaManagerAdapter {
9595
"No variants found": "",
9696
"Actions": "",
9797
"Yes": "",
98-
"No": ""
98+
"No": "",
99+
'File type are not supported': ""
99100
};
100101

101102
return Object.fromEntries(

src/lib/media-manager/AbstractMediaManager.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export interface MediaManagerWidgetClientItem extends MediaManagerWidgetItem {
4141
*/
4242
mimeType: string;
4343
variants: MediaManagerItem[];
44+
filename: string;
4445
url?: string;
4546
}
4647

src/lib/media-manager/DefaultMediaManager.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ export class DefaultMediaManager extends AbstractMediaManager {
124124
widgetItems.push({
125125
id: file[fieldName].id,
126126
mimeType: file[fieldName].mimeType,
127+
filename: file[fieldName].filename,
127128
url: file[fieldName].url,
128129
variants: []
129130
})

src/lib/model/adapter/waterline.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,16 +41,29 @@ export class WaterlineModel<T> extends AbstractModel<T> {
4141
return await query;
4242
}
4343

44-
protected async _find(criteria: Partial<T> = {}, options: FindOptions = {}): Promise<T[]> {
44+
protected async _find(criteria: Partial<any> = {}, options: FindOptions = {}): Promise<T[]> {
4545

4646
// Hack
4747
const attributes = this.model.attributes;
4848
const associations = Object.keys(attributes).filter(
4949
attr => attributes[attr].model || attributes[attr].collection
5050
);
5151

52-
//@ts-ignore
53-
if(associations.includes(criteria?.sort?.split(' ')[0]) && JSON.stringify(criteria.where) === '{}') criteria.sort = undefined
52+
if (JSON.stringify(criteria.where) === '{}') {
53+
let sortField;
54+
55+
if (criteria?.sort) {
56+
if (typeof criteria.sort === 'string') {
57+
sortField = criteria.sort.split(' ')[0];
58+
} else if (Array.isArray(criteria.sort)) {
59+
sortField = criteria.sort[0];
60+
}
61+
}
62+
63+
if (sortField && associations.includes(sortField)) {
64+
criteria.sort = undefined;
65+
}
66+
}
5467

5568
let query = this.model.find(criteria);
5669

src/translations/en.json

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
"Actions": "Actions",
44
"All": "All",
55
"Are you sure?": "Are you sure?",
6-
"Back": "Back",
7-
"Back to Login": "Back to Login",
8-
"Additional login page": "Additional login page",
9-
"Clean": "Clean",
6+
"Back": "Back",
7+
"Back to Login": "Back to Login",
8+
"Additional login page": "Additional login page",
9+
"Clean": "Clean",
1010
"Confirm Password": "Confirm Password",
1111
"Confirm Password*": "Confirm Password*",
1212
"Create": "Create",
@@ -139,5 +139,6 @@
139139
"W x H (orig.)": "W x H (orig.)",
140140
"Sizes/Ver": "Sizes/Ver",
141141
"Locales": "Locales",
142-
"Date": "Date"
143-
}
142+
"Date": "Date",
143+
"File type are not supported": "File type are not supported"
144+
}

0 commit comments

Comments
 (0)