+
+
{{ t('logs.no-logs-to-display') }} {{ formatDateFilter(selectedDate) }}.
+
+
+
+
{{ t('logs.no-logs-to-display') }}
{{ t('return-to-index') }}
@@ -64,27 +87,50 @@
@@ -227,4 +297,47 @@ onMounted(() => {
text-decoration: underline;
}
-
\ No newline at end of file
+.timestamp-header {
+ display: flex;
+ flex-direction: column;
+ gap: 0.25rem;
+}
+
+.date-filter-indicator {
+ display: flex;
+ align-items: center;
+ gap: 0.25rem;
+ font-size: 0.75rem;
+ font-weight: normal;
+ color: var(--text-secondary, #666);
+ white-space: nowrap;
+}
+
+.date-filter-text {
+ font-style: italic;
+}
+
+.timestamp-header .clear-date-button {
+ background: none;
+ border: none;
+ cursor: pointer;
+ padding: 0.125rem;
+ border-radius: 3px;
+ display: flex;
+ align-items: center;
+ flex-shrink: 0;
+ opacity: 0.7;
+ transition: opacity 0.2s;
+}
+
+.timestamp-header .clear-date-button:hover {
+ opacity: 1;
+ background: var(--hover-background, rgba(0, 0, 0, 0.05));
+}
+
+.timestamp-header .clear-date-button svg {
+ width: 0.75rem;
+ height: 0.75rem;
+}
+
+
diff --git a/frontend/style.css b/frontend/style.css
index 6b520c2..1c2391b 100644
--- a/frontend/style.css
+++ b/frontend/style.css
@@ -1,3 +1,5 @@
+@layer components, karma, theme;
+
header {
position: fixed;
width: 100%;
@@ -37,3 +39,27 @@ div.buttons button svg {
section.small {
border-radius: .4em;
}
+
+.sm-side-icons .action-button button {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+}
+
+.sm-imageicons-fullwidth .action-button button .icon img {
+ width: 100%;
+}
+
+.sm-transparent-header header {
+ background-color: transparent;
+ box-shadow: none;
+ border-color: transparent;
+}
+
+.sm-transparent-header #sidebar-button {
+ border-color: transparent;
+}
+
+.sm-transparent-footer footer span {
+ background-color: transparent;
+}
\ No newline at end of file
diff --git a/frontend/vite.config.js b/frontend/vite.config.js
index 6042ebc..243919a 100644
--- a/frontend/vite.config.js
+++ b/frontend/vite.config.js
@@ -18,6 +18,15 @@ export default defineConfig({
target: 'http://localhost:1337',
changeOrigin: true,
secure: false,
+ },
+ '/theme.css': {
+ target: 'http://localhost:1337',
+ changeOrigin: true,
+ secure: false,
+ },
+ "/custom-webui": {
+ target: "http://localhost:1337",
+ changeOrigin: true,
}
},
},
diff --git a/integration-tests/tests/customTheme/custom-webui/themes/test-theme/theme.css b/integration-tests/tests/customTheme/custom-webui/themes/test-theme/theme.css
deleted file mode 100644
index 5117969..0000000
--- a/integration-tests/tests/customTheme/custom-webui/themes/test-theme/theme.css
+++ /dev/null
@@ -1,14 +0,0 @@
-/* Custom theme for integration testing */
-body {
- background-color: #ff6b6b;
-}
-
-/* Add a distinctive style that we can test for */
-#content {
- border: 5px solid #4ecdc4;
-}
-
-
-
-
-
diff --git a/integration-tests/tests/customTheme/customTheme.mjs b/integration-tests/tests/customTheme/customTheme.mjs
deleted file mode 100644
index ca8546a..0000000
--- a/integration-tests/tests/customTheme/customTheme.mjs
+++ /dev/null
@@ -1,82 +0,0 @@
-import { describe, it, before, after } from 'mocha'
-import { expect } from 'chai'
-import { By } from 'selenium-webdriver'
-import {
- getRootAndWait,
- takeScreenshotOnFailure,
-} from '../../lib/elements.js'
-
-describe('config: customTheme', function () {
- before(async function () {
- await runner.start('customTheme')
- })
-
- after(async () => {
- await runner.stop()
- })
-
- afterEach(function () {
- takeScreenshotOnFailure(this.currentTest, webdriver)
- })
-
- it('Custom theme CSS is loaded and accessible', async function () {
- await getRootAndWait()
-
- // Fetch the theme CSS directly
- const themeCssUrl = runner.baseUrl() + 'theme.css'
- await webdriver.get(themeCssUrl)
-
- // Wait for the page to load
- await webdriver.sleep(500)
-
- // Get the page source (should be CSS content)
- const pageSource = await webdriver.getPageSource()
-
- // Verify the theme CSS contains our custom styles
- expect(pageSource).to.include('background-color: #ff6b6b')
- expect(pageSource).to.include('border: 5px solid #4ecdc4')
- expect(pageSource).to.include('Custom theme for integration testing')
- })
-
- it('Custom theme styles are applied to the page', async function () {
- await getRootAndWait()
-
- // Wait a bit for CSS to be fully loaded
- await webdriver.sleep(500)
-
- // Get computed background color of body
- const backgroundColor = await webdriver.executeScript(
- 'return window.getComputedStyle(document.body).backgroundColor'
- )
-
- // The background color should be rgb(255, 107, 107) which is #ff6b6b
- // Different browsers might return different formats, so we check for the RGB values
- expect(backgroundColor).to.include('255, 107, 107')
-
- // Get computed border color of content element
- const borderColor = await webdriver.executeScript(
- 'const el = document.getElementById("content"); return el ? window.getComputedStyle(el).borderColor : null'
- )
-
- // The border color should be rgb(78, 205, 196) which is #4ecdc4
- // borderColor might return "rgb(78, 205, 196)" or similar format
- expect(borderColor).to.include('78, 205, 196')
- })
-
- it('Theme CSS link is present in the HTML', async function () {
- await getRootAndWait()
-
- // Find the theme.css link in the head
- const themeLink = await webdriver.findElement(By.css('link[href="/theme.css"]'))
-
- expect(themeLink).to.not.be.null
-
- // Verify it's a stylesheet
- const rel = await themeLink.getAttribute('rel')
- expect(rel).to.equal('stylesheet')
-
- const type = await themeLink.getAttribute('type')
- expect(type).to.equal('text/css')
- })
-})
-
diff --git a/integration-tests/tests/enabledExpression/config.yaml b/integration-tests/tests/enabledExpression/config.yaml
new file mode 100644
index 0000000..30c718f
--- /dev/null
+++ b/integration-tests/tests/enabledExpression/config.yaml
@@ -0,0 +1,39 @@
+#
+# Integration Test Config: EnabledExpression
+#
+
+listenAddressSingleHTTPFrontend: 0.0.0.0:1337
+
+logLevel: "DEBUG"
+checkForUpdates: false
+
+actions:
+ - title: Turn On Light
+ shell: echo "Turning on light"
+ icon: light
+ entity: light
+ enabledExpression: "{{ eq .CurrentEntity.powered_on false }}"
+
+ - title: Turn Off Light
+ shell: echo "Turning off light"
+ icon: light
+ entity: light
+ enabledExpression: "{{ eq .CurrentEntity.powered_on true }}"
+
+ - title: Always Enabled Action
+ shell: echo "Always enabled"
+ icon: check
+
+entities:
+ - file: entities/lights.yaml
+ name: light
+
+dashboards:
+ - title: LightDashboard
+ contents:
+ - title: Light Controls
+ type: fieldset
+ entity: light
+ contents:
+ - title: Turn On Light
+ - title: Turn Off Light
diff --git a/integration-tests/tests/enabledExpression/enabledExpression.mjs b/integration-tests/tests/enabledExpression/enabledExpression.mjs
new file mode 100644
index 0000000..98f32c0
--- /dev/null
+++ b/integration-tests/tests/enabledExpression/enabledExpression.mjs
@@ -0,0 +1,150 @@
+import { describe, it, before, after } from 'mocha'
+import { expect } from 'chai'
+import { By, until, Condition } from 'selenium-webdriver'
+import {
+ getRootAndWait,
+ takeScreenshotOnFailure,
+} from '../../lib/elements.js'
+
+describe('config: enabledExpression', function () {
+ this.timeout(30000) // Increase timeout for async operations
+
+ before(async function () {
+ await runner.start('enabledExpression')
+ })
+
+ after(async () => {
+ await runner.stop()
+ })
+
+ afterEach(function () {
+ takeScreenshotOnFailure(this.currentTest, webdriver);
+ });
+
+ it('Action with enabledExpression for lights enable the correct action', async function() {
+ await getRootAndWait()
+
+ // Navigate to the Lights Dashboard
+ // Use the path with space encoded as %20 - Vue Router should decode it
+ await webdriver.get(runner.baseUrl() + '/dashboards/LightDashboard')
+
+ // Wait for the URL to change and the route to be processed
+ await webdriver.wait(new Condition('wait for URL to contain dashboards', async function() {
+ const url = await webdriver.getCurrentUrl()
+ return url.includes('/dashboards/')
+ }), 5000)
+
+ // Wait for dashboard to load by checking the loaded-dashboard attribute
+ // The attribute should be set to the decoded title "LightDashboard"
+ await webdriver.wait(new Condition('wait for loaded-dashboard', async function() {
+ const body = await webdriver.findElement(By.tagName('body'))
+ const attr = await body.getAttribute('loaded-dashboard')
+ if (attr) {
+ console.log('Current loaded-dashboard attribute:', attr)
+ }
+ // Accept either decoded or encoded version (component should decode, but handle both)
+ return attr === 'LightDashboard'
+ }), 10000)
+
+ // Verify we got the correct dashboard (prefer decoded, but accept encoded)
+ const body = await webdriver.findElement(By.tagName('body'))
+ const attr = await body.getAttribute('loaded-dashboard')
+ if (attr !== 'LightDashboard') {
+ const currentUrl = await webdriver.getCurrentUrl()
+ throw new Error(`Dashboard not loaded correctly. Expected "LightDashboard", got "${attr}". Current URL: ${currentUrl}`)
+ }
+
+ // Wait for dashboard content to appear - check for dashboard rows first
+ await webdriver.wait(until.elementsLocated(By.css('.dashboard-row')), 5000)
+
+ // Debug: Check what's on the page
+ const dashboardRows = await webdriver.findElements(By.css('.dashboard-row'))
+ console.log(`Found ${dashboardRows.length} dashboard rows`)
+
+ for (let i = 0; i < dashboardRows.length; i++) {
+ const row = dashboardRows[i]
+ const h2Elements = await row.findElements(By.css('h2'))
+ if (h2Elements.length > 0) {
+ const h2Text = await h2Elements[0].getText()
+ console.log(`Row ${i} h2: "${h2Text}"`)
+ }
+ const fieldsets = await row.findElements(By.css('fieldset'))
+ console.log(`Row ${i} has ${fieldsets.length} fieldsets`)
+ if (fieldsets.length > 0) {
+ const buttons = await fieldsets[0].findElements(By.css('.action-button button'))
+ console.log(`Row ${i} fieldset has ${buttons.length} buttons`)
+ }
+ }
+
+ // Find buttons by looking within entity fieldsets
+ // Both rows have h2 title "Light Controls", so we identify them by which buttons are enabled
+ // Living Room Light (powered_on: false) - Turn On should be enabled, Turn Off disabled
+ // Bedroom Light (powered_on: true) - Turn Off should be enabled, Turn On disabled
+ let turnOnButton = null
+ let turnOffButton = null
+
+ for (const row of dashboardRows) {
+ // Get the fieldset in this row
+ const fieldsets = await row.findElements(By.css('fieldset'))
+ if (fieldsets.length === 0) continue
+
+ const buttons = await fieldsets[0].findElements(By.css('.action-button button'))
+
+ // Check each button to identify which entity this row represents
+ for (const btn of buttons) {
+ const title = await btn.getAttribute('title')
+ const disabled = await btn.getAttribute('disabled')
+ const isEnabled = disabled === null
+
+ if (title === 'Turn On Light' && isEnabled) {
+ // This is the Living Room Light row (Turn On is enabled because powered_on: false)
+ turnOnButton = btn
+ }
+
+ if (title === 'Turn Off Light' && isEnabled) {
+ // This is the Bedroom Light row (Turn Off is enabled because powered_on: true)
+ turnOffButton = btn
+ }
+ }
+ }
+
+ expect(turnOnButton).to.not.be.null
+ expect(turnOffButton).to.not.be.null
+
+ // Check that Turn On button is enabled (light is off)
+ const turnOnDisabled = await turnOnButton.getAttribute('disabled')
+ expect(turnOnDisabled).to.be.null
+
+ // Check that Turn Off button is enabled (light is on)
+ const turnOffDisabled = await turnOffButton.getAttribute('disabled')
+ expect(turnOffDisabled).to.be.null
+ })
+
+ it('Action without enabledExpression is always enabled', async function() {
+ await getRootAndWait()
+
+ // Navigate to actions view
+ await webdriver.get(runner.baseUrl())
+
+ // Wait for action buttons
+ await webdriver.wait(until.elementLocated(By.css('.action-button')), 10000)
+
+ // Find "Always Enabled Action" button
+ const actionButtons = await webdriver.findElements(By.css('.action-button button'))
+ let alwaysEnabledButton = null
+
+ for (const btn of actionButtons) {
+ const title = await btn.getAttribute('title')
+ if (title === 'Always Enabled Action') {
+ alwaysEnabledButton = btn
+ break
+ }
+ }
+
+ expect(alwaysEnabledButton).to.not.be.null
+
+ // Check that it's enabled
+ const disabled = await alwaysEnabledButton.getAttribute('disabled')
+ expect(disabled).to.be.null
+ })
+})
diff --git a/integration-tests/tests/enabledExpression/entities/lights.yaml b/integration-tests/tests/enabledExpression/entities/lights.yaml
new file mode 100644
index 0000000..628fcc1
--- /dev/null
+++ b/integration-tests/tests/enabledExpression/entities/lights.yaml
@@ -0,0 +1,5 @@
+- name: "Living Room Light"
+ powered_on: false
+
+- name: "Bedroom Light"
+ powered_on: true
diff --git a/integration-tests/tests/stdoutMostRecentExecution/config.yaml b/integration-tests/tests/stdoutMostRecentExecution/config.yaml
index 9e448b2..dd1d511 100644
--- a/integration-tests/tests/stdoutMostRecentExecution/config.yaml
+++ b/integration-tests/tests/stdoutMostRecentExecution/config.yaml
@@ -1,5 +1,7 @@
logLevel: debug
+insecureAllowDumpActionMap: true
+
actions:
- title: Check status
id: status_command
diff --git a/integration-tests/tests/stdoutMostRecentExecution/stdoutMostRecentExecution.mjs b/integration-tests/tests/stdoutMostRecentExecution/stdoutMostRecentExecution.mjs
index 6c72d96..5388eb0 100644
--- a/integration-tests/tests/stdoutMostRecentExecution/stdoutMostRecentExecution.mjs
+++ b/integration-tests/tests/stdoutMostRecentExecution/stdoutMostRecentExecution.mjs
@@ -59,8 +59,7 @@ describe('config: stdout-most-recent-execution', function () {
})
it('stdout-most-recent-execution updates after action execution', async function () {
- this.timeout(30000) // Increase timeout for this test
-
+ this.timeout(45000)
await getRootAndWait()
// Wait for the mre-output element
@@ -105,7 +104,7 @@ describe('config: stdout-most-recent-execution', function () {
await statusButton.click()
// Wait a moment for the action to start
- await webdriver.sleep(500)
+ await webdriver.sleep(2000)
// Wait for the output to update (the component listens to EventExecutionFinished events)
// We'll wait for the output to change from the initial state
@@ -138,4 +137,4 @@ describe('config: stdout-most-recent-execution', function () {
expect(updatedText).to.not.include('No execution found')
expect(updatedText.trim().length).to.be.greaterThan(0)
})
-})
\ No newline at end of file
+})
diff --git a/integration-tests/tests/suggestionsBrowserKey/config.yaml b/integration-tests/tests/suggestionsBrowserKey/config.yaml
new file mode 100644
index 0000000..eb2c1df
--- /dev/null
+++ b/integration-tests/tests/suggestionsBrowserKey/config.yaml
@@ -0,0 +1,19 @@
+---
+listenAddressSingleHTTPFrontend: 0.0.0.0:1337
+
+logLevel: "DEBUG"
+checkForUpdates: false
+
+actions:
+ - title: Test suggestionsBrowserKey
+ shell: "echo 'Input value: {{ testInput }}, Second input: {{ testInput2 }}'"
+ icon: ping
+ arguments:
+ - name: testInput
+ title: Test Input
+ description: "This input uses suggestionsBrowserKey"
+ suggestionsBrowserKey: test-suggestions-key
+ - name: testInput2
+ title: Test Input 2
+ description: "This input shares the same suggestionsBrowserKey"
+ suggestionsBrowserKey: test-suggestions-key
diff --git a/integration-tests/tests/suggestionsBrowserKey/suggestionsBrowserKey.mjs b/integration-tests/tests/suggestionsBrowserKey/suggestionsBrowserKey.mjs
new file mode 100644
index 0000000..c5cd4cf
--- /dev/null
+++ b/integration-tests/tests/suggestionsBrowserKey/suggestionsBrowserKey.mjs
@@ -0,0 +1,325 @@
+import { describe, it, before, after } from 'mocha'
+import { expect } from 'chai'
+import { By, Condition } from 'selenium-webdriver'
+import {
+ getRootAndWait,
+ getActionButton,
+ takeScreenshotOnFailure,
+ getTerminalBuffer,
+} from '../../lib/elements.js'
+
+async function openArgumentForm() {
+ await getRootAndWait()
+ const btn = await getActionButton(webdriver, 'Test suggestionsBrowserKey')
+ await btn.click()
+
+ await webdriver.wait(
+ new Condition('wait for argument form page', async () => {
+ const url = await webdriver.getCurrentUrl()
+ return url.includes('/actionBinding/') && url.includes('/argumentForm')
+ }),
+ 5000
+ )
+}
+
+async function getTestInput() {
+ return await webdriver.findElement(By.id('testInput'))
+}
+
+async function getTestInput2() {
+ return await webdriver.findElement(By.id('testInput2'))
+}
+
+async function getDatalistOptions(inputName = 'testInput') {
+ return await webdriver.findElements(By.css(`datalist#${inputName}-choices option`))
+}
+
+async function submitForm() {
+ const submitButton = await webdriver.findElement(By.css('button[name="start"]'))
+ await submitButton.click()
+}
+
+async function waitForLogsPage() {
+ await webdriver.wait(
+ new Condition('wait for logs page', async () => {
+ const url = await webdriver.getCurrentUrl()
+ return url.includes('/logs/') && !url.endsWith('/logs')
+ }),
+ 5000
+ )
+}
+
+async function waitForExecutionComplete() {
+ await webdriver.wait(
+ new Condition('wait for execution status', async () => {
+ const statusElements = await webdriver.findElements(By.id('execution-dialog-status'))
+ return statusElements.length > 0
+ }),
+ 5000
+ )
+
+ await webdriver.wait(
+ new Condition('wait for execution to finish', async () => {
+ try {
+ const statusElement = await webdriver.findElement(By.id('execution-dialog-status'))
+ const statusText = await statusElement.getText()
+ return !statusText.includes('Executing')
+ } catch (e) {
+ return false
+ }
+ }),
+ 5000
+ )
+
+ await webdriver.sleep(500)
+}
+
+async function getLocalStorageItem(key) {
+ return await webdriver.executeScript(`return localStorage.getItem('${key}')`)
+}
+
+async function clearLocalStorage() {
+ await webdriver.executeScript('return localStorage.clear()')
+}
+
+describe('config: suggestionsBrowserKey', function () {
+ before(async function () {
+ await runner.start('suggestionsBrowserKey')
+ })
+
+ after(async () => {
+ await runner.stop()
+ })
+
+ afterEach(function () {
+ takeScreenshotOnFailure(this.currentTest, webdriver)
+ })
+
+ it('Input fields with suggestionsBrowserKey are rendered', async function () {
+ await openArgumentForm()
+
+ const input1 = await getTestInput()
+ expect(await input1.getTagName()).to.equal('input')
+ expect(await input1.getAttribute('type')).to.equal('text')
+
+ const label1 = await webdriver.findElement(By.css('label[for="testInput"]'))
+ expect(await label1.getText()).to.contain('Test Input')
+
+ const input2 = await getTestInput2()
+ expect(await input2.getTagName()).to.equal('input')
+ expect(await input2.getAttribute('type')).to.equal('text')
+
+ const label2 = await webdriver.findElement(By.css('label[for="testInput2"]'))
+ expect(await label2.getText()).to.contain('Test Input 2')
+ })
+
+ it('Submitting form saves value to localStorage', async function () {
+ this.timeout(15000)
+
+ // Clear localStorage first
+ await clearLocalStorage()
+
+ await openArgumentForm()
+
+ const input = await getTestInput()
+ const testValue = 'test-value-123'
+ await input.clear()
+ await input.sendKeys(testValue)
+
+ await submitForm()
+ await waitForLogsPage()
+ await waitForExecutionComplete()
+
+ // Verify value was saved to localStorage
+ const stored = await getLocalStorageItem('olivetin-suggestions-test-suggestions-key')
+ expect(stored).to.not.be.null
+
+ const suggestions = JSON.parse(stored)
+ expect(suggestions).to.be.an('array')
+ expect(suggestions).to.include(testValue)
+ })
+
+ it('Previously saved values appear in datalist', async function () {
+ this.timeout(15000)
+
+ // First, save a value to localStorage
+ const testValue = 'saved-suggestion-456'
+ await webdriver.executeScript(`
+ const key = 'olivetin-suggestions-test-suggestions-key';
+ localStorage.setItem(key, JSON.stringify(['${testValue}']));
+ `)
+
+ // Open the form
+ await openArgumentForm()
+
+ // Check that datalist exists and contains the saved value
+ const datalist = await webdriver.findElement(By.id('testInput-choices'))
+ expect(datalist).to.not.be.null
+
+ const options = await getDatalistOptions()
+ expect(options.length).to.be.greaterThan(0)
+
+ // Check if the saved value appears in the datalist
+ let foundValue = false
+ for (const option of options) {
+ const value = await option.getAttribute('value')
+ if (value === testValue) {
+ foundValue = true
+ break
+ }
+ }
+ expect(foundValue).to.be.true
+ })
+
+ it('Multiple submissions accumulate suggestions', async function () {
+ this.timeout(20000)
+
+ // Clear localStorage first
+ await clearLocalStorage()
+
+ // Submit first value
+ await openArgumentForm()
+ const input1 = await getTestInput()
+ await input1.clear()
+ await input1.sendKeys('first-value')
+ await submitForm()
+ await waitForLogsPage()
+ await waitForExecutionComplete()
+
+ // Submit second value
+ await openArgumentForm()
+ const input2 = await getTestInput()
+ await input2.clear()
+ await input2.sendKeys('second-value')
+ await submitForm()
+ await waitForLogsPage()
+ await waitForExecutionComplete()
+
+ // Verify both values are in localStorage
+ const stored = await getLocalStorageItem('olivetin-suggestions-test-suggestions-key')
+ expect(stored).to.not.be.null
+
+ const suggestions = JSON.parse(stored)
+ expect(suggestions).to.be.an('array')
+ expect(suggestions).to.include('first-value')
+ expect(suggestions).to.include('second-value')
+ expect(suggestions[0]).to.equal('second-value') // Most recent should be first
+ })
+
+ it('Empty values are not saved to localStorage', async function () {
+ this.timeout(15000)
+
+ // Clear localStorage first
+ await clearLocalStorage()
+
+ await openArgumentForm()
+
+ const input = await getTestInput()
+ // Leave input empty (or clear it if it has a default)
+ await input.clear()
+
+ await submitForm()
+ await waitForLogsPage()
+ await waitForExecutionComplete()
+
+ // Verify empty value was not saved - localStorage should be null or empty-equivalent
+ const stored = await getLocalStorageItem('olivetin-suggestions-test-suggestions-key')
+ // Should be null OR empty JSON array string ("[]") OR parse to empty array
+ if (stored !== null) {
+ const suggestions = JSON.parse(stored)
+ expect(suggestions).to.be.an('array')
+ expect(suggestions).to.have.length(0)
+ }
+ // If stored is null, that's also acceptable - no assertion needed
+ })
+
+ it('Suggestions are shared across inputs with the same suggestionsBrowserKey', async function () {
+ this.timeout(20000)
+
+ // Clear localStorage first
+ await clearLocalStorage()
+
+ // Submit a value using the first input
+ await openArgumentForm()
+ const input1 = await getTestInput()
+ await input1.clear()
+ await input1.sendKeys('shared-value-from-input1')
+ await submitForm()
+ await waitForLogsPage()
+ await waitForExecutionComplete()
+
+ // Open the form again and verify the value appears in both datalists
+ await openArgumentForm()
+
+ // Check first input's datalist
+ const datalist1 = await webdriver.findElement(By.id('testInput-choices'))
+ expect(datalist1).to.not.be.null
+ const options1 = await getDatalistOptions('testInput')
+ let foundInInput1 = false
+ for (const option of options1) {
+ const value = await option.getAttribute('value')
+ if (value === 'shared-value-from-input1') {
+ foundInInput1 = true
+ break
+ }
+ }
+ expect(foundInInput1).to.be.true
+
+ // Check second input's datalist
+ const datalist2 = await webdriver.findElement(By.id('testInput2-choices'))
+ expect(datalist2).to.not.be.null
+ const options2 = await getDatalistOptions('testInput2')
+ let foundInInput2 = false
+ for (const option of options2) {
+ const value = await option.getAttribute('value')
+ if (value === 'shared-value-from-input1') {
+ foundInInput2 = true
+ break
+ }
+ }
+ expect(foundInInput2).to.be.true
+
+ // Now submit a value using the second input
+ const input2 = await getTestInput2()
+ await input2.clear()
+ await input2.sendKeys('shared-value-from-input2')
+ await submitForm()
+ await waitForLogsPage()
+ await waitForExecutionComplete()
+
+ // Verify both values appear in both datalists
+ await openArgumentForm()
+
+ // Check that both values are in the first input's datalist
+ const options1After = await getDatalistOptions('testInput')
+ let foundValue1 = false
+ let foundValue2 = false
+ for (const option of options1After) {
+ const value = await option.getAttribute('value')
+ if (value === 'shared-value-from-input1') {
+ foundValue1 = true
+ }
+ if (value === 'shared-value-from-input2') {
+ foundValue2 = true
+ }
+ }
+ expect(foundValue1).to.be.true
+ expect(foundValue2).to.be.true
+
+ // Check that both values are in the second input's datalist
+ const options2After = await getDatalistOptions('testInput2')
+ foundValue1 = false
+ foundValue2 = false
+ for (const option of options2After) {
+ const value = await option.getAttribute('value')
+ if (value === 'shared-value-from-input1') {
+ foundValue1 = true
+ }
+ if (value === 'shared-value-from-input2') {
+ foundValue2 = true
+ }
+ }
+ expect(foundValue1).to.be.true
+ expect(foundValue2).to.be.true
+ })
+})
diff --git a/integration-tests/tests/customTheme/config.yaml b/integration-tests/tests/themeLoading/config.yaml
similarity index 64%
rename from integration-tests/tests/customTheme/config.yaml
rename to integration-tests/tests/themeLoading/config.yaml
index 0cef319..dbca056 100644
--- a/integration-tests/tests/customTheme/config.yaml
+++ b/integration-tests/tests/themeLoading/config.yaml
@@ -4,14 +4,8 @@ listenAddressSingleHTTPFrontend: 0.0.0.0:1337
logLevel: "DEBUG"
checkForUpdates: false
-themeName: "test-theme"
-
actions:
- title: Test action
- shell: "echo 'Hello from themed OliveTin'"
+ shell: "echo 'Hello from theme loading test'"
icon: ping
-
-
-
-
diff --git a/integration-tests/tests/themeLoading/custom-webui/themes/theme-one/theme.css b/integration-tests/tests/themeLoading/custom-webui/themes/theme-one/theme.css
new file mode 100644
index 0000000..2ea8a4d
--- /dev/null
+++ b/integration-tests/tests/themeLoading/custom-webui/themes/theme-one/theme.css
@@ -0,0 +1,5 @@
+/* Theme One CSS */
+body {
+ background-color: #theme-one;
+}
+
diff --git a/integration-tests/tests/themeLoading/custom-webui/themes/theme-two/theme.css b/integration-tests/tests/themeLoading/custom-webui/themes/theme-two/theme.css
new file mode 100644
index 0000000..ad920fd
--- /dev/null
+++ b/integration-tests/tests/themeLoading/custom-webui/themes/theme-two/theme.css
@@ -0,0 +1,5 @@
+/* Theme Two CSS */
+body {
+ background-color: #theme-two;
+}
+
diff --git a/integration-tests/tests/themeLoading/themeLoading.mjs b/integration-tests/tests/themeLoading/themeLoading.mjs
new file mode 100644
index 0000000..22b2928
--- /dev/null
+++ b/integration-tests/tests/themeLoading/themeLoading.mjs
@@ -0,0 +1,73 @@
+import { describe, it, before, after } from 'mocha'
+import { expect } from 'chai'
+import {
+ getRootAndWait,
+ takeScreenshotOnFailure,
+} from '../../lib/elements.js'
+
+describe('config: themeLoading', function () {
+ before(async function () {
+ await runner.start('themeLoading')
+ })
+
+ after(async () => {
+ await runner.stop()
+ })
+
+ afterEach(function () {
+ takeScreenshotOnFailure(this.currentTest, webdriver)
+ })
+
+ it('Available themes are discovered and returned in Init response', async function () {
+ await getRootAndWait()
+
+ // Wait for initResponse to be available
+ await webdriver.wait(async () => {
+ const hasInitResponse = await webdriver.executeScript(
+ 'return typeof window.initResponse !== "undefined" && window.initResponse !== null'
+ )
+ return hasInitResponse
+ }, 5000, 'Init response should be available')
+
+ // Get available themes from the Init response
+ const availableThemes = await webdriver.executeScript(
+ 'return window.initResponse ? (window.initResponse.availableThemes || []) : []'
+ )
+
+ // Verify themes array exists and is an array
+ expect(availableThemes).to.be.an('array')
+
+ // Verify that themes with theme.css are discovered
+ // theme-one and theme-two have theme.css, invalid-theme does not
+ expect(availableThemes).to.include('theme-one')
+ expect(availableThemes).to.include('theme-two')
+
+ // Verify that themes without theme.css are not included
+ expect(availableThemes).to.not.include('invalid-theme')
+
+ // Verify themes are sorted alphabetically
+ const sortedThemes = [...availableThemes].sort()
+ expect(availableThemes).to.deep.equal(sortedThemes)
+ })
+
+ it('Available themes list is accessible via JavaScript', async function () {
+ await getRootAndWait()
+
+ // Wait for initResponse to be available
+ await webdriver.wait(async () => {
+ const hasInitResponse = await webdriver.executeScript(
+ 'return typeof window.initResponse !== "undefined" && window.initResponse !== null'
+ )
+ return hasInitResponse
+ }, 5000, 'Init response should be available')
+
+ // Verify availableThemes is accessible
+ const availableThemes = await webdriver.executeScript(
+ 'return window.initResponse ? (window.initResponse.availableThemes || []) : []'
+ )
+
+ expect(availableThemes).to.be.an('array')
+ expect(availableThemes.length).to.be.at.least(2)
+ })
+})
+
diff --git a/lang/combined_output.json b/lang/combined_output.json
index ec612d0..3fda01a 100644
--- a/lang/combined_output.json
+++ b/lang/combined_output.json
@@ -27,7 +27,11 @@
"language-dialog.title": "Sprache auswählen",
"login-button": "Login",
"logs.action": "Aktion",
+ "logs.back-to-list": "Zurück zur Liste",
"logs.blocked": "Blockiert",
+ "logs.calendar": "Kalender",
+ "logs.calendar-title": "Protokoll-Kalender",
+ "logs.clear-date-filter": "Datumsfilter löschen",
"logs.clear-filter": "Suchfilter löschen",
"logs.completed": "Abgeschlossen",
"logs.exit-code": "Ausführungscode",
@@ -45,6 +49,9 @@
"raise-issue": "Ein Problem melden auf GitHub",
"return-to-index": "Zurück zur Startseite",
"search-filter": "Filter aktuelle Seite",
+ "theme-dialog.close": "Schließen",
+ "theme-dialog.default": "Standard-Design",
+ "theme-dialog.title": "Design auswählen",
"welcome": "Willkommen bei OliveTin"
},
"en": {
@@ -73,7 +80,11 @@
"language-dialog.title": "Select Language",
"login-button": "Login",
"logs.action": "Action",
+ "logs.back-to-list": "Back to List",
"logs.blocked": "Blocked",
+ "logs.calendar": "Calendar",
+ "logs.calendar-title": "Logs Calendar",
+ "logs.clear-date-filter": "Clear date filter",
"logs.clear-filter": "Clear search filter",
"logs.completed": "Completed",
"logs.exit-code": "Exit code",
@@ -91,6 +102,9 @@
"raise-issue": "Raise an issue on GitHub",
"return-to-index": "Return to index",
"search-filter": "Filter current page",
+ "theme-dialog.close": "Close",
+ "theme-dialog.default": "Default Theme",
+ "theme-dialog.title": "Select Theme",
"welcome": "Welcome to OliveTin"
},
"es-ES": {
@@ -119,7 +133,11 @@
"language-dialog.title": "Seleccionar idioma",
"login-button": "Iniciar sesión",
"logs.action": "Acción",
+ "logs.back-to-list": "Volver a la Lista",
"logs.blocked": "Bloqueado",
+ "logs.calendar": "Calendario",
+ "logs.calendar-title": "Calendario de Registros",
+ "logs.clear-date-filter": "Limpiar filtro de fecha",
"logs.clear-filter": "Limpiar filtro de búsqueda",
"logs.completed": "Completado",
"logs.exit-code": "Código de salida",
@@ -137,6 +155,9 @@
"raise-issue": "Reportar un problema en GitHub",
"return-to-index": "Volver a la página principal",
"search-filter": "Filtrar página actual",
+ "theme-dialog.close": "Cerrar",
+ "theme-dialog.default": "Tema Predeterminado",
+ "theme-dialog.title": "Seleccionar tema",
"welcome": "Bienvenido a OliveTin"
},
"it-IT": {
@@ -165,7 +186,11 @@
"language-dialog.title": "Seleziona lingua",
"login-button": "Login",
"logs.action": "Azione",
+ "logs.back-to-list": "Torna all'Elenco",
"logs.blocked": "Bloccato",
+ "logs.calendar": "Calendario",
+ "logs.calendar-title": "Calendario dei Registri",
+ "logs.clear-date-filter": "Cancella filtro data",
"logs.clear-filter": "Cancella filtro di ricerca",
"logs.completed": "Completato",
"logs.exit-code": "Codice di uscita",
@@ -183,6 +208,9 @@
"raise-issue": "Segnala un problema su GitHub",
"return-to-index": "Torna alla pagina principale",
"search-filter": "Filtra la pagina corrente",
+ "theme-dialog.close": "Chiudi",
+ "theme-dialog.default": "Tema Predefinito",
+ "theme-dialog.title": "Seleziona tema",
"welcome": "Benvenuto in OliveTin"
},
"zh-Hans-CN": {
@@ -211,7 +239,11 @@
"language-dialog.title": "选择语言",
"login-button": "登录",
"logs.action": "动作",
+ "logs.back-to-list": "返回列表",
"logs.blocked": "阻塞",
+ "logs.calendar": "日历",
+ "logs.calendar-title": "日志日历",
+ "logs.clear-date-filter": "清除日期筛选器",
"logs.clear-filter": "清除搜索筛选器",
"logs.completed": "完成",
"logs.exit-code": "退出代码",
@@ -229,6 +261,9 @@
"raise-issue": "在 GitHub 上报告问题",
"return-to-index": "返回首页",
"search-filter": "过滤当前页面",
+ "theme-dialog.close": "关闭",
+ "theme-dialog.default": "默认主题",
+ "theme-dialog.title": "选择主题",
"welcome": "欢迎使用 OliveTin"
}
}
diff --git a/lang/de-DE.yaml b/lang/de-DE.yaml
index cc398b3..2e5f6c7 100644
--- a/lang/de-DE.yaml
+++ b/lang/de-DE.yaml
@@ -21,6 +21,10 @@ translations:
logs.exit-code: Ausführungscode
logs.completed: Abgeschlossen
logs.clear-filter: Suchfilter löschen
+ logs.clear-date-filter: Datumsfilter löschen
+ logs.calendar: Kalender
+ logs.calendar-title: Protokoll-Kalender
+ logs.back-to-list: Zurück zur Liste
diagnostics.get-support: Unterstützung erhalten
diagnostics.get-support-description: Wenn Sie Probleme mit OliveTin haben und eine Support-Anfrage stellen möchten, wäre es sehr hilfreich, einen sosreport von dieser Seite einzufügen.
diagnostics.where-to-find-help: Wo Sie Hilfe finden
@@ -43,4 +47,7 @@ translations:
language-dialog.title: Sprache auswählen
language-dialog.browser-languages: Browser-Sprachen
language-dialog.not-available: Nicht verfügbar
- language-dialog.close: Schließen
\ No newline at end of file
+ language-dialog.close: Schließen
+ theme-dialog.title: Design auswählen
+ theme-dialog.default: Standard-Design
+ theme-dialog.close: Schließen
\ No newline at end of file
diff --git a/lang/en.yaml b/lang/en.yaml
index 76ebc93..8cf5c25 100644
--- a/lang/en.yaml
+++ b/lang/en.yaml
@@ -21,6 +21,10 @@ translations:
logs.exit-code: Exit code
logs.completed: Completed
logs.clear-filter: Clear search filter
+ logs.clear-date-filter: Clear date filter
+ logs.calendar: Calendar
+ logs.calendar-title: Logs Calendar
+ logs.back-to-list: Back to List
diagnostics.get-support: Get support
diagnostics.get-support-description: If you are having problems with OliveTin and want to raise a support request, it would be very helpful to include a sosreport from this page.
diagnostics.where-to-find-help: Where to find help
@@ -43,4 +47,7 @@ translations:
language-dialog.title: Select Language
language-dialog.browser-languages: Browser languages
language-dialog.not-available: Not available
- language-dialog.close: Close
\ No newline at end of file
+ language-dialog.close: Close
+ theme-dialog.title: Select Theme
+ theme-dialog.default: Default Theme
+ theme-dialog.close: Close
\ No newline at end of file
diff --git a/lang/es-ES.yaml b/lang/es-ES.yaml
index c0d36a5..974eaf6 100644
--- a/lang/es-ES.yaml
+++ b/lang/es-ES.yaml
@@ -21,6 +21,10 @@ translations:
logs.exit-code: Código de salida
logs.completed: Completado
logs.clear-filter: Limpiar filtro de búsqueda
+ logs.clear-date-filter: Limpiar filtro de fecha
+ logs.calendar: Calendario
+ logs.calendar-title: Calendario de Registros
+ logs.back-to-list: Volver a la Lista
diagnostics.get-support: Obtener soporte
diagnostics.get-support-description: Si tiene problemas con OliveTin y desea presentar una solicitud de soporte, sería muy útil incluir un sosreport de esta página.
diagnostics.where-to-find-help: Dónde encontrar ayuda
@@ -43,4 +47,7 @@ translations:
language-dialog.title: Seleccionar idioma
language-dialog.browser-languages: Idiomas del navegador
language-dialog.not-available: No disponible
- language-dialog.close: Cerrar
\ No newline at end of file
+ language-dialog.close: Cerrar
+ theme-dialog.title: Seleccionar tema
+ theme-dialog.default: Tema Predeterminado
+ theme-dialog.close: Cerrar
\ No newline at end of file
diff --git a/lang/it-IT.yaml b/lang/it-IT.yaml
index bac329c..4bc9c66 100644
--- a/lang/it-IT.yaml
+++ b/lang/it-IT.yaml
@@ -21,6 +21,10 @@ translations:
logs.exit-code: Codice di uscita
logs.completed: Completato
logs.clear-filter: Cancella filtro di ricerca
+ logs.clear-date-filter: Cancella filtro data
+ logs.calendar: Calendario
+ logs.calendar-title: Calendario dei Registri
+ logs.back-to-list: Torna all'Elenco
diagnostics.get-support: Ottenere supporto
diagnostics.get-support-description: Se hai problemi con OliveTin e vuoi presentare una richiesta di supporto, sarebbe molto utile includere un sosreport da questa pagina.
diagnostics.where-to-find-help: Dove trovare aiuto
@@ -43,4 +47,7 @@ translations:
language-dialog.title: Seleziona lingua
language-dialog.browser-languages: Lingue del browser
language-dialog.not-available: Non disponibile
- language-dialog.close: Chiudi
\ No newline at end of file
+ language-dialog.close: Chiudi
+ theme-dialog.title: Seleziona tema
+ theme-dialog.default: Tema Predefinito
+ theme-dialog.close: Chiudi
\ No newline at end of file
diff --git a/lang/zh-Hans-CN.yaml b/lang/zh-Hans-CN.yaml
index baaf72e..ad84897 100644
--- a/lang/zh-Hans-CN.yaml
+++ b/lang/zh-Hans-CN.yaml
@@ -22,11 +22,18 @@ translations:
language-dialog.browser-languages: 浏览器语言
language-dialog.not-available: 不可用
language-dialog.close: 关闭
+ theme-dialog.title: 选择主题
+ theme-dialog.default: 默认主题
+ theme-dialog.close: 关闭
logs.timed-out: 超时
logs.blocked: 阻塞
logs.exit-code: 退出代码
logs.completed: 完成
logs.clear-filter: 清除搜索筛选器
+ logs.clear-date-filter: 清除日期筛选器
+ logs.calendar: 日历
+ logs.calendar-title: 日志日历
+ logs.back-to-list: 返回列表
diagnostics.get-support: 获取支持
diagnostics.get-support-description: 如果您在使用 OliveTin 时遇到问题并希望提交支持请求,从本页面包含 sosreport 将非常有帮助。
diagnostics.where-to-find-help: 在哪里找到帮助
diff --git a/proto/olivetin/api/v1/olivetin.proto b/proto/olivetin/api/v1/olivetin.proto
index 07032c5..ced1982 100644
--- a/proto/olivetin/api/v1/olivetin.proto
+++ b/proto/olivetin/api/v1/olivetin.proto
@@ -13,6 +13,7 @@ message Action {
string popup_on_start = 6;
int32 order = 7;
int32 timeout = 8;
+ string datetime_rate_limit_expires = 9; // Datetime when rate limit expires (empty string if not rate limited), format: "2006-01-02 15:04:05"
}
message ActionArgument {
@@ -25,6 +26,7 @@ message ActionArgument {
string description = 6;
map
suggestions = 7;
+ string suggestions_browser_key = 8;
}
message ActionArgumentChoice {
@@ -118,6 +120,7 @@ message StartActionByGetAndWaitResponse {
message GetLogsRequest{
int64 start_offset = 1;
+ string date_filter = 2; // Optional date filter in YYYY-MM-DD format
};
message LogEntry {
@@ -132,12 +135,13 @@ message LogEntry {
repeated string tags = 10;
string execution_tracking_id = 11;
string datetime_finished = 12;
- string action_id = 13;
bool execution_started = 14;
bool execution_finished = 15;
bool blocked = 16;
int64 datetime_index = 17;
bool can_kill = 18;
+ string datetime_rate_limit_expires = 19; // Datetime when rate limit expires (empty string if not rate limited), format: "2006-01-02 15:04:05"
+ string binding_id = 20; // Binding ID for matching rate limits to action buttons
}
message GetLogsResponse {
@@ -215,7 +219,7 @@ message DumpVarsResponse {
map contents = 2;
}
-message ActionEntityPair {
+message DebugBinding {
string action_title = 1;
string entity_prefix = 2;
}
@@ -223,7 +227,7 @@ message ActionEntityPair {
message DumpPublicIdActionMapRequest {}
message DumpPublicIdActionMapResponse {
string alert = 1;
- map contents = 2;
+ map contents = 2;
}
message GetReadyzRequest {}
@@ -328,6 +332,7 @@ message InitResponse {
bool show_diagnostics = 21;
bool show_log_list = 22;
bool login_required = 23;
+ repeated string available_themes = 24; // List of available theme names
}
message AdditionalLink {
diff --git a/service/gen/olivetin/api/v1/olivetin.pb.go b/service/gen/olivetin/api/v1/olivetin.pb.go
index e49869b..9516ebd 100644
--- a/service/gen/olivetin/api/v1/olivetin.pb.go
+++ b/service/gen/olivetin/api/v1/olivetin.pb.go
@@ -22,17 +22,18 @@ const (
)
type Action struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- BindingId string `protobuf:"bytes,1,opt,name=binding_id,json=bindingId,proto3" json:"binding_id,omitempty"`
- Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"`
- Icon string `protobuf:"bytes,3,opt,name=icon,proto3" json:"icon,omitempty"`
- CanExec bool `protobuf:"varint,4,opt,name=can_exec,json=canExec,proto3" json:"can_exec,omitempty"`
- Arguments []*ActionArgument `protobuf:"bytes,5,rep,name=arguments,proto3" json:"arguments,omitempty"`
- PopupOnStart string `protobuf:"bytes,6,opt,name=popup_on_start,json=popupOnStart,proto3" json:"popup_on_start,omitempty"`
- Order int32 `protobuf:"varint,7,opt,name=order,proto3" json:"order,omitempty"`
- Timeout int32 `protobuf:"varint,8,opt,name=timeout,proto3" json:"timeout,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
+ state protoimpl.MessageState `protogen:"open.v1"`
+ BindingId string `protobuf:"bytes,1,opt,name=binding_id,json=bindingId,proto3" json:"binding_id,omitempty"`
+ Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"`
+ Icon string `protobuf:"bytes,3,opt,name=icon,proto3" json:"icon,omitempty"`
+ CanExec bool `protobuf:"varint,4,opt,name=can_exec,json=canExec,proto3" json:"can_exec,omitempty"`
+ Arguments []*ActionArgument `protobuf:"bytes,5,rep,name=arguments,proto3" json:"arguments,omitempty"`
+ PopupOnStart string `protobuf:"bytes,6,opt,name=popup_on_start,json=popupOnStart,proto3" json:"popup_on_start,omitempty"`
+ Order int32 `protobuf:"varint,7,opt,name=order,proto3" json:"order,omitempty"`
+ Timeout int32 `protobuf:"varint,8,opt,name=timeout,proto3" json:"timeout,omitempty"`
+ DatetimeRateLimitExpires string `protobuf:"bytes,9,opt,name=datetime_rate_limit_expires,json=datetimeRateLimitExpires,proto3" json:"datetime_rate_limit_expires,omitempty"` // Datetime when rate limit expires (empty string if not rate limited), format: "2006-01-02 15:04:05"
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
}
func (x *Action) Reset() {
@@ -121,17 +122,25 @@ func (x *Action) GetTimeout() int32 {
return 0
}
+func (x *Action) GetDatetimeRateLimitExpires() string {
+ if x != nil {
+ return x.DatetimeRateLimitExpires
+ }
+ return ""
+}
+
type ActionArgument struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
- Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"`
- Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"`
- DefaultValue string `protobuf:"bytes,4,opt,name=default_value,json=defaultValue,proto3" json:"default_value,omitempty"`
- Choices []*ActionArgumentChoice `protobuf:"bytes,5,rep,name=choices,proto3" json:"choices,omitempty"`
- Description string `protobuf:"bytes,6,opt,name=description,proto3" json:"description,omitempty"`
- Suggestions map[string]string `protobuf:"bytes,7,rep,name=suggestions,proto3" json:"suggestions,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+ Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"`
+ Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"`
+ DefaultValue string `protobuf:"bytes,4,opt,name=default_value,json=defaultValue,proto3" json:"default_value,omitempty"`
+ Choices []*ActionArgumentChoice `protobuf:"bytes,5,rep,name=choices,proto3" json:"choices,omitempty"`
+ Description string `protobuf:"bytes,6,opt,name=description,proto3" json:"description,omitempty"`
+ Suggestions map[string]string `protobuf:"bytes,7,rep,name=suggestions,proto3" json:"suggestions,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+ SuggestionsBrowserKey string `protobuf:"bytes,8,opt,name=suggestions_browser_key,json=suggestionsBrowserKey,proto3" json:"suggestions_browser_key,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
}
func (x *ActionArgument) Reset() {
@@ -213,6 +222,13 @@ func (x *ActionArgument) GetSuggestions() map[string]string {
return nil
}
+func (x *ActionArgument) GetSuggestionsBrowserKey() string {
+ if x != nil {
+ return x.SuggestionsBrowserKey
+ }
+ return ""
+}
+
type ActionArgumentChoice struct {
state protoimpl.MessageState `protogen:"open.v1"`
Value string `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"`
@@ -1088,6 +1104,7 @@ func (x *StartActionByGetAndWaitResponse) GetLogEntry() *LogEntry {
type GetLogsRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
StartOffset int64 `protobuf:"varint,1,opt,name=start_offset,json=startOffset,proto3" json:"start_offset,omitempty"`
+ DateFilter string `protobuf:"bytes,2,opt,name=date_filter,json=dateFilter,proto3" json:"date_filter,omitempty"` // Optional date filter in YYYY-MM-DD format
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
@@ -1129,27 +1146,35 @@ func (x *GetLogsRequest) GetStartOffset() int64 {
return 0
}
+func (x *GetLogsRequest) GetDateFilter() string {
+ if x != nil {
+ return x.DateFilter
+ }
+ return ""
+}
+
type LogEntry struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- DatetimeStarted string `protobuf:"bytes,1,opt,name=datetime_started,json=datetimeStarted,proto3" json:"datetime_started,omitempty"`
- ActionTitle string `protobuf:"bytes,2,opt,name=action_title,json=actionTitle,proto3" json:"action_title,omitempty"`
- Output string `protobuf:"bytes,3,opt,name=output,proto3" json:"output,omitempty"`
- TimedOut bool `protobuf:"varint,5,opt,name=timed_out,json=timedOut,proto3" json:"timed_out,omitempty"`
- ExitCode int32 `protobuf:"varint,6,opt,name=exit_code,json=exitCode,proto3" json:"exit_code,omitempty"`
- User string `protobuf:"bytes,7,opt,name=user,proto3" json:"user,omitempty"`
- UserClass string `protobuf:"bytes,8,opt,name=user_class,json=userClass,proto3" json:"user_class,omitempty"`
- ActionIcon string `protobuf:"bytes,9,opt,name=action_icon,json=actionIcon,proto3" json:"action_icon,omitempty"`
- Tags []string `protobuf:"bytes,10,rep,name=tags,proto3" json:"tags,omitempty"`
- ExecutionTrackingId string `protobuf:"bytes,11,opt,name=execution_tracking_id,json=executionTrackingId,proto3" json:"execution_tracking_id,omitempty"`
- DatetimeFinished string `protobuf:"bytes,12,opt,name=datetime_finished,json=datetimeFinished,proto3" json:"datetime_finished,omitempty"`
- ActionId string `protobuf:"bytes,13,opt,name=action_id,json=actionId,proto3" json:"action_id,omitempty"`
- ExecutionStarted bool `protobuf:"varint,14,opt,name=execution_started,json=executionStarted,proto3" json:"execution_started,omitempty"`
- ExecutionFinished bool `protobuf:"varint,15,opt,name=execution_finished,json=executionFinished,proto3" json:"execution_finished,omitempty"`
- Blocked bool `protobuf:"varint,16,opt,name=blocked,proto3" json:"blocked,omitempty"`
- DatetimeIndex int64 `protobuf:"varint,17,opt,name=datetime_index,json=datetimeIndex,proto3" json:"datetime_index,omitempty"`
- CanKill bool `protobuf:"varint,18,opt,name=can_kill,json=canKill,proto3" json:"can_kill,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
+ state protoimpl.MessageState `protogen:"open.v1"`
+ DatetimeStarted string `protobuf:"bytes,1,opt,name=datetime_started,json=datetimeStarted,proto3" json:"datetime_started,omitempty"`
+ ActionTitle string `protobuf:"bytes,2,opt,name=action_title,json=actionTitle,proto3" json:"action_title,omitempty"`
+ Output string `protobuf:"bytes,3,opt,name=output,proto3" json:"output,omitempty"`
+ TimedOut bool `protobuf:"varint,5,opt,name=timed_out,json=timedOut,proto3" json:"timed_out,omitempty"`
+ ExitCode int32 `protobuf:"varint,6,opt,name=exit_code,json=exitCode,proto3" json:"exit_code,omitempty"`
+ User string `protobuf:"bytes,7,opt,name=user,proto3" json:"user,omitempty"`
+ UserClass string `protobuf:"bytes,8,opt,name=user_class,json=userClass,proto3" json:"user_class,omitempty"`
+ ActionIcon string `protobuf:"bytes,9,opt,name=action_icon,json=actionIcon,proto3" json:"action_icon,omitempty"`
+ Tags []string `protobuf:"bytes,10,rep,name=tags,proto3" json:"tags,omitempty"`
+ ExecutionTrackingId string `protobuf:"bytes,11,opt,name=execution_tracking_id,json=executionTrackingId,proto3" json:"execution_tracking_id,omitempty"`
+ DatetimeFinished string `protobuf:"bytes,12,opt,name=datetime_finished,json=datetimeFinished,proto3" json:"datetime_finished,omitempty"`
+ ExecutionStarted bool `protobuf:"varint,14,opt,name=execution_started,json=executionStarted,proto3" json:"execution_started,omitempty"`
+ ExecutionFinished bool `protobuf:"varint,15,opt,name=execution_finished,json=executionFinished,proto3" json:"execution_finished,omitempty"`
+ Blocked bool `protobuf:"varint,16,opt,name=blocked,proto3" json:"blocked,omitempty"`
+ DatetimeIndex int64 `protobuf:"varint,17,opt,name=datetime_index,json=datetimeIndex,proto3" json:"datetime_index,omitempty"`
+ CanKill bool `protobuf:"varint,18,opt,name=can_kill,json=canKill,proto3" json:"can_kill,omitempty"`
+ DatetimeRateLimitExpires string `protobuf:"bytes,19,opt,name=datetime_rate_limit_expires,json=datetimeRateLimitExpires,proto3" json:"datetime_rate_limit_expires,omitempty"` // Datetime when rate limit expires (empty string if not rate limited), format: "2006-01-02 15:04:05"
+ BindingId string `protobuf:"bytes,20,opt,name=binding_id,json=bindingId,proto3" json:"binding_id,omitempty"` // Binding ID for matching rate limits to action buttons
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
}
func (x *LogEntry) Reset() {
@@ -1259,13 +1284,6 @@ func (x *LogEntry) GetDatetimeFinished() string {
return ""
}
-func (x *LogEntry) GetActionId() string {
- if x != nil {
- return x.ActionId
- }
- return ""
-}
-
func (x *LogEntry) GetExecutionStarted() bool {
if x != nil {
return x.ExecutionStarted
@@ -1301,6 +1319,20 @@ func (x *LogEntry) GetCanKill() bool {
return false
}
+func (x *LogEntry) GetDatetimeRateLimitExpires() string {
+ if x != nil {
+ return x.DatetimeRateLimitExpires
+ }
+ return ""
+}
+
+func (x *LogEntry) GetBindingId() string {
+ if x != nil {
+ return x.BindingId
+ }
+ return ""
+}
+
type GetLogsResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
Logs []*LogEntry `protobuf:"bytes,1,rep,name=logs,proto3" json:"logs,omitempty"`
@@ -2089,7 +2121,7 @@ func (x *DumpVarsResponse) GetContents() map[string]string {
return nil
}
-type ActionEntityPair struct {
+type DebugBinding struct {
state protoimpl.MessageState `protogen:"open.v1"`
ActionTitle string `protobuf:"bytes,1,opt,name=action_title,json=actionTitle,proto3" json:"action_title,omitempty"`
EntityPrefix string `protobuf:"bytes,2,opt,name=entity_prefix,json=entityPrefix,proto3" json:"entity_prefix,omitempty"`
@@ -2097,20 +2129,20 @@ type ActionEntityPair struct {
sizeCache protoimpl.SizeCache
}
-func (x *ActionEntityPair) Reset() {
- *x = ActionEntityPair{}
+func (x *DebugBinding) Reset() {
+ *x = DebugBinding{}
mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[35]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
-func (x *ActionEntityPair) String() string {
+func (x *DebugBinding) String() string {
return protoimpl.X.MessageStringOf(x)
}
-func (*ActionEntityPair) ProtoMessage() {}
+func (*DebugBinding) ProtoMessage() {}
-func (x *ActionEntityPair) ProtoReflect() protoreflect.Message {
+func (x *DebugBinding) ProtoReflect() protoreflect.Message {
mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[35]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@@ -2122,19 +2154,19 @@ func (x *ActionEntityPair) ProtoReflect() protoreflect.Message {
return mi.MessageOf(x)
}
-// Deprecated: Use ActionEntityPair.ProtoReflect.Descriptor instead.
-func (*ActionEntityPair) Descriptor() ([]byte, []int) {
+// Deprecated: Use DebugBinding.ProtoReflect.Descriptor instead.
+func (*DebugBinding) Descriptor() ([]byte, []int) {
return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{35}
}
-func (x *ActionEntityPair) GetActionTitle() string {
+func (x *DebugBinding) GetActionTitle() string {
if x != nil {
return x.ActionTitle
}
return ""
}
-func (x *ActionEntityPair) GetEntityPrefix() string {
+func (x *DebugBinding) GetEntityPrefix() string {
if x != nil {
return x.EntityPrefix
}
@@ -2178,9 +2210,9 @@ func (*DumpPublicIdActionMapRequest) Descriptor() ([]byte, []int) {
}
type DumpPublicIdActionMapResponse struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- Alert string `protobuf:"bytes,1,opt,name=alert,proto3" json:"alert,omitempty"`
- Contents map[string]*ActionEntityPair `protobuf:"bytes,2,rep,name=contents,proto3" json:"contents,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Alert string `protobuf:"bytes,1,opt,name=alert,proto3" json:"alert,omitempty"`
+ Contents map[string]*DebugBinding `protobuf:"bytes,2,rep,name=contents,proto3" json:"contents,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
@@ -2222,7 +2254,7 @@ func (x *DumpPublicIdActionMapResponse) GetAlert() string {
return ""
}
-func (x *DumpPublicIdActionMapResponse) GetContents() map[string]*ActionEntityPair {
+func (x *DumpPublicIdActionMapResponse) GetContents() map[string]*DebugBinding {
if x != nil {
return x.Contents
}
@@ -3204,6 +3236,7 @@ type InitResponse struct {
ShowDiagnostics bool `protobuf:"varint,21,opt,name=show_diagnostics,json=showDiagnostics,proto3" json:"show_diagnostics,omitempty"`
ShowLogList bool `protobuf:"varint,22,opt,name=show_log_list,json=showLogList,proto3" json:"show_log_list,omitempty"`
LoginRequired bool `protobuf:"varint,23,opt,name=login_required,json=loginRequired,proto3" json:"login_required,omitempty"`
+ AvailableThemes []string `protobuf:"bytes,24,rep,name=available_themes,json=availableThemes,proto3" json:"available_themes,omitempty"` // List of available theme names
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
@@ -3399,6 +3432,13 @@ func (x *InitResponse) GetLoginRequired() bool {
return false
}
+func (x *InitResponse) GetAvailableThemes() []string {
+ if x != nil {
+ return x.AvailableThemes
+ }
+ return nil
+}
+
type AdditionalLink struct {
state protoimpl.MessageState `protogen:"open.v1"`
Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"`
@@ -3839,7 +3879,7 @@ var File_olivetin_api_v1_olivetin_proto protoreflect.FileDescriptor
const file_olivetin_api_v1_olivetin_proto_rawDesc = "" +
"\n" +
- "\x1eolivetin/api/v1/olivetin.proto\x12\x0folivetin.api.v1\"\x81\x02\n" +
+ "\x1eolivetin/api/v1/olivetin.proto\x12\x0folivetin.api.v1\"\xc0\x02\n" +
"\x06Action\x12\x1d\n" +
"\n" +
"binding_id\x18\x01 \x01(\tR\tbindingId\x12\x14\n" +
@@ -3849,7 +3889,8 @@ const file_olivetin_api_v1_olivetin_proto_rawDesc = "" +
"\targuments\x18\x05 \x03(\v2\x1f.olivetin.api.v1.ActionArgumentR\targuments\x12$\n" +
"\x0epopup_on_start\x18\x06 \x01(\tR\fpopupOnStart\x12\x14\n" +
"\x05order\x18\a \x01(\x05R\x05order\x12\x18\n" +
- "\atimeout\x18\b \x01(\x05R\atimeout\"\xea\x02\n" +
+ "\atimeout\x18\b \x01(\x05R\atimeout\x12=\n" +
+ "\x1bdatetime_rate_limit_expires\x18\t \x01(\tR\x18datetimeRateLimitExpires\"\xa2\x03\n" +
"\x0eActionArgument\x12\x12\n" +
"\x04name\x18\x01 \x01(\tR\x04name\x12\x14\n" +
"\x05title\x18\x02 \x01(\tR\x05title\x12\x12\n" +
@@ -3857,7 +3898,8 @@ const file_olivetin_api_v1_olivetin_proto_rawDesc = "" +
"\rdefault_value\x18\x04 \x01(\tR\fdefaultValue\x12?\n" +
"\achoices\x18\x05 \x03(\v2%.olivetin.api.v1.ActionArgumentChoiceR\achoices\x12 \n" +
"\vdescription\x18\x06 \x01(\tR\vdescription\x12R\n" +
- "\vsuggestions\x18\a \x03(\v20.olivetin.api.v1.ActionArgument.SuggestionsEntryR\vsuggestions\x1a>\n" +
+ "\vsuggestions\x18\a \x03(\v20.olivetin.api.v1.ActionArgument.SuggestionsEntryR\vsuggestions\x126\n" +
+ "\x17suggestions_browser_key\x18\b \x01(\tR\x15suggestionsBrowserKey\x1a>\n" +
"\x10SuggestionsEntry\x12\x10\n" +
"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
"\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"B\n" +
@@ -3922,9 +3964,11 @@ const file_olivetin_api_v1_olivetin_proto_rawDesc = "" +
"\x1eStartActionByGetAndWaitRequest\x12\x1b\n" +
"\taction_id\x18\x01 \x01(\tR\bactionId\"Y\n" +
"\x1fStartActionByGetAndWaitResponse\x126\n" +
- "\tlog_entry\x18\x01 \x01(\v2\x19.olivetin.api.v1.LogEntryR\blogEntry\"3\n" +
+ "\tlog_entry\x18\x01 \x01(\v2\x19.olivetin.api.v1.LogEntryR\blogEntry\"T\n" +
"\x0eGetLogsRequest\x12!\n" +
- "\fstart_offset\x18\x01 \x01(\x03R\vstartOffset\"\xc8\x04\n" +
+ "\fstart_offset\x18\x01 \x01(\x03R\vstartOffset\x12\x1f\n" +
+ "\vdate_filter\x18\x02 \x01(\tR\n" +
+ "dateFilter\"\x89\x05\n" +
"\bLogEntry\x12)\n" +
"\x10datetime_started\x18\x01 \x01(\tR\x0fdatetimeStarted\x12!\n" +
"\faction_title\x18\x02 \x01(\tR\vactionTitle\x12\x16\n" +
@@ -3939,13 +3983,15 @@ const file_olivetin_api_v1_olivetin_proto_rawDesc = "" +
"\x04tags\x18\n" +
" \x03(\tR\x04tags\x122\n" +
"\x15execution_tracking_id\x18\v \x01(\tR\x13executionTrackingId\x12+\n" +
- "\x11datetime_finished\x18\f \x01(\tR\x10datetimeFinished\x12\x1b\n" +
- "\taction_id\x18\r \x01(\tR\bactionId\x12+\n" +
+ "\x11datetime_finished\x18\f \x01(\tR\x10datetimeFinished\x12+\n" +
"\x11execution_started\x18\x0e \x01(\bR\x10executionStarted\x12-\n" +
"\x12execution_finished\x18\x0f \x01(\bR\x11executionFinished\x12\x18\n" +
"\ablocked\x18\x10 \x01(\bR\ablocked\x12%\n" +
"\x0edatetime_index\x18\x11 \x01(\x03R\rdatetimeIndex\x12\x19\n" +
- "\bcan_kill\x18\x12 \x01(\bR\acanKill\"\xca\x01\n" +
+ "\bcan_kill\x18\x12 \x01(\bR\acanKill\x12=\n" +
+ "\x1bdatetime_rate_limit_expires\x18\x13 \x01(\tR\x18datetimeRateLimitExpires\x12\x1d\n" +
+ "\n" +
+ "binding_id\x18\x14 \x01(\tR\tbindingId\"\xca\x01\n" +
"\x0fGetLogsResponse\x12-\n" +
"\x04logs\x18\x01 \x03(\v2\x19.olivetin.api.v1.LogEntryR\x04logs\x12'\n" +
"\x0fcount_remaining\x18\x02 \x01(\x03R\x0ecountRemaining\x12\x1b\n" +
@@ -3997,17 +4043,17 @@ const file_olivetin_api_v1_olivetin_proto_rawDesc = "" +
"\bcontents\x18\x02 \x03(\v2/.olivetin.api.v1.DumpVarsResponse.ContentsEntryR\bcontents\x1a;\n" +
"\rContentsEntry\x12\x10\n" +
"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
- "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"Z\n" +
- "\x10ActionEntityPair\x12!\n" +
+ "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"V\n" +
+ "\fDebugBinding\x12!\n" +
"\faction_title\x18\x01 \x01(\tR\vactionTitle\x12#\n" +
"\rentity_prefix\x18\x02 \x01(\tR\fentityPrefix\"\x1e\n" +
- "\x1cDumpPublicIdActionMapRequest\"\xef\x01\n" +
+ "\x1cDumpPublicIdActionMapRequest\"\xeb\x01\n" +
"\x1dDumpPublicIdActionMapResponse\x12\x14\n" +
"\x05alert\x18\x01 \x01(\tR\x05alert\x12X\n" +
- "\bcontents\x18\x02 \x03(\v2<.olivetin.api.v1.DumpPublicIdActionMapResponse.ContentsEntryR\bcontents\x1a^\n" +
+ "\bcontents\x18\x02 \x03(\v2<.olivetin.api.v1.DumpPublicIdActionMapResponse.ContentsEntryR\bcontents\x1aZ\n" +
"\rContentsEntry\x12\x10\n" +
- "\x03key\x18\x01 \x01(\tR\x03key\x127\n" +
- "\x05value\x18\x02 \x01(\v2!.olivetin.api.v1.ActionEntityPairR\x05value:\x028\x01\"\x12\n" +
+ "\x03key\x18\x01 \x01(\tR\x03key\x123\n" +
+ "\x05value\x18\x02 \x01(\v2\x1d.olivetin.api.v1.DebugBindingR\x05value:\x028\x01\"\x12\n" +
"\x10GetReadyzRequest\"+\n" +
"\x11GetReadyzResponse\x12\x16\n" +
"\x06status\x18\x01 \x01(\tR\x06status\"\x14\n" +
@@ -4050,7 +4096,7 @@ const file_olivetin_api_v1_olivetin_proto_rawDesc = "" +
"\x16GetDiagnosticsResponse\x12 \n" +
"\vSshFoundKey\x18\x01 \x01(\tR\vSshFoundKey\x12&\n" +
"\x0eSshFoundConfig\x18\x02 \x01(\tR\x0eSshFoundConfig\"\r\n" +
- "\vInitRequest\"\xa2\b\n" +
+ "\vInitRequest\"\xcd\b\n" +
"\fInitResponse\x12\x1e\n" +
"\n" +
"showFooter\x18\x01 \x01(\bR\n" +
@@ -4078,7 +4124,8 @@ const file_olivetin_api_v1_olivetin_proto_rawDesc = "" +
"banner_css\x18\x14 \x01(\tR\tbannerCss\x12)\n" +
"\x10show_diagnostics\x18\x15 \x01(\bR\x0fshowDiagnostics\x12\"\n" +
"\rshow_log_list\x18\x16 \x01(\bR\vshowLogList\x12%\n" +
- "\x0elogin_required\x18\x17 \x01(\bR\rloginRequired\"8\n" +
+ "\x0elogin_required\x18\x17 \x01(\bR\rloginRequired\x12)\n" +
+ "\x10available_themes\x18\x18 \x03(\tR\x0favailableThemes\"8\n" +
"\x0eAdditionalLink\x12\x14\n" +
"\x05title\x18\x01 \x01(\tR\x05title\x12\x10\n" +
"\x03url\x18\x02 \x01(\tR\x03url\"L\n" +
@@ -4181,7 +4228,7 @@ var file_olivetin_api_v1_olivetin_proto_goTypes = []any{
(*SosReportResponse)(nil), // 32: olivetin.api.v1.SosReportResponse
(*DumpVarsRequest)(nil), // 33: olivetin.api.v1.DumpVarsRequest
(*DumpVarsResponse)(nil), // 34: olivetin.api.v1.DumpVarsResponse
- (*ActionEntityPair)(nil), // 35: olivetin.api.v1.ActionEntityPair
+ (*DebugBinding)(nil), // 35: olivetin.api.v1.DebugBinding
(*DumpPublicIdActionMapRequest)(nil), // 36: olivetin.api.v1.DumpPublicIdActionMapRequest
(*DumpPublicIdActionMapResponse)(nil), // 37: olivetin.api.v1.DumpPublicIdActionMapResponse
(*GetReadyzRequest)(nil), // 38: olivetin.api.v1.GetReadyzRequest
@@ -4250,7 +4297,7 @@ var file_olivetin_api_v1_olivetin_proto_depIdxs = []int32{
0, // 27: olivetin.api.v1.GetActionBindingResponse.action:type_name -> olivetin.api.v1.Action
65, // 28: olivetin.api.v1.GetEntitiesResponse.entity_definitions:type_name -> olivetin.api.v1.EntityDefinition
3, // 29: olivetin.api.v1.EntityDefinition.instances:type_name -> olivetin.api.v1.Entity
- 35, // 30: olivetin.api.v1.DumpPublicIdActionMapResponse.ContentsEntry.value:type_name -> olivetin.api.v1.ActionEntityPair
+ 35, // 30: olivetin.api.v1.DumpPublicIdActionMapResponse.ContentsEntry.value:type_name -> olivetin.api.v1.DebugBinding
6, // 31: olivetin.api.v1.OliveTinApiService.GetDashboard:input_type -> olivetin.api.v1.GetDashboardRequest
9, // 32: olivetin.api.v1.OliveTinApiService.StartAction:input_type -> olivetin.api.v1.StartActionRequest
12, // 33: olivetin.api.v1.OliveTinApiService.StartActionAndWait:input_type -> olivetin.api.v1.StartActionAndWaitRequest
diff --git a/service/gen/olivetin/api/v1/olivetin.pb.go.orig b/service/gen/olivetin/api/v1/olivetin.pb.go.orig
new file mode 100644
index 0000000..74592d6
--- /dev/null
+++ b/service/gen/olivetin/api/v1/olivetin.pb.go.orig
@@ -0,0 +1,4378 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.36.11
+// protoc (unknown)
+// source: olivetin/api/v1/olivetin.proto
+
+package apiv1
+
+import (
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ reflect "reflect"
+ sync "sync"
+ unsafe "unsafe"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type Action struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ BindingId string `protobuf:"bytes,1,opt,name=binding_id,json=bindingId,proto3" json:"binding_id,omitempty"`
+ Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"`
+ Icon string `protobuf:"bytes,3,opt,name=icon,proto3" json:"icon,omitempty"`
+ CanExec bool `protobuf:"varint,4,opt,name=can_exec,json=canExec,proto3" json:"can_exec,omitempty"`
+ Arguments []*ActionArgument `protobuf:"bytes,5,rep,name=arguments,proto3" json:"arguments,omitempty"`
+ PopupOnStart string `protobuf:"bytes,6,opt,name=popup_on_start,json=popupOnStart,proto3" json:"popup_on_start,omitempty"`
+ Order int32 `protobuf:"varint,7,opt,name=order,proto3" json:"order,omitempty"`
+ Timeout int32 `protobuf:"varint,8,opt,name=timeout,proto3" json:"timeout,omitempty"`
+ DatetimeRateLimitExpires string `protobuf:"bytes,9,opt,name=datetime_rate_limit_expires,json=datetimeRateLimitExpires,proto3" json:"datetime_rate_limit_expires,omitempty"` // Datetime when rate limit expires (empty string if not rate limited), format: "2006-01-02 15:04:05"
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *Action) Reset() {
+ *x = Action{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *Action) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Action) ProtoMessage() {}
+
+func (x *Action) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[0]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use Action.ProtoReflect.Descriptor instead.
+func (*Action) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *Action) GetBindingId() string {
+ if x != nil {
+ return x.BindingId
+ }
+ return ""
+}
+
+func (x *Action) GetTitle() string {
+ if x != nil {
+ return x.Title
+ }
+ return ""
+}
+
+func (x *Action) GetIcon() string {
+ if x != nil {
+ return x.Icon
+ }
+ return ""
+}
+
+func (x *Action) GetCanExec() bool {
+ if x != nil {
+ return x.CanExec
+ }
+ return false
+}
+
+func (x *Action) GetArguments() []*ActionArgument {
+ if x != nil {
+ return x.Arguments
+ }
+ return nil
+}
+
+func (x *Action) GetPopupOnStart() string {
+ if x != nil {
+ return x.PopupOnStart
+ }
+ return ""
+}
+
+func (x *Action) GetOrder() int32 {
+ if x != nil {
+ return x.Order
+ }
+ return 0
+}
+
+func (x *Action) GetTimeout() int32 {
+ if x != nil {
+ return x.Timeout
+ }
+ return 0
+}
+
+func (x *Action) GetDatetimeRateLimitExpires() string {
+ if x != nil {
+ return x.DatetimeRateLimitExpires
+ }
+ return ""
+}
+
+type ActionArgument struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+ Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"`
+ Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"`
+ DefaultValue string `protobuf:"bytes,4,opt,name=default_value,json=defaultValue,proto3" json:"default_value,omitempty"`
+ Choices []*ActionArgumentChoice `protobuf:"bytes,5,rep,name=choices,proto3" json:"choices,omitempty"`
+ Description string `protobuf:"bytes,6,opt,name=description,proto3" json:"description,omitempty"`
+ Suggestions map[string]string `protobuf:"bytes,7,rep,name=suggestions,proto3" json:"suggestions,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+ SuggestionsBrowserKey string `protobuf:"bytes,8,opt,name=suggestions_browser_key,json=suggestionsBrowserKey,proto3" json:"suggestions_browser_key,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ActionArgument) Reset() {
+ *x = ActionArgument{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ActionArgument) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ActionArgument) ProtoMessage() {}
+
+func (x *ActionArgument) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[1]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ActionArgument.ProtoReflect.Descriptor instead.
+func (*ActionArgument) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *ActionArgument) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *ActionArgument) GetTitle() string {
+ if x != nil {
+ return x.Title
+ }
+ return ""
+}
+
+func (x *ActionArgument) GetType() string {
+ if x != nil {
+ return x.Type
+ }
+ return ""
+}
+
+func (x *ActionArgument) GetDefaultValue() string {
+ if x != nil {
+ return x.DefaultValue
+ }
+ return ""
+}
+
+func (x *ActionArgument) GetChoices() []*ActionArgumentChoice {
+ if x != nil {
+ return x.Choices
+ }
+ return nil
+}
+
+func (x *ActionArgument) GetDescription() string {
+ if x != nil {
+ return x.Description
+ }
+ return ""
+}
+
+func (x *ActionArgument) GetSuggestions() map[string]string {
+ if x != nil {
+ return x.Suggestions
+ }
+ return nil
+}
+
+func (x *ActionArgument) GetSuggestionsBrowserKey() string {
+ if x != nil {
+ return x.SuggestionsBrowserKey
+ }
+ return ""
+}
+
+type ActionArgumentChoice struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Value string `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"`
+ Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ActionArgumentChoice) Reset() {
+ *x = ActionArgumentChoice{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[2]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ActionArgumentChoice) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ActionArgumentChoice) ProtoMessage() {}
+
+func (x *ActionArgumentChoice) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[2]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ActionArgumentChoice.ProtoReflect.Descriptor instead.
+func (*ActionArgumentChoice) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *ActionArgumentChoice) GetValue() string {
+ if x != nil {
+ return x.Value
+ }
+ return ""
+}
+
+func (x *ActionArgumentChoice) GetTitle() string {
+ if x != nil {
+ return x.Title
+ }
+ return ""
+}
+
+type Entity struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"`
+ UniqueKey string `protobuf:"bytes,2,opt,name=unique_key,json=uniqueKey,proto3" json:"unique_key,omitempty"`
+ Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"`
+ Directories []string `protobuf:"bytes,4,rep,name=directories,proto3" json:"directories,omitempty"`
+ Fields map[string]string `protobuf:"bytes,5,rep,name=fields,proto3" json:"fields,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *Entity) Reset() {
+ *x = Entity{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[3]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *Entity) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Entity) ProtoMessage() {}
+
+func (x *Entity) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[3]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use Entity.ProtoReflect.Descriptor instead.
+func (*Entity) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *Entity) GetTitle() string {
+ if x != nil {
+ return x.Title
+ }
+ return ""
+}
+
+func (x *Entity) GetUniqueKey() string {
+ if x != nil {
+ return x.UniqueKey
+ }
+ return ""
+}
+
+func (x *Entity) GetType() string {
+ if x != nil {
+ return x.Type
+ }
+ return ""
+}
+
+func (x *Entity) GetDirectories() []string {
+ if x != nil {
+ return x.Directories
+ }
+ return nil
+}
+
+func (x *Entity) GetFields() map[string]string {
+ if x != nil {
+ return x.Fields
+ }
+ return nil
+}
+
+type GetDashboardResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"`
+ Dashboard *Dashboard `protobuf:"bytes,4,opt,name=dashboard,proto3" json:"dashboard,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetDashboardResponse) Reset() {
+ *x = GetDashboardResponse{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[4]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GetDashboardResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetDashboardResponse) ProtoMessage() {}
+
+func (x *GetDashboardResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[4]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetDashboardResponse.ProtoReflect.Descriptor instead.
+func (*GetDashboardResponse) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *GetDashboardResponse) GetTitle() string {
+ if x != nil {
+ return x.Title
+ }
+ return ""
+}
+
+func (x *GetDashboardResponse) GetDashboard() *Dashboard {
+ if x != nil {
+ return x.Dashboard
+ }
+ return nil
+}
+
+type EffectivePolicy struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ ShowDiagnostics bool `protobuf:"varint,1,opt,name=show_diagnostics,json=showDiagnostics,proto3" json:"show_diagnostics,omitempty"`
+ ShowLogList bool `protobuf:"varint,2,opt,name=show_log_list,json=showLogList,proto3" json:"show_log_list,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *EffectivePolicy) Reset() {
+ *x = EffectivePolicy{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[5]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *EffectivePolicy) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*EffectivePolicy) ProtoMessage() {}
+
+func (x *EffectivePolicy) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[5]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use EffectivePolicy.ProtoReflect.Descriptor instead.
+func (*EffectivePolicy) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *EffectivePolicy) GetShowDiagnostics() bool {
+ if x != nil {
+ return x.ShowDiagnostics
+ }
+ return false
+}
+
+func (x *EffectivePolicy) GetShowLogList() bool {
+ if x != nil {
+ return x.ShowLogList
+ }
+ return false
+}
+
+type GetDashboardRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"`
+ EntityType string `protobuf:"bytes,2,opt,name=entity_type,json=entityType,proto3" json:"entity_type,omitempty"`
+ EntityKey string `protobuf:"bytes,3,opt,name=entity_key,json=entityKey,proto3" json:"entity_key,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetDashboardRequest) Reset() {
+ *x = GetDashboardRequest{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[6]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GetDashboardRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetDashboardRequest) ProtoMessage() {}
+
+func (x *GetDashboardRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[6]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetDashboardRequest.ProtoReflect.Descriptor instead.
+func (*GetDashboardRequest) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{6}
+}
+
+func (x *GetDashboardRequest) GetTitle() string {
+ if x != nil {
+ return x.Title
+ }
+ return ""
+}
+
+func (x *GetDashboardRequest) GetEntityType() string {
+ if x != nil {
+ return x.EntityType
+ }
+ return ""
+}
+
+func (x *GetDashboardRequest) GetEntityKey() string {
+ if x != nil {
+ return x.EntityKey
+ }
+ return ""
+}
+
+type Dashboard struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"`
+ Contents []*DashboardComponent `protobuf:"bytes,2,rep,name=contents,proto3" json:"contents,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *Dashboard) Reset() {
+ *x = Dashboard{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[7]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *Dashboard) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Dashboard) ProtoMessage() {}
+
+func (x *Dashboard) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[7]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use Dashboard.ProtoReflect.Descriptor instead.
+func (*Dashboard) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{7}
+}
+
+func (x *Dashboard) GetTitle() string {
+ if x != nil {
+ return x.Title
+ }
+ return ""
+}
+
+func (x *Dashboard) GetContents() []*DashboardComponent {
+ if x != nil {
+ return x.Contents
+ }
+ return nil
+}
+
+type DashboardComponent struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"`
+ Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"`
+ Contents []*DashboardComponent `protobuf:"bytes,3,rep,name=contents,proto3" json:"contents,omitempty"`
+ Icon string `protobuf:"bytes,4,opt,name=icon,proto3" json:"icon,omitempty"`
+ CssClass string `protobuf:"bytes,5,opt,name=css_class,json=cssClass,proto3" json:"css_class,omitempty"`
+ Action *Action `protobuf:"bytes,6,opt,name=action,proto3" json:"action,omitempty"`
+ EntityType string `protobuf:"bytes,7,opt,name=entity_type,json=entityType,proto3" json:"entity_type,omitempty"`
+ EntityKey string `protobuf:"bytes,8,opt,name=entity_key,json=entityKey,proto3" json:"entity_key,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *DashboardComponent) Reset() {
+ *x = DashboardComponent{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[8]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *DashboardComponent) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DashboardComponent) ProtoMessage() {}
+
+func (x *DashboardComponent) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[8]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use DashboardComponent.ProtoReflect.Descriptor instead.
+func (*DashboardComponent) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{8}
+}
+
+func (x *DashboardComponent) GetTitle() string {
+ if x != nil {
+ return x.Title
+ }
+ return ""
+}
+
+func (x *DashboardComponent) GetType() string {
+ if x != nil {
+ return x.Type
+ }
+ return ""
+}
+
+func (x *DashboardComponent) GetContents() []*DashboardComponent {
+ if x != nil {
+ return x.Contents
+ }
+ return nil
+}
+
+func (x *DashboardComponent) GetIcon() string {
+ if x != nil {
+ return x.Icon
+ }
+ return ""
+}
+
+func (x *DashboardComponent) GetCssClass() string {
+ if x != nil {
+ return x.CssClass
+ }
+ return ""
+}
+
+func (x *DashboardComponent) GetAction() *Action {
+ if x != nil {
+ return x.Action
+ }
+ return nil
+}
+
+func (x *DashboardComponent) GetEntityType() string {
+ if x != nil {
+ return x.EntityType
+ }
+ return ""
+}
+
+func (x *DashboardComponent) GetEntityKey() string {
+ if x != nil {
+ return x.EntityKey
+ }
+ return ""
+}
+
+type StartActionRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ BindingId string `protobuf:"bytes,1,opt,name=binding_id,json=bindingId,proto3" json:"binding_id,omitempty"`
+ Arguments []*StartActionArgument `protobuf:"bytes,2,rep,name=arguments,proto3" json:"arguments,omitempty"`
+ UniqueTrackingId string `protobuf:"bytes,3,opt,name=unique_tracking_id,json=uniqueTrackingId,proto3" json:"unique_tracking_id,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *StartActionRequest) Reset() {
+ *x = StartActionRequest{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[9]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *StartActionRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*StartActionRequest) ProtoMessage() {}
+
+func (x *StartActionRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[9]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use StartActionRequest.ProtoReflect.Descriptor instead.
+func (*StartActionRequest) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{9}
+}
+
+func (x *StartActionRequest) GetBindingId() string {
+ if x != nil {
+ return x.BindingId
+ }
+ return ""
+}
+
+func (x *StartActionRequest) GetArguments() []*StartActionArgument {
+ if x != nil {
+ return x.Arguments
+ }
+ return nil
+}
+
+func (x *StartActionRequest) GetUniqueTrackingId() string {
+ if x != nil {
+ return x.UniqueTrackingId
+ }
+ return ""
+}
+
+type StartActionArgument struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+ Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *StartActionArgument) Reset() {
+ *x = StartActionArgument{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[10]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *StartActionArgument) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*StartActionArgument) ProtoMessage() {}
+
+func (x *StartActionArgument) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[10]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use StartActionArgument.ProtoReflect.Descriptor instead.
+func (*StartActionArgument) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{10}
+}
+
+func (x *StartActionArgument) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *StartActionArgument) GetValue() string {
+ if x != nil {
+ return x.Value
+ }
+ return ""
+}
+
+type StartActionResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ ExecutionTrackingId string `protobuf:"bytes,2,opt,name=execution_tracking_id,json=executionTrackingId,proto3" json:"execution_tracking_id,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *StartActionResponse) Reset() {
+ *x = StartActionResponse{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[11]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *StartActionResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*StartActionResponse) ProtoMessage() {}
+
+func (x *StartActionResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[11]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use StartActionResponse.ProtoReflect.Descriptor instead.
+func (*StartActionResponse) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{11}
+}
+
+func (x *StartActionResponse) GetExecutionTrackingId() string {
+ if x != nil {
+ return x.ExecutionTrackingId
+ }
+ return ""
+}
+
+type StartActionAndWaitRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ ActionId string `protobuf:"bytes,1,opt,name=action_id,json=actionId,proto3" json:"action_id,omitempty"`
+ Arguments []*StartActionArgument `protobuf:"bytes,2,rep,name=arguments,proto3" json:"arguments,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *StartActionAndWaitRequest) Reset() {
+ *x = StartActionAndWaitRequest{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[12]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *StartActionAndWaitRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*StartActionAndWaitRequest) ProtoMessage() {}
+
+func (x *StartActionAndWaitRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[12]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use StartActionAndWaitRequest.ProtoReflect.Descriptor instead.
+func (*StartActionAndWaitRequest) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{12}
+}
+
+func (x *StartActionAndWaitRequest) GetActionId() string {
+ if x != nil {
+ return x.ActionId
+ }
+ return ""
+}
+
+func (x *StartActionAndWaitRequest) GetArguments() []*StartActionArgument {
+ if x != nil {
+ return x.Arguments
+ }
+ return nil
+}
+
+type StartActionAndWaitResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ LogEntry *LogEntry `protobuf:"bytes,1,opt,name=log_entry,json=logEntry,proto3" json:"log_entry,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *StartActionAndWaitResponse) Reset() {
+ *x = StartActionAndWaitResponse{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[13]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *StartActionAndWaitResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*StartActionAndWaitResponse) ProtoMessage() {}
+
+func (x *StartActionAndWaitResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[13]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use StartActionAndWaitResponse.ProtoReflect.Descriptor instead.
+func (*StartActionAndWaitResponse) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{13}
+}
+
+func (x *StartActionAndWaitResponse) GetLogEntry() *LogEntry {
+ if x != nil {
+ return x.LogEntry
+ }
+ return nil
+}
+
+type StartActionByGetRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ ActionId string `protobuf:"bytes,1,opt,name=action_id,json=actionId,proto3" json:"action_id,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *StartActionByGetRequest) Reset() {
+ *x = StartActionByGetRequest{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[14]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *StartActionByGetRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*StartActionByGetRequest) ProtoMessage() {}
+
+func (x *StartActionByGetRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[14]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use StartActionByGetRequest.ProtoReflect.Descriptor instead.
+func (*StartActionByGetRequest) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{14}
+}
+
+func (x *StartActionByGetRequest) GetActionId() string {
+ if x != nil {
+ return x.ActionId
+ }
+ return ""
+}
+
+type StartActionByGetResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ ExecutionTrackingId string `protobuf:"bytes,2,opt,name=execution_tracking_id,json=executionTrackingId,proto3" json:"execution_tracking_id,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *StartActionByGetResponse) Reset() {
+ *x = StartActionByGetResponse{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[15]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *StartActionByGetResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*StartActionByGetResponse) ProtoMessage() {}
+
+func (x *StartActionByGetResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[15]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use StartActionByGetResponse.ProtoReflect.Descriptor instead.
+func (*StartActionByGetResponse) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{15}
+}
+
+func (x *StartActionByGetResponse) GetExecutionTrackingId() string {
+ if x != nil {
+ return x.ExecutionTrackingId
+ }
+ return ""
+}
+
+type StartActionByGetAndWaitRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ ActionId string `protobuf:"bytes,1,opt,name=action_id,json=actionId,proto3" json:"action_id,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *StartActionByGetAndWaitRequest) Reset() {
+ *x = StartActionByGetAndWaitRequest{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[16]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *StartActionByGetAndWaitRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*StartActionByGetAndWaitRequest) ProtoMessage() {}
+
+func (x *StartActionByGetAndWaitRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[16]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use StartActionByGetAndWaitRequest.ProtoReflect.Descriptor instead.
+func (*StartActionByGetAndWaitRequest) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{16}
+}
+
+func (x *StartActionByGetAndWaitRequest) GetActionId() string {
+ if x != nil {
+ return x.ActionId
+ }
+ return ""
+}
+
+type StartActionByGetAndWaitResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ LogEntry *LogEntry `protobuf:"bytes,1,opt,name=log_entry,json=logEntry,proto3" json:"log_entry,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *StartActionByGetAndWaitResponse) Reset() {
+ *x = StartActionByGetAndWaitResponse{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[17]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *StartActionByGetAndWaitResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*StartActionByGetAndWaitResponse) ProtoMessage() {}
+
+func (x *StartActionByGetAndWaitResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[17]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use StartActionByGetAndWaitResponse.ProtoReflect.Descriptor instead.
+func (*StartActionByGetAndWaitResponse) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{17}
+}
+
+func (x *StartActionByGetAndWaitResponse) GetLogEntry() *LogEntry {
+ if x != nil {
+ return x.LogEntry
+ }
+ return nil
+}
+
+type GetLogsRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ StartOffset int64 `protobuf:"varint,1,opt,name=start_offset,json=startOffset,proto3" json:"start_offset,omitempty"`
+ DateFilter string `protobuf:"bytes,2,opt,name=date_filter,json=dateFilter,proto3" json:"date_filter,omitempty"` // Optional date filter in YYYY-MM-DD format
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetLogsRequest) Reset() {
+ *x = GetLogsRequest{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[18]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GetLogsRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetLogsRequest) ProtoMessage() {}
+
+func (x *GetLogsRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[18]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetLogsRequest.ProtoReflect.Descriptor instead.
+func (*GetLogsRequest) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{18}
+}
+
+func (x *GetLogsRequest) GetStartOffset() int64 {
+ if x != nil {
+ return x.StartOffset
+ }
+ return 0
+}
+
+func (x *GetLogsRequest) GetDateFilter() string {
+ if x != nil {
+ return x.DateFilter
+ }
+ return ""
+}
+
+type LogEntry struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ DatetimeStarted string `protobuf:"bytes,1,opt,name=datetime_started,json=datetimeStarted,proto3" json:"datetime_started,omitempty"`
+ ActionTitle string `protobuf:"bytes,2,opt,name=action_title,json=actionTitle,proto3" json:"action_title,omitempty"`
+ Output string `protobuf:"bytes,3,opt,name=output,proto3" json:"output,omitempty"`
+ TimedOut bool `protobuf:"varint,5,opt,name=timed_out,json=timedOut,proto3" json:"timed_out,omitempty"`
+ ExitCode int32 `protobuf:"varint,6,opt,name=exit_code,json=exitCode,proto3" json:"exit_code,omitempty"`
+ User string `protobuf:"bytes,7,opt,name=user,proto3" json:"user,omitempty"`
+ UserClass string `protobuf:"bytes,8,opt,name=user_class,json=userClass,proto3" json:"user_class,omitempty"`
+ ActionIcon string `protobuf:"bytes,9,opt,name=action_icon,json=actionIcon,proto3" json:"action_icon,omitempty"`
+ Tags []string `protobuf:"bytes,10,rep,name=tags,proto3" json:"tags,omitempty"`
+ ExecutionTrackingId string `protobuf:"bytes,11,opt,name=execution_tracking_id,json=executionTrackingId,proto3" json:"execution_tracking_id,omitempty"`
+ DatetimeFinished string `protobuf:"bytes,12,opt,name=datetime_finished,json=datetimeFinished,proto3" json:"datetime_finished,omitempty"`
+ ExecutionStarted bool `protobuf:"varint,14,opt,name=execution_started,json=executionStarted,proto3" json:"execution_started,omitempty"`
+ ExecutionFinished bool `protobuf:"varint,15,opt,name=execution_finished,json=executionFinished,proto3" json:"execution_finished,omitempty"`
+ Blocked bool `protobuf:"varint,16,opt,name=blocked,proto3" json:"blocked,omitempty"`
+ DatetimeIndex int64 `protobuf:"varint,17,opt,name=datetime_index,json=datetimeIndex,proto3" json:"datetime_index,omitempty"`
+ CanKill bool `protobuf:"varint,18,opt,name=can_kill,json=canKill,proto3" json:"can_kill,omitempty"`
+ DatetimeRateLimitExpires string `protobuf:"bytes,19,opt,name=datetime_rate_limit_expires,json=datetimeRateLimitExpires,proto3" json:"datetime_rate_limit_expires,omitempty"` // Datetime when rate limit expires (empty string if not rate limited), format: "2006-01-02 15:04:05"
+ BindingId string `protobuf:"bytes,20,opt,name=binding_id,json=bindingId,proto3" json:"binding_id,omitempty"` // Binding ID for matching rate limits to action buttons
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *LogEntry) Reset() {
+ *x = LogEntry{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[19]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *LogEntry) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*LogEntry) ProtoMessage() {}
+
+func (x *LogEntry) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[19]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use LogEntry.ProtoReflect.Descriptor instead.
+func (*LogEntry) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{19}
+}
+
+func (x *LogEntry) GetDatetimeStarted() string {
+ if x != nil {
+ return x.DatetimeStarted
+ }
+ return ""
+}
+
+func (x *LogEntry) GetActionTitle() string {
+ if x != nil {
+ return x.ActionTitle
+ }
+ return ""
+}
+
+func (x *LogEntry) GetOutput() string {
+ if x != nil {
+ return x.Output
+ }
+ return ""
+}
+
+func (x *LogEntry) GetTimedOut() bool {
+ if x != nil {
+ return x.TimedOut
+ }
+ return false
+}
+
+func (x *LogEntry) GetExitCode() int32 {
+ if x != nil {
+ return x.ExitCode
+ }
+ return 0
+}
+
+func (x *LogEntry) GetUser() string {
+ if x != nil {
+ return x.User
+ }
+ return ""
+}
+
+func (x *LogEntry) GetUserClass() string {
+ if x != nil {
+ return x.UserClass
+ }
+ return ""
+}
+
+func (x *LogEntry) GetActionIcon() string {
+ if x != nil {
+ return x.ActionIcon
+ }
+ return ""
+}
+
+func (x *LogEntry) GetTags() []string {
+ if x != nil {
+ return x.Tags
+ }
+ return nil
+}
+
+func (x *LogEntry) GetExecutionTrackingId() string {
+ if x != nil {
+ return x.ExecutionTrackingId
+ }
+ return ""
+}
+
+func (x *LogEntry) GetDatetimeFinished() string {
+ if x != nil {
+ return x.DatetimeFinished
+ }
+ return ""
+}
+
+func (x *LogEntry) GetExecutionStarted() bool {
+ if x != nil {
+ return x.ExecutionStarted
+ }
+ return false
+}
+
+func (x *LogEntry) GetExecutionFinished() bool {
+ if x != nil {
+ return x.ExecutionFinished
+ }
+ return false
+}
+
+func (x *LogEntry) GetBlocked() bool {
+ if x != nil {
+ return x.Blocked
+ }
+ return false
+}
+
+func (x *LogEntry) GetDatetimeIndex() int64 {
+ if x != nil {
+ return x.DatetimeIndex
+ }
+ return 0
+}
+
+func (x *LogEntry) GetCanKill() bool {
+ if x != nil {
+ return x.CanKill
+ }
+ return false
+}
+
+func (x *LogEntry) GetDatetimeRateLimitExpires() string {
+ if x != nil {
+ return x.DatetimeRateLimitExpires
+ }
+ return ""
+}
+
+func (x *LogEntry) GetBindingId() string {
+ if x != nil {
+ return x.BindingId
+ }
+ return ""
+}
+
+type GetLogsResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Logs []*LogEntry `protobuf:"bytes,1,rep,name=logs,proto3" json:"logs,omitempty"`
+ CountRemaining int64 `protobuf:"varint,2,opt,name=count_remaining,json=countRemaining,proto3" json:"count_remaining,omitempty"`
+ PageSize int64 `protobuf:"varint,3,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"`
+ TotalCount int64 `protobuf:"varint,4,opt,name=total_count,json=totalCount,proto3" json:"total_count,omitempty"`
+ StartOffset int64 `protobuf:"varint,5,opt,name=start_offset,json=startOffset,proto3" json:"start_offset,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetLogsResponse) Reset() {
+ *x = GetLogsResponse{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[20]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GetLogsResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetLogsResponse) ProtoMessage() {}
+
+func (x *GetLogsResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[20]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetLogsResponse.ProtoReflect.Descriptor instead.
+func (*GetLogsResponse) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{20}
+}
+
+func (x *GetLogsResponse) GetLogs() []*LogEntry {
+ if x != nil {
+ return x.Logs
+ }
+ return nil
+}
+
+func (x *GetLogsResponse) GetCountRemaining() int64 {
+ if x != nil {
+ return x.CountRemaining
+ }
+ return 0
+}
+
+func (x *GetLogsResponse) GetPageSize() int64 {
+ if x != nil {
+ return x.PageSize
+ }
+ return 0
+}
+
+func (x *GetLogsResponse) GetTotalCount() int64 {
+ if x != nil {
+ return x.TotalCount
+ }
+ return 0
+}
+
+func (x *GetLogsResponse) GetStartOffset() int64 {
+ if x != nil {
+ return x.StartOffset
+ }
+ return 0
+}
+
+type GetActionLogsRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ ActionId string `protobuf:"bytes,1,opt,name=action_id,json=actionId,proto3" json:"action_id,omitempty"`
+ StartOffset int64 `protobuf:"varint,2,opt,name=start_offset,json=startOffset,proto3" json:"start_offset,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetActionLogsRequest) Reset() {
+ *x = GetActionLogsRequest{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[21]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GetActionLogsRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetActionLogsRequest) ProtoMessage() {}
+
+func (x *GetActionLogsRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[21]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetActionLogsRequest.ProtoReflect.Descriptor instead.
+func (*GetActionLogsRequest) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{21}
+}
+
+func (x *GetActionLogsRequest) GetActionId() string {
+ if x != nil {
+ return x.ActionId
+ }
+ return ""
+}
+
+func (x *GetActionLogsRequest) GetStartOffset() int64 {
+ if x != nil {
+ return x.StartOffset
+ }
+ return 0
+}
+
+type GetActionLogsResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Logs []*LogEntry `protobuf:"bytes,1,rep,name=logs,proto3" json:"logs,omitempty"`
+ CountRemaining int64 `protobuf:"varint,2,opt,name=count_remaining,json=countRemaining,proto3" json:"count_remaining,omitempty"`
+ PageSize int64 `protobuf:"varint,3,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"`
+ TotalCount int64 `protobuf:"varint,4,opt,name=total_count,json=totalCount,proto3" json:"total_count,omitempty"`
+ StartOffset int64 `protobuf:"varint,5,opt,name=start_offset,json=startOffset,proto3" json:"start_offset,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetActionLogsResponse) Reset() {
+ *x = GetActionLogsResponse{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[22]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GetActionLogsResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetActionLogsResponse) ProtoMessage() {}
+
+func (x *GetActionLogsResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[22]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetActionLogsResponse.ProtoReflect.Descriptor instead.
+func (*GetActionLogsResponse) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{22}
+}
+
+func (x *GetActionLogsResponse) GetLogs() []*LogEntry {
+ if x != nil {
+ return x.Logs
+ }
+ return nil
+}
+
+func (x *GetActionLogsResponse) GetCountRemaining() int64 {
+ if x != nil {
+ return x.CountRemaining
+ }
+ return 0
+}
+
+func (x *GetActionLogsResponse) GetPageSize() int64 {
+ if x != nil {
+ return x.PageSize
+ }
+ return 0
+}
+
+func (x *GetActionLogsResponse) GetTotalCount() int64 {
+ if x != nil {
+ return x.TotalCount
+ }
+ return 0
+}
+
+func (x *GetActionLogsResponse) GetStartOffset() int64 {
+ if x != nil {
+ return x.StartOffset
+ }
+ return 0
+}
+
+type ValidateArgumentTypeRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Value string `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"`
+ Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"`
+ BindingId string `protobuf:"bytes,3,opt,name=binding_id,json=bindingId,proto3" json:"binding_id,omitempty"`
+ ArgumentName string `protobuf:"bytes,4,opt,name=argument_name,json=argumentName,proto3" json:"argument_name,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ValidateArgumentTypeRequest) Reset() {
+ *x = ValidateArgumentTypeRequest{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[23]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ValidateArgumentTypeRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ValidateArgumentTypeRequest) ProtoMessage() {}
+
+func (x *ValidateArgumentTypeRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[23]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ValidateArgumentTypeRequest.ProtoReflect.Descriptor instead.
+func (*ValidateArgumentTypeRequest) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{23}
+}
+
+func (x *ValidateArgumentTypeRequest) GetValue() string {
+ if x != nil {
+ return x.Value
+ }
+ return ""
+}
+
+func (x *ValidateArgumentTypeRequest) GetType() string {
+ if x != nil {
+ return x.Type
+ }
+ return ""
+}
+
+func (x *ValidateArgumentTypeRequest) GetBindingId() string {
+ if x != nil {
+ return x.BindingId
+ }
+ return ""
+}
+
+func (x *ValidateArgumentTypeRequest) GetArgumentName() string {
+ if x != nil {
+ return x.ArgumentName
+ }
+ return ""
+}
+
+type ValidateArgumentTypeResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Valid bool `protobuf:"varint,1,opt,name=valid,proto3" json:"valid,omitempty"`
+ Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ValidateArgumentTypeResponse) Reset() {
+ *x = ValidateArgumentTypeResponse{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[24]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ValidateArgumentTypeResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ValidateArgumentTypeResponse) ProtoMessage() {}
+
+func (x *ValidateArgumentTypeResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[24]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ValidateArgumentTypeResponse.ProtoReflect.Descriptor instead.
+func (*ValidateArgumentTypeResponse) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{24}
+}
+
+func (x *ValidateArgumentTypeResponse) GetValid() bool {
+ if x != nil {
+ return x.Valid
+ }
+ return false
+}
+
+func (x *ValidateArgumentTypeResponse) GetDescription() string {
+ if x != nil {
+ return x.Description
+ }
+ return ""
+}
+
+type WatchExecutionRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ ExecutionTrackingId string `protobuf:"bytes,1,opt,name=execution_tracking_id,json=executionTrackingId,proto3" json:"execution_tracking_id,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *WatchExecutionRequest) Reset() {
+ *x = WatchExecutionRequest{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[25]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *WatchExecutionRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*WatchExecutionRequest) ProtoMessage() {}
+
+func (x *WatchExecutionRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[25]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use WatchExecutionRequest.ProtoReflect.Descriptor instead.
+func (*WatchExecutionRequest) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{25}
+}
+
+func (x *WatchExecutionRequest) GetExecutionTrackingId() string {
+ if x != nil {
+ return x.ExecutionTrackingId
+ }
+ return ""
+}
+
+type WatchExecutionUpdate struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Update string `protobuf:"bytes,1,opt,name=update,proto3" json:"update,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *WatchExecutionUpdate) Reset() {
+ *x = WatchExecutionUpdate{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[26]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *WatchExecutionUpdate) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*WatchExecutionUpdate) ProtoMessage() {}
+
+func (x *WatchExecutionUpdate) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[26]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use WatchExecutionUpdate.ProtoReflect.Descriptor instead.
+func (*WatchExecutionUpdate) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{26}
+}
+
+func (x *WatchExecutionUpdate) GetUpdate() string {
+ if x != nil {
+ return x.Update
+ }
+ return ""
+}
+
+type ExecutionStatusRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ ExecutionTrackingId string `protobuf:"bytes,1,opt,name=execution_tracking_id,json=executionTrackingId,proto3" json:"execution_tracking_id,omitempty"`
+ ActionId string `protobuf:"bytes,2,opt,name=action_id,json=actionId,proto3" json:"action_id,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ExecutionStatusRequest) Reset() {
+ *x = ExecutionStatusRequest{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[27]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ExecutionStatusRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ExecutionStatusRequest) ProtoMessage() {}
+
+func (x *ExecutionStatusRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[27]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ExecutionStatusRequest.ProtoReflect.Descriptor instead.
+func (*ExecutionStatusRequest) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{27}
+}
+
+func (x *ExecutionStatusRequest) GetExecutionTrackingId() string {
+ if x != nil {
+ return x.ExecutionTrackingId
+ }
+ return ""
+}
+
+func (x *ExecutionStatusRequest) GetActionId() string {
+ if x != nil {
+ return x.ActionId
+ }
+ return ""
+}
+
+type ExecutionStatusResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ LogEntry *LogEntry `protobuf:"bytes,1,opt,name=log_entry,json=logEntry,proto3" json:"log_entry,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ExecutionStatusResponse) Reset() {
+ *x = ExecutionStatusResponse{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[28]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ExecutionStatusResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ExecutionStatusResponse) ProtoMessage() {}
+
+func (x *ExecutionStatusResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[28]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ExecutionStatusResponse.ProtoReflect.Descriptor instead.
+func (*ExecutionStatusResponse) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{28}
+}
+
+func (x *ExecutionStatusResponse) GetLogEntry() *LogEntry {
+ if x != nil {
+ return x.LogEntry
+ }
+ return nil
+}
+
+type WhoAmIRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *WhoAmIRequest) Reset() {
+ *x = WhoAmIRequest{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[29]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *WhoAmIRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*WhoAmIRequest) ProtoMessage() {}
+
+func (x *WhoAmIRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[29]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use WhoAmIRequest.ProtoReflect.Descriptor instead.
+func (*WhoAmIRequest) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{29}
+}
+
+type WhoAmIResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ AuthenticatedUser string `protobuf:"bytes,1,opt,name=authenticated_user,json=authenticatedUser,proto3" json:"authenticated_user,omitempty"`
+ Usergroup string `protobuf:"bytes,2,opt,name=usergroup,proto3" json:"usergroup,omitempty"`
+ Provider string `protobuf:"bytes,3,opt,name=provider,proto3" json:"provider,omitempty"`
+ Acls []string `protobuf:"bytes,4,rep,name=acls,proto3" json:"acls,omitempty"`
+ Sid string `protobuf:"bytes,5,opt,name=sid,proto3" json:"sid,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *WhoAmIResponse) Reset() {
+ *x = WhoAmIResponse{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[30]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *WhoAmIResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*WhoAmIResponse) ProtoMessage() {}
+
+func (x *WhoAmIResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[30]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use WhoAmIResponse.ProtoReflect.Descriptor instead.
+func (*WhoAmIResponse) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{30}
+}
+
+func (x *WhoAmIResponse) GetAuthenticatedUser() string {
+ if x != nil {
+ return x.AuthenticatedUser
+ }
+ return ""
+}
+
+func (x *WhoAmIResponse) GetUsergroup() string {
+ if x != nil {
+ return x.Usergroup
+ }
+ return ""
+}
+
+func (x *WhoAmIResponse) GetProvider() string {
+ if x != nil {
+ return x.Provider
+ }
+ return ""
+}
+
+func (x *WhoAmIResponse) GetAcls() []string {
+ if x != nil {
+ return x.Acls
+ }
+ return nil
+}
+
+func (x *WhoAmIResponse) GetSid() string {
+ if x != nil {
+ return x.Sid
+ }
+ return ""
+}
+
+type SosReportRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *SosReportRequest) Reset() {
+ *x = SosReportRequest{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[31]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *SosReportRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SosReportRequest) ProtoMessage() {}
+
+func (x *SosReportRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[31]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SosReportRequest.ProtoReflect.Descriptor instead.
+func (*SosReportRequest) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{31}
+}
+
+type SosReportResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Alert string `protobuf:"bytes,1,opt,name=alert,proto3" json:"alert,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *SosReportResponse) Reset() {
+ *x = SosReportResponse{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[32]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *SosReportResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SosReportResponse) ProtoMessage() {}
+
+func (x *SosReportResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[32]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SosReportResponse.ProtoReflect.Descriptor instead.
+func (*SosReportResponse) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{32}
+}
+
+func (x *SosReportResponse) GetAlert() string {
+ if x != nil {
+ return x.Alert
+ }
+ return ""
+}
+
+type DumpVarsRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *DumpVarsRequest) Reset() {
+ *x = DumpVarsRequest{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[33]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *DumpVarsRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DumpVarsRequest) ProtoMessage() {}
+
+func (x *DumpVarsRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[33]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use DumpVarsRequest.ProtoReflect.Descriptor instead.
+func (*DumpVarsRequest) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{33}
+}
+
+type DumpVarsResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Alert string `protobuf:"bytes,1,opt,name=alert,proto3" json:"alert,omitempty"`
+ Contents map[string]string `protobuf:"bytes,2,rep,name=contents,proto3" json:"contents,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *DumpVarsResponse) Reset() {
+ *x = DumpVarsResponse{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[34]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *DumpVarsResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DumpVarsResponse) ProtoMessage() {}
+
+func (x *DumpVarsResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[34]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use DumpVarsResponse.ProtoReflect.Descriptor instead.
+func (*DumpVarsResponse) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{34}
+}
+
+func (x *DumpVarsResponse) GetAlert() string {
+ if x != nil {
+ return x.Alert
+ }
+ return ""
+}
+
+func (x *DumpVarsResponse) GetContents() map[string]string {
+ if x != nil {
+ return x.Contents
+ }
+ return nil
+}
+
+type DebugBinding struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ ActionTitle string `protobuf:"bytes,1,opt,name=action_title,json=actionTitle,proto3" json:"action_title,omitempty"`
+ EntityPrefix string `protobuf:"bytes,2,opt,name=entity_prefix,json=entityPrefix,proto3" json:"entity_prefix,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *DebugBinding) Reset() {
+ *x = DebugBinding{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[35]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *DebugBinding) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DebugBinding) ProtoMessage() {}
+
+func (x *DebugBinding) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[35]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use DebugBinding.ProtoReflect.Descriptor instead.
+func (*DebugBinding) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{35}
+}
+
+func (x *DebugBinding) GetActionTitle() string {
+ if x != nil {
+ return x.ActionTitle
+ }
+ return ""
+}
+
+func (x *DebugBinding) GetEntityPrefix() string {
+ if x != nil {
+ return x.EntityPrefix
+ }
+ return ""
+}
+
+type DumpPublicIdActionMapRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *DumpPublicIdActionMapRequest) Reset() {
+ *x = DumpPublicIdActionMapRequest{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[36]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *DumpPublicIdActionMapRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DumpPublicIdActionMapRequest) ProtoMessage() {}
+
+func (x *DumpPublicIdActionMapRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[36]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use DumpPublicIdActionMapRequest.ProtoReflect.Descriptor instead.
+func (*DumpPublicIdActionMapRequest) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{36}
+}
+
+type DumpPublicIdActionMapResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Alert string `protobuf:"bytes,1,opt,name=alert,proto3" json:"alert,omitempty"`
+ Contents map[string]*DebugBinding `protobuf:"bytes,2,rep,name=contents,proto3" json:"contents,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *DumpPublicIdActionMapResponse) Reset() {
+ *x = DumpPublicIdActionMapResponse{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[37]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *DumpPublicIdActionMapResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DumpPublicIdActionMapResponse) ProtoMessage() {}
+
+func (x *DumpPublicIdActionMapResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[37]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use DumpPublicIdActionMapResponse.ProtoReflect.Descriptor instead.
+func (*DumpPublicIdActionMapResponse) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{37}
+}
+
+func (x *DumpPublicIdActionMapResponse) GetAlert() string {
+ if x != nil {
+ return x.Alert
+ }
+ return ""
+}
+
+func (x *DumpPublicIdActionMapResponse) GetContents() map[string]*DebugBinding {
+ if x != nil {
+ return x.Contents
+ }
+ return nil
+}
+
+type GetReadyzRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetReadyzRequest) Reset() {
+ *x = GetReadyzRequest{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[38]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GetReadyzRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetReadyzRequest) ProtoMessage() {}
+
+func (x *GetReadyzRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[38]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetReadyzRequest.ProtoReflect.Descriptor instead.
+func (*GetReadyzRequest) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{38}
+}
+
+type GetReadyzResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Status string `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetReadyzResponse) Reset() {
+ *x = GetReadyzResponse{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[39]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GetReadyzResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetReadyzResponse) ProtoMessage() {}
+
+func (x *GetReadyzResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[39]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetReadyzResponse.ProtoReflect.Descriptor instead.
+func (*GetReadyzResponse) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{39}
+}
+
+func (x *GetReadyzResponse) GetStatus() string {
+ if x != nil {
+ return x.Status
+ }
+ return ""
+}
+
+type EventStreamRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *EventStreamRequest) Reset() {
+ *x = EventStreamRequest{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[40]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *EventStreamRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*EventStreamRequest) ProtoMessage() {}
+
+func (x *EventStreamRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[40]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use EventStreamRequest.ProtoReflect.Descriptor instead.
+func (*EventStreamRequest) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{40}
+}
+
+type EventStreamResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Types that are valid to be assigned to Event:
+ //
+ // *EventStreamResponse_EntityChanged
+ // *EventStreamResponse_ConfigChanged
+ // *EventStreamResponse_ExecutionFinished
+ // *EventStreamResponse_ExecutionStarted
+ // *EventStreamResponse_OutputChunk
+ Event isEventStreamResponse_Event `protobuf_oneof:"event"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *EventStreamResponse) Reset() {
+ *x = EventStreamResponse{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[41]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *EventStreamResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*EventStreamResponse) ProtoMessage() {}
+
+func (x *EventStreamResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[41]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use EventStreamResponse.ProtoReflect.Descriptor instead.
+func (*EventStreamResponse) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{41}
+}
+
+func (x *EventStreamResponse) GetEvent() isEventStreamResponse_Event {
+ if x != nil {
+ return x.Event
+ }
+ return nil
+}
+
+func (x *EventStreamResponse) GetEntityChanged() *EventEntityChanged {
+ if x != nil {
+ if x, ok := x.Event.(*EventStreamResponse_EntityChanged); ok {
+ return x.EntityChanged
+ }
+ }
+ return nil
+}
+
+func (x *EventStreamResponse) GetConfigChanged() *EventConfigChanged {
+ if x != nil {
+ if x, ok := x.Event.(*EventStreamResponse_ConfigChanged); ok {
+ return x.ConfigChanged
+ }
+ }
+ return nil
+}
+
+func (x *EventStreamResponse) GetExecutionFinished() *EventExecutionFinished {
+ if x != nil {
+ if x, ok := x.Event.(*EventStreamResponse_ExecutionFinished); ok {
+ return x.ExecutionFinished
+ }
+ }
+ return nil
+}
+
+func (x *EventStreamResponse) GetExecutionStarted() *EventExecutionStarted {
+ if x != nil {
+ if x, ok := x.Event.(*EventStreamResponse_ExecutionStarted); ok {
+ return x.ExecutionStarted
+ }
+ }
+ return nil
+}
+
+func (x *EventStreamResponse) GetOutputChunk() *EventOutputChunk {
+ if x != nil {
+ if x, ok := x.Event.(*EventStreamResponse_OutputChunk); ok {
+ return x.OutputChunk
+ }
+ }
+ return nil
+}
+
+type isEventStreamResponse_Event interface {
+ isEventStreamResponse_Event()
+}
+
+type EventStreamResponse_EntityChanged struct {
+ EntityChanged *EventEntityChanged `protobuf:"bytes,2,opt,name=entity_changed,json=entityChanged,proto3,oneof"`
+}
+
+type EventStreamResponse_ConfigChanged struct {
+ ConfigChanged *EventConfigChanged `protobuf:"bytes,3,opt,name=config_changed,json=configChanged,proto3,oneof"`
+}
+
+type EventStreamResponse_ExecutionFinished struct {
+ ExecutionFinished *EventExecutionFinished `protobuf:"bytes,4,opt,name=execution_finished,json=executionFinished,proto3,oneof"`
+}
+
+type EventStreamResponse_ExecutionStarted struct {
+ ExecutionStarted *EventExecutionStarted `protobuf:"bytes,5,opt,name=execution_started,json=executionStarted,proto3,oneof"`
+}
+
+type EventStreamResponse_OutputChunk struct {
+ OutputChunk *EventOutputChunk `protobuf:"bytes,6,opt,name=output_chunk,json=outputChunk,proto3,oneof"`
+}
+
+func (*EventStreamResponse_EntityChanged) isEventStreamResponse_Event() {}
+
+func (*EventStreamResponse_ConfigChanged) isEventStreamResponse_Event() {}
+
+func (*EventStreamResponse_ExecutionFinished) isEventStreamResponse_Event() {}
+
+func (*EventStreamResponse_ExecutionStarted) isEventStreamResponse_Event() {}
+
+func (*EventStreamResponse_OutputChunk) isEventStreamResponse_Event() {}
+
+type EventOutputChunk struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ ExecutionTrackingId string `protobuf:"bytes,1,opt,name=execution_tracking_id,json=executionTrackingId,proto3" json:"execution_tracking_id,omitempty"`
+ Output string `protobuf:"bytes,2,opt,name=output,proto3" json:"output,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *EventOutputChunk) Reset() {
+ *x = EventOutputChunk{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[42]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *EventOutputChunk) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*EventOutputChunk) ProtoMessage() {}
+
+func (x *EventOutputChunk) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[42]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use EventOutputChunk.ProtoReflect.Descriptor instead.
+func (*EventOutputChunk) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{42}
+}
+
+func (x *EventOutputChunk) GetExecutionTrackingId() string {
+ if x != nil {
+ return x.ExecutionTrackingId
+ }
+ return ""
+}
+
+func (x *EventOutputChunk) GetOutput() string {
+ if x != nil {
+ return x.Output
+ }
+ return ""
+}
+
+type EventEntityChanged struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *EventEntityChanged) Reset() {
+ *x = EventEntityChanged{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[43]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *EventEntityChanged) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*EventEntityChanged) ProtoMessage() {}
+
+func (x *EventEntityChanged) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[43]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use EventEntityChanged.ProtoReflect.Descriptor instead.
+func (*EventEntityChanged) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{43}
+}
+
+type EventConfigChanged struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *EventConfigChanged) Reset() {
+ *x = EventConfigChanged{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[44]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *EventConfigChanged) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*EventConfigChanged) ProtoMessage() {}
+
+func (x *EventConfigChanged) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[44]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use EventConfigChanged.ProtoReflect.Descriptor instead.
+func (*EventConfigChanged) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{44}
+}
+
+type EventExecutionFinished struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ LogEntry *LogEntry `protobuf:"bytes,1,opt,name=log_entry,json=logEntry,proto3" json:"log_entry,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *EventExecutionFinished) Reset() {
+ *x = EventExecutionFinished{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[45]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *EventExecutionFinished) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*EventExecutionFinished) ProtoMessage() {}
+
+func (x *EventExecutionFinished) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[45]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use EventExecutionFinished.ProtoReflect.Descriptor instead.
+func (*EventExecutionFinished) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{45}
+}
+
+func (x *EventExecutionFinished) GetLogEntry() *LogEntry {
+ if x != nil {
+ return x.LogEntry
+ }
+ return nil
+}
+
+type EventExecutionStarted struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ LogEntry *LogEntry `protobuf:"bytes,1,opt,name=log_entry,json=logEntry,proto3" json:"log_entry,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *EventExecutionStarted) Reset() {
+ *x = EventExecutionStarted{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[46]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *EventExecutionStarted) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*EventExecutionStarted) ProtoMessage() {}
+
+func (x *EventExecutionStarted) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[46]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use EventExecutionStarted.ProtoReflect.Descriptor instead.
+func (*EventExecutionStarted) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{46}
+}
+
+func (x *EventExecutionStarted) GetLogEntry() *LogEntry {
+ if x != nil {
+ return x.LogEntry
+ }
+ return nil
+}
+
+type KillActionRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ ExecutionTrackingId string `protobuf:"bytes,1,opt,name=execution_tracking_id,json=executionTrackingId,proto3" json:"execution_tracking_id,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *KillActionRequest) Reset() {
+ *x = KillActionRequest{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[47]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *KillActionRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*KillActionRequest) ProtoMessage() {}
+
+func (x *KillActionRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[47]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use KillActionRequest.ProtoReflect.Descriptor instead.
+func (*KillActionRequest) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{47}
+}
+
+func (x *KillActionRequest) GetExecutionTrackingId() string {
+ if x != nil {
+ return x.ExecutionTrackingId
+ }
+ return ""
+}
+
+type KillActionResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ ExecutionTrackingId string `protobuf:"bytes,1,opt,name=execution_tracking_id,json=executionTrackingId,proto3" json:"execution_tracking_id,omitempty"`
+ Killed bool `protobuf:"varint,2,opt,name=killed,proto3" json:"killed,omitempty"`
+ AlreadyCompleted bool `protobuf:"varint,3,opt,name=already_completed,json=alreadyCompleted,proto3" json:"already_completed,omitempty"`
+ Found bool `protobuf:"varint,4,opt,name=found,proto3" json:"found,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *KillActionResponse) Reset() {
+ *x = KillActionResponse{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[48]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *KillActionResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*KillActionResponse) ProtoMessage() {}
+
+func (x *KillActionResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[48]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use KillActionResponse.ProtoReflect.Descriptor instead.
+func (*KillActionResponse) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{48}
+}
+
+func (x *KillActionResponse) GetExecutionTrackingId() string {
+ if x != nil {
+ return x.ExecutionTrackingId
+ }
+ return ""
+}
+
+func (x *KillActionResponse) GetKilled() bool {
+ if x != nil {
+ return x.Killed
+ }
+ return false
+}
+
+func (x *KillActionResponse) GetAlreadyCompleted() bool {
+ if x != nil {
+ return x.AlreadyCompleted
+ }
+ return false
+}
+
+func (x *KillActionResponse) GetFound() bool {
+ if x != nil {
+ return x.Found
+ }
+ return false
+}
+
+type LocalUserLoginRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"`
+ Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *LocalUserLoginRequest) Reset() {
+ *x = LocalUserLoginRequest{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[49]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *LocalUserLoginRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*LocalUserLoginRequest) ProtoMessage() {}
+
+func (x *LocalUserLoginRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[49]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use LocalUserLoginRequest.ProtoReflect.Descriptor instead.
+func (*LocalUserLoginRequest) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{49}
+}
+
+func (x *LocalUserLoginRequest) GetUsername() string {
+ if x != nil {
+ return x.Username
+ }
+ return ""
+}
+
+func (x *LocalUserLoginRequest) GetPassword() string {
+ if x != nil {
+ return x.Password
+ }
+ return ""
+}
+
+type LocalUserLoginResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *LocalUserLoginResponse) Reset() {
+ *x = LocalUserLoginResponse{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[50]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *LocalUserLoginResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*LocalUserLoginResponse) ProtoMessage() {}
+
+func (x *LocalUserLoginResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[50]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use LocalUserLoginResponse.ProtoReflect.Descriptor instead.
+func (*LocalUserLoginResponse) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{50}
+}
+
+func (x *LocalUserLoginResponse) GetSuccess() bool {
+ if x != nil {
+ return x.Success
+ }
+ return false
+}
+
+type PasswordHashRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Password string `protobuf:"bytes,1,opt,name=password,proto3" json:"password,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *PasswordHashRequest) Reset() {
+ *x = PasswordHashRequest{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[51]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *PasswordHashRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PasswordHashRequest) ProtoMessage() {}
+
+func (x *PasswordHashRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[51]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use PasswordHashRequest.ProtoReflect.Descriptor instead.
+func (*PasswordHashRequest) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{51}
+}
+
+func (x *PasswordHashRequest) GetPassword() string {
+ if x != nil {
+ return x.Password
+ }
+ return ""
+}
+
+type PasswordHashResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Hash string `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *PasswordHashResponse) Reset() {
+ *x = PasswordHashResponse{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[52]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *PasswordHashResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PasswordHashResponse) ProtoMessage() {}
+
+func (x *PasswordHashResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[52]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use PasswordHashResponse.ProtoReflect.Descriptor instead.
+func (*PasswordHashResponse) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{52}
+}
+
+func (x *PasswordHashResponse) GetHash() string {
+ if x != nil {
+ return x.Hash
+ }
+ return ""
+}
+
+type LogoutRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *LogoutRequest) Reset() {
+ *x = LogoutRequest{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[53]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *LogoutRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*LogoutRequest) ProtoMessage() {}
+
+func (x *LogoutRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[53]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use LogoutRequest.ProtoReflect.Descriptor instead.
+func (*LogoutRequest) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{53}
+}
+
+type LogoutResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *LogoutResponse) Reset() {
+ *x = LogoutResponse{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[54]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *LogoutResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*LogoutResponse) ProtoMessage() {}
+
+func (x *LogoutResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[54]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use LogoutResponse.ProtoReflect.Descriptor instead.
+func (*LogoutResponse) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{54}
+}
+
+type GetDiagnosticsRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetDiagnosticsRequest) Reset() {
+ *x = GetDiagnosticsRequest{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[55]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GetDiagnosticsRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetDiagnosticsRequest) ProtoMessage() {}
+
+func (x *GetDiagnosticsRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[55]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetDiagnosticsRequest.ProtoReflect.Descriptor instead.
+func (*GetDiagnosticsRequest) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{55}
+}
+
+type GetDiagnosticsResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ SshFoundKey string `protobuf:"bytes,1,opt,name=SshFoundKey,proto3" json:"SshFoundKey,omitempty"`
+ SshFoundConfig string `protobuf:"bytes,2,opt,name=SshFoundConfig,proto3" json:"SshFoundConfig,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetDiagnosticsResponse) Reset() {
+ *x = GetDiagnosticsResponse{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[56]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GetDiagnosticsResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetDiagnosticsResponse) ProtoMessage() {}
+
+func (x *GetDiagnosticsResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[56]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetDiagnosticsResponse.ProtoReflect.Descriptor instead.
+func (*GetDiagnosticsResponse) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{56}
+}
+
+func (x *GetDiagnosticsResponse) GetSshFoundKey() string {
+ if x != nil {
+ return x.SshFoundKey
+ }
+ return ""
+}
+
+func (x *GetDiagnosticsResponse) GetSshFoundConfig() string {
+ if x != nil {
+ return x.SshFoundConfig
+ }
+ return ""
+}
+
+type InitRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *InitRequest) Reset() {
+ *x = InitRequest{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[57]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *InitRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*InitRequest) ProtoMessage() {}
+
+func (x *InitRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[57]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use InitRequest.ProtoReflect.Descriptor instead.
+func (*InitRequest) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{57}
+}
+
+type InitResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ ShowFooter bool `protobuf:"varint,1,opt,name=showFooter,proto3" json:"showFooter,omitempty"`
+ ShowNavigation bool `protobuf:"varint,2,opt,name=showNavigation,proto3" json:"showNavigation,omitempty"`
+ ShowNewVersions bool `protobuf:"varint,3,opt,name=showNewVersions,proto3" json:"showNewVersions,omitempty"`
+ AvailableVersion string `protobuf:"bytes,4,opt,name=availableVersion,proto3" json:"availableVersion,omitempty"`
+ CurrentVersion string `protobuf:"bytes,5,opt,name=currentVersion,proto3" json:"currentVersion,omitempty"`
+ PageTitle string `protobuf:"bytes,6,opt,name=pageTitle,proto3" json:"pageTitle,omitempty"`
+ SectionNavigationStyle string `protobuf:"bytes,7,opt,name=sectionNavigationStyle,proto3" json:"sectionNavigationStyle,omitempty"`
+ DefaultIconForBack string `protobuf:"bytes,8,opt,name=defaultIconForBack,proto3" json:"defaultIconForBack,omitempty"`
+ EnableCustomJs bool `protobuf:"varint,9,opt,name=enableCustomJs,proto3" json:"enableCustomJs,omitempty"`
+ AuthLoginUrl string `protobuf:"bytes,10,opt,name=authLoginUrl,proto3" json:"authLoginUrl,omitempty"`
+ AuthLocalLogin bool `protobuf:"varint,11,opt,name=authLocalLogin,proto3" json:"authLocalLogin,omitempty"`
+ StyleMods []string `protobuf:"bytes,12,rep,name=styleMods,proto3" json:"styleMods,omitempty"`
+ OAuth2Providers []*OAuth2Provider `protobuf:"bytes,13,rep,name=oAuth2Providers,proto3" json:"oAuth2Providers,omitempty"`
+ AdditionalLinks []*AdditionalLink `protobuf:"bytes,14,rep,name=additionalLinks,proto3" json:"additionalLinks,omitempty"`
+ RootDashboards []string `protobuf:"bytes,15,rep,name=rootDashboards,proto3" json:"rootDashboards,omitempty"`
+ AuthenticatedUser string `protobuf:"bytes,16,opt,name=authenticated_user,json=authenticatedUser,proto3" json:"authenticated_user,omitempty"`
+ AuthenticatedUserProvider string `protobuf:"bytes,17,opt,name=authenticated_user_provider,json=authenticatedUserProvider,proto3" json:"authenticated_user_provider,omitempty"`
+ EffectivePolicy *EffectivePolicy `protobuf:"bytes,18,opt,name=effective_policy,json=effectivePolicy,proto3" json:"effective_policy,omitempty"`
+ BannerMessage string `protobuf:"bytes,19,opt,name=banner_message,json=bannerMessage,proto3" json:"banner_message,omitempty"`
+ BannerCss string `protobuf:"bytes,20,opt,name=banner_css,json=bannerCss,proto3" json:"banner_css,omitempty"`
+ ShowDiagnostics bool `protobuf:"varint,21,opt,name=show_diagnostics,json=showDiagnostics,proto3" json:"show_diagnostics,omitempty"`
+ ShowLogList bool `protobuf:"varint,22,opt,name=show_log_list,json=showLogList,proto3" json:"show_log_list,omitempty"`
+ LoginRequired bool `protobuf:"varint,23,opt,name=login_required,json=loginRequired,proto3" json:"login_required,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *InitResponse) Reset() {
+ *x = InitResponse{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[58]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *InitResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*InitResponse) ProtoMessage() {}
+
+func (x *InitResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[58]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use InitResponse.ProtoReflect.Descriptor instead.
+func (*InitResponse) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{58}
+}
+
+func (x *InitResponse) GetShowFooter() bool {
+ if x != nil {
+ return x.ShowFooter
+ }
+ return false
+}
+
+func (x *InitResponse) GetShowNavigation() bool {
+ if x != nil {
+ return x.ShowNavigation
+ }
+ return false
+}
+
+func (x *InitResponse) GetShowNewVersions() bool {
+ if x != nil {
+ return x.ShowNewVersions
+ }
+ return false
+}
+
+func (x *InitResponse) GetAvailableVersion() string {
+ if x != nil {
+ return x.AvailableVersion
+ }
+ return ""
+}
+
+func (x *InitResponse) GetCurrentVersion() string {
+ if x != nil {
+ return x.CurrentVersion
+ }
+ return ""
+}
+
+func (x *InitResponse) GetPageTitle() string {
+ if x != nil {
+ return x.PageTitle
+ }
+ return ""
+}
+
+func (x *InitResponse) GetSectionNavigationStyle() string {
+ if x != nil {
+ return x.SectionNavigationStyle
+ }
+ return ""
+}
+
+func (x *InitResponse) GetDefaultIconForBack() string {
+ if x != nil {
+ return x.DefaultIconForBack
+ }
+ return ""
+}
+
+func (x *InitResponse) GetEnableCustomJs() bool {
+ if x != nil {
+ return x.EnableCustomJs
+ }
+ return false
+}
+
+func (x *InitResponse) GetAuthLoginUrl() string {
+ if x != nil {
+ return x.AuthLoginUrl
+ }
+ return ""
+}
+
+func (x *InitResponse) GetAuthLocalLogin() bool {
+ if x != nil {
+ return x.AuthLocalLogin
+ }
+ return false
+}
+
+func (x *InitResponse) GetStyleMods() []string {
+ if x != nil {
+ return x.StyleMods
+ }
+ return nil
+}
+
+func (x *InitResponse) GetOAuth2Providers() []*OAuth2Provider {
+ if x != nil {
+ return x.OAuth2Providers
+ }
+ return nil
+}
+
+func (x *InitResponse) GetAdditionalLinks() []*AdditionalLink {
+ if x != nil {
+ return x.AdditionalLinks
+ }
+ return nil
+}
+
+func (x *InitResponse) GetRootDashboards() []string {
+ if x != nil {
+ return x.RootDashboards
+ }
+ return nil
+}
+
+func (x *InitResponse) GetAuthenticatedUser() string {
+ if x != nil {
+ return x.AuthenticatedUser
+ }
+ return ""
+}
+
+func (x *InitResponse) GetAuthenticatedUserProvider() string {
+ if x != nil {
+ return x.AuthenticatedUserProvider
+ }
+ return ""
+}
+
+func (x *InitResponse) GetEffectivePolicy() *EffectivePolicy {
+ if x != nil {
+ return x.EffectivePolicy
+ }
+ return nil
+}
+
+func (x *InitResponse) GetBannerMessage() string {
+ if x != nil {
+ return x.BannerMessage
+ }
+ return ""
+}
+
+func (x *InitResponse) GetBannerCss() string {
+ if x != nil {
+ return x.BannerCss
+ }
+ return ""
+}
+
+func (x *InitResponse) GetShowDiagnostics() bool {
+ if x != nil {
+ return x.ShowDiagnostics
+ }
+ return false
+}
+
+func (x *InitResponse) GetShowLogList() bool {
+ if x != nil {
+ return x.ShowLogList
+ }
+ return false
+}
+
+func (x *InitResponse) GetLoginRequired() bool {
+ if x != nil {
+ return x.LoginRequired
+ }
+ return false
+}
+
+type AdditionalLink struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"`
+ Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *AdditionalLink) Reset() {
+ *x = AdditionalLink{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[59]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *AdditionalLink) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AdditionalLink) ProtoMessage() {}
+
+func (x *AdditionalLink) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[59]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use AdditionalLink.ProtoReflect.Descriptor instead.
+func (*AdditionalLink) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{59}
+}
+
+func (x *AdditionalLink) GetTitle() string {
+ if x != nil {
+ return x.Title
+ }
+ return ""
+}
+
+func (x *AdditionalLink) GetUrl() string {
+ if x != nil {
+ return x.Url
+ }
+ return ""
+}
+
+type OAuth2Provider struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"`
+ Icon string `protobuf:"bytes,3,opt,name=icon,proto3" json:"icon,omitempty"`
+ Key string `protobuf:"bytes,4,opt,name=key,proto3" json:"key,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *OAuth2Provider) Reset() {
+ *x = OAuth2Provider{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[60]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *OAuth2Provider) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*OAuth2Provider) ProtoMessage() {}
+
+func (x *OAuth2Provider) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[60]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use OAuth2Provider.ProtoReflect.Descriptor instead.
+func (*OAuth2Provider) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{60}
+}
+
+func (x *OAuth2Provider) GetTitle() string {
+ if x != nil {
+ return x.Title
+ }
+ return ""
+}
+
+func (x *OAuth2Provider) GetIcon() string {
+ if x != nil {
+ return x.Icon
+ }
+ return ""
+}
+
+func (x *OAuth2Provider) GetKey() string {
+ if x != nil {
+ return x.Key
+ }
+ return ""
+}
+
+type GetActionBindingRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ BindingId string `protobuf:"bytes,1,opt,name=binding_id,json=bindingId,proto3" json:"binding_id,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetActionBindingRequest) Reset() {
+ *x = GetActionBindingRequest{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[61]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GetActionBindingRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetActionBindingRequest) ProtoMessage() {}
+
+func (x *GetActionBindingRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[61]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetActionBindingRequest.ProtoReflect.Descriptor instead.
+func (*GetActionBindingRequest) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{61}
+}
+
+func (x *GetActionBindingRequest) GetBindingId() string {
+ if x != nil {
+ return x.BindingId
+ }
+ return ""
+}
+
+type GetActionBindingResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Action *Action `protobuf:"bytes,1,opt,name=action,proto3" json:"action,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetActionBindingResponse) Reset() {
+ *x = GetActionBindingResponse{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[62]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GetActionBindingResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetActionBindingResponse) ProtoMessage() {}
+
+func (x *GetActionBindingResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[62]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetActionBindingResponse.ProtoReflect.Descriptor instead.
+func (*GetActionBindingResponse) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{62}
+}
+
+func (x *GetActionBindingResponse) GetAction() *Action {
+ if x != nil {
+ return x.Action
+ }
+ return nil
+}
+
+type GetEntitiesRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetEntitiesRequest) Reset() {
+ *x = GetEntitiesRequest{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[63]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GetEntitiesRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetEntitiesRequest) ProtoMessage() {}
+
+func (x *GetEntitiesRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[63]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetEntitiesRequest.ProtoReflect.Descriptor instead.
+func (*GetEntitiesRequest) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{63}
+}
+
+type GetEntitiesResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ EntityDefinitions []*EntityDefinition `protobuf:"bytes,1,rep,name=entity_definitions,json=entityDefinitions,proto3" json:"entity_definitions,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetEntitiesResponse) Reset() {
+ *x = GetEntitiesResponse{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[64]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GetEntitiesResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetEntitiesResponse) ProtoMessage() {}
+
+func (x *GetEntitiesResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[64]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetEntitiesResponse.ProtoReflect.Descriptor instead.
+func (*GetEntitiesResponse) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{64}
+}
+
+func (x *GetEntitiesResponse) GetEntityDefinitions() []*EntityDefinition {
+ if x != nil {
+ return x.EntityDefinitions
+ }
+ return nil
+}
+
+type EntityDefinition struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"`
+ Instances []*Entity `protobuf:"bytes,2,rep,name=instances,proto3" json:"instances,omitempty"`
+ UsedOnDashboards []string `protobuf:"bytes,3,rep,name=used_on_dashboards,json=usedOnDashboards,proto3" json:"used_on_dashboards,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *EntityDefinition) Reset() {
+ *x = EntityDefinition{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[65]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *EntityDefinition) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*EntityDefinition) ProtoMessage() {}
+
+func (x *EntityDefinition) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[65]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use EntityDefinition.ProtoReflect.Descriptor instead.
+func (*EntityDefinition) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{65}
+}
+
+func (x *EntityDefinition) GetTitle() string {
+ if x != nil {
+ return x.Title
+ }
+ return ""
+}
+
+func (x *EntityDefinition) GetInstances() []*Entity {
+ if x != nil {
+ return x.Instances
+ }
+ return nil
+}
+
+func (x *EntityDefinition) GetUsedOnDashboards() []string {
+ if x != nil {
+ return x.UsedOnDashboards
+ }
+ return nil
+}
+
+type GetEntityRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ UniqueKey string `protobuf:"bytes,1,opt,name=unique_key,json=uniqueKey,proto3" json:"unique_key,omitempty"`
+ Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetEntityRequest) Reset() {
+ *x = GetEntityRequest{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[66]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GetEntityRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetEntityRequest) ProtoMessage() {}
+
+func (x *GetEntityRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[66]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetEntityRequest.ProtoReflect.Descriptor instead.
+func (*GetEntityRequest) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{66}
+}
+
+func (x *GetEntityRequest) GetUniqueKey() string {
+ if x != nil {
+ return x.UniqueKey
+ }
+ return ""
+}
+
+func (x *GetEntityRequest) GetType() string {
+ if x != nil {
+ return x.Type
+ }
+ return ""
+}
+
+type RestartActionRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ ExecutionTrackingId string `protobuf:"bytes,1,opt,name=execution_tracking_id,json=executionTrackingId,proto3" json:"execution_tracking_id,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *RestartActionRequest) Reset() {
+ *x = RestartActionRequest{}
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[67]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *RestartActionRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RestartActionRequest) ProtoMessage() {}
+
+func (x *RestartActionRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_olivetin_api_v1_olivetin_proto_msgTypes[67]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use RestartActionRequest.ProtoReflect.Descriptor instead.
+func (*RestartActionRequest) Descriptor() ([]byte, []int) {
+ return file_olivetin_api_v1_olivetin_proto_rawDescGZIP(), []int{67}
+}
+
+func (x *RestartActionRequest) GetExecutionTrackingId() string {
+ if x != nil {
+ return x.ExecutionTrackingId
+ }
+ return ""
+}
+
+var File_olivetin_api_v1_olivetin_proto protoreflect.FileDescriptor
+
+const file_olivetin_api_v1_olivetin_proto_rawDesc = "" +
+ "\n" +
+ "\x1eolivetin/api/v1/olivetin.proto\x12\x0folivetin.api.v1\"\xc0\x02\n" +
+ "\x06Action\x12\x1d\n" +
+ "\n" +
+ "binding_id\x18\x01 \x01(\tR\tbindingId\x12\x14\n" +
+ "\x05title\x18\x02 \x01(\tR\x05title\x12\x12\n" +
+ "\x04icon\x18\x03 \x01(\tR\x04icon\x12\x19\n" +
+ "\bcan_exec\x18\x04 \x01(\bR\acanExec\x12=\n" +
+ "\targuments\x18\x05 \x03(\v2\x1f.olivetin.api.v1.ActionArgumentR\targuments\x12$\n" +
+ "\x0epopup_on_start\x18\x06 \x01(\tR\fpopupOnStart\x12\x14\n" +
+ "\x05order\x18\a \x01(\x05R\x05order\x12\x18\n" +
+ "\atimeout\x18\b \x01(\x05R\atimeout\x12=\n" +
+ "\x1bdatetime_rate_limit_expires\x18\t \x01(\tR\x18datetimeRateLimitExpires\"\xa2\x03\n" +
+ "\x0eActionArgument\x12\x12\n" +
+ "\x04name\x18\x01 \x01(\tR\x04name\x12\x14\n" +
+ "\x05title\x18\x02 \x01(\tR\x05title\x12\x12\n" +
+ "\x04type\x18\x03 \x01(\tR\x04type\x12#\n" +
+ "\rdefault_value\x18\x04 \x01(\tR\fdefaultValue\x12?\n" +
+ "\achoices\x18\x05 \x03(\v2%.olivetin.api.v1.ActionArgumentChoiceR\achoices\x12 \n" +
+ "\vdescription\x18\x06 \x01(\tR\vdescription\x12R\n" +
+ "\vsuggestions\x18\a \x03(\v20.olivetin.api.v1.ActionArgument.SuggestionsEntryR\vsuggestions\x126\n" +
+ "\x17suggestions_browser_key\x18\b \x01(\tR\x15suggestionsBrowserKey\x1a>\n" +
+ "\x10SuggestionsEntry\x12\x10\n" +
+ "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
+ "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"B\n" +
+ "\x14ActionArgumentChoice\x12\x14\n" +
+ "\x05value\x18\x01 \x01(\tR\x05value\x12\x14\n" +
+ "\x05title\x18\x02 \x01(\tR\x05title\"\xeb\x01\n" +
+ "\x06Entity\x12\x14\n" +
+ "\x05title\x18\x01 \x01(\tR\x05title\x12\x1d\n" +
+ "\n" +
+ "unique_key\x18\x02 \x01(\tR\tuniqueKey\x12\x12\n" +
+ "\x04type\x18\x03 \x01(\tR\x04type\x12 \n" +
+ "\vdirectories\x18\x04 \x03(\tR\vdirectories\x12;\n" +
+ "\x06fields\x18\x05 \x03(\v2#.olivetin.api.v1.Entity.FieldsEntryR\x06fields\x1a9\n" +
+ "\vFieldsEntry\x12\x10\n" +
+ "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
+ "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"f\n" +
+ "\x14GetDashboardResponse\x12\x14\n" +
+ "\x05title\x18\x01 \x01(\tR\x05title\x128\n" +
+ "\tdashboard\x18\x04 \x01(\v2\x1a.olivetin.api.v1.DashboardR\tdashboard\"`\n" +
+ "\x0fEffectivePolicy\x12)\n" +
+ "\x10show_diagnostics\x18\x01 \x01(\bR\x0fshowDiagnostics\x12\"\n" +
+ "\rshow_log_list\x18\x02 \x01(\bR\vshowLogList\"k\n" +
+ "\x13GetDashboardRequest\x12\x14\n" +
+ "\x05title\x18\x01 \x01(\tR\x05title\x12\x1f\n" +
+ "\ventity_type\x18\x02 \x01(\tR\n" +
+ "entityType\x12\x1d\n" +
+ "\n" +
+ "entity_key\x18\x03 \x01(\tR\tentityKey\"b\n" +
+ "\tDashboard\x12\x14\n" +
+ "\x05title\x18\x01 \x01(\tR\x05title\x12?\n" +
+ "\bcontents\x18\x02 \x03(\v2#.olivetin.api.v1.DashboardComponentR\bcontents\"\xa1\x02\n" +
+ "\x12DashboardComponent\x12\x14\n" +
+ "\x05title\x18\x01 \x01(\tR\x05title\x12\x12\n" +
+ "\x04type\x18\x02 \x01(\tR\x04type\x12?\n" +
+ "\bcontents\x18\x03 \x03(\v2#.olivetin.api.v1.DashboardComponentR\bcontents\x12\x12\n" +
+ "\x04icon\x18\x04 \x01(\tR\x04icon\x12\x1b\n" +
+ "\tcss_class\x18\x05 \x01(\tR\bcssClass\x12/\n" +
+ "\x06action\x18\x06 \x01(\v2\x17.olivetin.api.v1.ActionR\x06action\x12\x1f\n" +
+ "\ventity_type\x18\a \x01(\tR\n" +
+ "entityType\x12\x1d\n" +
+ "\n" +
+ "entity_key\x18\b \x01(\tR\tentityKey\"\xa5\x01\n" +
+ "\x12StartActionRequest\x12\x1d\n" +
+ "\n" +
+ "binding_id\x18\x01 \x01(\tR\tbindingId\x12B\n" +
+ "\targuments\x18\x02 \x03(\v2$.olivetin.api.v1.StartActionArgumentR\targuments\x12,\n" +
+ "\x12unique_tracking_id\x18\x03 \x01(\tR\x10uniqueTrackingId\"?\n" +
+ "\x13StartActionArgument\x12\x12\n" +
+ "\x04name\x18\x01 \x01(\tR\x04name\x12\x14\n" +
+ "\x05value\x18\x02 \x01(\tR\x05value\"I\n" +
+ "\x13StartActionResponse\x122\n" +
+ "\x15execution_tracking_id\x18\x02 \x01(\tR\x13executionTrackingId\"|\n" +
+ "\x19StartActionAndWaitRequest\x12\x1b\n" +
+ "\taction_id\x18\x01 \x01(\tR\bactionId\x12B\n" +
+ "\targuments\x18\x02 \x03(\v2$.olivetin.api.v1.StartActionArgumentR\targuments\"T\n" +
+ "\x1aStartActionAndWaitResponse\x126\n" +
+ "\tlog_entry\x18\x01 \x01(\v2\x19.olivetin.api.v1.LogEntryR\blogEntry\"6\n" +
+ "\x17StartActionByGetRequest\x12\x1b\n" +
+ "\taction_id\x18\x01 \x01(\tR\bactionId\"N\n" +
+ "\x18StartActionByGetResponse\x122\n" +
+ "\x15execution_tracking_id\x18\x02 \x01(\tR\x13executionTrackingId\"=\n" +
+ "\x1eStartActionByGetAndWaitRequest\x12\x1b\n" +
+ "\taction_id\x18\x01 \x01(\tR\bactionId\"Y\n" +
+ "\x1fStartActionByGetAndWaitResponse\x126\n" +
+ "\tlog_entry\x18\x01 \x01(\v2\x19.olivetin.api.v1.LogEntryR\blogEntry\"T\n" +
+ "\x0eGetLogsRequest\x12!\n" +
+ "\fstart_offset\x18\x01 \x01(\x03R\vstartOffset\x12\x1f\n" +
+ "\vdate_filter\x18\x02 \x01(\tR\n" +
+ "dateFilter\"\x89\x05\n" +
+ "\bLogEntry\x12)\n" +
+ "\x10datetime_started\x18\x01 \x01(\tR\x0fdatetimeStarted\x12!\n" +
+ "\faction_title\x18\x02 \x01(\tR\vactionTitle\x12\x16\n" +
+ "\x06output\x18\x03 \x01(\tR\x06output\x12\x1b\n" +
+ "\ttimed_out\x18\x05 \x01(\bR\btimedOut\x12\x1b\n" +
+ "\texit_code\x18\x06 \x01(\x05R\bexitCode\x12\x12\n" +
+ "\x04user\x18\a \x01(\tR\x04user\x12\x1d\n" +
+ "\n" +
+ "user_class\x18\b \x01(\tR\tuserClass\x12\x1f\n" +
+ "\vaction_icon\x18\t \x01(\tR\n" +
+ "actionIcon\x12\x12\n" +
+ "\x04tags\x18\n" +
+ " \x03(\tR\x04tags\x122\n" +
+ "\x15execution_tracking_id\x18\v \x01(\tR\x13executionTrackingId\x12+\n" +
+ "\x11datetime_finished\x18\f \x01(\tR\x10datetimeFinished\x12+\n" +
+ "\x11execution_started\x18\x0e \x01(\bR\x10executionStarted\x12-\n" +
+ "\x12execution_finished\x18\x0f \x01(\bR\x11executionFinished\x12\x18\n" +
+ "\ablocked\x18\x10 \x01(\bR\ablocked\x12%\n" +
+ "\x0edatetime_index\x18\x11 \x01(\x03R\rdatetimeIndex\x12\x19\n" +
+ "\bcan_kill\x18\x12 \x01(\bR\acanKill\x12=\n" +
+ "\x1bdatetime_rate_limit_expires\x18\x13 \x01(\tR\x18datetimeRateLimitExpires\x12\x1d\n" +
+ "\n" +
+ "binding_id\x18\x14 \x01(\tR\tbindingId\"\xca\x01\n" +
+ "\x0fGetLogsResponse\x12-\n" +
+ "\x04logs\x18\x01 \x03(\v2\x19.olivetin.api.v1.LogEntryR\x04logs\x12'\n" +
+ "\x0fcount_remaining\x18\x02 \x01(\x03R\x0ecountRemaining\x12\x1b\n" +
+ "\tpage_size\x18\x03 \x01(\x03R\bpageSize\x12\x1f\n" +
+ "\vtotal_count\x18\x04 \x01(\x03R\n" +
+ "totalCount\x12!\n" +
+ "\fstart_offset\x18\x05 \x01(\x03R\vstartOffset\"V\n" +
+ "\x14GetActionLogsRequest\x12\x1b\n" +
+ "\taction_id\x18\x01 \x01(\tR\bactionId\x12!\n" +
+ "\fstart_offset\x18\x02 \x01(\x03R\vstartOffset\"\xd0\x01\n" +
+ "\x15GetActionLogsResponse\x12-\n" +
+ "\x04logs\x18\x01 \x03(\v2\x19.olivetin.api.v1.LogEntryR\x04logs\x12'\n" +
+ "\x0fcount_remaining\x18\x02 \x01(\x03R\x0ecountRemaining\x12\x1b\n" +
+ "\tpage_size\x18\x03 \x01(\x03R\bpageSize\x12\x1f\n" +
+ "\vtotal_count\x18\x04 \x01(\x03R\n" +
+ "totalCount\x12!\n" +
+ "\fstart_offset\x18\x05 \x01(\x03R\vstartOffset\"\x8b\x01\n" +
+ "\x1bValidateArgumentTypeRequest\x12\x14\n" +
+ "\x05value\x18\x01 \x01(\tR\x05value\x12\x12\n" +
+ "\x04type\x18\x02 \x01(\tR\x04type\x12\x1d\n" +
+ "\n" +
+ "binding_id\x18\x03 \x01(\tR\tbindingId\x12#\n" +
+ "\rargument_name\x18\x04 \x01(\tR\fargumentName\"V\n" +
+ "\x1cValidateArgumentTypeResponse\x12\x14\n" +
+ "\x05valid\x18\x01 \x01(\bR\x05valid\x12 \n" +
+ "\vdescription\x18\x02 \x01(\tR\vdescription\"K\n" +
+ "\x15WatchExecutionRequest\x122\n" +
+ "\x15execution_tracking_id\x18\x01 \x01(\tR\x13executionTrackingId\".\n" +
+ "\x14WatchExecutionUpdate\x12\x16\n" +
+ "\x06update\x18\x01 \x01(\tR\x06update\"i\n" +
+ "\x16ExecutionStatusRequest\x122\n" +
+ "\x15execution_tracking_id\x18\x01 \x01(\tR\x13executionTrackingId\x12\x1b\n" +
+ "\taction_id\x18\x02 \x01(\tR\bactionId\"Q\n" +
+ "\x17ExecutionStatusResponse\x126\n" +
+ "\tlog_entry\x18\x01 \x01(\v2\x19.olivetin.api.v1.LogEntryR\blogEntry\"\x0f\n" +
+ "\rWhoAmIRequest\"\x9f\x01\n" +
+ "\x0eWhoAmIResponse\x12-\n" +
+ "\x12authenticated_user\x18\x01 \x01(\tR\x11authenticatedUser\x12\x1c\n" +
+ "\tusergroup\x18\x02 \x01(\tR\tusergroup\x12\x1a\n" +
+ "\bprovider\x18\x03 \x01(\tR\bprovider\x12\x12\n" +
+ "\x04acls\x18\x04 \x03(\tR\x04acls\x12\x10\n" +
+ "\x03sid\x18\x05 \x01(\tR\x03sid\"\x12\n" +
+ "\x10SosReportRequest\")\n" +
+ "\x11SosReportResponse\x12\x14\n" +
+ "\x05alert\x18\x01 \x01(\tR\x05alert\"\x11\n" +
+ "\x0fDumpVarsRequest\"\xb2\x01\n" +
+ "\x10DumpVarsResponse\x12\x14\n" +
+ "\x05alert\x18\x01 \x01(\tR\x05alert\x12K\n" +
+ "\bcontents\x18\x02 \x03(\v2/.olivetin.api.v1.DumpVarsResponse.ContentsEntryR\bcontents\x1a;\n" +
+ "\rContentsEntry\x12\x10\n" +
+ "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
+ "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"V\n" +
+ "\fDebugBinding\x12!\n" +
+ "\faction_title\x18\x01 \x01(\tR\vactionTitle\x12#\n" +
+ "\rentity_prefix\x18\x02 \x01(\tR\fentityPrefix\"\x1e\n" +
+ "\x1cDumpPublicIdActionMapRequest\"\xeb\x01\n" +
+ "\x1dDumpPublicIdActionMapResponse\x12\x14\n" +
+ "\x05alert\x18\x01 \x01(\tR\x05alert\x12X\n" +
+ "\bcontents\x18\x02 \x03(\v2<.olivetin.api.v1.DumpPublicIdActionMapResponse.ContentsEntryR\bcontents\x1aZ\n" +
+ "\rContentsEntry\x12\x10\n" +
+ "\x03key\x18\x01 \x01(\tR\x03key\x123\n" +
+ "\x05value\x18\x02 \x01(\v2\x1d.olivetin.api.v1.DebugBindingR\x05value:\x028\x01\"\x12\n" +
+ "\x10GetReadyzRequest\"+\n" +
+ "\x11GetReadyzResponse\x12\x16\n" +
+ "\x06status\x18\x01 \x01(\tR\x06status\"\x14\n" +
+ "\x12EventStreamRequest\"\xb3\x03\n" +
+ "\x13EventStreamResponse\x12L\n" +
+ "\x0eentity_changed\x18\x02 \x01(\v2#.olivetin.api.v1.EventEntityChangedH\x00R\rentityChanged\x12L\n" +
+ "\x0econfig_changed\x18\x03 \x01(\v2#.olivetin.api.v1.EventConfigChangedH\x00R\rconfigChanged\x12X\n" +
+ "\x12execution_finished\x18\x04 \x01(\v2'.olivetin.api.v1.EventExecutionFinishedH\x00R\x11executionFinished\x12U\n" +
+ "\x11execution_started\x18\x05 \x01(\v2&.olivetin.api.v1.EventExecutionStartedH\x00R\x10executionStarted\x12F\n" +
+ "\foutput_chunk\x18\x06 \x01(\v2!.olivetin.api.v1.EventOutputChunkH\x00R\voutputChunkB\a\n" +
+ "\x05event\"^\n" +
+ "\x10EventOutputChunk\x122\n" +
+ "\x15execution_tracking_id\x18\x01 \x01(\tR\x13executionTrackingId\x12\x16\n" +
+ "\x06output\x18\x02 \x01(\tR\x06output\"\x14\n" +
+ "\x12EventEntityChanged\"\x14\n" +
+ "\x12EventConfigChanged\"P\n" +
+ "\x16EventExecutionFinished\x126\n" +
+ "\tlog_entry\x18\x01 \x01(\v2\x19.olivetin.api.v1.LogEntryR\blogEntry\"O\n" +
+ "\x15EventExecutionStarted\x126\n" +
+ "\tlog_entry\x18\x01 \x01(\v2\x19.olivetin.api.v1.LogEntryR\blogEntry\"G\n" +
+ "\x11KillActionRequest\x122\n" +
+ "\x15execution_tracking_id\x18\x01 \x01(\tR\x13executionTrackingId\"\xa3\x01\n" +
+ "\x12KillActionResponse\x122\n" +
+ "\x15execution_tracking_id\x18\x01 \x01(\tR\x13executionTrackingId\x12\x16\n" +
+ "\x06killed\x18\x02 \x01(\bR\x06killed\x12+\n" +
+ "\x11already_completed\x18\x03 \x01(\bR\x10alreadyCompleted\x12\x14\n" +
+ "\x05found\x18\x04 \x01(\bR\x05found\"O\n" +
+ "\x15LocalUserLoginRequest\x12\x1a\n" +
+ "\busername\x18\x01 \x01(\tR\busername\x12\x1a\n" +
+ "\bpassword\x18\x02 \x01(\tR\bpassword\"2\n" +
+ "\x16LocalUserLoginResponse\x12\x18\n" +
+ "\asuccess\x18\x01 \x01(\bR\asuccess\"1\n" +
+ "\x13PasswordHashRequest\x12\x1a\n" +
+ "\bpassword\x18\x01 \x01(\tR\bpassword\"*\n" +
+ "\x14PasswordHashResponse\x12\x12\n" +
+ "\x04hash\x18\x01 \x01(\tR\x04hash\"\x0f\n" +
+ "\rLogoutRequest\"\x10\n" +
+ "\x0eLogoutResponse\"\x17\n" +
+ "\x15GetDiagnosticsRequest\"b\n" +
+ "\x16GetDiagnosticsResponse\x12 \n" +
+ "\vSshFoundKey\x18\x01 \x01(\tR\vSshFoundKey\x12&\n" +
+ "\x0eSshFoundConfig\x18\x02 \x01(\tR\x0eSshFoundConfig\"\r\n" +
+ "\vInitRequest\"\xa2\b\n" +
+ "\fInitResponse\x12\x1e\n" +
+ "\n" +
+ "showFooter\x18\x01 \x01(\bR\n" +
+ "showFooter\x12&\n" +
+ "\x0eshowNavigation\x18\x02 \x01(\bR\x0eshowNavigation\x12(\n" +
+ "\x0fshowNewVersions\x18\x03 \x01(\bR\x0fshowNewVersions\x12*\n" +
+ "\x10availableVersion\x18\x04 \x01(\tR\x10availableVersion\x12&\n" +
+ "\x0ecurrentVersion\x18\x05 \x01(\tR\x0ecurrentVersion\x12\x1c\n" +
+ "\tpageTitle\x18\x06 \x01(\tR\tpageTitle\x126\n" +
+ "\x16sectionNavigationStyle\x18\a \x01(\tR\x16sectionNavigationStyle\x12.\n" +
+ "\x12defaultIconForBack\x18\b \x01(\tR\x12defaultIconForBack\x12&\n" +
+ "\x0eenableCustomJs\x18\t \x01(\bR\x0eenableCustomJs\x12\"\n" +
+ "\fauthLoginUrl\x18\n" +
+ " \x01(\tR\fauthLoginUrl\x12&\n" +
+ "\x0eauthLocalLogin\x18\v \x01(\bR\x0eauthLocalLogin\x12\x1c\n" +
+ "\tstyleMods\x18\f \x03(\tR\tstyleMods\x12I\n" +
+ "\x0foAuth2Providers\x18\r \x03(\v2\x1f.olivetin.api.v1.OAuth2ProviderR\x0foAuth2Providers\x12I\n" +
+ "\x0fadditionalLinks\x18\x0e \x03(\v2\x1f.olivetin.api.v1.AdditionalLinkR\x0fadditionalLinks\x12&\n" +
+ "\x0erootDashboards\x18\x0f \x03(\tR\x0erootDashboards\x12-\n" +
+ "\x12authenticated_user\x18\x10 \x01(\tR\x11authenticatedUser\x12>\n" +
+ "\x1bauthenticated_user_provider\x18\x11 \x01(\tR\x19authenticatedUserProvider\x12K\n" +
+ "\x10effective_policy\x18\x12 \x01(\v2 .olivetin.api.v1.EffectivePolicyR\x0feffectivePolicy\x12%\n" +
+ "\x0ebanner_message\x18\x13 \x01(\tR\rbannerMessage\x12\x1d\n" +
+ "\n" +
+ "banner_css\x18\x14 \x01(\tR\tbannerCss\x12)\n" +
+ "\x10show_diagnostics\x18\x15 \x01(\bR\x0fshowDiagnostics\x12\"\n" +
+ "\rshow_log_list\x18\x16 \x01(\bR\vshowLogList\x12%\n" +
+ "\x0elogin_required\x18\x17 \x01(\bR\rloginRequired\"8\n" +
+ "\x0eAdditionalLink\x12\x14\n" +
+ "\x05title\x18\x01 \x01(\tR\x05title\x12\x10\n" +
+ "\x03url\x18\x02 \x01(\tR\x03url\"L\n" +
+ "\x0eOAuth2Provider\x12\x14\n" +
+ "\x05title\x18\x01 \x01(\tR\x05title\x12\x12\n" +
+ "\x04icon\x18\x03 \x01(\tR\x04icon\x12\x10\n" +
+ "\x03key\x18\x04 \x01(\tR\x03key\"8\n" +
+ "\x17GetActionBindingRequest\x12\x1d\n" +
+ "\n" +
+ "binding_id\x18\x01 \x01(\tR\tbindingId\"K\n" +
+ "\x18GetActionBindingResponse\x12/\n" +
+ "\x06action\x18\x01 \x01(\v2\x17.olivetin.api.v1.ActionR\x06action\"\x14\n" +
+ "\x12GetEntitiesRequest\"g\n" +
+ "\x13GetEntitiesResponse\x12P\n" +
+ "\x12entity_definitions\x18\x01 \x03(\v2!.olivetin.api.v1.EntityDefinitionR\x11entityDefinitions\"\x8d\x01\n" +
+ "\x10EntityDefinition\x12\x14\n" +
+ "\x05title\x18\x01 \x01(\tR\x05title\x125\n" +
+ "\tinstances\x18\x02 \x03(\v2\x17.olivetin.api.v1.EntityR\tinstances\x12,\n" +
+ "\x12used_on_dashboards\x18\x03 \x03(\tR\x10usedOnDashboards\"E\n" +
+ "\x10GetEntityRequest\x12\x1d\n" +
+ "\n" +
+ "unique_key\x18\x01 \x01(\tR\tuniqueKey\x12\x12\n" +
+ "\x04type\x18\x02 \x01(\tR\x04type\"J\n" +
+ "\x14RestartActionRequest\x122\n" +
+ "\x15execution_tracking_id\x18\x01 \x01(\tR\x13executionTrackingId2\xe8\x12\n" +
+ "\x12OliveTinApiService\x12]\n" +
+ "\fGetDashboard\x12$.olivetin.api.v1.GetDashboardRequest\x1a%.olivetin.api.v1.GetDashboardResponse\"\x00\x12Z\n" +
+ "\vStartAction\x12#.olivetin.api.v1.StartActionRequest\x1a$.olivetin.api.v1.StartActionResponse\"\x00\x12o\n" +
+ "\x12StartActionAndWait\x12*.olivetin.api.v1.StartActionAndWaitRequest\x1a+.olivetin.api.v1.StartActionAndWaitResponse\"\x00\x12i\n" +
+ "\x10StartActionByGet\x12(.olivetin.api.v1.StartActionByGetRequest\x1a).olivetin.api.v1.StartActionByGetResponse\"\x00\x12~\n" +
+ "\x17StartActionByGetAndWait\x12/.olivetin.api.v1.StartActionByGetAndWaitRequest\x1a0.olivetin.api.v1.StartActionByGetAndWaitResponse\"\x00\x12^\n" +
+ "\rRestartAction\x12%.olivetin.api.v1.RestartActionRequest\x1a$.olivetin.api.v1.StartActionResponse\"\x00\x12W\n" +
+ "\n" +
+ "KillAction\x12\".olivetin.api.v1.KillActionRequest\x1a#.olivetin.api.v1.KillActionResponse\"\x00\x12f\n" +
+ "\x0fExecutionStatus\x12'.olivetin.api.v1.ExecutionStatusRequest\x1a(.olivetin.api.v1.ExecutionStatusResponse\"\x00\x12N\n" +
+ "\aGetLogs\x12\x1f.olivetin.api.v1.GetLogsRequest\x1a .olivetin.api.v1.GetLogsResponse\"\x00\x12`\n" +
+ "\rGetActionLogs\x12%.olivetin.api.v1.GetActionLogsRequest\x1a&.olivetin.api.v1.GetActionLogsResponse\"\x00\x12u\n" +
+ "\x14ValidateArgumentType\x12,.olivetin.api.v1.ValidateArgumentTypeRequest\x1a-.olivetin.api.v1.ValidateArgumentTypeResponse\"\x00\x12K\n" +
+ "\x06WhoAmI\x12\x1e.olivetin.api.v1.WhoAmIRequest\x1a\x1f.olivetin.api.v1.WhoAmIResponse\"\x00\x12T\n" +
+ "\tSosReport\x12!.olivetin.api.v1.SosReportRequest\x1a\".olivetin.api.v1.SosReportResponse\"\x00\x12Q\n" +
+ "\bDumpVars\x12 .olivetin.api.v1.DumpVarsRequest\x1a!.olivetin.api.v1.DumpVarsResponse\"\x00\x12x\n" +
+ "\x15DumpPublicIdActionMap\x12-.olivetin.api.v1.DumpPublicIdActionMapRequest\x1a..olivetin.api.v1.DumpPublicIdActionMapResponse\"\x00\x12T\n" +
+ "\tGetReadyz\x12!.olivetin.api.v1.GetReadyzRequest\x1a\".olivetin.api.v1.GetReadyzResponse\"\x00\x12c\n" +
+ "\x0eLocalUserLogin\x12&.olivetin.api.v1.LocalUserLoginRequest\x1a'.olivetin.api.v1.LocalUserLoginResponse\"\x00\x12]\n" +
+ "\fPasswordHash\x12$.olivetin.api.v1.PasswordHashRequest\x1a%.olivetin.api.v1.PasswordHashResponse\"\x00\x12K\n" +
+ "\x06Logout\x12\x1e.olivetin.api.v1.LogoutRequest\x1a\x1f.olivetin.api.v1.LogoutResponse\"\x00\x12\\\n" +
+ "\vEventStream\x12#.olivetin.api.v1.EventStreamRequest\x1a$.olivetin.api.v1.EventStreamResponse\"\x000\x01\x12c\n" +
+ "\x0eGetDiagnostics\x12&.olivetin.api.v1.GetDiagnosticsRequest\x1a'.olivetin.api.v1.GetDiagnosticsResponse\"\x00\x12E\n" +
+ "\x04Init\x12\x1c.olivetin.api.v1.InitRequest\x1a\x1d.olivetin.api.v1.InitResponse\"\x00\x12i\n" +
+ "\x10GetActionBinding\x12(.olivetin.api.v1.GetActionBindingRequest\x1a).olivetin.api.v1.GetActionBindingResponse\"\x00\x12Z\n" +
+ "\vGetEntities\x12#.olivetin.api.v1.GetEntitiesRequest\x1a$.olivetin.api.v1.GetEntitiesResponse\"\x00\x12I\n" +
+ "\tGetEntity\x12!.olivetin.api.v1.GetEntityRequest\x1a\x17.olivetin.api.v1.Entity\"\x00B8Z6github.com/OliveTin/OliveTin/gen/olivetin/api/v1;apiv1b\x06proto3"
+
+var (
+ file_olivetin_api_v1_olivetin_proto_rawDescOnce sync.Once
+ file_olivetin_api_v1_olivetin_proto_rawDescData []byte
+)
+
+func file_olivetin_api_v1_olivetin_proto_rawDescGZIP() []byte {
+ file_olivetin_api_v1_olivetin_proto_rawDescOnce.Do(func() {
+ file_olivetin_api_v1_olivetin_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_olivetin_api_v1_olivetin_proto_rawDesc), len(file_olivetin_api_v1_olivetin_proto_rawDesc)))
+ })
+ return file_olivetin_api_v1_olivetin_proto_rawDescData
+}
+
+var file_olivetin_api_v1_olivetin_proto_msgTypes = make([]protoimpl.MessageInfo, 72)
+var file_olivetin_api_v1_olivetin_proto_goTypes = []any{
+ (*Action)(nil), // 0: olivetin.api.v1.Action
+ (*ActionArgument)(nil), // 1: olivetin.api.v1.ActionArgument
+ (*ActionArgumentChoice)(nil), // 2: olivetin.api.v1.ActionArgumentChoice
+ (*Entity)(nil), // 3: olivetin.api.v1.Entity
+ (*GetDashboardResponse)(nil), // 4: olivetin.api.v1.GetDashboardResponse
+ (*EffectivePolicy)(nil), // 5: olivetin.api.v1.EffectivePolicy
+ (*GetDashboardRequest)(nil), // 6: olivetin.api.v1.GetDashboardRequest
+ (*Dashboard)(nil), // 7: olivetin.api.v1.Dashboard
+ (*DashboardComponent)(nil), // 8: olivetin.api.v1.DashboardComponent
+ (*StartActionRequest)(nil), // 9: olivetin.api.v1.StartActionRequest
+ (*StartActionArgument)(nil), // 10: olivetin.api.v1.StartActionArgument
+ (*StartActionResponse)(nil), // 11: olivetin.api.v1.StartActionResponse
+ (*StartActionAndWaitRequest)(nil), // 12: olivetin.api.v1.StartActionAndWaitRequest
+ (*StartActionAndWaitResponse)(nil), // 13: olivetin.api.v1.StartActionAndWaitResponse
+ (*StartActionByGetRequest)(nil), // 14: olivetin.api.v1.StartActionByGetRequest
+ (*StartActionByGetResponse)(nil), // 15: olivetin.api.v1.StartActionByGetResponse
+ (*StartActionByGetAndWaitRequest)(nil), // 16: olivetin.api.v1.StartActionByGetAndWaitRequest
+ (*StartActionByGetAndWaitResponse)(nil), // 17: olivetin.api.v1.StartActionByGetAndWaitResponse
+ (*GetLogsRequest)(nil), // 18: olivetin.api.v1.GetLogsRequest
+ (*LogEntry)(nil), // 19: olivetin.api.v1.LogEntry
+ (*GetLogsResponse)(nil), // 20: olivetin.api.v1.GetLogsResponse
+ (*GetActionLogsRequest)(nil), // 21: olivetin.api.v1.GetActionLogsRequest
+ (*GetActionLogsResponse)(nil), // 22: olivetin.api.v1.GetActionLogsResponse
+ (*ValidateArgumentTypeRequest)(nil), // 23: olivetin.api.v1.ValidateArgumentTypeRequest
+ (*ValidateArgumentTypeResponse)(nil), // 24: olivetin.api.v1.ValidateArgumentTypeResponse
+ (*WatchExecutionRequest)(nil), // 25: olivetin.api.v1.WatchExecutionRequest
+ (*WatchExecutionUpdate)(nil), // 26: olivetin.api.v1.WatchExecutionUpdate
+ (*ExecutionStatusRequest)(nil), // 27: olivetin.api.v1.ExecutionStatusRequest
+ (*ExecutionStatusResponse)(nil), // 28: olivetin.api.v1.ExecutionStatusResponse
+ (*WhoAmIRequest)(nil), // 29: olivetin.api.v1.WhoAmIRequest
+ (*WhoAmIResponse)(nil), // 30: olivetin.api.v1.WhoAmIResponse
+ (*SosReportRequest)(nil), // 31: olivetin.api.v1.SosReportRequest
+ (*SosReportResponse)(nil), // 32: olivetin.api.v1.SosReportResponse
+ (*DumpVarsRequest)(nil), // 33: olivetin.api.v1.DumpVarsRequest
+ (*DumpVarsResponse)(nil), // 34: olivetin.api.v1.DumpVarsResponse
+ (*DebugBinding)(nil), // 35: olivetin.api.v1.DebugBinding
+ (*DumpPublicIdActionMapRequest)(nil), // 36: olivetin.api.v1.DumpPublicIdActionMapRequest
+ (*DumpPublicIdActionMapResponse)(nil), // 37: olivetin.api.v1.DumpPublicIdActionMapResponse
+ (*GetReadyzRequest)(nil), // 38: olivetin.api.v1.GetReadyzRequest
+ (*GetReadyzResponse)(nil), // 39: olivetin.api.v1.GetReadyzResponse
+ (*EventStreamRequest)(nil), // 40: olivetin.api.v1.EventStreamRequest
+ (*EventStreamResponse)(nil), // 41: olivetin.api.v1.EventStreamResponse
+ (*EventOutputChunk)(nil), // 42: olivetin.api.v1.EventOutputChunk
+ (*EventEntityChanged)(nil), // 43: olivetin.api.v1.EventEntityChanged
+ (*EventConfigChanged)(nil), // 44: olivetin.api.v1.EventConfigChanged
+ (*EventExecutionFinished)(nil), // 45: olivetin.api.v1.EventExecutionFinished
+ (*EventExecutionStarted)(nil), // 46: olivetin.api.v1.EventExecutionStarted
+ (*KillActionRequest)(nil), // 47: olivetin.api.v1.KillActionRequest
+ (*KillActionResponse)(nil), // 48: olivetin.api.v1.KillActionResponse
+ (*LocalUserLoginRequest)(nil), // 49: olivetin.api.v1.LocalUserLoginRequest
+ (*LocalUserLoginResponse)(nil), // 50: olivetin.api.v1.LocalUserLoginResponse
+ (*PasswordHashRequest)(nil), // 51: olivetin.api.v1.PasswordHashRequest
+ (*PasswordHashResponse)(nil), // 52: olivetin.api.v1.PasswordHashResponse
+ (*LogoutRequest)(nil), // 53: olivetin.api.v1.LogoutRequest
+ (*LogoutResponse)(nil), // 54: olivetin.api.v1.LogoutResponse
+ (*GetDiagnosticsRequest)(nil), // 55: olivetin.api.v1.GetDiagnosticsRequest
+ (*GetDiagnosticsResponse)(nil), // 56: olivetin.api.v1.GetDiagnosticsResponse
+ (*InitRequest)(nil), // 57: olivetin.api.v1.InitRequest
+ (*InitResponse)(nil), // 58: olivetin.api.v1.InitResponse
+ (*AdditionalLink)(nil), // 59: olivetin.api.v1.AdditionalLink
+ (*OAuth2Provider)(nil), // 60: olivetin.api.v1.OAuth2Provider
+ (*GetActionBindingRequest)(nil), // 61: olivetin.api.v1.GetActionBindingRequest
+ (*GetActionBindingResponse)(nil), // 62: olivetin.api.v1.GetActionBindingResponse
+ (*GetEntitiesRequest)(nil), // 63: olivetin.api.v1.GetEntitiesRequest
+ (*GetEntitiesResponse)(nil), // 64: olivetin.api.v1.GetEntitiesResponse
+ (*EntityDefinition)(nil), // 65: olivetin.api.v1.EntityDefinition
+ (*GetEntityRequest)(nil), // 66: olivetin.api.v1.GetEntityRequest
+ (*RestartActionRequest)(nil), // 67: olivetin.api.v1.RestartActionRequest
+ nil, // 68: olivetin.api.v1.ActionArgument.SuggestionsEntry
+ nil, // 69: olivetin.api.v1.Entity.FieldsEntry
+ nil, // 70: olivetin.api.v1.DumpVarsResponse.ContentsEntry
+ nil, // 71: olivetin.api.v1.DumpPublicIdActionMapResponse.ContentsEntry
+}
+var file_olivetin_api_v1_olivetin_proto_depIdxs = []int32{
+ 1, // 0: olivetin.api.v1.Action.arguments:type_name -> olivetin.api.v1.ActionArgument
+ 2, // 1: olivetin.api.v1.ActionArgument.choices:type_name -> olivetin.api.v1.ActionArgumentChoice
+ 68, // 2: olivetin.api.v1.ActionArgument.suggestions:type_name -> olivetin.api.v1.ActionArgument.SuggestionsEntry
+ 69, // 3: olivetin.api.v1.Entity.fields:type_name -> olivetin.api.v1.Entity.FieldsEntry
+ 7, // 4: olivetin.api.v1.GetDashboardResponse.dashboard:type_name -> olivetin.api.v1.Dashboard
+ 8, // 5: olivetin.api.v1.Dashboard.contents:type_name -> olivetin.api.v1.DashboardComponent
+ 8, // 6: olivetin.api.v1.DashboardComponent.contents:type_name -> olivetin.api.v1.DashboardComponent
+ 0, // 7: olivetin.api.v1.DashboardComponent.action:type_name -> olivetin.api.v1.Action
+ 10, // 8: olivetin.api.v1.StartActionRequest.arguments:type_name -> olivetin.api.v1.StartActionArgument
+ 10, // 9: olivetin.api.v1.StartActionAndWaitRequest.arguments:type_name -> olivetin.api.v1.StartActionArgument
+ 19, // 10: olivetin.api.v1.StartActionAndWaitResponse.log_entry:type_name -> olivetin.api.v1.LogEntry
+ 19, // 11: olivetin.api.v1.StartActionByGetAndWaitResponse.log_entry:type_name -> olivetin.api.v1.LogEntry
+ 19, // 12: olivetin.api.v1.GetLogsResponse.logs:type_name -> olivetin.api.v1.LogEntry
+ 19, // 13: olivetin.api.v1.GetActionLogsResponse.logs:type_name -> olivetin.api.v1.LogEntry
+ 19, // 14: olivetin.api.v1.ExecutionStatusResponse.log_entry:type_name -> olivetin.api.v1.LogEntry
+ 70, // 15: olivetin.api.v1.DumpVarsResponse.contents:type_name -> olivetin.api.v1.DumpVarsResponse.ContentsEntry
+ 71, // 16: olivetin.api.v1.DumpPublicIdActionMapResponse.contents:type_name -> olivetin.api.v1.DumpPublicIdActionMapResponse.ContentsEntry
+ 43, // 17: olivetin.api.v1.EventStreamResponse.entity_changed:type_name -> olivetin.api.v1.EventEntityChanged
+ 44, // 18: olivetin.api.v1.EventStreamResponse.config_changed:type_name -> olivetin.api.v1.EventConfigChanged
+ 45, // 19: olivetin.api.v1.EventStreamResponse.execution_finished:type_name -> olivetin.api.v1.EventExecutionFinished
+ 46, // 20: olivetin.api.v1.EventStreamResponse.execution_started:type_name -> olivetin.api.v1.EventExecutionStarted
+ 42, // 21: olivetin.api.v1.EventStreamResponse.output_chunk:type_name -> olivetin.api.v1.EventOutputChunk
+ 19, // 22: olivetin.api.v1.EventExecutionFinished.log_entry:type_name -> olivetin.api.v1.LogEntry
+ 19, // 23: olivetin.api.v1.EventExecutionStarted.log_entry:type_name -> olivetin.api.v1.LogEntry
+ 60, // 24: olivetin.api.v1.InitResponse.oAuth2Providers:type_name -> olivetin.api.v1.OAuth2Provider
+ 59, // 25: olivetin.api.v1.InitResponse.additionalLinks:type_name -> olivetin.api.v1.AdditionalLink
+ 5, // 26: olivetin.api.v1.InitResponse.effective_policy:type_name -> olivetin.api.v1.EffectivePolicy
+ 0, // 27: olivetin.api.v1.GetActionBindingResponse.action:type_name -> olivetin.api.v1.Action
+ 65, // 28: olivetin.api.v1.GetEntitiesResponse.entity_definitions:type_name -> olivetin.api.v1.EntityDefinition
+ 3, // 29: olivetin.api.v1.EntityDefinition.instances:type_name -> olivetin.api.v1.Entity
+ 35, // 30: olivetin.api.v1.DumpPublicIdActionMapResponse.ContentsEntry.value:type_name -> olivetin.api.v1.DebugBinding
+ 6, // 31: olivetin.api.v1.OliveTinApiService.GetDashboard:input_type -> olivetin.api.v1.GetDashboardRequest
+ 9, // 32: olivetin.api.v1.OliveTinApiService.StartAction:input_type -> olivetin.api.v1.StartActionRequest
+ 12, // 33: olivetin.api.v1.OliveTinApiService.StartActionAndWait:input_type -> olivetin.api.v1.StartActionAndWaitRequest
+ 14, // 34: olivetin.api.v1.OliveTinApiService.StartActionByGet:input_type -> olivetin.api.v1.StartActionByGetRequest
+ 16, // 35: olivetin.api.v1.OliveTinApiService.StartActionByGetAndWait:input_type -> olivetin.api.v1.StartActionByGetAndWaitRequest
+ 67, // 36: olivetin.api.v1.OliveTinApiService.RestartAction:input_type -> olivetin.api.v1.RestartActionRequest
+ 47, // 37: olivetin.api.v1.OliveTinApiService.KillAction:input_type -> olivetin.api.v1.KillActionRequest
+ 27, // 38: olivetin.api.v1.OliveTinApiService.ExecutionStatus:input_type -> olivetin.api.v1.ExecutionStatusRequest
+ 18, // 39: olivetin.api.v1.OliveTinApiService.GetLogs:input_type -> olivetin.api.v1.GetLogsRequest
+ 21, // 40: olivetin.api.v1.OliveTinApiService.GetActionLogs:input_type -> olivetin.api.v1.GetActionLogsRequest
+ 23, // 41: olivetin.api.v1.OliveTinApiService.ValidateArgumentType:input_type -> olivetin.api.v1.ValidateArgumentTypeRequest
+ 29, // 42: olivetin.api.v1.OliveTinApiService.WhoAmI:input_type -> olivetin.api.v1.WhoAmIRequest
+ 31, // 43: olivetin.api.v1.OliveTinApiService.SosReport:input_type -> olivetin.api.v1.SosReportRequest
+ 33, // 44: olivetin.api.v1.OliveTinApiService.DumpVars:input_type -> olivetin.api.v1.DumpVarsRequest
+ 36, // 45: olivetin.api.v1.OliveTinApiService.DumpPublicIdActionMap:input_type -> olivetin.api.v1.DumpPublicIdActionMapRequest
+ 38, // 46: olivetin.api.v1.OliveTinApiService.GetReadyz:input_type -> olivetin.api.v1.GetReadyzRequest
+ 49, // 47: olivetin.api.v1.OliveTinApiService.LocalUserLogin:input_type -> olivetin.api.v1.LocalUserLoginRequest
+ 51, // 48: olivetin.api.v1.OliveTinApiService.PasswordHash:input_type -> olivetin.api.v1.PasswordHashRequest
+ 53, // 49: olivetin.api.v1.OliveTinApiService.Logout:input_type -> olivetin.api.v1.LogoutRequest
+ 40, // 50: olivetin.api.v1.OliveTinApiService.EventStream:input_type -> olivetin.api.v1.EventStreamRequest
+ 55, // 51: olivetin.api.v1.OliveTinApiService.GetDiagnostics:input_type -> olivetin.api.v1.GetDiagnosticsRequest
+ 57, // 52: olivetin.api.v1.OliveTinApiService.Init:input_type -> olivetin.api.v1.InitRequest
+ 61, // 53: olivetin.api.v1.OliveTinApiService.GetActionBinding:input_type -> olivetin.api.v1.GetActionBindingRequest
+ 63, // 54: olivetin.api.v1.OliveTinApiService.GetEntities:input_type -> olivetin.api.v1.GetEntitiesRequest
+ 66, // 55: olivetin.api.v1.OliveTinApiService.GetEntity:input_type -> olivetin.api.v1.GetEntityRequest
+ 4, // 56: olivetin.api.v1.OliveTinApiService.GetDashboard:output_type -> olivetin.api.v1.GetDashboardResponse
+ 11, // 57: olivetin.api.v1.OliveTinApiService.StartAction:output_type -> olivetin.api.v1.StartActionResponse
+ 13, // 58: olivetin.api.v1.OliveTinApiService.StartActionAndWait:output_type -> olivetin.api.v1.StartActionAndWaitResponse
+ 15, // 59: olivetin.api.v1.OliveTinApiService.StartActionByGet:output_type -> olivetin.api.v1.StartActionByGetResponse
+ 17, // 60: olivetin.api.v1.OliveTinApiService.StartActionByGetAndWait:output_type -> olivetin.api.v1.StartActionByGetAndWaitResponse
+ 11, // 61: olivetin.api.v1.OliveTinApiService.RestartAction:output_type -> olivetin.api.v1.StartActionResponse
+ 48, // 62: olivetin.api.v1.OliveTinApiService.KillAction:output_type -> olivetin.api.v1.KillActionResponse
+ 28, // 63: olivetin.api.v1.OliveTinApiService.ExecutionStatus:output_type -> olivetin.api.v1.ExecutionStatusResponse
+ 20, // 64: olivetin.api.v1.OliveTinApiService.GetLogs:output_type -> olivetin.api.v1.GetLogsResponse
+ 22, // 65: olivetin.api.v1.OliveTinApiService.GetActionLogs:output_type -> olivetin.api.v1.GetActionLogsResponse
+ 24, // 66: olivetin.api.v1.OliveTinApiService.ValidateArgumentType:output_type -> olivetin.api.v1.ValidateArgumentTypeResponse
+ 30, // 67: olivetin.api.v1.OliveTinApiService.WhoAmI:output_type -> olivetin.api.v1.WhoAmIResponse
+ 32, // 68: olivetin.api.v1.OliveTinApiService.SosReport:output_type -> olivetin.api.v1.SosReportResponse
+ 34, // 69: olivetin.api.v1.OliveTinApiService.DumpVars:output_type -> olivetin.api.v1.DumpVarsResponse
+ 37, // 70: olivetin.api.v1.OliveTinApiService.DumpPublicIdActionMap:output_type -> olivetin.api.v1.DumpPublicIdActionMapResponse
+ 39, // 71: olivetin.api.v1.OliveTinApiService.GetReadyz:output_type -> olivetin.api.v1.GetReadyzResponse
+ 50, // 72: olivetin.api.v1.OliveTinApiService.LocalUserLogin:output_type -> olivetin.api.v1.LocalUserLoginResponse
+ 52, // 73: olivetin.api.v1.OliveTinApiService.PasswordHash:output_type -> olivetin.api.v1.PasswordHashResponse
+ 54, // 74: olivetin.api.v1.OliveTinApiService.Logout:output_type -> olivetin.api.v1.LogoutResponse
+ 41, // 75: olivetin.api.v1.OliveTinApiService.EventStream:output_type -> olivetin.api.v1.EventStreamResponse
+ 56, // 76: olivetin.api.v1.OliveTinApiService.GetDiagnostics:output_type -> olivetin.api.v1.GetDiagnosticsResponse
+ 58, // 77: olivetin.api.v1.OliveTinApiService.Init:output_type -> olivetin.api.v1.InitResponse
+ 62, // 78: olivetin.api.v1.OliveTinApiService.GetActionBinding:output_type -> olivetin.api.v1.GetActionBindingResponse
+ 64, // 79: olivetin.api.v1.OliveTinApiService.GetEntities:output_type -> olivetin.api.v1.GetEntitiesResponse
+ 3, // 80: olivetin.api.v1.OliveTinApiService.GetEntity:output_type -> olivetin.api.v1.Entity
+ 56, // [56:81] is the sub-list for method output_type
+ 31, // [31:56] is the sub-list for method input_type
+ 31, // [31:31] is the sub-list for extension type_name
+ 31, // [31:31] is the sub-list for extension extendee
+ 0, // [0:31] is the sub-list for field type_name
+}
+
+func init() { file_olivetin_api_v1_olivetin_proto_init() }
+func file_olivetin_api_v1_olivetin_proto_init() {
+ if File_olivetin_api_v1_olivetin_proto != nil {
+ return
+ }
+ file_olivetin_api_v1_olivetin_proto_msgTypes[41].OneofWrappers = []any{
+ (*EventStreamResponse_EntityChanged)(nil),
+ (*EventStreamResponse_ConfigChanged)(nil),
+ (*EventStreamResponse_ExecutionFinished)(nil),
+ (*EventStreamResponse_ExecutionStarted)(nil),
+ (*EventStreamResponse_OutputChunk)(nil),
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: unsafe.Slice(unsafe.StringData(file_olivetin_api_v1_olivetin_proto_rawDesc), len(file_olivetin_api_v1_olivetin_proto_rawDesc)),
+ NumEnums: 0,
+ NumMessages: 72,
+ NumExtensions: 0,
+ NumServices: 1,
+ },
+ GoTypes: file_olivetin_api_v1_olivetin_proto_goTypes,
+ DependencyIndexes: file_olivetin_api_v1_olivetin_proto_depIdxs,
+ MessageInfos: file_olivetin_api_v1_olivetin_proto_msgTypes,
+ }.Build()
+ File_olivetin_api_v1_olivetin_proto = out.File
+ file_olivetin_api_v1_olivetin_proto_goTypes = nil
+ file_olivetin_api_v1_olivetin_proto_depIdxs = nil
+}
diff --git a/service/go.mod b/service/go.mod
index 132a6ec..3805d38 100644
--- a/service/go.mod
+++ b/service/go.mod
@@ -10,14 +10,15 @@ require (
connectrpc.com/connect v1.19.1
github.com/Masterminds/semver v1.5.0
github.com/MicahParks/keyfunc/v3 v3.7.0
+ github.com/PaesslerAG/jsonpath v0.1.1
github.com/alexedwards/argon2id v1.0.0
- github.com/bufbuild/buf v1.61.0
+ github.com/bufbuild/buf v1.63.0
github.com/fsnotify/fsnotify v1.9.0
github.com/fzipp/gocyclo v0.6.0
github.com/go-critic/go-critic v0.14.2
github.com/golang-jwt/jwt/v5 v5.3.0
github.com/google/uuid v1.6.0
- github.com/jamesread/golure v0.0.0-20250919212919-976d085a100c
+ github.com/jamesread/golure v0.0.0-20260104005024-ad0d6ec8c0ac
github.com/knadh/koanf/parsers/yaml v1.1.0
github.com/knadh/koanf/providers/env v1.1.0
github.com/knadh/koanf/providers/file v1.2.1
@@ -51,13 +52,14 @@ require (
buf.build/go/spdx v0.2.0 // indirect
buf.build/go/standard v0.1.0 // indirect
cel.dev/expr v0.25.1 // indirect
- connectrpc.com/otelconnect v0.8.0 // indirect
+ connectrpc.com/otelconnect v0.9.0 // indirect
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
github.com/MicahParks/jwkset v0.11.0 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
+ github.com/PaesslerAG/gval v1.2.4 // indirect
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
github.com/beorn7/perks v1.0.1 // indirect
- github.com/bufbuild/protocompile v0.14.2-0.20251223142729-db46c1b9d34e // indirect
+ github.com/bufbuild/protocompile v0.14.2-0.20260105175043-4d8d90b1c6b8 // indirect
github.com/bufbuild/protoplugin v0.0.0-20250218205857-750e09ce93e1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/cli/browser v1.3.0 // indirect
@@ -112,7 +114,7 @@ require (
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.6.2 // indirect
- github.com/prometheus/common v0.67.4 // indirect
+ github.com/prometheus/common v0.67.5 // indirect
github.com/prometheus/procfs v0.19.2 // indirect
github.com/quasilyte/go-ruleguard v0.4.5 // indirect
github.com/quasilyte/gogrep v0.5.0 // indirect
@@ -125,6 +127,7 @@ require (
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/segmentio/asm v1.2.1 // indirect
github.com/segmentio/encoding v0.5.3 // indirect
+ github.com/shopspring/decimal v1.4.0 // indirect
github.com/spf13/cobra v1.10.2 // indirect
github.com/spf13/pflag v1.0.10 // indirect
github.com/stoewer/go-strcase v1.3.1 // indirect
diff --git a/service/go.sum b/service/go.sum
index 8af88a2..722c4a0 100644
--- a/service/go.sum
+++ b/service/go.sum
@@ -32,6 +32,8 @@ connectrpc.com/connect v1.19.1 h1:R5M57z05+90EfEvCY1b7hBxDVOUl45PrtXtAV2fOC14=
connectrpc.com/connect v1.19.1/go.mod h1:tN20fjdGlewnSFeZxLKb0xwIZ6ozc3OQs2hTXy4du9w=
connectrpc.com/otelconnect v0.8.0 h1:a4qrN4H8aEE2jAoCxheZYYfEjXMgVPyL9OzPQLBEFXU=
connectrpc.com/otelconnect v0.8.0/go.mod h1:AEkVLjCPXra+ObGFCOClcJkNjS7zPaQSqvO0lCyjfZc=
+connectrpc.com/otelconnect v0.9.0 h1:NggB3pzRC3pukQWaYbRHJulxuXvmCKCKkQ9hbrHAWoA=
+connectrpc.com/otelconnect v0.9.0/go.mod h1:AEkVLjCPXra+ObGFCOClcJkNjS7zPaQSqvO0lCyjfZc=
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
@@ -42,6 +44,13 @@ github.com/MicahParks/keyfunc/v3 v3.7.0 h1:pdafUNyq+p3ZlvjJX1HWFP7MA3+cLpDtg69U3
github.com/MicahParks/keyfunc/v3 v3.7.0/go.mod h1:z66bkCviwqfg2YUp+Jcc/xRE9IXLcMq6DrgV/+Htru0=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
+github.com/PaesslerAG/gval v1.0.0 h1:GEKnRwkWDdf9dOmKcNrar9EA1bz1z9DqPIO1+iLzhd8=
+github.com/PaesslerAG/gval v1.0.0/go.mod h1:y/nm5yEyTeX6av0OfKJNp9rBNj2XrGhAf5+v24IBN1I=
+github.com/PaesslerAG/gval v1.2.4 h1:rhX7MpjJlcxYwL2eTTYIOBUyEKZ+A96T9vQySWkVUiU=
+github.com/PaesslerAG/gval v1.2.4/go.mod h1:XRFLwvmkTEdYziLdaCeCa5ImcGVrfQbeNUbVR+C6xac=
+github.com/PaesslerAG/jsonpath v0.1.0/go.mod h1:4BzmtoM/PI8fPO4aQGIusjGxGir2BzcV0grWtFzq1Y8=
+github.com/PaesslerAG/jsonpath v0.1.1 h1:c1/AToHQMVsduPAa4Vh6xp2U0evy4t8SWp8imEsylIk=
+github.com/PaesslerAG/jsonpath v0.1.1/go.mod h1:lVboNxFGal/VwW6d9JzIy56bUsYAP6tH/x80vjnCseY=
github.com/alexedwards/argon2id v1.0.0 h1:wJzDx66hqWX7siL/SRUmgz3F8YMrd/nfX/xHHcQQP0w=
github.com/alexedwards/argon2id v1.0.0/go.mod h1:tYKkqIjzXvZdzPvADMWOEZ+l6+BD6CtBXMj5fnJppiw=
github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ=
@@ -54,8 +63,12 @@ github.com/brianvoe/gofakeit/v6 v6.28.0 h1:Xib46XXuQfmlLS2EXRuJpqcw8St6qSZz75OUo
github.com/brianvoe/gofakeit/v6 v6.28.0/go.mod h1:Xj58BMSnFqcn/fAQeSK+/PLtC5kSb7FJIq4JyGa8vEs=
github.com/bufbuild/buf v1.61.0 h1:JPaK/RM2eoheyzznW+1LxaFgN6xjBCi8s25q2kUbH9A=
github.com/bufbuild/buf v1.61.0/go.mod h1:Xs3leBmxjL5tTnSVYfNwNXHXD1k5et3fR/tJyIyQl4s=
+github.com/bufbuild/buf v1.63.0 h1:vMIRozWqYcOU992FqcGgAp8LjoWVTzr52qEolUT+xi4=
+github.com/bufbuild/buf v1.63.0/go.mod h1:IWF+TIxwmk4DeyDmguN8WhxKFKQitcX2WnP+RlJlDiY=
github.com/bufbuild/protocompile v0.14.2-0.20251223142729-db46c1b9d34e h1:LQA+1MyiPkolGHJGC2GMDC5Xu+0RDVH6jGMKech7Exs=
github.com/bufbuild/protocompile v0.14.2-0.20251223142729-db46c1b9d34e/go.mod h1:5UUj46Eu+U+C59C5N6YilaMI7WWfP2bW9xGcOkme2DI=
+github.com/bufbuild/protocompile v0.14.2-0.20260105175043-4d8d90b1c6b8 h1:cQYwUyAzyMmYr7AyJU1C6pVCpUrJJBkmx7UunZosxxs=
+github.com/bufbuild/protocompile v0.14.2-0.20260105175043-4d8d90b1c6b8/go.mod h1:5UUj46Eu+U+C59C5N6YilaMI7WWfP2bW9xGcOkme2DI=
github.com/bufbuild/protoplugin v0.0.0-20250218205857-750e09ce93e1 h1:V1xulAoqLqVg44rY97xOR+mQpD2N+GzhMHVwJ030WEU=
github.com/bufbuild/protoplugin v0.0.0-20250218205857-750e09ce93e1/go.mod h1:c5D8gWRIZ2HLWO3gXYTtUfw/hbJyD8xikv2ooPxnklQ=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
@@ -152,6 +165,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jamesread/golure v0.0.0-20250919212919-976d085a100c h1:v8gN2xXFQjkF0PsoGSqDviRNmPHcBsvl6rMSbvXz1sM=
github.com/jamesread/golure v0.0.0-20250919212919-976d085a100c/go.mod h1:BZ/CMtZJJ4LNEBDSjGfafTJMjlDPIA9FS16+reN9NUE=
+github.com/jamesread/golure v0.0.0-20260104005024-ad0d6ec8c0ac h1:JQ6AC9tf2xhwTxMY9nuIeOPM7Cj0BDeCNgKPrNgQvtQ=
+github.com/jamesread/golure v0.0.0-20260104005024-ad0d6ec8c0ac/go.mod h1:BZ/CMtZJJ4LNEBDSjGfafTJMjlDPIA9FS16+reN9NUE=
github.com/jdx/go-netrc v1.0.0 h1:QbLMLyCZGj0NA8glAhxUpf1zDg6cxnWgMBbjq40W0gQ=
github.com/jdx/go-netrc v1.0.0/go.mod h1:Gh9eFQJnoTNIRHXl2j5bJXA1u84hQWJWgGh569zF3v8=
github.com/jhump/protoreflect/v2 v2.0.0-beta.2 h1:qZU+rEZUOYTz1Bnhi3xbwn+VxdXkLVeEpAeZzVXLY88=
@@ -216,6 +231,8 @@ github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNw
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
github.com/prometheus/common v0.67.4 h1:yR3NqWO1/UyO1w2PhUvXlGQs/PtFmoveVO0KZ4+Lvsc=
github.com/prometheus/common v0.67.4/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI=
+github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4=
+github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw=
github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws=
github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw=
github.com/protocolbuffers/protoscope v0.0.0-20221109213918-8e7a6aafa2c9 h1:arwj11zP0yJIxIRiDn22E0H8PxfF7TsTrc2wIPFIsf4=
@@ -242,12 +259,17 @@ github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0t
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA=
github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
+github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww=
+github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/segmentio/asm v1.2.1 h1:DTNbBqs57ioxAD4PrArqftgypG4/qNpXoJx8TVXxPR0=
github.com/segmentio/asm v1.2.1/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
github.com/segmentio/encoding v0.5.3 h1:OjMgICtcSFuNvQCdwqMCv9Tg7lEOXGwm1J5RPQccx6w=
github.com/segmentio/encoding v0.5.3/go.mod h1:HS1ZKa3kSN32ZHVZ7ZLPLXWvOVIiZtyJnO1gPH1sKt0=
+github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
+github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
+github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
@@ -293,6 +315,7 @@ go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 h1:f0cb2XPmrqn4XMy9PNliTgRKJgS5WcL/u0/WRYGz4t0=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.33.0 h1:wpMfgF8E1rkrT1Z6meFh1NDtownE9Ii3n3X2GJYjsaU=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.33.0/go.mod h1:wAy0T/dUbs468uOlkT31xjvqQgEVXv58BRFWEgn5v/0=
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
@@ -305,6 +328,7 @@ go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
go.opentelemetry.io/proto/otlp v1.8.0 h1:fRAZQDcAFHySxpJ1TwlA1cJ4tvcrw7nXl9xWWC8N5CE=
go.opentelemetry.io/proto/otlp v1.8.0/go.mod h1:tIeYOeNBU4cvmPqpaji1P+KbB4Oloai8wN4rWzRrFF0=
+go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
diff --git a/service/internal/api/api.go b/service/internal/api/api.go
index d1bf652..c7ee481 100644
--- a/service/internal/api/api.go
+++ b/service/internal/api/api.go
@@ -3,6 +3,8 @@ package api
import (
ctx "context"
"encoding/json"
+ "os"
+ "path"
"sort"
"connectrpc.com/connect"
@@ -16,6 +18,7 @@ import (
"fmt"
"net/http"
"sync"
+ "time"
acl "github.com/OliveTin/OliveTin/internal/acl"
auth "github.com/OliveTin/OliveTin/internal/auth"
@@ -275,23 +278,37 @@ func (api *oliveTinAPI) StartActionByGetAndWait(ctx ctx.Context, req *connect.Re
}
}
+func calculateRateLimitExpires(api *oliveTinAPI, logEntry *executor.InternalLogEntry) string {
+ if logEntry.Binding == nil || logEntry.Binding.Action == nil {
+ return ""
+ }
+
+ expiryUnix := api.executor.GetTimeUntilAvailable(logEntry.Binding)
+ if expiryUnix <= 0 {
+ return ""
+ }
+
+ return time.Unix(expiryUnix, 0).Format("2006-01-02 15:04:05")
+}
+
func (api *oliveTinAPI) internalLogEntryToPb(logEntry *executor.InternalLogEntry, authenticatedUser *authpublic.AuthenticatedUser) *apiv1.LogEntry {
pble := &apiv1.LogEntry{
- ActionTitle: logEntry.ActionTitle,
- ActionIcon: logEntry.ActionIcon,
- ActionId: logEntry.ActionId,
- DatetimeStarted: logEntry.DatetimeStarted.Format("2006-01-02 15:04:05"),
- DatetimeFinished: logEntry.DatetimeFinished.Format("2006-01-02 15:04:05"),
- DatetimeIndex: logEntry.Index,
- Output: logEntry.Output,
- TimedOut: logEntry.TimedOut,
- Blocked: logEntry.Blocked,
- ExitCode: logEntry.ExitCode,
- Tags: logEntry.Tags,
- ExecutionTrackingId: logEntry.ExecutionTrackingID,
- ExecutionStarted: logEntry.ExecutionStarted,
- ExecutionFinished: logEntry.ExecutionFinished,
- User: logEntry.Username,
+ ActionTitle: logEntry.ActionTitle,
+ ActionIcon: logEntry.ActionIcon,
+ DatetimeStarted: logEntry.DatetimeStarted.Format("2006-01-02 15:04:05"),
+ DatetimeFinished: logEntry.DatetimeFinished.Format("2006-01-02 15:04:05"),
+ DatetimeIndex: logEntry.Index,
+ Output: logEntry.Output,
+ TimedOut: logEntry.TimedOut,
+ Blocked: logEntry.Blocked,
+ ExitCode: logEntry.ExitCode,
+ Tags: logEntry.Tags,
+ ExecutionTrackingId: logEntry.ExecutionTrackingID,
+ ExecutionStarted: logEntry.ExecutionStarted,
+ ExecutionFinished: logEntry.ExecutionFinished,
+ User: logEntry.Username,
+ BindingId: logEntry.Binding.ID,
+ DatetimeRateLimitExpires: calculateRateLimitExpires(api, logEntry),
}
if !pble.ExecutionFinished {
@@ -311,10 +328,20 @@ func getExecutionStatusByTrackingID(api *oliveTinAPI, executionTrackingId string
return logEntry
}
-func getMostRecentExecutionStatusById(api *oliveTinAPI, actionId string) *executor.InternalLogEntry {
+// This is the actual action ID, not the binding ID.
+func getMostRecentExecutionStatusByActionId(api *oliveTinAPI, actionId string) *executor.InternalLogEntry {
var ile *executor.InternalLogEntry
- logs := api.executor.GetLogsByActionId(actionId)
+ binding := api.executor.FindBindingByID(actionId)
+ if binding == nil {
+ return nil
+ }
+
+ logs := api.executor.GetLogsByBindingId(binding.ID)
+
+ if len(logs) == 0 {
+ return nil
+ }
if len(logs) == 0 {
return nil
@@ -341,7 +368,7 @@ func (api *oliveTinAPI) ExecutionStatus(ctx ctx.Context, req *connect.Request[ap
ile = getExecutionStatusByTrackingID(api, req.Msg.ExecutionTrackingId)
} else {
- ile = getMostRecentExecutionStatusById(api, req.Msg.ActionId)
+ ile = getMostRecentExecutionStatusByActionId(api, req.Msg.ActionId)
}
if ile == nil {
@@ -474,7 +501,11 @@ func (api *oliveTinAPI) GetLogs(ctx ctx.Context, req *connect.Request[apiv1.GetL
}
ret := &apiv1.GetLogsResponse{}
- logEntries, paging := api.executor.GetLogTrackingIdsACL(api.cfg, user, req.Msg.StartOffset, api.cfg.LogHistoryPageSize)
+ dateFilter := ""
+ if req.Msg.DateFilter != "" {
+ dateFilter = req.Msg.DateFilter
+ }
+ logEntries, paging := api.executor.GetLogTrackingIdsACL(api.cfg, user, req.Msg.StartOffset, api.cfg.LogHistoryPageSize, dateFilter)
for _, le := range logEntries {
ret.Logs = append(ret.Logs, api.internalLogEntryToPb(le, user))
}
@@ -539,7 +570,7 @@ func (api *oliveTinAPI) GetActionLogs(ctx ctx.Context, req *connect.Request[apiv
return nil, err
}
- filtered := api.filterLogsByACL(api.executor.GetLogsByActionId(req.Msg.ActionId), user)
+ filtered := api.filterLogsByACL(api.executor.GetLogsByBindingId(req.Msg.ActionId), user)
page := paginate(int64(len(filtered)), api.cfg.LogHistoryPageSize, req.Msg.StartOffset)
if page.empty {
return connect.NewResponse(buildEmptyPageResponse(page)), nil
@@ -688,7 +719,7 @@ func (api *oliveTinAPI) DumpVars(ctx ctx.Context, req *connect.Request[apiv1.Dum
func (api *oliveTinAPI) DumpPublicIdActionMap(ctx ctx.Context, req *connect.Request[apiv1.DumpPublicIdActionMapRequest]) (*connect.Response[apiv1.DumpPublicIdActionMapResponse], error) {
res := &apiv1.DumpPublicIdActionMapResponse{}
- res.Contents = make(map[string]*apiv1.ActionEntityPair)
+ res.Contents = make(map[string]*apiv1.DebugBinding)
if !api.cfg.InsecureAllowDumpActionMap {
res.Alert = "Dumping Public IDs is disallowed."
@@ -696,16 +727,15 @@ func (api *oliveTinAPI) DumpPublicIdActionMap(ctx ctx.Context, req *connect.Requ
return connect.NewResponse(res), nil
}
- api.executor.MapActionIdToBindingLock.RLock()
+ api.executor.MapActionBindingsLock.RLock()
- for k, v := range api.executor.MapActionIdToBinding {
- res.Contents[k] = &apiv1.ActionEntityPair{
- ActionTitle: v.Action.Title,
- EntityPrefix: "?",
+ for k, v := range api.executor.MapActionBindings {
+ res.Contents[k] = &apiv1.DebugBinding{
+ ActionTitle: v.Action.Title,
}
}
- api.executor.MapActionIdToBindingLock.RUnlock()
+ api.executor.MapActionBindingsLock.RUnlock()
res.Alert = "Dumping variables has been enabled in the configuration. Please set InsecureAllowDumpActionMap = false again after you don't need it anymore"
@@ -723,6 +753,10 @@ func (api *oliveTinAPI) GetReadyz(ctx ctx.Context, req *connect.Request[apiv1.Ge
func (api *oliveTinAPI) EventStream(ctx ctx.Context, req *connect.Request[apiv1.EventStreamRequest], srv *connect.ServerStream[apiv1.EventStreamResponse]) error {
log.Debugf("EventStream: %v", req.Msg)
+ // Set X-Accel-Buffering header to disable nginx buffering for this stream
+ // https://github.com/OliveTin/OliveTin/issues/765
+ srv.ResponseHeader().Set("X-Accel-Buffering", "no")
+
user := auth.UserFromApiCall(ctx, req, api.cfg)
if err := api.checkDashboardAccess(user); err != nil {
@@ -809,7 +843,7 @@ func (api *oliveTinAPI) OnExecutionStarted(ex *executor.InternalLogEntry) {
}
}
-func (api *oliveTinAPI) OnExecutionFinished(ex *executor.InternalLogEntry) {
+func (api *oliveTinAPI) OnExecutionFinished(ile *executor.InternalLogEntry) {
toRemove := []*streamingClient{}
for _, client := range api.copyOfStreamingClients() {
@@ -817,7 +851,7 @@ func (api *oliveTinAPI) OnExecutionFinished(ex *executor.InternalLogEntry) {
case client.channel <- &apiv1.EventStreamResponse{
Event: &apiv1.EventStreamResponse_ExecutionFinished{
ExecutionFinished: &apiv1.EventExecutionFinished{
- LogEntry: api.internalLogEntryToPb(ex, client.AuthenticatedUser),
+ LogEntry: api.internalLogEntryToPb(ile, client.AuthenticatedUser),
},
},
}:
@@ -870,11 +904,62 @@ func (api *oliveTinAPI) Init(ctx ctx.Context, req *connect.Request[apiv1.InitReq
ShowDiagnostics: user.EffectivePolicy.ShowDiagnostics,
ShowLogList: user.EffectivePolicy.ShowLogList,
LoginRequired: loginRequired,
+ AvailableThemes: discoverAvailableThemes(api.cfg),
}
return connect.NewResponse(res), nil
}
+// discoverAvailableThemes finds all available themes in the custom-webui/themes directory.
+// A theme is considered available if it has a theme.css file.
+func discoverAvailableThemes(cfg *config.Config) []string {
+ configDir := cfg.GetDir()
+ if configDir == "" {
+ return []string{}
+ }
+
+ themesDir := path.Join(configDir, "custom-webui", "themes")
+ entries, err := os.ReadDir(themesDir)
+ if err != nil {
+ log.WithFields(log.Fields{
+ "themesDir": themesDir,
+ "error": err,
+ }).Tracef("Could not read themes directory")
+ return []string{}
+ }
+
+ themes := collectValidThemes(themesDir, entries)
+ sort.Strings(themes)
+ return themes
+}
+
+// collectValidThemes collects theme names from directory entries that have a theme.css file.
+func collectValidThemes(themesDir string, entries []os.DirEntry) []string {
+ var themes []string
+ for _, entry := range entries {
+ if themeName := getValidThemeName(themesDir, entry); themeName != "" {
+ themes = append(themes, themeName)
+ }
+ }
+ return themes
+}
+
+// getValidThemeName returns the theme name if the entry is a valid theme directory with theme.css, otherwise returns empty string.
+func getValidThemeName(themesDir string, entry os.DirEntry) string {
+ if !entry.IsDir() {
+ return ""
+ }
+
+ themeName := entry.Name()
+ themeCssPath := path.Join(themesDir, themeName, "theme.css")
+
+ if _, err := os.Stat(themeCssPath); err != nil {
+ return ""
+ }
+
+ return themeName
+}
+
func (api *oliveTinAPI) buildRootDashboards(user *authpublic.AuthenticatedUser, dashboards []*config.DashboardComponent) []string {
var rootDashboards []string
dashboardRenderRequest := api.createDashboardRenderRequest(user, "", "")
diff --git a/service/internal/api/apiActions.go b/service/internal/api/apiActions.go
index 6046691..55728b9 100644
--- a/service/internal/api/apiActions.go
+++ b/service/internal/api/apiActions.go
@@ -1,6 +1,12 @@
package api
import (
+ "strconv"
+ "strings"
+ "time"
+
+ log "github.com/sirupsen/logrus"
+
apiv1 "github.com/OliveTin/OliveTin/gen/olivetin/api/v1"
acl "github.com/OliveTin/OliveTin/internal/acl"
authpublic "github.com/OliveTin/OliveTin/internal/auth/authpublic"
@@ -22,10 +28,10 @@ func (rr *DashboardRenderRequest) findAction(title string) *apiv1.Action {
}
func (rr *DashboardRenderRequest) findActionForEntity(title string, entity *entities.Entity) *apiv1.Action {
- rr.ex.MapActionIdToBindingLock.RLock()
- defer rr.ex.MapActionIdToBindingLock.RUnlock()
+ rr.ex.MapActionBindingsLock.RLock()
+ defer rr.ex.MapActionBindingsLock.RUnlock()
- for _, binding := range rr.ex.MapActionIdToBinding {
+ for _, binding := range rr.ex.MapActionBindings {
if binding.Action.Title != title {
continue
}
@@ -55,28 +61,84 @@ func buildEffectivePolicy(policy *config.ConfigurationPolicy) *apiv1.EffectivePo
return ret
}
+func evaluateEnabledExpression(action *config.Action, entity *entities.Entity) bool {
+ if action.EnabledExpression == "" {
+ return true
+ }
+
+ result := entities.ParseTemplateWith(action.EnabledExpression, entity)
+ result = strings.TrimSpace(result)
+
+ if result == "" {
+ return false
+ }
+
+ if isTemplateError(result, action) {
+ return false
+ }
+
+ return evaluateResultValue(result)
+}
+
+func isTemplateError(result string, action *config.Action) bool {
+ if !strings.HasPrefix(result, "tpl ") || !strings.Contains(result, "error") {
+ return false
+ }
+
+ log.WithFields(log.Fields{
+ "actionTitle": action.Title,
+ "enabledExpression": action.EnabledExpression,
+ "result": result,
+ }).Warn("enabledExpression template evaluation failed, treating as disabled")
+ return true
+}
+
+func evaluateResultValue(result string) bool {
+ if strings.EqualFold(result, "true") {
+ return true
+ }
+
+ if num, err := strconv.Atoi(result); err == nil {
+ return num != 0
+ }
+
+ return false
+}
+
func buildAction(actionBinding *executor.ActionBinding, rr *DashboardRenderRequest) *apiv1.Action {
action := actionBinding.Action
+ aclCanExec := acl.IsAllowedExec(rr.cfg, rr.AuthenticatedUser, action)
+ enabledExprCanExec := evaluateEnabledExpression(action, actionBinding.Entity)
+
+ // Calculate rate limit expiry time
+ expiryUnix := rr.ex.GetTimeUntilAvailable(actionBinding)
+ datetimeRateLimitExpires := ""
+ if expiryUnix > 0 {
+ datetimeRateLimitExpires = time.Unix(expiryUnix, 0).Format("2006-01-02 15:04:05")
+ }
+
btn := apiv1.Action{
- BindingId: actionBinding.ID,
- Title: entities.ParseTemplateWith(action.Title, actionBinding.Entity),
- Icon: entities.ParseTemplateWith(action.Icon, actionBinding.Entity),
- CanExec: acl.IsAllowedExec(rr.cfg, rr.AuthenticatedUser, action),
- PopupOnStart: action.PopupOnStart,
- Order: int32(actionBinding.ConfigOrder),
- Timeout: int32(action.Timeout),
+ BindingId: actionBinding.ID,
+ Title: entities.ParseTemplateWith(action.Title, actionBinding.Entity),
+ Icon: entities.ParseTemplateWith(action.Icon, actionBinding.Entity),
+ CanExec: aclCanExec && enabledExprCanExec,
+ PopupOnStart: action.PopupOnStart,
+ Order: int32(actionBinding.ConfigOrder),
+ Timeout: int32(action.Timeout),
+ DatetimeRateLimitExpires: datetimeRateLimitExpires,
}
for _, cfgArg := range action.Arguments {
pbArg := apiv1.ActionArgument{
- Name: cfgArg.Name,
- Title: cfgArg.Title,
- Type: cfgArg.Type,
- Description: cfgArg.Description,
- DefaultValue: cfgArg.Default,
- Choices: buildChoices(cfgArg),
- Suggestions: cfgArg.Suggestions,
+ Name: cfgArg.Name,
+ Title: cfgArg.Title,
+ Type: cfgArg.Type,
+ Description: cfgArg.Description,
+ DefaultValue: cfgArg.Default,
+ Choices: buildChoices(cfgArg),
+ Suggestions: cfgArg.Suggestions,
+ SuggestionsBrowserKey: cfgArg.SuggestionsBrowserKey,
}
btn.Arguments = append(btn.Arguments, &pbArg)
diff --git a/service/internal/api/api_test.go b/service/internal/api/api_test.go
index 68341ae..c2977f7 100644
--- a/service/internal/api/api_test.go
+++ b/service/internal/api/api_test.go
@@ -11,6 +11,7 @@ import (
apiv1 "github.com/OliveTin/OliveTin/gen/olivetin/api/v1"
apiv1connect "github.com/OliveTin/OliveTin/gen/olivetin/api/v1/apiv1connect"
+ authpublic "github.com/OliveTin/OliveTin/internal/auth/authpublic"
config "github.com/OliveTin/OliveTin/internal/config"
"github.com/OliveTin/OliveTin/internal/entities"
"github.com/OliveTin/OliveTin/internal/executor"
@@ -20,7 +21,7 @@ import (
"path"
)
-func getNewTestServerAndClient(t *testing.T, injectedConfig *config.Config) (*httptest.Server, apiv1connect.OliveTinApiServiceClient) {
+func getNewTestServerAndClient(injectedConfig *config.Config) (*httptest.Server, apiv1connect.OliveTinApiServiceClient) {
ex := executor.DefaultExecutor(injectedConfig)
ex.RebuildActionMap()
@@ -62,7 +63,7 @@ func TestGetActionsAndStart(t *testing.T) {
ex := executor.DefaultExecutor(cfg)
ex.RebuildActionMap()
- conn, client := getNewTestServerAndClient(t, cfg)
+ conn, client := getNewTestServerAndClient(cfg)
respInit, errInit := client.Init(context.Background(), connect.NewRequest(&apiv1.InitRequest{}))
respGetReady, errReady := client.GetReadyz(context.Background(), connect.NewRequest(&apiv1.GetReadyzRequest{}))
@@ -98,7 +99,7 @@ func TestGetActionsAndStart(t *testing.T) {
func TestGetEntities(t *testing.T) {
cfg := config.DefaultConfig()
- ts, client := getNewTestServerAndClient(t, cfg)
+ ts, client := getNewTestServerAndClient(cfg)
defer ts.Close()
setupTestEntities()
@@ -173,3 +174,164 @@ func validateConsistency(t *testing.T, client apiv1connect.OliveTinApiServiceCli
}
}
}
+
+func TestEvaluateEnabledExpression(t *testing.T) {
+ tests := []struct {
+ name string
+ expression string
+ entity *entities.Entity
+ expectedResult bool
+ }{
+ {
+ name: "empty expression returns true",
+ expression: "",
+ entity: nil,
+ expectedResult: true,
+ },
+ {
+ name: "literal true returns true",
+ expression: "true",
+ entity: nil,
+ expectedResult: true,
+ },
+ {
+ name: "literal True returns true (case insensitive)",
+ expression: "True",
+ entity: nil,
+ expectedResult: true,
+ },
+ {
+ name: "literal 1 returns true",
+ expression: "1",
+ entity: nil,
+ expectedResult: true,
+ },
+ {
+ name: "literal false returns false",
+ expression: "false",
+ entity: nil,
+ expectedResult: false,
+ },
+ {
+ name: "literal 0 returns false",
+ expression: "0",
+ entity: nil,
+ expectedResult: false,
+ },
+ {
+ name: "empty result returns false",
+ expression: "{{ .NonExistent }}",
+ entity: nil,
+ expectedResult: false,
+ },
+ {
+ name: "expression with CurrentEntity true",
+ expression: "{{ eq .CurrentEntity.powered_on true }}",
+ entity: &entities.Entity{Data: map[string]any{"powered_on": true}},
+ expectedResult: true,
+ },
+ {
+ name: "expression with CurrentEntity false",
+ expression: "{{ eq .CurrentEntity.powered_on true }}",
+ entity: &entities.Entity{Data: map[string]any{"powered_on": false}},
+ expectedResult: false,
+ },
+ {
+ name: "expression with CurrentEntity integer 1",
+ expression: "{{ .CurrentEntity.status }}",
+ entity: &entities.Entity{Data: map[string]any{"status": 1}},
+ expectedResult: true,
+ },
+ {
+ name: "expression with CurrentEntity integer 0",
+ expression: "{{ .CurrentEntity.status }}",
+ entity: &entities.Entity{Data: map[string]any{"status": 0}},
+ expectedResult: false,
+ },
+ {
+ name: "template parse error returns false",
+ expression: "{{ invalid syntax }}",
+ entity: nil,
+ expectedResult: false,
+ },
+ {
+ name: "template exec error returns false",
+ expression: "{{ .CurrentEntity.nonexistent }}",
+ entity: nil,
+ expectedResult: false,
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ action := &config.Action{
+ EnabledExpression: tt.expression,
+ }
+ result := evaluateEnabledExpression(action, tt.entity)
+ assert.Equal(t, tt.expectedResult, result, "evaluateEnabledExpression should return expected result")
+ })
+ }
+}
+
+func TestBuildActionWithEnabledExpression(t *testing.T) {
+ cfg := config.DefaultConfig()
+ cfg.DefaultPermissions.Exec = true
+
+ action := &config.Action{
+ Title: "Test Action",
+ Shell: "echo test",
+ EnabledExpression: "{{ eq .CurrentEntity.enabled true }}",
+ }
+ cfg.Actions = append(cfg.Actions, action)
+
+ ex := executor.DefaultExecutor(cfg)
+ ex.RebuildActionMap()
+
+ binding := findBindingByTitle(ex, "Test Action")
+ assert.NotNil(t, binding, "Binding should be found")
+
+ rr := &DashboardRenderRequest{
+ AuthenticatedUser: &authpublic.AuthenticatedUser{Username: "testuser"},
+ cfg: cfg,
+ ex: ex,
+ }
+
+ testWithEntity(t, binding, rr, true, true, "Action should be executable when entity.enabled is true")
+ testWithEntity(t, binding, rr, false, false, "Action should not be executable when entity.enabled is false")
+
+ bindingNoExpr := findBindingByTitle(ex, "Test Action No Expression")
+ if bindingNoExpr == nil {
+ actionNoExpression := &config.Action{
+ Title: "Test Action No Expression",
+ Shell: "echo test",
+ }
+ cfg.Actions = append(cfg.Actions, actionNoExpression)
+ ex.RebuildActionMap()
+ bindingNoExpr = findBindingByTitle(ex, "Test Action No Expression")
+ }
+
+ actionResult := buildAction(bindingNoExpr, rr)
+ assert.True(t, actionResult.CanExec, "Action without enabledExpression should be executable")
+}
+
+func findBindingByTitle(ex *executor.Executor, title string) *executor.ActionBinding {
+ ex.MapActionBindingsLock.RLock()
+ defer ex.MapActionBindingsLock.RUnlock()
+
+ for _, b := range ex.MapActionBindings {
+ if b.Action.Title == title {
+ return b
+ }
+ }
+ return nil
+}
+
+func testWithEntity(t *testing.T, binding *executor.ActionBinding, rr *DashboardRenderRequest, enabled bool, expectedCanExec bool, message string) {
+ binding.Entity = &entities.Entity{
+ UniqueKey: "test-entity",
+ Data: map[string]any{"enabled": enabled},
+ }
+
+ actionResult := buildAction(binding, rr)
+ assert.Equal(t, expectedCanExec, actionResult.CanExec, message)
+}
diff --git a/service/internal/api/dashboards.go b/service/internal/api/dashboards.go
index eebf055..12ae2d5 100644
--- a/service/internal/api/dashboards.go
+++ b/service/internal/api/dashboards.go
@@ -128,7 +128,7 @@ func buildDefaultDashboard(rr *DashboardRenderRequest) *apiv1.Dashboard {
Contents: make([]*apiv1.DashboardComponent, 0),
}
- for _, binding := range rr.ex.MapActionIdToBinding {
+ for _, binding := range rr.ex.MapActionBindings {
if binding.Action.Hidden {
continue
}
diff --git a/service/internal/config/config.go b/service/internal/config/config.go
index 722e492..d22e86f 100644
--- a/service/internal/config/config.go
+++ b/service/internal/config/config.go
@@ -22,25 +22,28 @@ type Action struct {
ExecOnFileCreatedInDir []string `koanf:"execOnFileCreatedInDir"`
ExecOnFileChangedInDir []string `koanf:"execOnFileChangedInDir"`
ExecOnCalendarFile string `koanf:"execOnCalendarFile"`
+ ExecOnWebhook []WebhookConfig `koanf:"execOnWebhook"`
Triggers []string `koanf:"triggers"`
MaxConcurrent int `koanf:"maxConcurrent"`
MaxRate []RateSpec `koanf:"maxRate"`
Arguments []ActionArgument `koanf:"arguments"`
PopupOnStart string `koanf:"popupOnStart"`
SaveLogs SaveLogsConfig `koanf:"saveLogs"`
+ EnabledExpression string `koanf:"enabledExpression"`
}
// ActionArgument objects appear on Actions.
type ActionArgument struct {
- Name string `koanf:"name"`
- Title string `koanf:"title"`
- Description string `koanf:"description"`
- Type string `koanf:"type"`
- Default string `koanf:"default"`
- Choices []ActionArgumentChoice `koanf:"choices"`
- Entity string `koanf:"entity"`
- RejectNull bool `koanf:"rejectNull"`
- Suggestions map[string]string `koanf:"suggestions"`
+ Name string `koanf:"name"`
+ Title string `koanf:"title"`
+ Description string `koanf:"description"`
+ Type string `koanf:"type"`
+ Default string `koanf:"default"`
+ Choices []ActionArgumentChoice `koanf:"choices"`
+ Entity string `koanf:"entity"`
+ RejectNull bool `koanf:"rejectNull"`
+ Suggestions map[string]string `koanf:"suggestions"`
+ SuggestionsBrowserKey string `koanf:"suggestionsBrowserKey"`
}
// ActionArgumentChoice represents a predefined choice for an argument.
@@ -55,6 +58,18 @@ type RateSpec struct {
Duration string `koanf:"duration"`
}
+// WebhookConfig defines configuration for generic webhook triggers.
+type WebhookConfig struct {
+ Secret string `koanf:"secret"` // Optional: secret for signature verification
+ AuthType string `koanf:"authType"` // Optional: "hmac-sha256", "hmac-sha1", "bearer", "basic", "none"
+ AuthHeader string `koanf:"authHeader"` // Optional: custom header name for auth (default: "X-Webhook-Signature")
+ MatchHeaders map[string]string `koanf:"matchHeaders"` // Match HTTP headers
+ MatchPath string `koanf:"matchPath"` // JSONPath expression to match in request body (format: "jsonpath=value" or just "jsonpath")
+ MatchQuery map[string]string `koanf:"matchQuery"` // Match URL query parameters
+ Extract map[string]string `koanf:"extract"` // Map action argument names to JSONPath expressions
+ Template string `koanf:"template"` // Optional: template name (e.g., "github-push", "github-pr")
+}
+
// Entity represents a "thing" that can have multiple actions associated with it.
// for example, a media player with a start and stop action.
type EntityFile struct {
diff --git a/service/internal/config/config_helpers.go b/service/internal/config/config_helpers.go
index 611dbe7..43443dd 100644
--- a/service/internal/config/config_helpers.go
+++ b/service/internal/config/config_helpers.go
@@ -58,5 +58,8 @@ func (cfg *Config) SetDir(dir string) {
}
func (cfg *Config) GetDir() string {
+ if len(cfg.sourceFiles) == 0 {
+ return ""
+ }
return cfg.sourceFiles[len(cfg.sourceFiles)-1]
}
diff --git a/service/internal/executor/executor.go b/service/internal/executor/executor.go
index a42e8c7..dbd4f69 100644
--- a/service/internal/executor/executor.go
+++ b/service/internal/executor/executor.go
@@ -49,12 +49,12 @@ type ActionBinding struct {
type Executor struct {
logs map[string]*InternalLogEntry
logsTrackingIdsByDate []string
- LogsByActionId map[string][]*InternalLogEntry
+ LogsByBindingId map[string][]*InternalLogEntry
logmutex sync.RWMutex
- MapActionIdToBinding map[string]*ActionBinding
- MapActionIdToBindingLock sync.RWMutex
+ MapActionBindings map[string]*ActionBinding
+ MapActionBindingsLock sync.RWMutex
Cfg *config.Config
@@ -86,7 +86,6 @@ type ExecutionRequest struct {
// easily serializable.
type InternalLogEntry struct {
Binding *ActionBinding
- BindingID string
DatetimeStarted time.Time
DatetimeFinished time.Time
Output string
@@ -110,7 +109,6 @@ type InternalLogEntry struct {
*/
ActionTitle string
ActionIcon string
- ActionId string
}
type executorStepFunc func(*ExecutionRequest) bool
@@ -122,8 +120,8 @@ func DefaultExecutor(cfg *config.Config) *Executor {
e.Cfg = cfg
e.logs = make(map[string]*InternalLogEntry)
e.logsTrackingIdsByDate = make([]string, 0)
- e.LogsByActionId = make(map[string][]*InternalLogEntry)
- e.MapActionIdToBinding = make(map[string]*ActionBinding)
+ e.LogsByBindingId = make(map[string][]*InternalLogEntry)
+ e.MapActionBindings = make(map[string]*ActionBinding)
e.chainOfCommand = []executorStepFunc{
stepRequestAction,
@@ -226,29 +224,25 @@ func (e *Executor) GetLogTrackingIds(startOffset int64, pageCount int64) ([]*Int
return trackingIds, pagingResult
}
-// isValidLogEntryForACL checks if a log entry has all required fields for ACL checking.
func isValidLogEntryForACL(entry *InternalLogEntry) bool {
return entry != nil && entry.Binding != nil && entry.Binding.Action != nil
}
-// isLogEntryAllowedByACL checks if a log entry is allowed to be viewed by the user.
func isLogEntryAllowedByACL(cfg *config.Config, user *authpublic.AuthenticatedUser, entry *InternalLogEntry) bool {
return acl.IsAllowedLogs(cfg, user, entry.Binding.Action)
}
-func (e *Executor) filterLogsByACL(cfg *config.Config, user *authpublic.AuthenticatedUser) []*InternalLogEntry {
+func (e *Executor) filterLogsByACL(cfg *config.Config, user *authpublic.AuthenticatedUser, dateFilter string) []*InternalLogEntry {
e.logmutex.RLock()
defer e.logmutex.RUnlock()
filtered := make([]*InternalLogEntry, 0, len(e.logsTrackingIdsByDate))
+ filterDate, hasDateFilter := parseDateFilter(dateFilter)
for _, trackingId := range e.logsTrackingIdsByDate {
entry := e.logs[trackingId]
- if !isValidLogEntryForACL(entry) {
- continue
- }
- if isLogEntryAllowedByACL(cfg, user, entry) {
+ if shouldIncludeLogEntry(cfg, user, entry, filterDate, hasDateFilter) {
filtered = append(filtered, entry)
}
}
@@ -256,6 +250,48 @@ func (e *Executor) filterLogsByACL(cfg *config.Config, user *authpublic.Authenti
return filtered
}
+// parseDateFilter parses the date filter string and returns filter information.
+func parseDateFilter(dateFilter string) (filterDate time.Time, hasDateFilter bool) {
+ if dateFilter == "" {
+ return time.Time{}, false
+ }
+
+ parsedDate, err := time.Parse("2006-01-02", dateFilter)
+ if err != nil {
+ log.WithFields(log.Fields{
+ "dateFilter": dateFilter,
+ "error": err,
+ }).Errorf("Failed to parse date filter, expected format YYYY-MM-DD")
+ return time.Time{}, false
+ }
+
+ return parsedDate, true
+}
+
+// shouldIncludeLogEntry determines if a log entry should be included based on ACL and date filter.
+func shouldIncludeLogEntry(cfg *config.Config, user *authpublic.AuthenticatedUser, entry *InternalLogEntry, filterDate time.Time, hasDateFilter bool) bool {
+ if !isValidLogEntryForACL(entry) {
+ return false
+ }
+
+ if !isLogEntryAllowedByACL(cfg, user, entry) {
+ return false
+ }
+
+ return matchesDateFilter(entry, filterDate, hasDateFilter)
+}
+
+// matchesDateFilter checks if the log entry matches the date filter.
+func matchesDateFilter(entry *InternalLogEntry, filterDate time.Time, hasDateFilter bool) bool {
+ if !hasDateFilter {
+ return true
+ }
+
+ entryDate := entry.DatetimeStarted.UTC().Truncate(24 * time.Hour)
+ filterDateUTC := filterDate.UTC().Truncate(24 * time.Hour)
+ return entryDate.Equal(filterDateUTC)
+}
+
// paginateFilteredLogs applies pagination to a filtered list of logs and returns
// the paginated results along with pagination metadata.
func paginateFilteredLogs(filtered []*InternalLogEntry, startOffset int64, pageCount int64) ([]*InternalLogEntry, *PagingResult) {
@@ -282,8 +318,9 @@ func paginateFilteredLogs(filtered []*InternalLogEntry, startOffset int64, pageC
// GetLogTrackingIdsACL returns logs filtered by ACL visibility for the user and
// paginated correctly based on the filtered set.
-func (e *Executor) GetLogTrackingIdsACL(cfg *config.Config, user *authpublic.AuthenticatedUser, startOffset int64, pageCount int64) ([]*InternalLogEntry, *PagingResult) {
- filtered := e.filterLogsByACL(cfg, user)
+// dateFilter is optional and should be in YYYY-MM-DD format. If empty, no date filtering is applied.
+func (e *Executor) GetLogTrackingIdsACL(cfg *config.Config, user *authpublic.AuthenticatedUser, startOffset int64, pageCount int64, dateFilter string) ([]*InternalLogEntry, *PagingResult) {
+ filtered := e.filterLogsByACL(cfg, user, dateFilter)
return paginateFilteredLogs(filtered, startOffset, pageCount)
}
@@ -297,10 +334,10 @@ func (e *Executor) GetLog(trackingID string) (*InternalLogEntry, bool) {
return entry, found
}
-func (e *Executor) GetLogsByActionId(actionId string) []*InternalLogEntry {
+func (e *Executor) GetLogsByBindingId(bindingId string) []*InternalLogEntry {
e.logmutex.RLock()
- logs, found := e.LogsByActionId[actionId]
+ logs, found := e.LogsByBindingId[bindingId]
e.logmutex.RUnlock()
@@ -311,6 +348,122 @@ func (e *Executor) GetLogsByActionId(actionId string) []*InternalLogEntry {
return logs
}
+// shouldCountExecution checks if a log entry should be counted for rate limiting.
+func shouldCountExecution(logEntry *InternalLogEntry, windowStart time.Time) bool {
+ return !logEntry.Blocked && logEntry.DatetimeStarted.After(windowStart)
+}
+
+// updateOldestExecution updates the oldest execution time if this entry is older.
+func updateOldestExecution(oldestExecutionTime **time.Time, logEntry *InternalLogEntry) {
+ if *oldestExecutionTime == nil {
+ *oldestExecutionTime = &logEntry.DatetimeStarted
+ } else if logEntry.DatetimeStarted.Before(**oldestExecutionTime) {
+ *oldestExecutionTime = &logEntry.DatetimeStarted
+ }
+}
+
+// findOldestExecutionInWindow finds the oldest execution within the time window and counts executions.
+// Returns the count of executions and the oldest execution time, or nil if none found.
+func findOldestExecutionInWindow(logs []*InternalLogEntry, windowStart time.Time) (int, *time.Time) {
+ executions := 0
+ var oldestExecutionTime *time.Time
+
+ for _, logEntry := range logs {
+ if !shouldCountExecution(logEntry, windowStart) {
+ continue
+ }
+
+ executions++
+ updateOldestExecution(&oldestExecutionTime, logEntry)
+ }
+
+ return executions, oldestExecutionTime
+}
+
+// calculateExpiryTime calculates when the oldest execution will fall outside the rate limit window.
+func calculateExpiryTime(oldestExecutionTime time.Time, duration time.Duration, now time.Time) time.Time {
+ expiryTime := oldestExecutionTime.Add(duration)
+ if !expiryTime.After(now) {
+ return time.Time{}
+ }
+ return expiryTime
+}
+
+// updateMaxExpiryTime updates maxExpiryTime if expiryTime is later.
+func updateMaxExpiryTime(maxExpiryTime *time.Time, expiryTime time.Time) {
+ if expiryTime.IsZero() {
+ return
+ }
+
+ if maxExpiryTime.IsZero() || expiryTime.After(*maxExpiryTime) {
+ *maxExpiryTime = expiryTime
+ }
+}
+
+// calculateExpiryForRate calculates the expiry time for a single rate limit rule.
+// Returns the expiry time if the rate limit is exceeded, or zero time if not.
+func calculateExpiryForRate(rate config.RateSpec, logs []*InternalLogEntry, now time.Time) time.Time {
+ duration := parseDuration(rate)
+ if duration <= 0 {
+ return time.Time{}
+ }
+
+ windowStart := now.Add(-duration)
+ executions, oldestExecutionTime := findOldestExecutionInWindow(logs, windowStart)
+
+ if executions < rate.Limit || oldestExecutionTime == nil {
+ return time.Time{}
+ }
+
+ return calculateExpiryTime(*oldestExecutionTime, duration, now)
+}
+
+// getLogsForBinding retrieves logs for a binding ID.
+func (e *Executor) getLogsForBinding(bindingId string) []*InternalLogEntry {
+ e.logmutex.RLock()
+ logs, found := e.LogsByBindingId[bindingId]
+ e.logmutex.RUnlock()
+
+ if !found || len(logs) == 0 {
+ return nil
+ }
+
+ return logs
+}
+
+// calculateMaxExpiryTimeFromRates calculates the maximum expiry time across all rate limit rules.
+func calculateMaxExpiryTimeFromRates(rates []config.RateSpec, logs []*InternalLogEntry, now time.Time) time.Time {
+ var maxExpiryTime time.Time
+
+ for _, rate := range rates {
+ expiryTime := calculateExpiryForRate(rate, logs, now)
+ updateMaxExpiryTime(&maxExpiryTime, expiryTime)
+ }
+
+ return maxExpiryTime
+}
+
+// GetTimeUntilAvailable calculates when an action will be available again based on rate limits.
+// Returns the Unix timestamp in seconds when the rate limit expires, or 0 if the action is available now.
+func (e *Executor) GetTimeUntilAvailable(binding *ActionBinding) int64 {
+ if len(binding.Action.MaxRate) == 0 {
+ return 0
+ }
+
+ logs := e.getLogsForBinding(binding.ID)
+ if logs == nil {
+ return 0
+ }
+
+ maxExpiryTime := calculateMaxExpiryTimeFromRates(binding.Action.MaxRate, logs, time.Now())
+
+ if maxExpiryTime.IsZero() {
+ return 0
+ }
+
+ return maxExpiryTime.Unix()
+}
+
func (e *Executor) SetLog(trackingID string, entry *InternalLogEntry) {
e.logmutex.Lock()
@@ -337,7 +490,6 @@ func (e *Executor) ExecRequest(req *ExecutionRequest) (*sync.WaitGroup, string)
ExitCode: DefaultExitCodeNotExecuted,
ExecutionStarted: false,
ExecutionFinished: false,
- ActionId: "",
ActionTitle: "notfound",
ActionIcon: "💩",
Username: req.AuthenticatedUser.Username,
@@ -374,6 +526,11 @@ func (e *Executor) execChain(req *ExecutionRequest) {
}
}
+ // Ensure DatetimeFinished is set even if execution was blocked early
+ if req.logEntry.DatetimeFinished.IsZero() {
+ req.logEntry.DatetimeFinished = time.Now()
+ }
+
req.logEntry.ExecutionFinished = true
// This isn't a step, because we want to notify all listeners, irrespective
@@ -386,7 +543,7 @@ func getConcurrentCount(req *ExecutionRequest) int {
req.executor.logmutex.RLock()
- for _, log := range req.executor.GetLogsByActionId(req.Binding.Action.ID) {
+ for _, log := range req.executor.GetLogsByBindingId(req.Binding.ID) {
if !log.ExecutionFinished {
concurrentCount += 1
}
@@ -436,7 +593,7 @@ func getExecutionsCount(rate config.RateSpec, req *ExecutionRequest) int {
then := time.Now().Add(-duration)
- for _, logEntry := range req.executor.GetLogsByActionId(req.Binding.Action.ID) {
+ for _, logEntry := range req.executor.GetLogsByBindingId(req.Binding.ID) {
// FIXME
/*
if logEntry.EntityPrefix != req.EntityPrefix {
@@ -573,16 +730,15 @@ func stepRequestAction(req *ExecutionRequest) bool {
req.logEntry.ActionConfigTitle = req.Binding.Action.Title
req.logEntry.ActionTitle = entities.ParseTemplateWith(req.Binding.Action.Title, req.Binding.Entity)
req.logEntry.ActionIcon = req.Binding.Action.Icon
- req.logEntry.ActionId = req.Binding.Action.ID
req.logEntry.Tags = req.Tags
req.executor.logmutex.Lock()
- if _, containsKey := req.executor.LogsByActionId[req.Binding.Action.ID]; !containsKey {
- req.executor.LogsByActionId[req.Binding.Action.ID] = make([]*InternalLogEntry, 0)
+ if _, containsKey := req.executor.LogsByBindingId[req.Binding.ID]; !containsKey {
+ req.executor.LogsByBindingId[req.Binding.ID] = make([]*InternalLogEntry, 0)
}
- req.executor.LogsByActionId[req.Binding.Action.ID] = append(req.executor.LogsByActionId[req.Binding.Action.ID], req.logEntry)
+ req.executor.LogsByBindingId[req.Binding.ID] = append(req.executor.LogsByBindingId[req.Binding.ID], req.logEntry)
req.executor.logmutex.Unlock()
diff --git a/service/internal/executor/executor_actions.go b/service/internal/executor/executor_actions.go
index 3f41fc5..fdf504c 100644
--- a/service/internal/executor/executor_actions.go
+++ b/service/internal/executor/executor_actions.go
@@ -11,9 +11,9 @@ import (
)
func (e *Executor) FindBindingByID(id string) *ActionBinding {
- e.MapActionIdToBindingLock.RLock()
- pair, found := e.MapActionIdToBinding[id]
- e.MapActionIdToBindingLock.RUnlock()
+ e.MapActionBindingsLock.RLock()
+ pair, found := e.MapActionBindings[id]
+ e.MapActionBindingsLock.RUnlock()
if !found {
return nil
@@ -23,11 +23,11 @@ func (e *Executor) FindBindingByID(id string) *ActionBinding {
}
func (e *Executor) FindBindingWithNoEntity(action *config.Action) *ActionBinding {
- e.MapActionIdToBindingLock.RLock()
+ e.MapActionBindingsLock.RLock()
- defer e.MapActionIdToBindingLock.RUnlock()
+ defer e.MapActionBindingsLock.RUnlock()
- for _, binding := range e.MapActionIdToBinding {
+ for _, binding := range e.MapActionBindings {
if binding.Action == action && binding.Entity == nil {
return binding
}
@@ -42,9 +42,9 @@ type RebuildActionMapRequest struct {
}
func (e *Executor) RebuildActionMap() {
- e.MapActionIdToBindingLock.Lock()
+ e.MapActionBindingsLock.Lock()
- clear(e.MapActionIdToBinding)
+ clear(e.MapActionBindings)
req := &RebuildActionMapRequest{
Cfg: e.Cfg,
@@ -65,7 +65,7 @@ func (e *Executor) RebuildActionMap() {
}
}
- e.MapActionIdToBindingLock.Unlock()
+ e.MapActionBindingsLock.Unlock()
for _, l := range e.listeners {
l.OnActionMapRebuilt()
@@ -100,10 +100,10 @@ func recurseDashboardForActionTitles(component *config.DashboardComponent, req *
}
func registerAction(e *Executor, configOrder int, action *config.Action, req *RebuildActionMapRequest) {
- actionId := hashActionToID(action, "")
+ bindingId := generateActionBindingId(action, "")
- e.MapActionIdToBinding[actionId] = &ActionBinding{
- ID: actionId,
+ e.MapActionBindings[bindingId] = &ActionBinding{
+ ID: bindingId,
Action: action,
Entity: nil,
ConfigOrder: configOrder,
@@ -118,9 +118,9 @@ func registerActionsFromEntities(e *Executor, configOrder int, entityTitle strin
}
func registerActionFromEntity(e *Executor, configOrder int, tpl *config.Action, ent *entities.Entity, req *RebuildActionMapRequest) {
- virtualActionId := hashActionToID(tpl, ent.UniqueKey)
+ virtualActionId := generateActionBindingId(tpl, ent.UniqueKey)
- e.MapActionIdToBinding[virtualActionId] = &ActionBinding{
+ e.MapActionBindings[virtualActionId] = &ActionBinding{
ID: virtualActionId,
Action: tpl,
Entity: ent,
@@ -129,7 +129,7 @@ func registerActionFromEntity(e *Executor, configOrder int, tpl *config.Action,
}
}
-func hashActionToID(action *config.Action, entityPrefix string) string {
+func generateActionBindingId(action *config.Action, entityPrefix string) string {
if action.ID != "" && entityPrefix == "" {
return action.ID
}
diff --git a/service/internal/httpservers/frontend.go b/service/internal/httpservers/frontend.go
index cda9cb5..9860650 100644
--- a/service/internal/httpservers/frontend.go
+++ b/service/internal/httpservers/frontend.go
@@ -19,6 +19,7 @@ import (
"github.com/OliveTin/OliveTin/internal/auth/otoauth2"
config "github.com/OliveTin/OliveTin/internal/config"
"github.com/OliveTin/OliveTin/internal/executor"
+ "github.com/OliveTin/OliveTin/internal/webhooks"
log "github.com/sirupsen/logrus"
)
@@ -72,6 +73,10 @@ func StartFrontendMux(cfg *config.Config, ex *executor.Executor) {
mux.HandleFunc("/readyz", handleReadyz)
+ webhookHandler := webhooks.NewWebhookHandler(cfg, ex)
+ mux.HandleFunc("/webhooks", webhookHandler.HandleWebhook)
+ mux.HandleFunc("/webhooks/", webhookHandler.HandleWebhook)
+
webuiServer := NewWebUIServer(cfg)
mux.HandleFunc("/theme.css", webuiServer.generateThemeCss)
diff --git a/service/internal/webhooks/auth.go b/service/internal/webhooks/auth.go
new file mode 100644
index 0000000..b03ce99
--- /dev/null
+++ b/service/internal/webhooks/auth.go
@@ -0,0 +1,169 @@
+package webhooks
+
+import (
+ "crypto/hmac"
+ "crypto/sha1"
+ "crypto/sha256"
+ "crypto/subtle"
+ "encoding/hex"
+ "net/http"
+ "strings"
+
+ "github.com/OliveTin/OliveTin/internal/config"
+ log "github.com/sirupsen/logrus"
+)
+
+type AuthVerifier struct {
+ config config.WebhookConfig
+}
+
+func NewAuthVerifier(cfg config.WebhookConfig) *AuthVerifier {
+ return &AuthVerifier{config: cfg}
+}
+
+func (v *AuthVerifier) Verify(r *http.Request, payload []byte) bool {
+ verifier := v.getVerifier()
+ if verifier == nil {
+ return v.handleUnknownAuthType()
+ }
+ return verifier(r, payload)
+}
+
+type authVerifierFunc func(*http.Request, []byte) bool
+
+func (v *AuthVerifier) getVerifier() authVerifierFunc {
+ if v.config.AuthType == "" || v.config.AuthType == "none" {
+ return func(_ *http.Request, _ []byte) bool {
+ return true
+ }
+ }
+
+ verifierMap := v.buildVerifierMap()
+ if verifier, ok := verifierMap[v.config.AuthType]; ok {
+ return verifier
+ }
+ return nil
+}
+
+func (v *AuthVerifier) buildVerifierMap() map[string]authVerifierFunc {
+ return map[string]authVerifierFunc{
+ "hmac-sha256": v.verifyHMAC256,
+ "hmac-sha1": v.verifyHMAC1,
+ "bearer": func(r *http.Request, _ []byte) bool {
+ return v.verifyBearer(r)
+ },
+ "basic": func(r *http.Request, _ []byte) bool {
+ return v.verifyBasic(r)
+ },
+ }
+}
+
+func (v *AuthVerifier) handleUnknownAuthType() bool {
+ log.WithFields(log.Fields{
+ "authType": v.config.AuthType,
+ }).Warnf("Unknown auth type, rejecting")
+ return false
+}
+
+func (v *AuthVerifier) verifyHMAC256(r *http.Request, payload []byte) bool {
+ if v.config.Secret == "" {
+ log.Warnf("HMAC-SHA256 auth requires secret")
+ return false
+ }
+
+ headerName := v.config.AuthHeader
+ if headerName == "" {
+ headerName = "X-Webhook-Signature"
+ }
+
+ signature := r.Header.Get(headerName)
+ if signature == "" {
+ log.Debugf("Missing signature header: %s", headerName)
+ return false
+ }
+
+ expectedSig := strings.TrimPrefix(signature, "sha256=")
+
+ mac := hmac.New(sha256.New, []byte(v.config.Secret))
+ mac.Write(payload)
+ computedSig := hex.EncodeToString(mac.Sum(nil))
+
+ return hmac.Equal([]byte(expectedSig), []byte(computedSig))
+}
+
+func (v *AuthVerifier) verifyHMAC1(r *http.Request, payload []byte) bool {
+ if v.config.Secret == "" {
+ log.Warnf("HMAC-SHA1 auth requires secret")
+ return false
+ }
+
+ headerName := v.config.AuthHeader
+ if headerName == "" {
+ headerName = "X-Webhook-Signature"
+ }
+
+ signature := r.Header.Get(headerName)
+ if signature == "" {
+ log.Debugf("Missing signature header: %s", headerName)
+ return false
+ }
+
+ expectedSig := strings.TrimPrefix(signature, "sha1=")
+
+ mac := hmac.New(sha1.New, []byte(v.config.Secret))
+ mac.Write(payload)
+ computedSig := hex.EncodeToString(mac.Sum(nil))
+
+ return hmac.Equal([]byte(expectedSig), []byte(computedSig))
+}
+
+func (v *AuthVerifier) verifyBearer(r *http.Request) bool {
+ if v.config.Secret == "" {
+ log.Warnf("Bearer auth requires secret")
+ return false
+ }
+
+ authHeader := r.Header.Get("Authorization")
+ if !strings.HasPrefix(authHeader, "Bearer ") {
+ log.Debugf("Missing or invalid Bearer token")
+ return false
+ }
+
+ token := strings.TrimPrefix(authHeader, "Bearer ")
+ tokenBytes := []byte(token)
+ secretBytes := []byte(v.config.Secret)
+ return len(tokenBytes) == len(secretBytes) && subtle.ConstantTimeCompare(tokenBytes, secretBytes) == 1
+}
+
+func (v *AuthVerifier) verifyBasic(r *http.Request) bool {
+ if v.config.Secret == "" {
+ log.Warnf("Basic auth requires secret")
+ return false
+ }
+
+ username, password, ok := r.BasicAuth()
+ if !ok {
+ log.Debugf("Missing Basic auth header")
+ return false
+ }
+
+ return v.verifyBasicCredentials(username, password)
+}
+
+func (v *AuthVerifier) verifyBasicCredentials(username, password string) bool {
+ parts := strings.SplitN(v.config.Secret, ":", 2)
+ if len(parts) == 2 {
+ return v.verifyBasicWithUsername(username, password, parts[0], parts[1])
+ }
+ return v.verifyBasicPasswordOnly(password)
+}
+
+func (v *AuthVerifier) verifyBasicWithUsername(username, password, expectedUsername, expectedPassword string) bool {
+ usernameMatch := subtle.ConstantTimeCompare([]byte(username), []byte(expectedUsername))
+ passwordMatch := subtle.ConstantTimeCompare([]byte(password), []byte(expectedPassword))
+ return usernameMatch == 1 && passwordMatch == 1
+}
+
+func (v *AuthVerifier) verifyBasicPasswordOnly(password string) bool {
+ return subtle.ConstantTimeCompare([]byte(password), []byte(v.config.Secret)) == 1
+}
diff --git a/service/internal/webhooks/github.go b/service/internal/webhooks/github.go
new file mode 100644
index 0000000..431e6ba
--- /dev/null
+++ b/service/internal/webhooks/github.go
@@ -0,0 +1,112 @@
+package webhooks
+
+import (
+ "github.com/OliveTin/OliveTin/internal/config"
+)
+
+// ApplyGitHubTemplate applies GitHub-specific template configurations
+// This allows users to use simple template names instead of configuring everything manually
+func ApplyGitHubTemplate(cfg *config.WebhookConfig, template string) {
+ applier := getTemplateApplier(template)
+ if applier != nil {
+ applier(cfg)
+ }
+}
+
+type templateApplier func(*config.WebhookConfig)
+
+func getTemplateApplier(template string) templateApplier {
+ templateMap := map[string]templateApplier{
+ "github-push": applyGitHubPushTemplate,
+ "github-pr": applyGitHubPRTemplate,
+ "github-pull-request": applyGitHubPRTemplate,
+ "github-release": applyGitHubReleaseTemplate,
+ "github-workflow": applyGitHubWorkflowTemplate,
+ }
+ return templateMap[template]
+}
+
+func setDefaultAuth(cfg *config.WebhookConfig) {
+ if cfg.AuthHeader == "" {
+ cfg.AuthHeader = "X-Hub-Signature-256"
+ }
+ if cfg.AuthType == "" {
+ cfg.AuthType = "hmac-sha256"
+ }
+}
+
+func ensureMatchHeaders(cfg *config.WebhookConfig) {
+ if len(cfg.MatchHeaders) == 0 {
+ cfg.MatchHeaders = make(map[string]string)
+ }
+}
+
+func ensureExtract(cfg *config.WebhookConfig) {
+ if len(cfg.Extract) == 0 {
+ cfg.Extract = make(map[string]string)
+ }
+}
+
+func setExtractIfMissing(cfg *config.WebhookConfig, key, value string) {
+ if _, exists := cfg.Extract[key]; !exists {
+ cfg.Extract[key] = value
+ }
+}
+
+func setMatchHeaderIfMissing(cfg *config.WebhookConfig, key, value string) {
+ if _, exists := cfg.MatchHeaders[key]; !exists {
+ cfg.MatchHeaders[key] = value
+ }
+}
+
+func applyGitHubPushTemplate(cfg *config.WebhookConfig) {
+ setDefaultAuth(cfg)
+ ensureMatchHeaders(cfg)
+ setMatchHeaderIfMissing(cfg, "X-GitHub-Event", "push")
+ ensureExtract(cfg)
+ setExtractIfMissing(cfg, "git_repository", "$.repository.full_name")
+ setExtractIfMissing(cfg, "git_ref", "$.ref")
+ setExtractIfMissing(cfg, "git_commit", "$.head_commit.id")
+ setExtractIfMissing(cfg, "git_branch", "$.ref")
+ setExtractIfMissing(cfg, "git_message", "$.head_commit.message")
+ setExtractIfMissing(cfg, "git_author", "$.head_commit.author.name")
+}
+
+func applyGitHubPRTemplate(cfg *config.WebhookConfig) {
+ setDefaultAuth(cfg)
+ ensureMatchHeaders(cfg)
+ setMatchHeaderIfMissing(cfg, "X-GitHub-Event", "pull_request")
+ ensureExtract(cfg)
+ setExtractIfMissing(cfg, "pr_number", "$.number")
+ setExtractIfMissing(cfg, "pr_title", "$.pull_request.title")
+ setExtractIfMissing(cfg, "pr_author", "$.pull_request.user.login")
+ setExtractIfMissing(cfg, "pr_action", "$.action")
+ setExtractIfMissing(cfg, "git_repository", "$.repository.full_name")
+ setExtractIfMissing(cfg, "pr_state", "$.pull_request.state")
+ setExtractIfMissing(cfg, "pr_head_sha", "$.pull_request.head.sha")
+}
+
+func applyGitHubReleaseTemplate(cfg *config.WebhookConfig) {
+ setDefaultAuth(cfg)
+ ensureMatchHeaders(cfg)
+ setMatchHeaderIfMissing(cfg, "X-GitHub-Event", "release")
+ ensureExtract(cfg)
+ setExtractIfMissing(cfg, "release_action", "$.action")
+ setExtractIfMissing(cfg, "release_tag", "$.release.tag_name")
+ setExtractIfMissing(cfg, "release_name", "$.release.name")
+ setExtractIfMissing(cfg, "git_repository", "$.repository.full_name")
+ setExtractIfMissing(cfg, "release_author", "$.release.author.login")
+}
+
+func applyGitHubWorkflowTemplate(cfg *config.WebhookConfig) {
+ setDefaultAuth(cfg)
+ ensureMatchHeaders(cfg)
+ setMatchHeaderIfMissing(cfg, "X-GitHub-Event", "workflow_run")
+ ensureExtract(cfg)
+ setExtractIfMissing(cfg, "workflow_name", "$.workflow_run.name")
+ setExtractIfMissing(cfg, "workflow_status", "$.workflow_run.status")
+ setExtractIfMissing(cfg, "workflow_conclusion", "$.workflow_run.conclusion")
+ setExtractIfMissing(cfg, "git_repository", "$.repository.full_name")
+ setExtractIfMissing(cfg, "git_commit", "$.workflow_run.head_sha")
+ setExtractIfMissing(cfg, "git_branch", "$.workflow_run.head_branch")
+}
diff --git a/service/internal/webhooks/handler.go b/service/internal/webhooks/handler.go
new file mode 100644
index 0000000..a530690
--- /dev/null
+++ b/service/internal/webhooks/handler.go
@@ -0,0 +1,162 @@
+package webhooks
+
+import (
+ "io"
+ "net/http"
+
+ "github.com/OliveTin/OliveTin/internal/auth"
+ "github.com/OliveTin/OliveTin/internal/config"
+ "github.com/OliveTin/OliveTin/internal/executor"
+ log "github.com/sirupsen/logrus"
+)
+
+type ActionWebhookConfig struct {
+ Action *config.Action
+ Config config.WebhookConfig
+}
+
+type WebhookHandler struct {
+ cfg *config.Config
+ executor *executor.Executor
+}
+
+func NewWebhookHandler(cfg *config.Config, ex *executor.Executor) *WebhookHandler {
+ return &WebhookHandler{
+ cfg: cfg,
+ executor: ex,
+ }
+}
+
+func (h *WebhookHandler) HandleWebhook(w http.ResponseWriter, r *http.Request) {
+ if r.Method != http.MethodPost {
+ http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
+ return
+ }
+
+ payload, err := h.readPayload(r)
+ if err != nil {
+ http.Error(w, "Failed to read payload", http.StatusBadRequest)
+ return
+ }
+
+ matchingActions := h.findMatchingActions(r, payload)
+ if len(matchingActions) == 0 {
+ h.writeOKResponse(w, "no matching webhook actions")
+ return
+ }
+
+ processed := h.processMatchingActions(matchingActions, r, payload)
+ log.WithFields(log.Fields{
+ "matched": len(matchingActions),
+ "processed": processed,
+ }).Infof("Webhook processed")
+
+ h.writeOKResponse(w, "webhook actions")
+}
+
+func (h *WebhookHandler) readPayload(r *http.Request) ([]byte, error) {
+ maxSize := int64(1024 * 1024)
+ payload, err := io.ReadAll(io.LimitReader(r.Body, maxSize))
+ if err != nil {
+ log.WithFields(log.Fields{
+ "error": err,
+ }).Warnf("Failed to read webhook payload")
+ return nil, err
+ }
+
+ return payload, nil
+}
+
+func (h *WebhookHandler) writeOKResponse(w http.ResponseWriter, context string) {
+ w.WriteHeader(http.StatusOK)
+ if _, err := w.Write([]byte("OK")); err != nil {
+ log.WithError(err).Warnf("Failed to write response for %s", context)
+ }
+}
+
+func (h *WebhookHandler) processMatchingActions(matchingActions []ActionWebhookConfig, r *http.Request, payload []byte) int {
+ processed := 0
+ for _, actionConfig := range matchingActions {
+ if h.processWebhook(actionConfig, r, payload) {
+ processed++
+ }
+ }
+ return processed
+}
+
+func (h *WebhookHandler) findMatchingActions(r *http.Request, payload []byte) []ActionWebhookConfig {
+ var matches []ActionWebhookConfig
+
+ for _, action := range h.cfg.Actions {
+ matches = append(matches, h.findMatchingWebhooksForAction(action, r, payload)...)
+ }
+
+ return matches
+}
+
+func (h *WebhookHandler) findMatchingWebhooksForAction(action *config.Action, r *http.Request, payload []byte) []ActionWebhookConfig {
+ var matches []ActionWebhookConfig
+
+ for _, webhookConfig := range action.ExecOnWebhook {
+ webhookConfigCopy := webhookConfig
+
+ if webhookConfigCopy.Template != "" {
+ ApplyGitHubTemplate(&webhookConfigCopy, webhookConfigCopy.Template)
+ }
+
+ matcher := NewWebhookMatcher(webhookConfigCopy, r, payload)
+ if matcher.Matches() {
+ matches = append(matches, ActionWebhookConfig{
+ Action: action,
+ Config: webhookConfigCopy,
+ })
+ }
+ }
+
+ return matches
+}
+
+func (h *WebhookHandler) processWebhook(actionConfig ActionWebhookConfig, r *http.Request, payload []byte) bool {
+ verifier := NewAuthVerifier(actionConfig.Config)
+ if !verifier.Verify(r, payload) {
+ log.WithFields(log.Fields{
+ "actionTitle": actionConfig.Action.Title,
+ "authType": actionConfig.Config.AuthType,
+ }).Warnf("Webhook authentication failed")
+ return false
+ }
+
+ matcher := NewWebhookMatcher(actionConfig.Config, r, payload)
+
+ args, err := matcher.ExtractArguments()
+ if err != nil {
+ log.WithFields(log.Fields{
+ "actionTitle": actionConfig.Action.Title,
+ "error": err,
+ }).Warnf("Failed to extract webhook arguments")
+ return false
+ }
+
+ h.executeAction(actionConfig.Action, args)
+ return true
+}
+
+func (h *WebhookHandler) executeAction(action *config.Action, args map[string]string) {
+ binding := h.executor.FindBindingWithNoEntity(action)
+ if binding == nil {
+ log.WithFields(log.Fields{
+ "actionTitle": action.Title,
+ }).Warnf("Action binding not found, skipping execution")
+ return
+ }
+
+ req := &executor.ExecutionRequest{
+ Binding: binding,
+ Cfg: h.cfg,
+ Tags: []string{"webhook"},
+ Arguments: args,
+ AuthenticatedUser: auth.UserFromSystem(h.cfg, "webhook"),
+ }
+
+ h.executor.ExecRequest(req)
+}
diff --git a/service/internal/webhooks/jsonpath.go b/service/internal/webhooks/jsonpath.go
new file mode 100644
index 0000000..8e51b70
--- /dev/null
+++ b/service/internal/webhooks/jsonpath.go
@@ -0,0 +1,60 @@
+package webhooks
+
+import (
+ "encoding/json"
+ "fmt"
+
+ "github.com/PaesslerAG/jsonpath"
+)
+
+type JSONMatcher struct {
+ payload interface{}
+}
+
+func NewJSONMatcher(payload []byte) (*JSONMatcher, error) {
+ var data interface{}
+ if err := json.Unmarshal(payload, &data); err != nil {
+ return nil, err
+ }
+ return &JSONMatcher{payload: data}, nil
+}
+
+func (m *JSONMatcher) MatchPath(pathExpr string, expectedValue string) (bool, error) {
+ value, err := jsonpath.Get(pathExpr, m.payload)
+ if err != nil {
+ return false, err
+ }
+
+ // For string values, compare directly without marshaling
+ if strValue, ok := value.(string); ok {
+ return strValue == expectedValue, nil
+ }
+
+ // For non-string values, marshal to JSON for consistent string representation
+ jsonBytes, err := json.Marshal(value)
+ if err != nil {
+ return false, fmt.Errorf("failed to marshal extracted value: %w", err)
+ }
+
+ valueStr := string(jsonBytes)
+ return valueStr == expectedValue, nil
+}
+
+func (m *JSONMatcher) ExtractValue(pathExpr string) (string, error) {
+ value, err := jsonpath.Get(pathExpr, m.payload)
+ if err != nil {
+ return "", err
+ }
+
+ // Marshal to JSON for consistent string representation
+ jsonBytes, err := json.Marshal(value)
+ if err != nil {
+ return "", fmt.Errorf("failed to marshal extracted value: %w", err)
+ }
+
+ return string(jsonBytes), nil
+}
+
+func (m *JSONMatcher) GetPayload() interface{} {
+ return m.payload
+}
diff --git a/service/internal/webhooks/matcher.go b/service/internal/webhooks/matcher.go
new file mode 100644
index 0000000..3d30d5e
--- /dev/null
+++ b/service/internal/webhooks/matcher.go
@@ -0,0 +1,185 @@
+package webhooks
+
+import (
+ "net/http"
+ "regexp"
+ "strings"
+
+ "github.com/OliveTin/OliveTin/internal/config"
+ log "github.com/sirupsen/logrus"
+)
+
+type WebhookMatcher struct {
+ config config.WebhookConfig
+ req *http.Request
+ bodyBytes []byte
+}
+
+func NewWebhookMatcher(cfg config.WebhookConfig, r *http.Request, bodyBytes []byte) *WebhookMatcher {
+ return &WebhookMatcher{
+ config: cfg,
+ req: r,
+ bodyBytes: bodyBytes,
+ }
+}
+
+func (m *WebhookMatcher) Matches() bool {
+ if !m.matchHeaders() {
+ return false
+ }
+
+ if !m.matchQuery() {
+ return false
+ }
+
+ if !m.matchPath() {
+ return false
+ }
+
+ return true
+}
+
+func (m *WebhookMatcher) matchHeaders() bool {
+ if len(m.config.MatchHeaders) == 0 {
+ return true
+ }
+
+ for key, expectedValue := range m.config.MatchHeaders {
+ actualValue := m.req.Header.Get(key)
+ if !m.compareValues(actualValue, expectedValue) {
+ log.WithFields(log.Fields{
+ "header": key,
+ "expected": expectedValue,
+ "actual": actualValue,
+ }).Debugf("Header mismatch")
+ return false
+ }
+ }
+ return true
+}
+
+func (m *WebhookMatcher) matchQuery() bool {
+ if len(m.config.MatchQuery) == 0 {
+ return true
+ }
+
+ query := m.req.URL.Query()
+ for key, expectedValue := range m.config.MatchQuery {
+ actualValue := query.Get(key)
+ if !m.compareValues(actualValue, expectedValue) {
+ log.WithFields(log.Fields{
+ "query": key,
+ "expected": expectedValue,
+ "actual": actualValue,
+ }).Debugf("Query parameter mismatch")
+ return false
+ }
+ }
+ return true
+}
+
+func (m *WebhookMatcher) matchPath() bool {
+ if m.config.MatchPath == "" {
+ return true
+ }
+
+ jsonPath, expectedValue := m.parseMatchPath()
+ matcher, err := NewJSONMatcher(m.bodyBytes)
+ if err != nil {
+ log.WithFields(log.Fields{
+ "error": err,
+ }).Debugf("Failed to create JSON matcher")
+ return false
+ }
+
+ return m.matchPathValue(matcher, jsonPath, expectedValue)
+}
+
+func (m *WebhookMatcher) parseMatchPath() (string, string) {
+ parts := strings.SplitN(m.config.MatchPath, "=", 2)
+ jsonPath := parts[0]
+ expectedValue := ""
+ if len(parts) == 2 {
+ expectedValue = parts[1]
+ }
+ return jsonPath, expectedValue
+}
+
+func (m *WebhookMatcher) matchPathValue(matcher *JSONMatcher, jsonPath, expectedValue string) bool {
+ if expectedValue == "" {
+ _, err := matcher.ExtractValue(jsonPath)
+ return err == nil
+ }
+
+ matches, err := matcher.MatchPath(jsonPath, expectedValue)
+ if err != nil {
+ log.WithFields(log.Fields{
+ "jsonPath": jsonPath,
+ "error": err,
+ }).Debugf("Failed to match JSONPath")
+ return false
+ }
+ return matches
+}
+
+func (m *WebhookMatcher) compareValues(actual, expected string) bool {
+ if strings.HasPrefix(expected, "regex:") {
+ pattern := strings.TrimPrefix(expected, "regex:")
+ matched, err := regexp.MatchString(pattern, actual)
+ if err != nil {
+ log.WithFields(log.Fields{
+ "pattern": pattern,
+ "error": err,
+ }).Warnf("Invalid regex pattern")
+ return false
+ }
+ return matched
+ }
+ return actual == expected
+}
+
+func (m *WebhookMatcher) ExtractArguments() (map[string]string, error) {
+ matcher, err := NewJSONMatcher(m.bodyBytes)
+ if err != nil {
+ return nil, err
+ }
+
+ args := m.extractJSONPathValues(matcher)
+ m.addWebhookMetadata(args)
+ m.addWebhookHeaders(args)
+
+ return args, nil
+}
+
+func (m *WebhookMatcher) extractJSONPathValues(matcher *JSONMatcher) map[string]string {
+ args := make(map[string]string)
+
+ for argName, jsonPath := range m.config.Extract {
+ value, err := matcher.ExtractValue(jsonPath)
+ if err != nil {
+ log.WithFields(log.Fields{
+ "argName": argName,
+ "jsonPath": jsonPath,
+ "error": err,
+ }).Debugf("Failed to extract value")
+ continue
+ }
+ args[argName] = value
+ }
+
+ return args
+}
+
+func (m *WebhookMatcher) addWebhookMetadata(args map[string]string) {
+ args["webhook_method"] = m.req.Method
+ args["webhook_path"] = m.req.URL.Path
+ args["webhook_query"] = m.req.URL.RawQuery
+}
+
+func (m *WebhookMatcher) addWebhookHeaders(args map[string]string) {
+ for key, values := range m.req.Header {
+ if len(values) > 0 {
+ args["webhook_header_"+strings.ToLower(key)] = values[0]
+ }
+ }
+}