mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-17 15:53:28 +00:00
feat: metadata shooting time
This commit is contained in:
39
frontend/package-lock.json
generated
39
frontend/package-lock.json
generated
@@ -17,9 +17,9 @@
|
||||
"@seafile/react-image-lightbox": "3.0.0",
|
||||
"@seafile/resumablejs": "1.1.16",
|
||||
"@seafile/sdoc-editor": "1.0.81",
|
||||
"@seafile/seafile-calendar": "0.0.12",
|
||||
"@seafile/seafile-calendar": "0.0.25",
|
||||
"@seafile/seafile-editor": "^1.0.116",
|
||||
"@seafile/sf-metadata-ui-component": "^0.0.32",
|
||||
"@seafile/sf-metadata-ui-component": "^0.0.33",
|
||||
"@uiw/codemirror-extensions-langs": "^4.19.4",
|
||||
"@uiw/react-codemirror": "^4.19.4",
|
||||
"axios": "^1.7.4",
|
||||
@@ -4969,19 +4969,24 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@seafile/seafile-calendar": {
|
||||
"version": "0.0.12",
|
||||
"resolved": "https://registry.npmjs.org/@seafile/seafile-calendar/-/seafile-calendar-0.0.12.tgz",
|
||||
"integrity": "sha512-TvttWwuZqDz2+Tvy4k3SeXDRbAjWmIw5BvJVeZkEzwuuFz2DB9TYucwT0tAWSSdzuRcD5jr42Y0V09D54Lig+Q==",
|
||||
"version": "0.0.25",
|
||||
"resolved": "https://registry.npmjs.org/@seafile/seafile-calendar/-/seafile-calendar-0.0.25.tgz",
|
||||
"integrity": "sha512-d6whp7NfKTjD021AEZYaTTrAipKsWqE736b3r1s6ID6XLxPsBitoGgbzeMK3wDLq0iBPQi9MokHif+8L3Kxq7g==",
|
||||
"dependencies": {
|
||||
"babel-runtime": "6.x",
|
||||
"classnames": "2.x",
|
||||
"moment": "2.x",
|
||||
"dayjs": "1.10.7",
|
||||
"prop-types": "^15.5.8",
|
||||
"rc-trigger": "^2.2.0",
|
||||
"rc-util": "^4.1.1",
|
||||
"react-lifecycles-compat": "^3.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@seafile/seafile-calendar/node_modules/dayjs": {
|
||||
"version": "1.10.7",
|
||||
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.7.tgz",
|
||||
"integrity": "sha512-P6twpd70BcPK34K26uJ1KT3wlhpuOAPoMwJzpsIWUxHZ7wpmbdZL/hQqBDfz7hGurYSa5PhzdhDHtt319hL3ig=="
|
||||
},
|
||||
"node_modules/@seafile/seafile-editor": {
|
||||
"version": "1.0.116",
|
||||
"resolved": "https://registry.npmjs.org/@seafile/seafile-editor/-/seafile-editor-1.0.116.tgz",
|
||||
@@ -5093,11 +5098,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@seafile/sf-metadata-ui-component": {
|
||||
"version": "0.0.32",
|
||||
"resolved": "https://registry.npmjs.org/@seafile/sf-metadata-ui-component/-/sf-metadata-ui-component-0.0.32.tgz",
|
||||
"integrity": "sha512-7Np8syp2YoauqaDhd6i6VXalA1XLAmvertdz/Uo1tvFl5xZTECjbi1ywjEosJqM6ej5W6TfvXjc/yvGDwxXoxQ==",
|
||||
"version": "0.0.33",
|
||||
"resolved": "https://registry.npmjs.org/@seafile/sf-metadata-ui-component/-/sf-metadata-ui-component-0.0.33.tgz",
|
||||
"integrity": "sha512-utCWgOCNPGr5w56+I+SfB60XJA1Amxfo8jfHELHiJG+hzp5bKNXvq6XQ9ampS/rVzzvwUFuCahOURyiQOx9hKw==",
|
||||
"dependencies": {
|
||||
"@seafile/seafile-calendar": "0.0.24",
|
||||
"@seafile/seafile-calendar": "0.0.25",
|
||||
"@seafile/seafile-editor": "~1.0.102",
|
||||
"classnames": "2.3.2",
|
||||
"dayjs": "1.10.7",
|
||||
@@ -5120,20 +5125,6 @@
|
||||
"react-dom": "17.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@seafile/sf-metadata-ui-component/node_modules/@seafile/seafile-calendar": {
|
||||
"version": "0.0.24",
|
||||
"resolved": "https://registry.npmjs.org/@seafile/seafile-calendar/-/seafile-calendar-0.0.24.tgz",
|
||||
"integrity": "sha512-q1efVDcHAxJ2foMgsR8mQPD6Fbd6ISu2WHRM82P7tO0KPiQNS5pz9V0YVCblgi7da085jaog2iAplJM+vH7xLQ==",
|
||||
"dependencies": {
|
||||
"babel-runtime": "6.x",
|
||||
"classnames": "2.x",
|
||||
"dayjs": "1.10.7",
|
||||
"prop-types": "^15.5.8",
|
||||
"rc-trigger": "^2.2.0",
|
||||
"rc-util": "^4.1.1",
|
||||
"react-lifecycles-compat": "^3.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@seafile/sf-metadata-ui-component/node_modules/classnames": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz",
|
||||
|
@@ -12,9 +12,9 @@
|
||||
"@seafile/react-image-lightbox": "3.0.0",
|
||||
"@seafile/resumablejs": "1.1.16",
|
||||
"@seafile/sdoc-editor": "1.0.81",
|
||||
"@seafile/seafile-calendar": "0.0.12",
|
||||
"@seafile/seafile-calendar": "0.0.25",
|
||||
"@seafile/seafile-editor": "^1.0.116",
|
||||
"@seafile/sf-metadata-ui-component": "^0.0.32",
|
||||
"@seafile/sf-metadata-ui-component": "^0.0.33",
|
||||
"@uiw/codemirror-extensions-langs": "^4.19.4",
|
||||
"@uiw/react-codemirror": "^4.19.4",
|
||||
"axios": "^1.7.4",
|
||||
|
@@ -103,10 +103,15 @@ const MetadataDetails = ({ repoID, filePath, repoInfo, direntType }) => {
|
||||
if (isLoading) return null;
|
||||
const { fields, record } = metadata;
|
||||
if (!record._id) return null;
|
||||
const fileName = record[PRIVATE_COLUMN_KEY.FILE_NAME];
|
||||
const isImage = record && (Utils.imageCheck(fileName) || Utils.videoCheck(fileName));
|
||||
return (
|
||||
<>
|
||||
{fields.map(field => {
|
||||
const canEdit = permission === 'rw' && field.editable;
|
||||
let canEdit = permission === 'rw' && field.editable;
|
||||
if (!isImage && canEdit && field.key === PRIVATE_COLUMN_KEY.SHOOTING_TIME) {
|
||||
canEdit = false;
|
||||
}
|
||||
const value = getCellValueByColumn(record, field);
|
||||
return (
|
||||
<DetailItem key={field.key} field={field} readonly={!canEdit}>
|
||||
|
@@ -40,11 +40,17 @@ const DateData = ({ value, onChange }) => {
|
||||
const onMinuteChange = useCallback((v) => {
|
||||
let newFormat = format || 'YYYY-MM-DD';
|
||||
const formats = format.split(' ');
|
||||
if (formats.length === 1) newFormat = format + ' HH:mm';
|
||||
if (formats.length === 1) newFormat = formats[0] + ' HH:mm';
|
||||
if (formats.length === 2) newFormat = formats[0];
|
||||
onChange({ format: newFormat });
|
||||
}, [format, onChange]);
|
||||
|
||||
const onSecondChange = useCallback((v) => {
|
||||
let newFormat = format || 'YYYY-MM-DD HH:mm';
|
||||
newFormat = format.indexOf('ss') === -1 ? newFormat + ':ss' : newFormat.slice(0, -3);
|
||||
onChange({ format: newFormat });
|
||||
}, [format, onChange]);
|
||||
|
||||
useEffect(() => {
|
||||
if (format) return;
|
||||
onChange({ format: 'YYYY-MM-DD' });
|
||||
@@ -52,6 +58,7 @@ const DateData = ({ value, onChange }) => {
|
||||
}, []);
|
||||
|
||||
const selectedValue = options.find(o => o.value === format) || options[0];
|
||||
const showMinute = format ? format.indexOf('HH:mm') > -1 : false;
|
||||
|
||||
return (
|
||||
<div className="sf-metadata-column-data-settings sf-metadata-date-column-data-settings">
|
||||
@@ -61,13 +68,23 @@ const DateData = ({ value, onChange }) => {
|
||||
</FormGroup>
|
||||
<div className="pb-4">
|
||||
<Switch
|
||||
checked={format ? format.indexOf('HH:mm') > -1 : false}
|
||||
checked={showMinute}
|
||||
size="large"
|
||||
textPosition="right"
|
||||
className="sf-metadata-date-column-data-minute w-100"
|
||||
onChange={onMinuteChange}
|
||||
placeholder={gettext('Accurate to minute')} />
|
||||
</div>
|
||||
<div className="pb-4">
|
||||
<Switch
|
||||
disabled={!showMinute}
|
||||
checked={format ? format.indexOf('HH:mm:ss') > -1 : false}
|
||||
size="large"
|
||||
textPosition="right"
|
||||
className="sf-metadata-date-column-data-minute w-100"
|
||||
onChange={onSecondChange}
|
||||
placeholder={gettext('Accurate to second')} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@@ -59,6 +59,14 @@ const COLUMNS = [
|
||||
key: PRIVATE_COLUMN_KEY.FILE_STATUS,
|
||||
canChangeName: false,
|
||||
groupby: 'predefined'
|
||||
}, {
|
||||
icon: COLUMNS_ICON_CONFIG[CellType.DATE],
|
||||
type: CellType.DATE,
|
||||
name: getColumnDisplayName(PRIVATE_COLUMN_KEY.SHOOTING_TIME),
|
||||
unique: true,
|
||||
key: PRIVATE_COLUMN_KEY.SHOOTING_TIME,
|
||||
canChangeName: false,
|
||||
groupby: 'predefined'
|
||||
}, {
|
||||
icon: COLUMNS_ICON_CONFIG[CellType.TEXT],
|
||||
type: CellType.TEXT,
|
||||
|
@@ -26,6 +26,7 @@ export const PRIVATE_COLUMN_KEY = {
|
||||
SIZE: '_size',
|
||||
SUFFIX: '_suffix',
|
||||
FILE_DETAILS: '_file_details',
|
||||
SHOOTING_TIME: '_shooting_time',
|
||||
};
|
||||
|
||||
export const PRIVATE_COLUMN_KEYS = [
|
||||
@@ -53,6 +54,7 @@ export const PRIVATE_COLUMN_KEYS = [
|
||||
PRIVATE_COLUMN_KEY.SIZE,
|
||||
PRIVATE_COLUMN_KEY.SUFFIX,
|
||||
PRIVATE_COLUMN_KEY.FILE_DETAILS,
|
||||
PRIVATE_COLUMN_KEY.SHOOTING_TIME,
|
||||
];
|
||||
|
||||
export const EDITABLE_PRIVATE_COLUMN_KEYS = [
|
||||
@@ -62,10 +64,11 @@ export const EDITABLE_PRIVATE_COLUMN_KEYS = [
|
||||
PRIVATE_COLUMN_KEY.FILE_DESCRIPTION,
|
||||
PRIVATE_COLUMN_KEY.FILE_EXPIRED,
|
||||
PRIVATE_COLUMN_KEY.FILE_STATUS,
|
||||
PRIVATE_COLUMN_KEY.SHOOTING_TIME,
|
||||
];
|
||||
|
||||
export const EDITABLE_DATA_PRIVATE_COLUMN_KEYS = [
|
||||
|
||||
PRIVATE_COLUMN_KEY.SHOOTING_TIME,
|
||||
];
|
||||
|
||||
export const DELETABLE_PRIVATE_COLUMN_KEY = [
|
||||
@@ -75,4 +78,5 @@ export const DELETABLE_PRIVATE_COLUMN_KEY = [
|
||||
PRIVATE_COLUMN_KEY.FILE_DESCRIPTION,
|
||||
PRIVATE_COLUMN_KEY.FILE_EXPIRED,
|
||||
PRIVATE_COLUMN_KEY.FILE_STATUS,
|
||||
PRIVATE_COLUMN_KEY.SHOOTING_TIME,
|
||||
];
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import metadataAPI from './api';
|
||||
import {
|
||||
PRIVATE_COLUMN_KEYS, EDITABLE_DATA_PRIVATE_COLUMN_KEYS, EDITABLE_PRIVATE_COLUMN_KEYS, PREDEFINED_COLUMN_KEYS,
|
||||
PRIVATE_COLUMN_KEYS, EDITABLE_DATA_PRIVATE_COLUMN_KEYS, EDITABLE_PRIVATE_COLUMN_KEYS, DELETABLE_PRIVATE_COLUMN_KEY,
|
||||
} from './constants';
|
||||
import LocalStorage from './utils/local-storage';
|
||||
import EventBus from '../components/common/event-bus';
|
||||
@@ -133,7 +133,7 @@ class Context {
|
||||
canDeleteColumn = (column) => {
|
||||
if (this.permission === 'r') return false;
|
||||
const { key } = column;
|
||||
if (PRIVATE_COLUMN_KEYS.includes(key)) return PREDEFINED_COLUMN_KEYS.includes(key);
|
||||
if (PRIVATE_COLUMN_KEYS.includes(key)) return DELETABLE_PRIVATE_COLUMN_KEY.includes(key);
|
||||
return true;
|
||||
};
|
||||
|
||||
|
@@ -27,10 +27,19 @@ const getDateDisplayString = (date, format) => {
|
||||
const formatDateList = formatValuesList[0].split('-');
|
||||
return `${formatDateList[2]}/${formatDateList[1]}/${formatDateList[0]} ${formatValuesList[1]}`;
|
||||
}
|
||||
case 'D/M/YYYY HH:mm:ss':
|
||||
case 'DD/MM/YYYY HH:mm:ss': {
|
||||
const formatValues = dateObj.format('YYYY-MM-DD HH:mm:ss');
|
||||
const formatValuesList = formatValues.split(' ');
|
||||
const formatDateList = formatValuesList[0].split('-');
|
||||
return `${formatDateList[2]}/${formatDateList[1]}/${formatDateList[0]} ${formatValuesList[1]}`;
|
||||
}
|
||||
case 'M/D/YYYY':
|
||||
return dateObj.format('M/D/YYYY');
|
||||
case 'M/D/YYYY HH:mm':
|
||||
return dateObj.format('M/D/YYYY HH:mm');
|
||||
case 'M/D/YYYY HH:mm:ss':
|
||||
return dateObj.format('M/D/YYYY HH:mm:ss');
|
||||
case 'YYYY-MM-DD':
|
||||
return dateObj.format('YYYY-MM-DD');
|
||||
case 'YYYY-MM-DD HH:mm':
|
||||
@@ -42,6 +51,8 @@ const getDateDisplayString = (date, format) => {
|
||||
return dateObj.format('DD.MM.YYYY');
|
||||
case 'DD.MM.YYYY HH:mm':
|
||||
return dateObj.format('DD.MM.YYYY HH:mm');
|
||||
case 'DD.MM.YYYY HH:mm:ss':
|
||||
return dateObj.format('DD.MM.YYYY HH:mm:ss');
|
||||
case 'YYYY':
|
||||
return dateObj.format('YYYY');
|
||||
case 'YYYY-MM':
|
||||
|
@@ -200,6 +200,8 @@ export const getColumnDisplayName = (key, name) => {
|
||||
return gettext('Size');
|
||||
case PRIVATE_COLUMN_KEY.FILE_DETAILS:
|
||||
return gettext('File details');
|
||||
case PRIVATE_COLUMN_KEY.SHOOTING_TIME:
|
||||
return gettext('Shooting time');
|
||||
default:
|
||||
return name;
|
||||
}
|
||||
|
@@ -100,6 +100,7 @@ const HeaderDropdownMenu = ({ column, view, renameColumn, modifyColumnData, dele
|
||||
}, [column, renameColumn]);
|
||||
|
||||
const renderDateFormat = useCallback((canModifyColumnData) => {
|
||||
const { data = {} } = column;
|
||||
if (!canModifyColumnData) {
|
||||
return (
|
||||
<DropdownItem
|
||||
@@ -111,15 +112,14 @@ const HeaderDropdownMenu = ({ column, view, renameColumn, modifyColumnData, dele
|
||||
/>
|
||||
);
|
||||
}
|
||||
const { data = {} } = column;
|
||||
const { format = DEFAULT_DATE_FORMAT } = data;
|
||||
const withMinutes = format.indexOf('HH:mm') > -1;
|
||||
let timeUnit = format.split(' ')[1];
|
||||
|
||||
const options = [
|
||||
{ label: `${gettext('ISO')} (${getDateDisplayString(today, classnames('YYYY-MM-DD', { 'HH:mm': withMinutes }))})`, value: classnames('YYYY-MM-DD', { 'HH:mm': withMinutes }) },
|
||||
{ label: `${gettext('US')} (${getDateDisplayString(today, classnames('M/D/YYYY', { 'HH:mm': withMinutes }))})`, value: classnames('M/D/YYYY', { 'HH:mm': withMinutes }) },
|
||||
{ label: `${gettext('European')} (${getDateDisplayString(today, classnames('DD/MM/YYYY', { 'HH:mm': withMinutes }))})`, value: classnames('DD/MM/YYYY', { 'HH:mm': withMinutes }) },
|
||||
{ label: `${gettext('Germany Russia etc')} (${getDateDisplayString(today, classnames('DD.MM.YYYY', { 'HH:mm': withMinutes }))})`, value: classnames('DD.MM.YYYY', { 'HH:mm': withMinutes }) }
|
||||
{ label: `${gettext('ISO')} (${getDateDisplayString(today, classnames('YYYY-MM-DD', timeUnit))})`, value: classnames('YYYY-MM-DD', timeUnit) },
|
||||
{ label: `${gettext('US')} (${getDateDisplayString(today, classnames('M/D/YYYY', timeUnit))})`, value: classnames('M/D/YYYY', timeUnit) },
|
||||
{ label: `${gettext('European')} (${getDateDisplayString(today, classnames('DD/MM/YYYY', timeUnit))})`, value: classnames('DD/MM/YYYY', timeUnit) },
|
||||
{ label: `${gettext('Germany Russia etc')} (${getDateDisplayString(today, classnames('DD.MM.YYYY', timeUnit))})`, value: classnames('DD.MM.YYYY', timeUnit) }
|
||||
];
|
||||
|
||||
return (
|
||||
|
@@ -2,7 +2,7 @@ import { Utils } from '../../../../utils/utils';
|
||||
import { getCellValueByColumn } from '../../../utils/cell';
|
||||
import { getGroupByPath } from '../../../utils/view';
|
||||
import { getColumnByIndex, canEditCell } from '../../../utils/column';
|
||||
import { SUPPORT_PREVIEW_COLUMN_TYPES, metadataZIndexes } from '../../../constants';
|
||||
import { PRIVATE_COLUMN_KEY, SUPPORT_PREVIEW_COLUMN_TYPES, metadataZIndexes } from '../../../constants';
|
||||
import { getGroupRecordByIndex } from './group-metrics';
|
||||
|
||||
const SELECT_DIRECTION = {
|
||||
@@ -45,8 +45,13 @@ export const isSelectedCellEditable = ({ enableCellSelect, selectedPosition, col
|
||||
const column = getSelectedColumn({ selectedPosition, columns });
|
||||
const row = getSelectedRow({ selectedPosition, isGroupView, recordGetterByIndex });
|
||||
if (!window.sfMetadataContext.canModifyRow(row)) return false;
|
||||
const isCellEditable = Utils.isFunction(onCheckCellIsEditable) ? onCheckCellIsEditable({ row, column, ...selectedPosition }) : true;
|
||||
return isCellEditable && canEditCell(column, row, enableCellSelect);
|
||||
let isCellEditable = Utils.isFunction(onCheckCellIsEditable) ? onCheckCellIsEditable({ row, column, ...selectedPosition }) : true;
|
||||
const fileName = row ? row[PRIVATE_COLUMN_KEY.FILE_NAME] : '';
|
||||
const imageRow = row && (Utils.imageCheck(fileName) || Utils.videoCheck(fileName));
|
||||
isCellEditable = isCellEditable && canEditCell(column, row, enableCellSelect);
|
||||
if (imageRow) return isCellEditable;
|
||||
if (column?.key === PRIVATE_COLUMN_KEY.SHOOTING_TIME) return false;
|
||||
return isCellEditable;
|
||||
};
|
||||
|
||||
export function selectedRangeIsSingleCell(selectedRange) {
|
||||
|
Reference in New Issue
Block a user