diff --git a/forge/containers/stub/index.js b/forge/containers/stub/index.js index fe08621cd2..02cc3fc383 100644 --- a/forge/containers/stub/index.js +++ b/forge/containers/stub/index.js @@ -228,27 +228,32 @@ module.exports = { { level: 'system', msg: 'Fake Log Entry', - ts: `${Date.now() - oneHour}` + ts: `${Date.now() - oneHour}`, + src: 'one' }, { level: 'system', msg: 'Starting Node-RED', - ts: `${Date.now() - oneHour / 2}` + ts: `${Date.now() - oneHour / 2}`, + src: 'one' }, { level: 'info', msg: '\n\nMulti Line Message\n===================\n', - ts: `${Date.now() - oneHour / 4}` + ts: `${Date.now() - oneHour / 4}`, + src: 'one' }, { level: 'warn', msg: 'This is the voice of the Mysterons. We know that you can hear us Earthmen.', - ts: `${Date.now() - oneHour / 5}` + ts: `${Date.now() - oneHour / 5}`, + src: 'one' }, { level: 'error', msg: 'Captain Scarlet is indestructible', - ts: `${Date.now()}` + ts: `${Date.now()}`, + src: 'two' } ] }, diff --git a/frontend/src/pages/instance/Logs.vue b/frontend/src/pages/instance/Logs.vue index 34caed1fdc..3c3862f46a 100644 --- a/frontend/src/pages/instance/Logs.vue +++ b/frontend/src/pages/instance/Logs.vue @@ -1,8 +1,21 @@ diff --git a/frontend/src/pages/instance/components/InstanceLogs.vue b/frontend/src/pages/instance/components/InstanceLogs.vue index 518174fd1b..2daf07a1d5 100644 --- a/frontend/src/pages/instance/components/InstanceLogs.vue +++ b/frontend/src/pages/instance/components/InstanceLogs.vue @@ -12,7 +12,12 @@
Load earlier...
-
+
+
[{{ item.src }}]
{{ item.date }}
[{{ item.level }}]
{{ item.msg }}
@@ -34,8 +39,14 @@ export default { instance: { type: Object, required: true + }, + filter: { + default: null, + type: String, + required: false } }, + emits: ['ha-instance-detected'], data () { return { doneInitialLoad: false, @@ -47,6 +58,16 @@ export default { showOfflineBanner: false } }, + computed: { + filteredLogEntries: function () { + if (this.filter && this.filter !== 'all') { + const filteredList = this.logEntries.filter(l => l.src === this.filter) + return filteredList + } else { + return this.logEntries + } + } + }, timers: { pollTimer: { time: POLL_TIME, repeat: true, autostart: false } }, @@ -105,6 +126,9 @@ export default { } else { toPrepend.push(l) } + if (l.src) { + this.$emit('ha-instance-detected', l.src) + } }) if (toPrepend.length > 0) { this.logEntries = toPrepend.concat(this.logEntries) diff --git a/test/e2e/frontend/cypress/tests-ee/instances/logs.spec.js b/test/e2e/frontend/cypress/tests-ee/instances/logs.spec.js new file mode 100644 index 0000000000..7e48357e5f --- /dev/null +++ b/test/e2e/frontend/cypress/tests-ee/instances/logs.spec.js @@ -0,0 +1,99 @@ +describe('FlowForge - Instance - Logs', () => { + let instance + function navigateToInstanceLogs (teamName, instanceName) { + cy.request('GET', '/api/v1/user/teams') + .then((response) => { + const team = response.body.teams.find( + (team) => team.name === teamName + ) + return cy.request('GET', `/api/v1/teams/${team.id}/projects`) + }) + .then((response) => { + instance = response.body.projects.find( + (app) => app.name === instanceName + ) + cy.visit(`/instance/${instance.id}/logs`) + cy.wait('@getInstance') + }) + } + + beforeEach(() => { + cy.intercept('GET', '/api/*/projects/*/logs?*', { + body: { + meta: {}, + log: [] + } + }).as('getLogsUpdates') + + cy.intercept('GET', '/api/*/projects/*').as('getInstance') + + cy.login('bob', 'bbPassword') + cy.home() + }) + + it('load all logs by default', () => { + // mock the API response with well-defined logs + cy.intercept('GET', '/api/*/projects/*/logs', { + body: { + meta: {}, + log: [ + { level: 'info', msg: 'Updated flows', ts: '16874362594840001' } + ] + } + }).as('getLogs') + + navigateToInstanceLogs('BTeam', 'instance-2-1') + cy.wait('@getLogs') + + cy.get('[data-el="instance-log-row"]').should('have.length', 1) + cy.get('[data-el="select-ha-replica"]').should('not.exist') + }) + + it('display a marker to indicuate with HA replica the logs are from, if present', () => { + // Modify our Instance so that HA is enabled + cy.intercept('GET', '/api/*/projects/*', (req) => { + req.continue((res) => { + // intercept the response and update the HA settings + res.body.ha = { + replicas: ['123', '456'] + } + }) + }).as('getInstance') + + // mock the API response with well-defined logs + cy.intercept('GET', '/api/*/projects/*/logs', { + body: { + meta: {}, + log: [ + { src: '123', level: 'info', msg: 'Created flows', ts: '16874362594840000' }, + { src: '123', level: 'info', msg: 'Updated flows', ts: '16874362594840001' }, + { src: '456', level: 'info', msg: 'Updated flows', ts: '16874362594840001' } + ] + } + }).as('getLogs') + + navigateToInstanceLogs('BTeam', 'instance-2-1') + cy.wait('@getLogs') + + // should load our stubbed logs + cy.get('[data-el="instance-log-row"]').should('have.length', 3) + + cy.get('[data-el="select-ha-replica"]').should('exist') + // open dropdown + cy.get('[data-el="select-ha-replica"]').click() + // check we have 3 options + cy.get('[data-el="select-ha-replica"] .ff-dropdown-option').should('have.length', 3) + // select the first HA Replica + cy.get('[data-el="select-ha-replica"] .ff-dropdown-option').eq(1).click() + + // logs should now be filtered to the 3 we've defined for first replica + cy.get('[data-el="instance-log-row"]').should('have.length', 2) + + // open dropdown and select "All" + cy.get('[data-el="select-ha-replica"]').click() + cy.get('[data-el="select-ha-replica"] .ff-dropdown-option').eq(0).click() + + // logs should be restored + cy.get('[data-el="instance-log-row"]').should('have.length', 3) + }) +})