diff --git a/cypress/e2e/column-datetime.cy.js b/cypress/e2e/column-datetime.cy.js new file mode 100644 index 000000000..716cda5ab --- /dev/null +++ b/cypress/e2e/column-datetime.cy.js @@ -0,0 +1,66 @@ +let localUser +const columnTitle = 'date and time' +const tableTitle = 'Test datetime' + +describe('Test column ' + columnTitle, () => { + + before(function() { + cy.createRandomUser().then(user => { + localUser = user + cy.login(localUser) + }) + }) + + beforeEach(function() { + cy.login(localUser) + cy.visit('apps/tables') + }) + + it('Table and column setup', () => { + cy.createTable(tableTitle) + }) + + it('Insert and test rows', () => { + cy.loadTable(tableTitle) + cy.createDatetimeColumn(columnTitle, null, true) + + // insert row with int value + cy.get('button').contains('Create row').click() + cy.get('.modal__content input').first().clear().type('2023-12-24 05:15') + cy.get('.modal-container .checkbox-radio-switch label').click().click() + cy.get('button').contains('Save').click() + cy.get('.custom-table table tr td div').contains('24').should('be.visible') + cy.get('.custom-table table tr td div').contains('Dec').should('be.visible') + cy.get('.custom-table table tr td div').contains('2023').should('be.visible') + cy.get('.custom-table table tr td div').contains('5:15').should('be.visible') + + // delete row + cy.get('.NcTable tr td button').first().click() + cy.get('button').contains('Delete').click() + cy.get('button').contains('I really').click() + + cy.removeColumn(columnTitle) + }) + + it('Insert and test rows - default now', () => { + cy.loadTable(tableTitle) + cy.createDatetimeColumn(columnTitle, true, true) + + // insert row with int value + cy.get('button').contains('Create row').click() + const hour = new Date().getHours().toString().length < 2 ? '0' + new Date().getHours() : new Date().getHours().toString() + const minutes = new Date().getMinutes().toString().length < 2 ? '0' + new Date().getMinutes() : new Date().getMinutes().toString() + const date = new Date().toISOString().slice(2, 10) + const datetime = date + ' ' + hour + ':' + minutes + cy.get('.modal__content input').first().should('contain.value', '20' + datetime) + cy.get('.modal-container .checkbox-radio-switch label').click().click() + cy.get('button').contains('Save').click() + const monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'June', + 'July', 'Aug', 'Sept', 'Oct', 'Nov', 'Dec'] + cy.get('.custom-table table tr td div').contains(new Date().getDate()).should('be.visible') + cy.get('.custom-table table tr td div').contains(monthNames[new Date().getMonth()]).should('be.visible') + cy.get('.custom-table table tr td div').contains(new Date().getFullYear()).should('be.visible') + cy.get('.custom-table table tr td div').contains(':' + minutes).should('be.visible') + }) + +}) diff --git a/cypress/e2e/column-datetimeDate.cy.js b/cypress/e2e/column-datetimeDate.cy.js new file mode 100644 index 000000000..c1f8ff22d --- /dev/null +++ b/cypress/e2e/column-datetimeDate.cy.js @@ -0,0 +1,63 @@ +let localUser +const columnTitle = 'date' +const tableTitle = 'Test datetime date' + +describe('Test column ' + columnTitle, () => { + + before(function() { + cy.createRandomUser().then(user => { + localUser = user + cy.login(localUser) + }) + }) + + beforeEach(function() { + cy.login(localUser) + cy.visit('apps/tables') + }) + + it('Table and column setup', () => { + cy.createTable(tableTitle) + }) + + it('Insert and test rows', () => { + cy.loadTable(tableTitle) + cy.createDatetimeDateColumn(columnTitle, null, true) + + // insert row with int value + cy.get('button').contains('Create row').click() + cy.get('.modal__content input').first().clear().type('2023-12-24') + cy.get('.modal-container .checkbox-radio-switch label').click().click() + cy.get('button').contains('Save').click() + cy.get('.custom-table table tr td div').contains('24').should('be.visible') + cy.get('.custom-table table tr td div').contains('Dec').should('be.visible') + cy.get('.custom-table table tr td div').contains('2023').should('be.visible') + + // delete row + cy.get('.NcTable tr td button').first().click() + cy.get('button').contains('Delete').click() + cy.get('button').contains('I really').click() + + cy.removeColumn(columnTitle) + }) + + it('Insert and test rows - default now', () => { + cy.loadTable(tableTitle) + cy.createDatetimeDateColumn(columnTitle, true, true) + + // insert row with int value + cy.get('button').contains('Create row').click() + const date = new Date().toISOString().slice(2, 10) + cy.get('.modal__content input').first().should('contain.value', date) + cy.get('.modal-container .checkbox-radio-switch label').click().click() + cy.get('button').contains('Save').click() + const monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'June', + 'July', 'Aug', 'Sept', 'Oct', 'Nov', 'Dec'] + const datetime2 = new Date().getDate() + ' ' + monthNames[new Date().getMonth()] + ' ' + new Date().getFullYear() + cy.log(datetime2) + cy.get('.custom-table table tr td div').contains(new Date().getDate()).should('be.visible') + cy.get('.custom-table table tr td div').contains(monthNames[new Date().getMonth()]).should('be.visible') + cy.get('.custom-table table tr td div').contains(new Date().getFullYear()).should('be.visible') + }) + +}) diff --git a/cypress/e2e/column-datetimeTime.cy.js b/cypress/e2e/column-datetimeTime.cy.js new file mode 100644 index 000000000..a46c41068 --- /dev/null +++ b/cypress/e2e/column-datetimeTime.cy.js @@ -0,0 +1,55 @@ +let localUser +const columnTitle = 'time' +const tableTitle = 'Test datetime time' + +describe('Test column ' + columnTitle, () => { + + before(function() { + cy.createRandomUser().then(user => { + localUser = user + cy.login(localUser) + }) + }) + + beforeEach(function() { + cy.login(localUser) + cy.visit('apps/tables') + }) + + it('Table and column setup', () => { + cy.createTable(tableTitle) + }) + + it('Insert and test rows', () => { + cy.loadTable(tableTitle) + cy.createDatetimeTimeColumn(columnTitle, null, true) + + // insert row with int value + cy.get('button').contains('Create row').click() + cy.get('.modal__content input').first().clear().type('05:15') + cy.get('.modal-container .checkbox-radio-switch label').click().click() + cy.get('button').contains('Save').click() + cy.get('.custom-table table tr td div').contains('5:15').should('be.visible') + + // delete row + cy.get('.NcTable tr td button').first().click() + cy.get('button').contains('Delete').click() + cy.get('button').contains('I really').click() + + cy.removeColumn(columnTitle) + }) + + it('Insert and test rows - default now', () => { + cy.loadTable(tableTitle) + cy.createDatetimeTimeColumn(columnTitle, true, true) + + // insert row with int value + cy.get('button').contains('Create row').click() + const minutes = ':' + new Date().getMinutes().toString().length < 2 ? '0' + new Date().getMinutes() : new Date().getMinutes().toString() + cy.get('.modal__content input').first().should('contain.value', minutes) + cy.get('.modal-container .checkbox-radio-switch label').click().click() + cy.get('button').contains('Save').click() + cy.get('.custom-table table tr td div').contains(minutes).should('be.visible') + }) + +}) diff --git a/cypress/support/commands.js b/cypress/support/commands.js index fa29cad76..0dc917116 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -188,6 +188,68 @@ Cypress.Commands.add('createTextLineColumn', (title, defaultValue, maxLength, fi cy.get('.custom-table table tr th .cell').contains(title).should('exist') }) +Cypress.Commands.add('createDatetimeColumn', (title, setNow, firstColumn) => { + if (firstColumn) { + cy.get('.button-vue__text').contains('Create column').click({ force: true }) + } else { + cy.get('[data-cy="customTableAction"] button').click() + cy.get('.v-popper__popper li button span').contains('Create column').click({ force: true }) + } + cy.get('.modal-container').get('input[placeholder*="Enter a column title"]').clear().type(title) + cy.get('.columnTypeSelection .vs__open-indicator').click({ force: true }) + cy.get('.multiSelectOptionLabel').contains('Date and time').click({ force: true }) + + if (setNow) { + cy.get('[data-cy="DatetimeForm"] label').first().click() + } + + cy.get('.modal-container button').contains('Save').click() + cy.wait(10).get('.toastify.toast-success').should('be.visible') + cy.get('.custom-table table tr th .cell').contains(title).should('exist') +}) + +Cypress.Commands.add('createDatetimeDateColumn', (title, setNow, firstColumn) => { + if (firstColumn) { + cy.get('.button-vue__text').contains('Create column').click({ force: true }) + } else { + cy.get('[data-cy="customTableAction"] button').click() + cy.get('.v-popper__popper li button span').contains('Create column').click({ force: true }) + } + cy.get('.modal-container').get('input[placeholder*="Enter a column title"]').clear().type(title) + cy.get('.columnTypeSelection .vs__open-indicator').click({ force: true }) + cy.get('.multiSelectOptionLabel').contains('Date and time').click({ force: true }) + cy.get('.modal-container label').contains('Date').click() + + if (setNow) { + cy.get('[data-cy="DatetimeDateForm"] label').first().click() + } + + cy.get('.modal-container button').contains('Save').click() + cy.wait(10).get('.toastify.toast-success').should('be.visible') + cy.get('.custom-table table tr th .cell').contains(title).should('exist') +}) + +Cypress.Commands.add('createDatetimeTimeColumn', (title, setNow, firstColumn) => { + if (firstColumn) { + cy.get('.button-vue__text').contains('Create column').click({ force: true }) + } else { + cy.get('[data-cy="customTableAction"] button').click() + cy.get('.v-popper__popper li button span').contains('Create column').click({ force: true }) + } + cy.get('.modal-container').get('input[placeholder*="Enter a column title"]').clear().type(title) + cy.get('.columnTypeSelection .vs__open-indicator').click({ force: true }) + cy.get('.multiSelectOptionLabel').contains('Date and time').click({ force: true }) + cy.get('.modal-container label').contains('Time').click() + + if (setNow) { + cy.get('[data-cy="DatetimeTimeForm"] label').first().click() + } + + cy.get('.modal-container button').contains('Save').click() + cy.wait(10).get('.toastify.toast-success').should('be.visible') + cy.get('.custom-table table tr th .cell').contains(title).should('exist') +}) + Cypress.Commands.add('createNumberColumn', (title, defaultValue, decimals, min, max, prefix, suffix, firstColumn) => { if (firstColumn) { cy.get('.button-vue__text').contains('Create column').click({ force: true }) diff --git a/lib/Service/ColumnTypes/DatetimeBusiness.php b/lib/Service/ColumnTypes/DatetimeBusiness.php index 6c95df5e3..7aaa73996 100644 --- a/lib/Service/ColumnTypes/DatetimeBusiness.php +++ b/lib/Service/ColumnTypes/DatetimeBusiness.php @@ -14,6 +14,10 @@ class DatetimeBusiness extends SuperBusiness implements IColumnTypeBusiness { * @return string */ public function parseValue($value, ?Column $column = null): string { + if ($value === '' || $value === null) { + return ''; + } + $allowedFormats = [\DateTimeInterface::ATOM, 'Y-m-d H:i']; $newDateTime = ''; @@ -38,6 +42,10 @@ public function parseValue($value, ?Column $column = null): string { * @return bool */ public function canBeParsed($value, ?Column $column = null): bool { + if ($value === '' || $value === null) { + return true; + } + try { new DateTime($value); } catch (Exception $e) {