James Read 5 месяцев назад
Родитель
Сommit
92b951d582

+ 1 - 0
frontend/package.json

@@ -34,6 +34,7 @@
 		"standard": "^17.1.2",
 		"unplugin-vue-components": "^30.0.0",
 		"vite": "^7.3.1",
+    "vue": "^3.5.26",
 		"vue-i18n": "^11.2.8",
 		"vue-router": "^4.6.4"
 	}

+ 7 - 0
frontend/resources/scripts/gen/olivetin/api/v1/olivetin_pb.d.ts

@@ -488,6 +488,13 @@ export declare type GetLogsRequest = Message<"olivetin.api.v1.GetLogsRequest"> &
    * @generated from field: int64 start_offset = 1;
    */
   startOffset: bigint;
+
+  /**
+   * Optional date filter in YYYY-MM-DD format
+   *
+   * @generated from field: string date_filter = 2;
+   */
+  dateFilter: string;
 };
 
 /**

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
frontend/resources/scripts/gen/olivetin/api/v1/olivetin_pb.js


+ 12 - 0
frontend/resources/vue/router.js

@@ -35,6 +35,18 @@ const routes = [
       icon: LeftToRightListDashIcon
     }
   },
+  {
+    path: '/logs/calendar',
+    name: 'LogsCalendar',
+    component: () => import('./views/LogsCalendarView.vue'),
+    meta: { 
+      title: 'Logs Calendar',
+      breadcrumb: [
+        { name: "Logs", href: "/logs" },
+        { name: "Calendar" },
+      ]
+    }
+  },
   {
     path: '/entities',
     name: 'Entities',

+ 168 - 0
frontend/resources/vue/views/LogsCalendarView.vue

@@ -0,0 +1,168 @@
+<template>
+  <Section :title="t('logs.calendar-title')" :padding="false">
+    <template #toolbar>
+      <router-link to="/logs" class="button neutral">
+        <svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
+          <path fill="currentColor" d="M20 11H7.83l5.59-5.59L12 4l-8 8l8 8l1.41-1.41L7.83 13H20z"/>
+        </svg>
+        {{ t('logs.back-to-list') }}
+      </router-link>
+    </template>
+
+    <div class="padding">
+      <Calendar
+        :events="calendarEvents"
+        :loading="loading"
+        :error="error"
+        :current-month="currentMonthIndex"
+        :current-year="currentYear"
+        @event-click="handleEventClick"
+        @date-click="handleDayClick"
+        @month-change="handleMonthChange"
+      />
+    </div>
+  </Section>
+</template>
+
+<script setup>
+import { ref, computed, onMounted } from 'vue'
+import { useRouter } from 'vue-router'
+import { useI18n } from 'vue-i18n'
+import Calendar from 'picocrank/vue/components/Calendar.vue'
+import Section from 'picocrank/vue/components/Section.vue'
+
+const router = useRouter()
+const { t } = useI18n()
+
+const logs = ref([])
+const loading = ref(false)
+const error = ref(null)
+const currentMonthIndex = ref(new Date().getMonth())
+const currentYear = ref(new Date().getFullYear())
+
+// Convert logs to calendar events format
+const calendarEvents = computed(() => {
+  return logs.value
+    .filter(log => {
+      // Only include logs with valid start dates
+      if (!log.datetimeStarted) return false
+      const startDate = new Date(log.datetimeStarted)
+      return !isNaN(startDate.getTime())
+    })
+    .map(log => {
+      const startDate = new Date(log.datetimeStarted)
+      let endDate = log.datetimeFinished ? new Date(log.datetimeFinished) : null
+      
+      // Validate end date
+      if (endDate && isNaN(endDate.getTime())) {
+        endDate = null
+      }
+
+      return {
+        id: log.executionTrackingId,
+        title: log.actionTitle || 'Untitled Action',
+        date: startDate,
+        startDate: startDate,
+        endDate: endDate,
+        actionIcon: log.actionIcon,
+        user: log.user,
+        tags: log.tags,
+        logEntry: log
+      }
+    })
+})
+
+async function fetchLogs() {
+  loading.value = true
+  error.value = null
+  
+  try {
+    // Currently fetches only the default page (startOffset: 0)
+    // Multi-page fetching: loop through pages until no more logs or limit reached
+    const allLogs = []
+    let startOffset = BigInt(0)
+    const maxLogs = 10000 // Reasonable limit to prevent excessive API calls
+    const pageSize = 100 // Typical page size, will be updated from API response
+    
+    while (allLogs.length < maxLogs) {
+      const args = {
+        "startOffset": startOffset,
+      }
+
+      const response = await window.client.getLogs(args)
+      const pageLogs = response.logs || []
+      
+      // If no logs returned, we've reached the end
+      if (pageLogs.length === 0) {
+        break
+      }
+      
+      // Append logs from this page
+      allLogs.push(...pageLogs)
+      
+      // Update offset for next page
+      const currentPageSize = Number(response.pageSize) || pageLogs.length
+      startOffset += BigInt(currentPageSize)
+      
+      // If we got fewer logs than the page size, we've reached the end
+      if (pageLogs.length < currentPageSize) {
+        break
+      }
+    }
+    
+    logs.value = allLogs
+  } catch (err) {
+    console.error('Failed to fetch logs:', err)
+    error.value = 'Failed to load logs'
+    window.showBigError('fetch-logs-calendar', 'getting logs for calendar', err, false)
+  } finally {
+    loading.value = false
+  }
+}
+
+function handleEventClick(event) {
+  // Navigate to the execution view when clicking on a calendar event
+  if (event.id) {
+    router.push(`/logs/${event.id}`)
+  }
+}
+
+function handleDayClick(date) {
+  // Navigate to logs list filtered by the selected date
+  // Format date as YYYY-MM-DD using local date components to avoid timezone issues
+  const year = date.getFullYear()
+  const month = String(date.getMonth() + 1).padStart(2, '0')
+  const day = String(date.getDate()).padStart(2, '0')
+  const dateString = `${year}-${month}-${day}`
+  router.push({ path: '/logs', query: { date: dateString } })
+}
+
+function handleMonthChange(month, year) {
+  currentMonthIndex.value = month
+  currentYear.value = year
+  // Optionally fetch logs for the new month if needed
+  // For now, we'll keep all logs loaded
+}
+
+onMounted(() => {
+  fetchLogs()
+})
+</script>
+
+<style scoped>
+.padding {
+  padding: 1rem;
+}
+
+@media (prefers-color-scheme: dark) {
+  :deep(div.calendar-header-nav) {
+    background-color: var(--bg, #111);
+    color: var(--text-color, #fff);
+    border-color: var(--border-color, #333);
+  }
+
+  :deep(div.calendar-header-nav h2.calendar-title) {
+    color: #fff !important;
+  }
+}
+</style>

+ 119 - 5
frontend/resources/vue/views/LogsListView.vue

@@ -1,6 +1,9 @@
 <template>
   <Section :title="t('logs.title')" :padding="false">
       <template #toolbar>
+        <router-link to="/logs/calendar" class="button neutral">
+          {{ t('logs.calendar') }}
+        </router-link>
         <label class="input-with-icons">
           <svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
             <path fill="currentColor"
@@ -21,7 +24,20 @@
         <table class="logs-table">
           <thead>
             <tr>
-              <th>{{ t('logs.timestamp') }}</th>
+              <th>
+                <div class="timestamp-header">
+                  <span>{{ t('logs.timestamp') }}</span>
+                  <span v-if="selectedDate" class="date-filter-indicator">
+                    <span class="date-filter-text">{{ formatDateFilter(selectedDate) }}</span>
+                    <button :title="t('logs.clear-date-filter')" @click="clearDateFilter" class="clear-date-button">
+                      <svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
+                        <path fill="currentColor"
+                          d="M19 6.41L17.59 5L12 10.59L6.41 5L5 6.41L10.59 12L5 17.59L6.41 19L12 13.41L17.59 19L19 17.59L13.41 12z" />
+                      </svg>
+                    </button>
+                  </span>
+                </div>
+              </th>
               <th>{{ t('logs.action') }}</th>
               <th>{{ t('logs.metadata') }}</th>
               <th>{{ t('logs.status') }}</th>
@@ -56,7 +72,14 @@
           @page-size-change="handlePageSizeChange" itemTitle="execution logs" />
       </div>
 
-      <div v-show="logs.length === 0" class="empty-state">
+      <div v-show="selectedDate && filteredLogs.length === 0" class="empty-state">
+        <p>{{ t('logs.no-logs-to-display') }} {{ formatDateFilter(selectedDate) }}.</p>
+        <button @click="clearDateFilter" class="button neutral">
+          {{ t('logs.clear-date-filter') }}
+        </button>
+      </div>
+
+      <div v-show="logs.length === 0 && !selectedDate" class="empty-state">
         <p>{{ t('logs.no-logs-to-display') }}</p>
         <router-link to="/">{{ t('return-to-index') }}</router-link>
       </div>
@@ -64,27 +87,50 @@
 </template>
 
 <script setup>
-import { ref, computed, onMounted } from 'vue'
+import { ref, computed, onMounted, watch } from 'vue'
+import { useRoute, useRouter } from 'vue-router'
 import Pagination from 'picocrank/vue/components/Pagination.vue'
 import Section from 'picocrank/vue/components/Section.vue'
 import { useI18n } from 'vue-i18n'
 import ActionStatusDisplay from '../components/ActionStatusDisplay.vue'
 
+const route = useRoute()
+const router = useRouter()
+
 const logs = ref([])
 const searchText = ref('')
 const pageSize = ref(10)
 const currentPage = ref(1)
 const loading = ref(false)
 const totalCount = ref(0)
+const selectedDate = ref(null)
 
 const { t } = useI18n()
 
+// Read date query parameter from route
+function updateDateFromRoute() {
+  const dateParam = route.query.date
+  if (dateParam) {
+    selectedDate.value = dateParam
+  } else {
+    selectedDate.value = null
+  }
+  // Re-fetch logs when date changes
+  fetchLogs()
+}
+
+// Watch for route changes to update date filter
+watch(() => route.query.date, () => {
+  updateDateFromRoute()
+})
+
 const filteredLogs = computed(() => {
   let result = logs.value
   
+  // Date filtering is now done server-side, so we only need to filter by search text
   if (searchText.value) {
     const searchLower = searchText.value.toLowerCase()
-    result = logs.value.filter(log =>
+    result = result.filter(log =>
       log.actionTitle.toLowerCase().includes(searchLower)
     )
   }
@@ -106,6 +152,11 @@ async function fetchLogs() {
       "startOffset": BigInt(startOffset),
     }
 
+    // Add date filter if selected
+    if (selectedDate.value) {
+      args.dateFilter = selectedDate.value
+    }
+
     const response = await window.client.getLogs(args)
 
     logs.value = response.logs
@@ -123,6 +174,24 @@ function clearSearch() {
   searchText.value = ''
 }
 
+function clearDateFilter() {
+  selectedDate.value = null
+  // Remove date query parameter from URL
+  const query = { ...route.query }
+  delete query.date
+  router.push({ path: route.path, query })
+}
+
+function formatDateFilter(dateString) {
+  // Format YYYY-MM-DD to a short format (e.g., "Jan 15, 2024")
+  try {
+    const date = new Date(dateString + 'T00:00:00')
+    return date.toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric' })
+  } catch (err) {
+    return dateString
+  }
+}
+
 function formatTimestamp(timestamp) {
   if (!timestamp) return 'Unknown'
   try {
@@ -141,9 +210,11 @@ function handlePageChange(page) {
 function handlePageSizeChange(newPageSize) {
   pageSize.value = newPageSize
   currentPage.value = 1 // Reset to first page
+  fetchLogs()
 }
 
 onMounted(() => {
+  updateDateFromRoute()
   fetchLogs()
 })
 </script>
@@ -227,4 +298,47 @@ onMounted(() => {
   text-decoration: underline;
 }
 
-</style>
+.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;
+}
+
+</style>

+ 20 - 0
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",
@@ -73,7 +77,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",
@@ -119,7 +127,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",
@@ -165,7 +177,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",
@@ -211,7 +227,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": "退出代码",

+ 4 - 0
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

+ 4 - 0
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

+ 4 - 0
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

+ 4 - 0
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

+ 4 - 0
lang/zh-Hans-CN.yaml

@@ -27,6 +27,10 @@ translations:
   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: 在哪里找到帮助

+ 1 - 0
proto/olivetin/api/v1/olivetin.proto

@@ -120,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 {

+ 12 - 2
service/gen/olivetin/api/v1/olivetin.pb.go

@@ -1104,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
 }
@@ -1145,6 +1146,13 @@ 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"`
@@ -3948,9 +3956,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\"\x89\x05\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" +

+ 4378 - 0
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
+}

+ 5 - 1
service/internal/api/api.go

@@ -499,7 +499,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))
 	}

+ 26 - 3
service/internal/executor/executor.go

@@ -234,12 +234,27 @@ func isLogEntryAllowedByACL(cfg *config.Config, user *authpublic.AuthenticatedUs
 	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))
 
+	var filterDate time.Time
+	var hasDateFilter bool
+	if dateFilter != "" {
+		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")
+		} else {
+			filterDate = parsedDate
+			hasDateFilter = true
+		}
+	}
+
 	for _, trackingId := range e.logsTrackingIdsByDate {
 		entry := e.logs[trackingId]
 
@@ -247,6 +262,13 @@ func (e *Executor) filterLogsByACL(cfg *config.Config, user *authpublic.Authenti
 			continue
 		}
 		if isLogEntryAllowedByACL(cfg, user, entry) {
+			if hasDateFilter {
+				entryDate := entry.DatetimeStarted.UTC().Truncate(24 * time.Hour)
+				filterDateUTC := filterDate.UTC().Truncate(24 * time.Hour)
+				if !entryDate.Equal(filterDateUTC) {
+					continue
+				}
+			}
 			filtered = append(filtered, entry)
 		}
 	}
@@ -280,8 +302,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)
 }
 

Некоторые файлы не были показаны из-за большого количества измененных файлов