diff --git a/Makefile b/Makefile index 186b56e..21a08f3 100644 --- a/Makefile +++ b/Makefile @@ -57,6 +57,7 @@ devrun: compile devcontainer: compile podman-image podman-container webui-dist: + $(call delete-files,webui) $(MAKE) -wC frontend dist mv frontend/dist webui diff --git a/config.yaml b/config.yaml index 5423fc3..37f555c 100644 --- a/config.yaml +++ b/config.yaml @@ -133,6 +133,7 @@ actions: # Docs: https://docs.olivetin.app/args/input_confirmation.html - title: Delete old backups icon: ashtonished + # A single space requires justification with no prefilled template (empty disables it). justification: " " shell: rm -rf /opt/oliveTinOldBackups/ && sleep 5 arguments: diff --git a/frontend/resources/scripts/gen/olivetin/api/v1/olivetin_pb.d.ts b/frontend/resources/scripts/gen/olivetin/api/v1/olivetin_pb.d.ts index 8a9886d..89619f5 100644 --- a/frontend/resources/scripts/gen/olivetin/api/v1/olivetin_pb.d.ts +++ b/frontend/resources/scripts/gen/olivetin/api/v1/olivetin_pb.d.ts @@ -92,7 +92,7 @@ export declare type Action = Message<"olivetin.api.v1.Action"> & { execOnWebhooks: ActionWebhookExecHint[]; /** - * @generated from field: string justification = 16; + * @generated from field: string justification = 20; */ justification: string; diff --git a/frontend/resources/scripts/gen/olivetin/api/v1/olivetin_pb.js b/frontend/resources/scripts/gen/olivetin/api/v1/olivetin_pb.js index c85bf6f..250208b 100644 --- a/frontend/resources/scripts/gen/olivetin/api/v1/olivetin_pb.js +++ b/frontend/resources/scripts/gen/olivetin/api/v1/olivetin_pb.js @@ -8,7 +8,7 @@ import { fileDesc, messageDesc, serviceDesc } from "@bufbuild/protobuf/codegenv2 * Describes the file olivetin/api/v1/olivetin.proto. */ export const file_olivetin_api_v1_olivetin = /*@__PURE__*/ - fileDesc("Ch5vbGl2ZXRpbi9hcGkvdjEvb2xpdmV0aW4ucHJvdG8SD29saXZldGluLmFwaS52MSLABAoGQWN0aW9uEhIKCmJpbmRpbmdfaWQYASABKAkSDQoFdGl0bGUYAiABKAkSDAoEaWNvbhgDIAEoCRIQCghjYW5fZXhlYxgEIAEoCBIyCglhcmd1bWVudHMYBSADKAsyHy5vbGl2ZXRpbi5hcGkudjEuQWN0aW9uQXJndW1lbnQSFgoOcG9wdXBfb25fc3RhcnQYBiABKAkSDQoFb3JkZXIYByABKAUSDwoHdGltZW91dBgIIAEoBRIjChtkYXRldGltZV9yYXRlX2xpbWl0X2V4cGlyZXMYCSABKAkSFwoPZXhlY19vbl9zdGFydHVwGAogASgIEhQKDGV4ZWNfb25fY3JvbhgLIAMoCRIjChtleGVjX29uX2ZpbGVfY3JlYXRlZF9pbl9kaXIYDCADKAkSIwobZXhlY19vbl9maWxlX2NoYW5nZWRfaW5fZGlyGA0gAygJEh0KFWV4ZWNfb25fY2FsZW5kYXJfZmlsZRgOIAEoCRJAChBleGVjX29uX3dlYmhvb2tzGA8gAygLMiYub2xpdmV0aW4uYXBpLnYxLkFjdGlvbldlYmhvb2tFeGVjSGludBIVCg1qdXN0aWZpY2F0aW9uGBAgASgJEhwKFGhhc19ydW5uaW5nX2luc3RhbmNlGBEgASgIEhsKE2hhc19xdWV1ZWRfaW5zdGFuY2UYEiABKAgSNgoGZ3JvdXBzGBMgAygLMiYub2xpdmV0aW4uYXBpLnYxLkFjdGlvbkdyb3VwTWVtYmVyc2hpcCJRChVBY3Rpb25Hcm91cE1lbWJlcnNoaXASDAoEbmFtZRgBIAEoCRIWCg5tYXhfY29uY3VycmVudBgCIAEoBRISCgpxdWV1ZV9zaXplGAMgASgFIsMCChVBY3Rpb25XZWJob29rRXhlY0hpbnQSEAoIdGVtcGxhdGUYASABKAkSEgoKbWF0Y2hfcGF0aBgCIAEoCRJPCg1tYXRjaF9oZWFkZXJzGAMgAygLMjgub2xpdmV0aW4uYXBpLnYxLkFjdGlvbldlYmhvb2tFeGVjSGludC5NYXRjaEhlYWRlcnNFbnRyeRJLCgttYXRjaF9xdWVyeRgEIAMoCzI2Lm9saXZldGluLmFwaS52MS5BY3Rpb25XZWJob29rRXhlY0hpbnQuTWF0Y2hRdWVyeUVudHJ5GjMKEU1hdGNoSGVhZGVyc0VudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEoCToCOAEaMQoPTWF0Y2hRdWVyeUVudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEoCToCOAEiuwIKDkFjdGlvbkFyZ3VtZW50EgwKBG5hbWUYASABKAkSDQoFdGl0bGUYAiABKAkSDAoEdHlwZRgDIAEoCRIVCg1kZWZhdWx0X3ZhbHVlGAQgASgJEjYKB2Nob2ljZXMYBSADKAsyJS5vbGl2ZXRpbi5hcGkudjEuQWN0aW9uQXJndW1lbnRDaG9pY2USEwoLZGVzY3JpcHRpb24YBiABKAkSRQoLc3VnZ2VzdGlvbnMYByADKAsyMC5vbGl2ZXRpbi5hcGkudjEuQWN0aW9uQXJndW1lbnQuU3VnZ2VzdGlvbnNFbnRyeRIfChdzdWdnZXN0aW9uc19icm93c2VyX2tleRgIIAEoCRoyChBTdWdnZXN0aW9uc0VudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEoCToCOAEiNAoUQWN0aW9uQXJndW1lbnRDaG9pY2USDQoFdmFsdWUYASABKAkSDQoFdGl0bGUYAiABKAki1AEKE0VudGl0eVJlbGF0ZWRBY3Rpb24SJwoGYWN0aW9uGAEgASgLMhcub2xpdmV0aW4uYXBpLnYxLkFjdGlvbhJZChNwcmVmaWxsZWRfYXJndW1lbnRzGAIgAygLMjwub2xpdmV0aW4uYXBpLnYxLkVudGl0eVJlbGF0ZWRBY3Rpb24uUHJlZmlsbGVkQXJndW1lbnRzRW50cnkaOQoXUHJlZmlsbGVkQXJndW1lbnRzRW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4ASL/AQoGRW50aXR5Eg0KBXRpdGxlGAEgASgJEhIKCnVuaXF1ZV9rZXkYAiABKAkSDAoEdHlwZRgDIAEoCRITCgtkaXJlY3RvcmllcxgEIAMoCRIzCgZmaWVsZHMYBSADKAsyIy5vbGl2ZXRpbi5hcGkudjEuRW50aXR5LkZpZWxkc0VudHJ5Ej0KD3JlbGF0ZWRfYWN0aW9ucxgGIAMoCzIkLm9saXZldGluLmFwaS52MS5FbnRpdHlSZWxhdGVkQWN0aW9uEgwKBGljb24YByABKAkaLQoLRmllbGRzRW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4ASJUChRHZXREYXNoYm9hcmRSZXNwb25zZRINCgV0aXRsZRgBIAEoCRItCglkYXNoYm9hcmQYBCABKAsyGi5vbGl2ZXRpbi5hcGkudjEuRGFzaGJvYXJkIl8KD0VmZmVjdGl2ZVBvbGljeRIYChBzaG93X2RpYWdub3N0aWNzGAEgASgIEhUKDXNob3dfbG9nX2xpc3QYAiABKAgSGwoTc2hvd192ZXJzaW9uX251bWJlchgDIAEoCCJNChNHZXREYXNoYm9hcmRSZXF1ZXN0Eg0KBXRpdGxlGAEgASgJEhMKC2VudGl0eV90eXBlGAIgASgJEhIKCmVudGl0eV9rZXkYAyABKAkiUQoJRGFzaGJvYXJkEg0KBXRpdGxlGAEgASgJEjUKCGNvbnRlbnRzGAIgAygLMiMub2xpdmV0aW4uYXBpLnYxLkRhc2hib2FyZENvbXBvbmVudCLbAQoSRGFzaGJvYXJkQ29tcG9uZW50Eg0KBXRpdGxlGAEgASgJEgwKBHR5cGUYAiABKAkSNQoIY29udGVudHMYAyADKAsyIy5vbGl2ZXRpbi5hcGkudjEuRGFzaGJvYXJkQ29tcG9uZW50EgwKBGljb24YBCABKAkSEQoJY3NzX2NsYXNzGAUgASgJEicKBmFjdGlvbhgGIAEoCzIXLm9saXZldGluLmFwaS52MS5BY3Rpb24SEwoLZW50aXR5X3R5cGUYByABKAkSEgoKZW50aXR5X2tleRgIIAEoCSKUAQoSU3RhcnRBY3Rpb25SZXF1ZXN0EhIKCmJpbmRpbmdfaWQYASABKAkSNwoJYXJndW1lbnRzGAIgAygLMiQub2xpdmV0aW4uYXBpLnYxLlN0YXJ0QWN0aW9uQXJndW1lbnQSGgoSdW5pcXVlX3RyYWNraW5nX2lkGAMgASgJEhUKDWp1c3RpZmljYXRpb24YBCABKAkiMgoTU3RhcnRBY3Rpb25Bcmd1bWVudBIMCgRuYW1lGAEgASgJEg0KBXZhbHVlGAIgASgJIjQKE1N0YXJ0QWN0aW9uUmVzcG9uc2USHQoVZXhlY3V0aW9uX3RyYWNraW5nX2lkGAIgASgJIn4KGVN0YXJ0QWN0aW9uQW5kV2FpdFJlcXVlc3QSEQoJYWN0aW9uX2lkGAEgASgJEjcKCWFyZ3VtZW50cxgCIAMoCzIkLm9saXZldGluLmFwaS52MS5TdGFydEFjdGlvbkFyZ3VtZW50EhUKDWp1c3RpZmljYXRpb24YAyABKAkiSgoaU3RhcnRBY3Rpb25BbmRXYWl0UmVzcG9uc2USLAoJbG9nX2VudHJ5GAEgASgLMhkub2xpdmV0aW4uYXBpLnYxLkxvZ0VudHJ5IiwKF1N0YXJ0QWN0aW9uQnlHZXRSZXF1ZXN0EhEKCWFjdGlvbl9pZBgBIAEoCSI5ChhTdGFydEFjdGlvbkJ5R2V0UmVzcG9uc2USHQoVZXhlY3V0aW9uX3RyYWNraW5nX2lkGAIgASgJIjMKHlN0YXJ0QWN0aW9uQnlHZXRBbmRXYWl0UmVxdWVzdBIRCglhY3Rpb25faWQYASABKAkiTwofU3RhcnRBY3Rpb25CeUdldEFuZFdhaXRSZXNwb25zZRIsCglsb2dfZW50cnkYASABKAsyGS5vbGl2ZXRpbi5hcGkudjEuTG9nRW50cnkiXgoOR2V0TG9nc1JlcXVlc3QSFAoMc3RhcnRfb2Zmc2V0GAEgASgDEhMKC2RhdGVfZmlsdGVyGAIgASgJEhEKCXBhZ2Vfc2l6ZRgDIAEoAxIOCgZmaWx0ZXIYBCABKAkilAQKCExvZ0VudHJ5EhgKEGRhdGV0aW1lX3N0YXJ0ZWQYASABKAkSFAoMYWN0aW9uX3RpdGxlGAIgASgJEg4KBm91dHB1dBgDIAEoCRIRCgl0aW1lZF9vdXQYBSABKAgSEQoJZXhpdF9jb2RlGAYgASgFEgwKBHVzZXIYByABKAkSEgoKdXNlcl9jbGFzcxgIIAEoCRITCgthY3Rpb25faWNvbhgJIAEoCRIMCgR0YWdzGAogAygJEh0KFWV4ZWN1dGlvbl90cmFja2luZ19pZBgLIAEoCRIZChFkYXRldGltZV9maW5pc2hlZBgMIAEoCRIZChFleGVjdXRpb25fc3RhcnRlZBgOIAEoCBIaChJleGVjdXRpb25fZmluaXNoZWQYDyABKAgSDwoHYmxvY2tlZBgQIAEoCBIWCg5kYXRldGltZV9pbmRleBgRIAEoAxIQCghjYW5fa2lsbBgSIAEoCBIjChtkYXRldGltZV9yYXRlX2xpbWl0X2V4cGlyZXMYEyABKAkSEgoKYmluZGluZ19pZBgUIAEoCRIOCgZxdWV1ZWQYFSABKAgSGAoQcXVldWVkX2Zvcl9ncm91cBgWIAEoCRIVCg1qdXN0aWZpY2F0aW9uGBcgASgJEjcKCWFyZ3VtZW50cxgYIAMoCzIkLm9saXZldGluLmFwaS52MS5TdGFydEFjdGlvbkFyZ3VtZW50IpEBCg9HZXRMb2dzUmVzcG9uc2USJwoEbG9ncxgBIAMoCzIZLm9saXZldGluLmFwaS52MS5Mb2dFbnRyeRIXCg9jb3VudF9yZW1haW5pbmcYAiABKAMSEQoJcGFnZV9zaXplGAMgASgDEhMKC3RvdGFsX2NvdW50GAQgASgDEhQKDHN0YXJ0X29mZnNldBgFIAEoAyI/ChRHZXRBY3Rpb25Mb2dzUmVxdWVzdBIRCglhY3Rpb25faWQYASABKAkSFAoMc3RhcnRfb2Zmc2V0GAIgASgDIpcBChVHZXRBY3Rpb25Mb2dzUmVzcG9uc2USJwoEbG9ncxgBIAMoCzIZLm9saXZldGluLmFwaS52MS5Mb2dFbnRyeRIXCg9jb3VudF9yZW1haW5pbmcYAiABKAMSEQoJcGFnZV9zaXplGAMgASgDEhMKC3RvdGFsX2NvdW50GAQgASgDEhQKDHN0YXJ0X29mZnNldBgFIAEoAyIaChhHZXRFeGVjdXRpb25RdWV1ZVJlcXVlc3QixgEKFEV4ZWN1dGlvblF1ZXVlQWN0aW9uEhIKCmJpbmRpbmdfaWQYASABKAkSFAoMYWN0aW9uX3RpdGxlGAIgASgJEhMKC2FjdGlvbl9pY29uGAMgASgJEhYKDm1heF9jb25jdXJyZW50GAQgASgFEhQKDGFjdGl2ZV9jb3VudBgFIAEoBRIVCg1lbnRpdHlfcHJlZml4GAYgASgJEioKB2VudHJpZXMYByADKAsyGS5vbGl2ZXRpbi5hcGkudjEuTG9nRW50cnkiwQEKE0V4ZWN1dGlvblF1ZXVlR3JvdXASDAoEbmFtZRgBIAEoCRIMCgRpY29uGAIgASgJEhYKDm1heF9jb25jdXJyZW50GAMgASgFEhQKDGFjdGl2ZV9jb3VudBgEIAEoBRI2CgdhY3Rpb25zGAUgAygLMiUub2xpdmV0aW4uYXBpLnYxLkV4ZWN1dGlvblF1ZXVlQWN0aW9uEhQKDHF1ZXVlZF9jb3VudBgGIAEoBRISCgpxdWV1ZV9zaXplGAcgASgFImcKGUdldEV4ZWN1dGlvblF1ZXVlUmVzcG9uc2USNAoGZ3JvdXBzGAEgAygLMiQub2xpdmV0aW4uYXBpLnYxLkV4ZWN1dGlvblF1ZXVlR3JvdXASFAoMdG90YWxfYWN0aXZlGAIgASgFImUKG1ZhbGlkYXRlQXJndW1lbnRUeXBlUmVxdWVzdBINCgV2YWx1ZRgBIAEoCRIMCgR0eXBlGAIgASgJEhIKCmJpbmRpbmdfaWQYAyABKAkSFQoNYXJndW1lbnRfbmFtZRgEIAEoCSJCChxWYWxpZGF0ZUFyZ3VtZW50VHlwZVJlc3BvbnNlEg0KBXZhbGlkGAEgASgIEhMKC2Rlc2NyaXB0aW9uGAIgASgJIjYKFVdhdGNoRXhlY3V0aW9uUmVxdWVzdBIdChVleGVjdXRpb25fdHJhY2tpbmdfaWQYASABKAkiJgoUV2F0Y2hFeGVjdXRpb25VcGRhdGUSDgoGdXBkYXRlGAEgASgJIkoKFkV4ZWN1dGlvblN0YXR1c1JlcXVlc3QSHQoVZXhlY3V0aW9uX3RyYWNraW5nX2lkGAEgASgJEhEKCWFjdGlvbl9pZBgCIAEoCSJhChlEYXNoYm9hcmROYXZpZ2F0aW9uVGFyZ2V0Eg0KBXRpdGxlGAEgASgJEhMKC2VudGl0eV90eXBlGAIgASgJEhIKCmVudGl0eV9rZXkYAyABKAkSDAoEcGF0aBgEIAEoCSKPAQoXRXhlY3V0aW9uU3RhdHVzUmVzcG9uc2USLAoJbG9nX2VudHJ5GAEgASgLMhkub2xpdmV0aW4uYXBpLnYxLkxvZ0VudHJ5EkYKEmJhY2tfdG9fZGFzaGJvYXJkcxgCIAMoCzIqLm9saXZldGluLmFwaS52MS5EYXNoYm9hcmROYXZpZ2F0aW9uVGFyZ2V0Ig8KDVdob0FtSVJlcXVlc3QibAoOV2hvQW1JUmVzcG9uc2USGgoSYXV0aGVudGljYXRlZF91c2VyGAEgASgJEhEKCXVzZXJncm91cBgCIAEoCRIQCghwcm92aWRlchgDIAEoCRIMCgRhY2xzGAQgAygJEgsKA3NpZBgFIAEoCSISChBTb3NSZXBvcnRSZXF1ZXN0IiIKEVNvc1JlcG9ydFJlc3BvbnNlEg0KBWFsZXJ0GAEgASgJIhEKD0R1bXBWYXJzUmVxdWVzdCKVAQoQRHVtcFZhcnNSZXNwb25zZRINCgVhbGVydBgBIAEoCRJBCghjb250ZW50cxgCIAMoCzIvLm9saXZldGluLmFwaS52MS5EdW1wVmFyc1Jlc3BvbnNlLkNvbnRlbnRzRW50cnkaLwoNQ29udGVudHNFbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAk6AjgBIjsKDERlYnVnQmluZGluZxIUCgxhY3Rpb25fdGl0bGUYASABKAkSFQoNZW50aXR5X3ByZWZpeBgCIAEoCSIeChxEdW1wUHVibGljSWRBY3Rpb25NYXBSZXF1ZXN0Is4BCh1EdW1wUHVibGljSWRBY3Rpb25NYXBSZXNwb25zZRINCgVhbGVydBgBIAEoCRJOCghjb250ZW50cxgCIAMoCzI8Lm9saXZldGluLmFwaS52MS5EdW1wUHVibGljSWRBY3Rpb25NYXBSZXNwb25zZS5Db250ZW50c0VudHJ5Gk4KDUNvbnRlbnRzRW50cnkSCwoDa2V5GAEgASgJEiwKBXZhbHVlGAIgASgLMh0ub2xpdmV0aW4uYXBpLnYxLkRlYnVnQmluZGluZzoCOAEiEgoQR2V0UmVhZHl6UmVxdWVzdCIjChFHZXRSZWFkeXpSZXNwb25zZRIOCgZzdGF0dXMYASABKAkiFAoSRXZlbnRTdHJlYW1SZXF1ZXN0IpkDChNFdmVudFN0cmVhbVJlc3BvbnNlEj0KDmVudGl0eV9jaGFuZ2VkGAIgASgLMiMub2xpdmV0aW4uYXBpLnYxLkV2ZW50RW50aXR5Q2hhbmdlZEgAEj0KDmNvbmZpZ19jaGFuZ2VkGAMgASgLMiMub2xpdmV0aW4uYXBpLnYxLkV2ZW50Q29uZmlnQ2hhbmdlZEgAEkUKEmV4ZWN1dGlvbl9maW5pc2hlZBgEIAEoCzInLm9saXZldGluLmFwaS52MS5FdmVudEV4ZWN1dGlvbkZpbmlzaGVkSAASQwoRZXhlY3V0aW9uX3N0YXJ0ZWQYBSABKAsyJi5vbGl2ZXRpbi5hcGkudjEuRXZlbnRFeGVjdXRpb25TdGFydGVkSAASOQoMb3V0cHV0X2NodW5rGAYgASgLMiEub2xpdmV0aW4uYXBpLnYxLkV2ZW50T3V0cHV0Q2h1bmtIABI0CgloZWFydGJlYXQYByABKAsyHy5vbGl2ZXRpbi5hcGkudjEuRXZlbnRIZWFydGJlYXRIAEIHCgVldmVudCJBChBFdmVudE91dHB1dENodW5rEh0KFWV4ZWN1dGlvbl90cmFja2luZ19pZBgBIAEoCRIOCgZvdXRwdXQYAiABKAkiFAoSRXZlbnRFbnRpdHlDaGFuZ2VkIhQKEkV2ZW50Q29uZmlnQ2hhbmdlZCIQCg5FdmVudEhlYXJ0YmVhdCJGChZFdmVudEV4ZWN1dGlvbkZpbmlzaGVkEiwKCWxvZ19lbnRyeRgBIAEoCzIZLm9saXZldGluLmFwaS52MS5Mb2dFbnRyeSJFChVFdmVudEV4ZWN1dGlvblN0YXJ0ZWQSLAoJbG9nX2VudHJ5GAEgASgLMhkub2xpdmV0aW4uYXBpLnYxLkxvZ0VudHJ5IjIKEUtpbGxBY3Rpb25SZXF1ZXN0Eh0KFWV4ZWN1dGlvbl90cmFja2luZ19pZBgBIAEoCSJtChJLaWxsQWN0aW9uUmVzcG9uc2USHQoVZXhlY3V0aW9uX3RyYWNraW5nX2lkGAEgASgJEg4KBmtpbGxlZBgCIAEoCBIZChFhbHJlYWR5X2NvbXBsZXRlZBgDIAEoCBINCgVmb3VuZBgEIAEoCCI7ChVMb2NhbFVzZXJMb2dpblJlcXVlc3QSEAoIdXNlcm5hbWUYASABKAkSEAoIcGFzc3dvcmQYAiABKAkiKQoWTG9jYWxVc2VyTG9naW5SZXNwb25zZRIPCgdzdWNjZXNzGAEgASgIIicKE1Bhc3N3b3JkSGFzaFJlcXVlc3QSEAoIcGFzc3dvcmQYASABKAkiJAoUUGFzc3dvcmRIYXNoUmVzcG9uc2USDAoEaGFzaBgBIAEoCSIPCg1Mb2dvdXRSZXF1ZXN0IhAKDkxvZ291dFJlc3BvbnNlIhcKFUdldERpYWdub3N0aWNzUmVxdWVzdCJFChZHZXREaWFnbm9zdGljc1Jlc3BvbnNlEhMKC1NzaEZvdW5kS2V5GAEgASgJEhYKDlNzaEZvdW5kQ29uZmlnGAIgASgJIg0KC0luaXRSZXF1ZXN0IusFCgxJbml0UmVzcG9uc2USEgoKc2hvd0Zvb3RlchgBIAEoCBIWCg5zaG93TmF2aWdhdGlvbhgCIAEoCBIXCg9zaG93TmV3VmVyc2lvbnMYAyABKAgSGAoQYXZhaWxhYmxlVmVyc2lvbhgEIAEoCRIWCg5jdXJyZW50VmVyc2lvbhgFIAEoCRIRCglwYWdlVGl0bGUYBiABKAkSHgoWc2VjdGlvbk5hdmlnYXRpb25TdHlsZRgHIAEoCRIaChJkZWZhdWx0SWNvbkZvckJhY2sYCCABKAkSFgoOZW5hYmxlQ3VzdG9tSnMYCSABKAgSFAoMYXV0aExvZ2luVXJsGAogASgJEhYKDmF1dGhMb2NhbExvZ2luGAsgASgIEhEKCXN0eWxlTW9kcxgMIAMoCRI4Cg9vQXV0aDJQcm92aWRlcnMYDSADKAsyHy5vbGl2ZXRpbi5hcGkudjEuT0F1dGgyUHJvdmlkZXISOAoPYWRkaXRpb25hbExpbmtzGA4gAygLMh8ub2xpdmV0aW4uYXBpLnYxLkFkZGl0aW9uYWxMaW5rEhYKDnJvb3REYXNoYm9hcmRzGA8gAygJEhoKEmF1dGhlbnRpY2F0ZWRfdXNlchgQIAEoCRIjChthdXRoZW50aWNhdGVkX3VzZXJfcHJvdmlkZXIYESABKAkSOgoQZWZmZWN0aXZlX3BvbGljeRgSIAEoCzIgLm9saXZldGluLmFwaS52MS5FZmZlY3RpdmVQb2xpY3kSFgoOYmFubmVyX21lc3NhZ2UYEyABKAkSEgoKYmFubmVyX2NzcxgUIAEoCRIYChBzaG93X2RpYWdub3N0aWNzGBUgASgIEhUKDXNob3dfbG9nX2xpc3QYFiABKAgSFgoObG9naW5fcmVxdWlyZWQYFyABKAgSGAoQYXZhaWxhYmxlX3RoZW1lcxgYIAMoCRIkChxzaG93X25hdmlnYXRlX29uX3N0YXJ0X2ljb25zGBkgASgIIiwKDkFkZGl0aW9uYWxMaW5rEg0KBXRpdGxlGAEgASgJEgsKA3VybBgCIAEoCSI6Cg5PQXV0aDJQcm92aWRlchINCgV0aXRsZRgBIAEoCRIMCgRpY29uGAMgASgJEgsKA2tleRgEIAEoCSItChdHZXRBY3Rpb25CaW5kaW5nUmVxdWVzdBISCgpiaW5kaW5nX2lkGAEgASgJIosBChhHZXRBY3Rpb25CaW5kaW5nUmVzcG9uc2USJwoGYWN0aW9uGAEgASgLMhcub2xpdmV0aW4uYXBpLnYxLkFjdGlvbhJGChJiYWNrX3RvX2Rhc2hib2FyZHMYAiADKAsyKi5vbGl2ZXRpbi5hcGkudjEuRGFzaGJvYXJkTmF2aWdhdGlvblRhcmdldCJaChJHZXRFbnRpdGllc1JlcXVlc3QSEwoLZW50aXR5X3R5cGUYASABKAkSDgoGZmlsdGVyGAIgASgJEgwKBHBhZ2UYAyABKAUSEQoJcGFnZV9zaXplGAQgASgFIlQKE0dldEVudGl0aWVzUmVzcG9uc2USPQoSZW50aXR5X2RlZmluaXRpb25zGAEgAygLMiEub2xpdmV0aW4uYXBpLnYxLkVudGl0eURlZmluaXRpb24ixQEKEEVudGl0eURlZmluaXRpb24SDQoFdGl0bGUYASABKAkSKgoJaW5zdGFuY2VzGAIgAygLMhcub2xpdmV0aW4uYXBpLnYxLkVudGl0eRIaChJ1c2VkX29uX2Rhc2hib2FyZHMYAyADKAkSDAoEaWNvbhgEIAEoCRIzCgpwcm9wZXJ0aWVzGAUgAygLMh8ub2xpdmV0aW4uYXBpLnYxLkVudGl0eVByb3BlcnR5EhcKD3RvdGFsX2luc3RhbmNlcxgGIAEoBSItCg5FbnRpdHlQcm9wZXJ0eRIMCgRuYW1lGAEgASgJEg0KBXRpdGxlGAIgASgJIjQKEEdldEVudGl0eVJlcXVlc3QSEgoKdW5pcXVlX2tleRgBIAEoCRIMCgR0eXBlGAIgASgJIjUKFFJlc3RhcnRBY3Rpb25SZXF1ZXN0Eh0KFWV4ZWN1dGlvbl90cmFja2luZ19pZBgBIAEoCTLWEwoST2xpdmVUaW5BcGlTZXJ2aWNlEl0KDEdldERhc2hib2FyZBIkLm9saXZldGluLmFwaS52MS5HZXREYXNoYm9hcmRSZXF1ZXN0GiUub2xpdmV0aW4uYXBpLnYxLkdldERhc2hib2FyZFJlc3BvbnNlIgASWgoLU3RhcnRBY3Rpb24SIy5vbGl2ZXRpbi5hcGkudjEuU3RhcnRBY3Rpb25SZXF1ZXN0GiQub2xpdmV0aW4uYXBpLnYxLlN0YXJ0QWN0aW9uUmVzcG9uc2UiABJvChJTdGFydEFjdGlvbkFuZFdhaXQSKi5vbGl2ZXRpbi5hcGkudjEuU3RhcnRBY3Rpb25BbmRXYWl0UmVxdWVzdBorLm9saXZldGluLmFwaS52MS5TdGFydEFjdGlvbkFuZFdhaXRSZXNwb25zZSIAEmkKEFN0YXJ0QWN0aW9uQnlHZXQSKC5vbGl2ZXRpbi5hcGkudjEuU3RhcnRBY3Rpb25CeUdldFJlcXVlc3QaKS5vbGl2ZXRpbi5hcGkudjEuU3RhcnRBY3Rpb25CeUdldFJlc3BvbnNlIgASfgoXU3RhcnRBY3Rpb25CeUdldEFuZFdhaXQSLy5vbGl2ZXRpbi5hcGkudjEuU3RhcnRBY3Rpb25CeUdldEFuZFdhaXRSZXF1ZXN0GjAub2xpdmV0aW4uYXBpLnYxLlN0YXJ0QWN0aW9uQnlHZXRBbmRXYWl0UmVzcG9uc2UiABJeCg1SZXN0YXJ0QWN0aW9uEiUub2xpdmV0aW4uYXBpLnYxLlJlc3RhcnRBY3Rpb25SZXF1ZXN0GiQub2xpdmV0aW4uYXBpLnYxLlN0YXJ0QWN0aW9uUmVzcG9uc2UiABJXCgpLaWxsQWN0aW9uEiIub2xpdmV0aW4uYXBpLnYxLktpbGxBY3Rpb25SZXF1ZXN0GiMub2xpdmV0aW4uYXBpLnYxLktpbGxBY3Rpb25SZXNwb25zZSIAEmYKD0V4ZWN1dGlvblN0YXR1cxInLm9saXZldGluLmFwaS52MS5FeGVjdXRpb25TdGF0dXNSZXF1ZXN0Gigub2xpdmV0aW4uYXBpLnYxLkV4ZWN1dGlvblN0YXR1c1Jlc3BvbnNlIgASTgoHR2V0TG9ncxIfLm9saXZldGluLmFwaS52MS5HZXRMb2dzUmVxdWVzdBogLm9saXZldGluLmFwaS52MS5HZXRMb2dzUmVzcG9uc2UiABJgCg1HZXRBY3Rpb25Mb2dzEiUub2xpdmV0aW4uYXBpLnYxLkdldEFjdGlvbkxvZ3NSZXF1ZXN0GiYub2xpdmV0aW4uYXBpLnYxLkdldEFjdGlvbkxvZ3NSZXNwb25zZSIAEmwKEUdldEV4ZWN1dGlvblF1ZXVlEikub2xpdmV0aW4uYXBpLnYxLkdldEV4ZWN1dGlvblF1ZXVlUmVxdWVzdBoqLm9saXZldGluLmFwaS52MS5HZXRFeGVjdXRpb25RdWV1ZVJlc3BvbnNlIgASdQoUVmFsaWRhdGVBcmd1bWVudFR5cGUSLC5vbGl2ZXRpbi5hcGkudjEuVmFsaWRhdGVBcmd1bWVudFR5cGVSZXF1ZXN0Gi0ub2xpdmV0aW4uYXBpLnYxLlZhbGlkYXRlQXJndW1lbnRUeXBlUmVzcG9uc2UiABJLCgZXaG9BbUkSHi5vbGl2ZXRpbi5hcGkudjEuV2hvQW1JUmVxdWVzdBofLm9saXZldGluLmFwaS52MS5XaG9BbUlSZXNwb25zZSIAElQKCVNvc1JlcG9ydBIhLm9saXZldGluLmFwaS52MS5Tb3NSZXBvcnRSZXF1ZXN0GiIub2xpdmV0aW4uYXBpLnYxLlNvc1JlcG9ydFJlc3BvbnNlIgASUQoIRHVtcFZhcnMSIC5vbGl2ZXRpbi5hcGkudjEuRHVtcFZhcnNSZXF1ZXN0GiEub2xpdmV0aW4uYXBpLnYxLkR1bXBWYXJzUmVzcG9uc2UiABJ4ChVEdW1wUHVibGljSWRBY3Rpb25NYXASLS5vbGl2ZXRpbi5hcGkudjEuRHVtcFB1YmxpY0lkQWN0aW9uTWFwUmVxdWVzdBouLm9saXZldGluLmFwaS52MS5EdW1wUHVibGljSWRBY3Rpb25NYXBSZXNwb25zZSIAElQKCUdldFJlYWR5ehIhLm9saXZldGluLmFwaS52MS5HZXRSZWFkeXpSZXF1ZXN0GiIub2xpdmV0aW4uYXBpLnYxLkdldFJlYWR5elJlc3BvbnNlIgASYwoOTG9jYWxVc2VyTG9naW4SJi5vbGl2ZXRpbi5hcGkudjEuTG9jYWxVc2VyTG9naW5SZXF1ZXN0Gicub2xpdmV0aW4uYXBpLnYxLkxvY2FsVXNlckxvZ2luUmVzcG9uc2UiABJdCgxQYXNzd29yZEhhc2gSJC5vbGl2ZXRpbi5hcGkudjEuUGFzc3dvcmRIYXNoUmVxdWVzdBolLm9saXZldGluLmFwaS52MS5QYXNzd29yZEhhc2hSZXNwb25zZSIAEksKBkxvZ291dBIeLm9saXZldGluLmFwaS52MS5Mb2dvdXRSZXF1ZXN0Gh8ub2xpdmV0aW4uYXBpLnYxLkxvZ291dFJlc3BvbnNlIgASXAoLRXZlbnRTdHJlYW0SIy5vbGl2ZXRpbi5hcGkudjEuRXZlbnRTdHJlYW1SZXF1ZXN0GiQub2xpdmV0aW4uYXBpLnYxLkV2ZW50U3RyZWFtUmVzcG9uc2UiADABEmMKDkdldERpYWdub3N0aWNzEiYub2xpdmV0aW4uYXBpLnYxLkdldERpYWdub3N0aWNzUmVxdWVzdBonLm9saXZldGluLmFwaS52MS5HZXREaWFnbm9zdGljc1Jlc3BvbnNlIgASRQoESW5pdBIcLm9saXZldGluLmFwaS52MS5Jbml0UmVxdWVzdBodLm9saXZldGluLmFwaS52MS5Jbml0UmVzcG9uc2UiABJpChBHZXRBY3Rpb25CaW5kaW5nEigub2xpdmV0aW4uYXBpLnYxLkdldEFjdGlvbkJpbmRpbmdSZXF1ZXN0Gikub2xpdmV0aW4uYXBpLnYxLkdldEFjdGlvbkJpbmRpbmdSZXNwb25zZSIAEloKC0dldEVudGl0aWVzEiMub2xpdmV0aW4uYXBpLnYxLkdldEVudGl0aWVzUmVxdWVzdBokLm9saXZldGluLmFwaS52MS5HZXRFbnRpdGllc1Jlc3BvbnNlIgASSQoJR2V0RW50aXR5EiEub2xpdmV0aW4uYXBpLnYxLkdldEVudGl0eVJlcXVlc3QaFy5vbGl2ZXRpbi5hcGkudjEuRW50aXR5IgBCOFo2Z2l0aHViLmNvbS9PbGl2ZVRpbi9PbGl2ZVRpbi9nZW4vb2xpdmV0aW4vYXBpL3YxO2FwaXYxYgZwcm90bzM"); + fileDesc("Ch5vbGl2ZXRpbi9hcGkvdjEvb2xpdmV0aW4ucHJvdG8SD29saXZldGluLmFwaS52MSLGBAoGQWN0aW9uEhIKCmJpbmRpbmdfaWQYASABKAkSDQoFdGl0bGUYAiABKAkSDAoEaWNvbhgDIAEoCRIQCghjYW5fZXhlYxgEIAEoCBIyCglhcmd1bWVudHMYBSADKAsyHy5vbGl2ZXRpbi5hcGkudjEuQWN0aW9uQXJndW1lbnQSFgoOcG9wdXBfb25fc3RhcnQYBiABKAkSDQoFb3JkZXIYByABKAUSDwoHdGltZW91dBgIIAEoBRIjChtkYXRldGltZV9yYXRlX2xpbWl0X2V4cGlyZXMYCSABKAkSFwoPZXhlY19vbl9zdGFydHVwGAogASgIEhQKDGV4ZWNfb25fY3JvbhgLIAMoCRIjChtleGVjX29uX2ZpbGVfY3JlYXRlZF9pbl9kaXIYDCADKAkSIwobZXhlY19vbl9maWxlX2NoYW5nZWRfaW5fZGlyGA0gAygJEh0KFWV4ZWNfb25fY2FsZW5kYXJfZmlsZRgOIAEoCRJAChBleGVjX29uX3dlYmhvb2tzGA8gAygLMiYub2xpdmV0aW4uYXBpLnYxLkFjdGlvbldlYmhvb2tFeGVjSGludBIVCg1qdXN0aWZpY2F0aW9uGBQgASgJEhwKFGhhc19ydW5uaW5nX2luc3RhbmNlGBEgASgIEhsKE2hhc19xdWV1ZWRfaW5zdGFuY2UYEiABKAgSNgoGZ3JvdXBzGBMgAygLMiYub2xpdmV0aW4uYXBpLnYxLkFjdGlvbkdyb3VwTWVtYmVyc2hpcEoECBAQESJRChVBY3Rpb25Hcm91cE1lbWJlcnNoaXASDAoEbmFtZRgBIAEoCRIWCg5tYXhfY29uY3VycmVudBgCIAEoBRISCgpxdWV1ZV9zaXplGAMgASgFIsMCChVBY3Rpb25XZWJob29rRXhlY0hpbnQSEAoIdGVtcGxhdGUYASABKAkSEgoKbWF0Y2hfcGF0aBgCIAEoCRJPCg1tYXRjaF9oZWFkZXJzGAMgAygLMjgub2xpdmV0aW4uYXBpLnYxLkFjdGlvbldlYmhvb2tFeGVjSGludC5NYXRjaEhlYWRlcnNFbnRyeRJLCgttYXRjaF9xdWVyeRgEIAMoCzI2Lm9saXZldGluLmFwaS52MS5BY3Rpb25XZWJob29rRXhlY0hpbnQuTWF0Y2hRdWVyeUVudHJ5GjMKEU1hdGNoSGVhZGVyc0VudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEoCToCOAEaMQoPTWF0Y2hRdWVyeUVudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEoCToCOAEiuwIKDkFjdGlvbkFyZ3VtZW50EgwKBG5hbWUYASABKAkSDQoFdGl0bGUYAiABKAkSDAoEdHlwZRgDIAEoCRIVCg1kZWZhdWx0X3ZhbHVlGAQgASgJEjYKB2Nob2ljZXMYBSADKAsyJS5vbGl2ZXRpbi5hcGkudjEuQWN0aW9uQXJndW1lbnRDaG9pY2USEwoLZGVzY3JpcHRpb24YBiABKAkSRQoLc3VnZ2VzdGlvbnMYByADKAsyMC5vbGl2ZXRpbi5hcGkudjEuQWN0aW9uQXJndW1lbnQuU3VnZ2VzdGlvbnNFbnRyeRIfChdzdWdnZXN0aW9uc19icm93c2VyX2tleRgIIAEoCRoyChBTdWdnZXN0aW9uc0VudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEoCToCOAEiNAoUQWN0aW9uQXJndW1lbnRDaG9pY2USDQoFdmFsdWUYASABKAkSDQoFdGl0bGUYAiABKAki1AEKE0VudGl0eVJlbGF0ZWRBY3Rpb24SJwoGYWN0aW9uGAEgASgLMhcub2xpdmV0aW4uYXBpLnYxLkFjdGlvbhJZChNwcmVmaWxsZWRfYXJndW1lbnRzGAIgAygLMjwub2xpdmV0aW4uYXBpLnYxLkVudGl0eVJlbGF0ZWRBY3Rpb24uUHJlZmlsbGVkQXJndW1lbnRzRW50cnkaOQoXUHJlZmlsbGVkQXJndW1lbnRzRW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4ASL/AQoGRW50aXR5Eg0KBXRpdGxlGAEgASgJEhIKCnVuaXF1ZV9rZXkYAiABKAkSDAoEdHlwZRgDIAEoCRITCgtkaXJlY3RvcmllcxgEIAMoCRIzCgZmaWVsZHMYBSADKAsyIy5vbGl2ZXRpbi5hcGkudjEuRW50aXR5LkZpZWxkc0VudHJ5Ej0KD3JlbGF0ZWRfYWN0aW9ucxgGIAMoCzIkLm9saXZldGluLmFwaS52MS5FbnRpdHlSZWxhdGVkQWN0aW9uEgwKBGljb24YByABKAkaLQoLRmllbGRzRW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4ASJUChRHZXREYXNoYm9hcmRSZXNwb25zZRINCgV0aXRsZRgBIAEoCRItCglkYXNoYm9hcmQYBCABKAsyGi5vbGl2ZXRpbi5hcGkudjEuRGFzaGJvYXJkIl8KD0VmZmVjdGl2ZVBvbGljeRIYChBzaG93X2RpYWdub3N0aWNzGAEgASgIEhUKDXNob3dfbG9nX2xpc3QYAiABKAgSGwoTc2hvd192ZXJzaW9uX251bWJlchgDIAEoCCJNChNHZXREYXNoYm9hcmRSZXF1ZXN0Eg0KBXRpdGxlGAEgASgJEhMKC2VudGl0eV90eXBlGAIgASgJEhIKCmVudGl0eV9rZXkYAyABKAkiUQoJRGFzaGJvYXJkEg0KBXRpdGxlGAEgASgJEjUKCGNvbnRlbnRzGAIgAygLMiMub2xpdmV0aW4uYXBpLnYxLkRhc2hib2FyZENvbXBvbmVudCLbAQoSRGFzaGJvYXJkQ29tcG9uZW50Eg0KBXRpdGxlGAEgASgJEgwKBHR5cGUYAiABKAkSNQoIY29udGVudHMYAyADKAsyIy5vbGl2ZXRpbi5hcGkudjEuRGFzaGJvYXJkQ29tcG9uZW50EgwKBGljb24YBCABKAkSEQoJY3NzX2NsYXNzGAUgASgJEicKBmFjdGlvbhgGIAEoCzIXLm9saXZldGluLmFwaS52MS5BY3Rpb24SEwoLZW50aXR5X3R5cGUYByABKAkSEgoKZW50aXR5X2tleRgIIAEoCSKUAQoSU3RhcnRBY3Rpb25SZXF1ZXN0EhIKCmJpbmRpbmdfaWQYASABKAkSNwoJYXJndW1lbnRzGAIgAygLMiQub2xpdmV0aW4uYXBpLnYxLlN0YXJ0QWN0aW9uQXJndW1lbnQSGgoSdW5pcXVlX3RyYWNraW5nX2lkGAMgASgJEhUKDWp1c3RpZmljYXRpb24YBCABKAkiMgoTU3RhcnRBY3Rpb25Bcmd1bWVudBIMCgRuYW1lGAEgASgJEg0KBXZhbHVlGAIgASgJIjQKE1N0YXJ0QWN0aW9uUmVzcG9uc2USHQoVZXhlY3V0aW9uX3RyYWNraW5nX2lkGAIgASgJIn4KGVN0YXJ0QWN0aW9uQW5kV2FpdFJlcXVlc3QSEQoJYWN0aW9uX2lkGAEgASgJEjcKCWFyZ3VtZW50cxgCIAMoCzIkLm9saXZldGluLmFwaS52MS5TdGFydEFjdGlvbkFyZ3VtZW50EhUKDWp1c3RpZmljYXRpb24YAyABKAkiSgoaU3RhcnRBY3Rpb25BbmRXYWl0UmVzcG9uc2USLAoJbG9nX2VudHJ5GAEgASgLMhkub2xpdmV0aW4uYXBpLnYxLkxvZ0VudHJ5IiwKF1N0YXJ0QWN0aW9uQnlHZXRSZXF1ZXN0EhEKCWFjdGlvbl9pZBgBIAEoCSI5ChhTdGFydEFjdGlvbkJ5R2V0UmVzcG9uc2USHQoVZXhlY3V0aW9uX3RyYWNraW5nX2lkGAIgASgJIjMKHlN0YXJ0QWN0aW9uQnlHZXRBbmRXYWl0UmVxdWVzdBIRCglhY3Rpb25faWQYASABKAkiTwofU3RhcnRBY3Rpb25CeUdldEFuZFdhaXRSZXNwb25zZRIsCglsb2dfZW50cnkYASABKAsyGS5vbGl2ZXRpbi5hcGkudjEuTG9nRW50cnkiXgoOR2V0TG9nc1JlcXVlc3QSFAoMc3RhcnRfb2Zmc2V0GAEgASgDEhMKC2RhdGVfZmlsdGVyGAIgASgJEhEKCXBhZ2Vfc2l6ZRgDIAEoAxIOCgZmaWx0ZXIYBCABKAkilAQKCExvZ0VudHJ5EhgKEGRhdGV0aW1lX3N0YXJ0ZWQYASABKAkSFAoMYWN0aW9uX3RpdGxlGAIgASgJEg4KBm91dHB1dBgDIAEoCRIRCgl0aW1lZF9vdXQYBSABKAgSEQoJZXhpdF9jb2RlGAYgASgFEgwKBHVzZXIYByABKAkSEgoKdXNlcl9jbGFzcxgIIAEoCRITCgthY3Rpb25faWNvbhgJIAEoCRIMCgR0YWdzGAogAygJEh0KFWV4ZWN1dGlvbl90cmFja2luZ19pZBgLIAEoCRIZChFkYXRldGltZV9maW5pc2hlZBgMIAEoCRIZChFleGVjdXRpb25fc3RhcnRlZBgOIAEoCBIaChJleGVjdXRpb25fZmluaXNoZWQYDyABKAgSDwoHYmxvY2tlZBgQIAEoCBIWCg5kYXRldGltZV9pbmRleBgRIAEoAxIQCghjYW5fa2lsbBgSIAEoCBIjChtkYXRldGltZV9yYXRlX2xpbWl0X2V4cGlyZXMYEyABKAkSEgoKYmluZGluZ19pZBgUIAEoCRIOCgZxdWV1ZWQYFSABKAgSGAoQcXVldWVkX2Zvcl9ncm91cBgWIAEoCRIVCg1qdXN0aWZpY2F0aW9uGBcgASgJEjcKCWFyZ3VtZW50cxgYIAMoCzIkLm9saXZldGluLmFwaS52MS5TdGFydEFjdGlvbkFyZ3VtZW50IpEBCg9HZXRMb2dzUmVzcG9uc2USJwoEbG9ncxgBIAMoCzIZLm9saXZldGluLmFwaS52MS5Mb2dFbnRyeRIXCg9jb3VudF9yZW1haW5pbmcYAiABKAMSEQoJcGFnZV9zaXplGAMgASgDEhMKC3RvdGFsX2NvdW50GAQgASgDEhQKDHN0YXJ0X29mZnNldBgFIAEoAyI/ChRHZXRBY3Rpb25Mb2dzUmVxdWVzdBIRCglhY3Rpb25faWQYASABKAkSFAoMc3RhcnRfb2Zmc2V0GAIgASgDIpcBChVHZXRBY3Rpb25Mb2dzUmVzcG9uc2USJwoEbG9ncxgBIAMoCzIZLm9saXZldGluLmFwaS52MS5Mb2dFbnRyeRIXCg9jb3VudF9yZW1haW5pbmcYAiABKAMSEQoJcGFnZV9zaXplGAMgASgDEhMKC3RvdGFsX2NvdW50GAQgASgDEhQKDHN0YXJ0X29mZnNldBgFIAEoAyIaChhHZXRFeGVjdXRpb25RdWV1ZVJlcXVlc3QixgEKFEV4ZWN1dGlvblF1ZXVlQWN0aW9uEhIKCmJpbmRpbmdfaWQYASABKAkSFAoMYWN0aW9uX3RpdGxlGAIgASgJEhMKC2FjdGlvbl9pY29uGAMgASgJEhYKDm1heF9jb25jdXJyZW50GAQgASgFEhQKDGFjdGl2ZV9jb3VudBgFIAEoBRIVCg1lbnRpdHlfcHJlZml4GAYgASgJEioKB2VudHJpZXMYByADKAsyGS5vbGl2ZXRpbi5hcGkudjEuTG9nRW50cnkiwQEKE0V4ZWN1dGlvblF1ZXVlR3JvdXASDAoEbmFtZRgBIAEoCRIMCgRpY29uGAIgASgJEhYKDm1heF9jb25jdXJyZW50GAMgASgFEhQKDGFjdGl2ZV9jb3VudBgEIAEoBRI2CgdhY3Rpb25zGAUgAygLMiUub2xpdmV0aW4uYXBpLnYxLkV4ZWN1dGlvblF1ZXVlQWN0aW9uEhQKDHF1ZXVlZF9jb3VudBgGIAEoBRISCgpxdWV1ZV9zaXplGAcgASgFImcKGUdldEV4ZWN1dGlvblF1ZXVlUmVzcG9uc2USNAoGZ3JvdXBzGAEgAygLMiQub2xpdmV0aW4uYXBpLnYxLkV4ZWN1dGlvblF1ZXVlR3JvdXASFAoMdG90YWxfYWN0aXZlGAIgASgFImUKG1ZhbGlkYXRlQXJndW1lbnRUeXBlUmVxdWVzdBINCgV2YWx1ZRgBIAEoCRIMCgR0eXBlGAIgASgJEhIKCmJpbmRpbmdfaWQYAyABKAkSFQoNYXJndW1lbnRfbmFtZRgEIAEoCSJCChxWYWxpZGF0ZUFyZ3VtZW50VHlwZVJlc3BvbnNlEg0KBXZhbGlkGAEgASgIEhMKC2Rlc2NyaXB0aW9uGAIgASgJIjYKFVdhdGNoRXhlY3V0aW9uUmVxdWVzdBIdChVleGVjdXRpb25fdHJhY2tpbmdfaWQYASABKAkiJgoUV2F0Y2hFeGVjdXRpb25VcGRhdGUSDgoGdXBkYXRlGAEgASgJIkoKFkV4ZWN1dGlvblN0YXR1c1JlcXVlc3QSHQoVZXhlY3V0aW9uX3RyYWNraW5nX2lkGAEgASgJEhEKCWFjdGlvbl9pZBgCIAEoCSJhChlEYXNoYm9hcmROYXZpZ2F0aW9uVGFyZ2V0Eg0KBXRpdGxlGAEgASgJEhMKC2VudGl0eV90eXBlGAIgASgJEhIKCmVudGl0eV9rZXkYAyABKAkSDAoEcGF0aBgEIAEoCSKPAQoXRXhlY3V0aW9uU3RhdHVzUmVzcG9uc2USLAoJbG9nX2VudHJ5GAEgASgLMhkub2xpdmV0aW4uYXBpLnYxLkxvZ0VudHJ5EkYKEmJhY2tfdG9fZGFzaGJvYXJkcxgCIAMoCzIqLm9saXZldGluLmFwaS52MS5EYXNoYm9hcmROYXZpZ2F0aW9uVGFyZ2V0Ig8KDVdob0FtSVJlcXVlc3QibAoOV2hvQW1JUmVzcG9uc2USGgoSYXV0aGVudGljYXRlZF91c2VyGAEgASgJEhEKCXVzZXJncm91cBgCIAEoCRIQCghwcm92aWRlchgDIAEoCRIMCgRhY2xzGAQgAygJEgsKA3NpZBgFIAEoCSISChBTb3NSZXBvcnRSZXF1ZXN0IiIKEVNvc1JlcG9ydFJlc3BvbnNlEg0KBWFsZXJ0GAEgASgJIhEKD0R1bXBWYXJzUmVxdWVzdCKVAQoQRHVtcFZhcnNSZXNwb25zZRINCgVhbGVydBgBIAEoCRJBCghjb250ZW50cxgCIAMoCzIvLm9saXZldGluLmFwaS52MS5EdW1wVmFyc1Jlc3BvbnNlLkNvbnRlbnRzRW50cnkaLwoNQ29udGVudHNFbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAk6AjgBIjsKDERlYnVnQmluZGluZxIUCgxhY3Rpb25fdGl0bGUYASABKAkSFQoNZW50aXR5X3ByZWZpeBgCIAEoCSIeChxEdW1wUHVibGljSWRBY3Rpb25NYXBSZXF1ZXN0Is4BCh1EdW1wUHVibGljSWRBY3Rpb25NYXBSZXNwb25zZRINCgVhbGVydBgBIAEoCRJOCghjb250ZW50cxgCIAMoCzI8Lm9saXZldGluLmFwaS52MS5EdW1wUHVibGljSWRBY3Rpb25NYXBSZXNwb25zZS5Db250ZW50c0VudHJ5Gk4KDUNvbnRlbnRzRW50cnkSCwoDa2V5GAEgASgJEiwKBXZhbHVlGAIgASgLMh0ub2xpdmV0aW4uYXBpLnYxLkRlYnVnQmluZGluZzoCOAEiEgoQR2V0UmVhZHl6UmVxdWVzdCIjChFHZXRSZWFkeXpSZXNwb25zZRIOCgZzdGF0dXMYASABKAkiFAoSRXZlbnRTdHJlYW1SZXF1ZXN0IpkDChNFdmVudFN0cmVhbVJlc3BvbnNlEj0KDmVudGl0eV9jaGFuZ2VkGAIgASgLMiMub2xpdmV0aW4uYXBpLnYxLkV2ZW50RW50aXR5Q2hhbmdlZEgAEj0KDmNvbmZpZ19jaGFuZ2VkGAMgASgLMiMub2xpdmV0aW4uYXBpLnYxLkV2ZW50Q29uZmlnQ2hhbmdlZEgAEkUKEmV4ZWN1dGlvbl9maW5pc2hlZBgEIAEoCzInLm9saXZldGluLmFwaS52MS5FdmVudEV4ZWN1dGlvbkZpbmlzaGVkSAASQwoRZXhlY3V0aW9uX3N0YXJ0ZWQYBSABKAsyJi5vbGl2ZXRpbi5hcGkudjEuRXZlbnRFeGVjdXRpb25TdGFydGVkSAASOQoMb3V0cHV0X2NodW5rGAYgASgLMiEub2xpdmV0aW4uYXBpLnYxLkV2ZW50T3V0cHV0Q2h1bmtIABI0CgloZWFydGJlYXQYByABKAsyHy5vbGl2ZXRpbi5hcGkudjEuRXZlbnRIZWFydGJlYXRIAEIHCgVldmVudCJBChBFdmVudE91dHB1dENodW5rEh0KFWV4ZWN1dGlvbl90cmFja2luZ19pZBgBIAEoCRIOCgZvdXRwdXQYAiABKAkiFAoSRXZlbnRFbnRpdHlDaGFuZ2VkIhQKEkV2ZW50Q29uZmlnQ2hhbmdlZCIQCg5FdmVudEhlYXJ0YmVhdCJGChZFdmVudEV4ZWN1dGlvbkZpbmlzaGVkEiwKCWxvZ19lbnRyeRgBIAEoCzIZLm9saXZldGluLmFwaS52MS5Mb2dFbnRyeSJFChVFdmVudEV4ZWN1dGlvblN0YXJ0ZWQSLAoJbG9nX2VudHJ5GAEgASgLMhkub2xpdmV0aW4uYXBpLnYxLkxvZ0VudHJ5IjIKEUtpbGxBY3Rpb25SZXF1ZXN0Eh0KFWV4ZWN1dGlvbl90cmFja2luZ19pZBgBIAEoCSJtChJLaWxsQWN0aW9uUmVzcG9uc2USHQoVZXhlY3V0aW9uX3RyYWNraW5nX2lkGAEgASgJEg4KBmtpbGxlZBgCIAEoCBIZChFhbHJlYWR5X2NvbXBsZXRlZBgDIAEoCBINCgVmb3VuZBgEIAEoCCI7ChVMb2NhbFVzZXJMb2dpblJlcXVlc3QSEAoIdXNlcm5hbWUYASABKAkSEAoIcGFzc3dvcmQYAiABKAkiKQoWTG9jYWxVc2VyTG9naW5SZXNwb25zZRIPCgdzdWNjZXNzGAEgASgIIicKE1Bhc3N3b3JkSGFzaFJlcXVlc3QSEAoIcGFzc3dvcmQYASABKAkiJAoUUGFzc3dvcmRIYXNoUmVzcG9uc2USDAoEaGFzaBgBIAEoCSIPCg1Mb2dvdXRSZXF1ZXN0IhAKDkxvZ291dFJlc3BvbnNlIhcKFUdldERpYWdub3N0aWNzUmVxdWVzdCJFChZHZXREaWFnbm9zdGljc1Jlc3BvbnNlEhMKC1NzaEZvdW5kS2V5GAEgASgJEhYKDlNzaEZvdW5kQ29uZmlnGAIgASgJIg0KC0luaXRSZXF1ZXN0IusFCgxJbml0UmVzcG9uc2USEgoKc2hvd0Zvb3RlchgBIAEoCBIWCg5zaG93TmF2aWdhdGlvbhgCIAEoCBIXCg9zaG93TmV3VmVyc2lvbnMYAyABKAgSGAoQYXZhaWxhYmxlVmVyc2lvbhgEIAEoCRIWCg5jdXJyZW50VmVyc2lvbhgFIAEoCRIRCglwYWdlVGl0bGUYBiABKAkSHgoWc2VjdGlvbk5hdmlnYXRpb25TdHlsZRgHIAEoCRIaChJkZWZhdWx0SWNvbkZvckJhY2sYCCABKAkSFgoOZW5hYmxlQ3VzdG9tSnMYCSABKAgSFAoMYXV0aExvZ2luVXJsGAogASgJEhYKDmF1dGhMb2NhbExvZ2luGAsgASgIEhEKCXN0eWxlTW9kcxgMIAMoCRI4Cg9vQXV0aDJQcm92aWRlcnMYDSADKAsyHy5vbGl2ZXRpbi5hcGkudjEuT0F1dGgyUHJvdmlkZXISOAoPYWRkaXRpb25hbExpbmtzGA4gAygLMh8ub2xpdmV0aW4uYXBpLnYxLkFkZGl0aW9uYWxMaW5rEhYKDnJvb3REYXNoYm9hcmRzGA8gAygJEhoKEmF1dGhlbnRpY2F0ZWRfdXNlchgQIAEoCRIjChthdXRoZW50aWNhdGVkX3VzZXJfcHJvdmlkZXIYESABKAkSOgoQZWZmZWN0aXZlX3BvbGljeRgSIAEoCzIgLm9saXZldGluLmFwaS52MS5FZmZlY3RpdmVQb2xpY3kSFgoOYmFubmVyX21lc3NhZ2UYEyABKAkSEgoKYmFubmVyX2NzcxgUIAEoCRIYChBzaG93X2RpYWdub3N0aWNzGBUgASgIEhUKDXNob3dfbG9nX2xpc3QYFiABKAgSFgoObG9naW5fcmVxdWlyZWQYFyABKAgSGAoQYXZhaWxhYmxlX3RoZW1lcxgYIAMoCRIkChxzaG93X25hdmlnYXRlX29uX3N0YXJ0X2ljb25zGBkgASgIIiwKDkFkZGl0aW9uYWxMaW5rEg0KBXRpdGxlGAEgASgJEgsKA3VybBgCIAEoCSI6Cg5PQXV0aDJQcm92aWRlchINCgV0aXRsZRgBIAEoCRIMCgRpY29uGAMgASgJEgsKA2tleRgEIAEoCSItChdHZXRBY3Rpb25CaW5kaW5nUmVxdWVzdBISCgpiaW5kaW5nX2lkGAEgASgJIosBChhHZXRBY3Rpb25CaW5kaW5nUmVzcG9uc2USJwoGYWN0aW9uGAEgASgLMhcub2xpdmV0aW4uYXBpLnYxLkFjdGlvbhJGChJiYWNrX3RvX2Rhc2hib2FyZHMYAiADKAsyKi5vbGl2ZXRpbi5hcGkudjEuRGFzaGJvYXJkTmF2aWdhdGlvblRhcmdldCJaChJHZXRFbnRpdGllc1JlcXVlc3QSEwoLZW50aXR5X3R5cGUYASABKAkSDgoGZmlsdGVyGAIgASgJEgwKBHBhZ2UYAyABKAUSEQoJcGFnZV9zaXplGAQgASgFIlQKE0dldEVudGl0aWVzUmVzcG9uc2USPQoSZW50aXR5X2RlZmluaXRpb25zGAEgAygLMiEub2xpdmV0aW4uYXBpLnYxLkVudGl0eURlZmluaXRpb24ixQEKEEVudGl0eURlZmluaXRpb24SDQoFdGl0bGUYASABKAkSKgoJaW5zdGFuY2VzGAIgAygLMhcub2xpdmV0aW4uYXBpLnYxLkVudGl0eRIaChJ1c2VkX29uX2Rhc2hib2FyZHMYAyADKAkSDAoEaWNvbhgEIAEoCRIzCgpwcm9wZXJ0aWVzGAUgAygLMh8ub2xpdmV0aW4uYXBpLnYxLkVudGl0eVByb3BlcnR5EhcKD3RvdGFsX2luc3RhbmNlcxgGIAEoBSItCg5FbnRpdHlQcm9wZXJ0eRIMCgRuYW1lGAEgASgJEg0KBXRpdGxlGAIgASgJIjQKEEdldEVudGl0eVJlcXVlc3QSEgoKdW5pcXVlX2tleRgBIAEoCRIMCgR0eXBlGAIgASgJIjUKFFJlc3RhcnRBY3Rpb25SZXF1ZXN0Eh0KFWV4ZWN1dGlvbl90cmFja2luZ19pZBgBIAEoCTLWEwoST2xpdmVUaW5BcGlTZXJ2aWNlEl0KDEdldERhc2hib2FyZBIkLm9saXZldGluLmFwaS52MS5HZXREYXNoYm9hcmRSZXF1ZXN0GiUub2xpdmV0aW4uYXBpLnYxLkdldERhc2hib2FyZFJlc3BvbnNlIgASWgoLU3RhcnRBY3Rpb24SIy5vbGl2ZXRpbi5hcGkudjEuU3RhcnRBY3Rpb25SZXF1ZXN0GiQub2xpdmV0aW4uYXBpLnYxLlN0YXJ0QWN0aW9uUmVzcG9uc2UiABJvChJTdGFydEFjdGlvbkFuZFdhaXQSKi5vbGl2ZXRpbi5hcGkudjEuU3RhcnRBY3Rpb25BbmRXYWl0UmVxdWVzdBorLm9saXZldGluLmFwaS52MS5TdGFydEFjdGlvbkFuZFdhaXRSZXNwb25zZSIAEmkKEFN0YXJ0QWN0aW9uQnlHZXQSKC5vbGl2ZXRpbi5hcGkudjEuU3RhcnRBY3Rpb25CeUdldFJlcXVlc3QaKS5vbGl2ZXRpbi5hcGkudjEuU3RhcnRBY3Rpb25CeUdldFJlc3BvbnNlIgASfgoXU3RhcnRBY3Rpb25CeUdldEFuZFdhaXQSLy5vbGl2ZXRpbi5hcGkudjEuU3RhcnRBY3Rpb25CeUdldEFuZFdhaXRSZXF1ZXN0GjAub2xpdmV0aW4uYXBpLnYxLlN0YXJ0QWN0aW9uQnlHZXRBbmRXYWl0UmVzcG9uc2UiABJeCg1SZXN0YXJ0QWN0aW9uEiUub2xpdmV0aW4uYXBpLnYxLlJlc3RhcnRBY3Rpb25SZXF1ZXN0GiQub2xpdmV0aW4uYXBpLnYxLlN0YXJ0QWN0aW9uUmVzcG9uc2UiABJXCgpLaWxsQWN0aW9uEiIub2xpdmV0aW4uYXBpLnYxLktpbGxBY3Rpb25SZXF1ZXN0GiMub2xpdmV0aW4uYXBpLnYxLktpbGxBY3Rpb25SZXNwb25zZSIAEmYKD0V4ZWN1dGlvblN0YXR1cxInLm9saXZldGluLmFwaS52MS5FeGVjdXRpb25TdGF0dXNSZXF1ZXN0Gigub2xpdmV0aW4uYXBpLnYxLkV4ZWN1dGlvblN0YXR1c1Jlc3BvbnNlIgASTgoHR2V0TG9ncxIfLm9saXZldGluLmFwaS52MS5HZXRMb2dzUmVxdWVzdBogLm9saXZldGluLmFwaS52MS5HZXRMb2dzUmVzcG9uc2UiABJgCg1HZXRBY3Rpb25Mb2dzEiUub2xpdmV0aW4uYXBpLnYxLkdldEFjdGlvbkxvZ3NSZXF1ZXN0GiYub2xpdmV0aW4uYXBpLnYxLkdldEFjdGlvbkxvZ3NSZXNwb25zZSIAEmwKEUdldEV4ZWN1dGlvblF1ZXVlEikub2xpdmV0aW4uYXBpLnYxLkdldEV4ZWN1dGlvblF1ZXVlUmVxdWVzdBoqLm9saXZldGluLmFwaS52MS5HZXRFeGVjdXRpb25RdWV1ZVJlc3BvbnNlIgASdQoUVmFsaWRhdGVBcmd1bWVudFR5cGUSLC5vbGl2ZXRpbi5hcGkudjEuVmFsaWRhdGVBcmd1bWVudFR5cGVSZXF1ZXN0Gi0ub2xpdmV0aW4uYXBpLnYxLlZhbGlkYXRlQXJndW1lbnRUeXBlUmVzcG9uc2UiABJLCgZXaG9BbUkSHi5vbGl2ZXRpbi5hcGkudjEuV2hvQW1JUmVxdWVzdBofLm9saXZldGluLmFwaS52MS5XaG9BbUlSZXNwb25zZSIAElQKCVNvc1JlcG9ydBIhLm9saXZldGluLmFwaS52MS5Tb3NSZXBvcnRSZXF1ZXN0GiIub2xpdmV0aW4uYXBpLnYxLlNvc1JlcG9ydFJlc3BvbnNlIgASUQoIRHVtcFZhcnMSIC5vbGl2ZXRpbi5hcGkudjEuRHVtcFZhcnNSZXF1ZXN0GiEub2xpdmV0aW4uYXBpLnYxLkR1bXBWYXJzUmVzcG9uc2UiABJ4ChVEdW1wUHVibGljSWRBY3Rpb25NYXASLS5vbGl2ZXRpbi5hcGkudjEuRHVtcFB1YmxpY0lkQWN0aW9uTWFwUmVxdWVzdBouLm9saXZldGluLmFwaS52MS5EdW1wUHVibGljSWRBY3Rpb25NYXBSZXNwb25zZSIAElQKCUdldFJlYWR5ehIhLm9saXZldGluLmFwaS52MS5HZXRSZWFkeXpSZXF1ZXN0GiIub2xpdmV0aW4uYXBpLnYxLkdldFJlYWR5elJlc3BvbnNlIgASYwoOTG9jYWxVc2VyTG9naW4SJi5vbGl2ZXRpbi5hcGkudjEuTG9jYWxVc2VyTG9naW5SZXF1ZXN0Gicub2xpdmV0aW4uYXBpLnYxLkxvY2FsVXNlckxvZ2luUmVzcG9uc2UiABJdCgxQYXNzd29yZEhhc2gSJC5vbGl2ZXRpbi5hcGkudjEuUGFzc3dvcmRIYXNoUmVxdWVzdBolLm9saXZldGluLmFwaS52MS5QYXNzd29yZEhhc2hSZXNwb25zZSIAEksKBkxvZ291dBIeLm9saXZldGluLmFwaS52MS5Mb2dvdXRSZXF1ZXN0Gh8ub2xpdmV0aW4uYXBpLnYxLkxvZ291dFJlc3BvbnNlIgASXAoLRXZlbnRTdHJlYW0SIy5vbGl2ZXRpbi5hcGkudjEuRXZlbnRTdHJlYW1SZXF1ZXN0GiQub2xpdmV0aW4uYXBpLnYxLkV2ZW50U3RyZWFtUmVzcG9uc2UiADABEmMKDkdldERpYWdub3N0aWNzEiYub2xpdmV0aW4uYXBpLnYxLkdldERpYWdub3N0aWNzUmVxdWVzdBonLm9saXZldGluLmFwaS52MS5HZXREaWFnbm9zdGljc1Jlc3BvbnNlIgASRQoESW5pdBIcLm9saXZldGluLmFwaS52MS5Jbml0UmVxdWVzdBodLm9saXZldGluLmFwaS52MS5Jbml0UmVzcG9uc2UiABJpChBHZXRBY3Rpb25CaW5kaW5nEigub2xpdmV0aW4uYXBpLnYxLkdldEFjdGlvbkJpbmRpbmdSZXF1ZXN0Gikub2xpdmV0aW4uYXBpLnYxLkdldEFjdGlvbkJpbmRpbmdSZXNwb25zZSIAEloKC0dldEVudGl0aWVzEiMub2xpdmV0aW4uYXBpLnYxLkdldEVudGl0aWVzUmVxdWVzdBokLm9saXZldGluLmFwaS52MS5HZXRFbnRpdGllc1Jlc3BvbnNlIgASSQoJR2V0RW50aXR5EiEub2xpdmV0aW4uYXBpLnYxLkdldEVudGl0eVJlcXVlc3QaFy5vbGl2ZXRpbi5hcGkudjEuRW50aXR5IgBCOFo2Z2l0aHViLmNvbS9PbGl2ZVRpbi9PbGl2ZVRpbi9nZW4vb2xpdmV0aW4vYXBpL3YxO2FwaXYxYgZwcm90bzM"); /** * Describes the message olivetin.api.v1.Action. diff --git a/frontend/resources/vue/views/ArgumentForm.vue b/frontend/resources/vue/views/ArgumentForm.vue index 23e827f..23bf564 100644 --- a/frontend/resources/vue/views/ArgumentForm.vue +++ b/frontend/resources/vue/views/ArgumentForm.vue @@ -82,7 +82,11 @@ import { requestReconnectNow } from '../../../js/websocket.js' import ChoiceCombobox from '../components/ChoiceCombobox.vue' import ChoiceChecklist from '../components/ChoiceChecklist.vue' import ActionIconGlyph from '../components/ActionIconGlyph.vue' -import { applyArgumentTemplate, actionJustificationTemplate, actionRequiresJustification } from '../utils/justificationTemplate.js' +import { + actionJustificationTemplate, + actionRequiresJustification, + applyArgumentTemplate +} from '../utils/justificationTemplate.js' import { getInitialArgumentValue, readPrefilledArgumentsFromNavigation } from '../utils/prefilledArguments.js' const router = useRouter() diff --git a/integration-tests/Makefile b/integration-tests/Makefile index 48dfed1..56e91fb 100644 --- a/integration-tests/Makefile +++ b/integration-tests/Makefile @@ -1,8 +1,12 @@ -default: test-install test-run +default: test-install prep test-run test-install: npm install --no-fund +prep: + $(MAKE) -wC .. webui-dist + $(MAKE) -wC ../service compile-currentenv + test-run: # GitHub Actions fails badly on the default timeout of 2000ms npx mocha tests --recursive -t 10000 @@ -24,4 +28,4 @@ getsnapshot: rm -rf /opt/OliveTin-snapshot/* gh run download -D /opt/OliveTin-snapshot/ -.PHONY: default find-flakey-tests find-flakey-tests-inf +.PHONY: default find-flakey-tests find-flakey-tests-inf prep diff --git a/proto/olivetin/api/v1/olivetin.proto b/proto/olivetin/api/v1/olivetin.proto index f6d8a54..e6295eb 100644 --- a/proto/olivetin/api/v1/olivetin.proto +++ b/proto/olivetin/api/v1/olivetin.proto @@ -20,7 +20,8 @@ message Action { repeated string exec_on_file_changed_in_dir = 13; string exec_on_calendar_file = 14; repeated ActionWebhookExecHint exec_on_webhooks = 15; - string justification = 16; + reserved 16; + string justification = 20; bool has_running_instance = 17; bool has_queued_instance = 18; repeated ActionGroupMembership groups = 19; diff --git a/service/gen/olivetin/api/v1/olivetin.pb.go b/service/gen/olivetin/api/v1/olivetin.pb.go index 9eb3974..e6c47c6 100644 --- a/service/gen/olivetin/api/v1/olivetin.pb.go +++ b/service/gen/olivetin/api/v1/olivetin.pb.go @@ -38,7 +38,7 @@ type Action struct { ExecOnFileChangedInDir []string `protobuf:"bytes,13,rep,name=exec_on_file_changed_in_dir,json=execOnFileChangedInDir,proto3" json:"exec_on_file_changed_in_dir,omitempty"` ExecOnCalendarFile string `protobuf:"bytes,14,opt,name=exec_on_calendar_file,json=execOnCalendarFile,proto3" json:"exec_on_calendar_file,omitempty"` ExecOnWebhooks []*ActionWebhookExecHint `protobuf:"bytes,15,rep,name=exec_on_webhooks,json=execOnWebhooks,proto3" json:"exec_on_webhooks,omitempty"` - Justification string `protobuf:"bytes,16,opt,name=justification,proto3" json:"justification,omitempty"` + Justification string `protobuf:"bytes,20,opt,name=justification,proto3" json:"justification,omitempty"` HasRunningInstance bool `protobuf:"varint,17,opt,name=has_running_instance,json=hasRunningInstance,proto3" json:"has_running_instance,omitempty"` HasQueuedInstance bool `protobuf:"varint,18,opt,name=has_queued_instance,json=hasQueuedInstance,proto3" json:"has_queued_instance,omitempty"` Groups []*ActionGroupMembership `protobuf:"bytes,19,rep,name=groups,proto3" json:"groups,omitempty"` @@ -4751,7 +4751,7 @@ var File_olivetin_api_v1_olivetin_proto protoreflect.FileDescriptor const file_olivetin_api_v1_olivetin_proto_rawDesc = "" + "\n" + - "\x1eolivetin/api/v1/olivetin.proto\x12\x0folivetin.api.v1\"\xd1\x06\n" + + "\x1eolivetin/api/v1/olivetin.proto\x12\x0folivetin.api.v1\"\xd7\x06\n" + "\x06Action\x12\x1d\n" + "\n" + "binding_id\x18\x01 \x01(\tR\tbindingId\x12\x14\n" + @@ -4771,10 +4771,10 @@ const file_olivetin_api_v1_olivetin_proto_rawDesc = "" + "\x1bexec_on_file_changed_in_dir\x18\r \x03(\tR\x16execOnFileChangedInDir\x121\n" + "\x15exec_on_calendar_file\x18\x0e \x01(\tR\x12execOnCalendarFile\x12P\n" + "\x10exec_on_webhooks\x18\x0f \x03(\v2&.olivetin.api.v1.ActionWebhookExecHintR\x0eexecOnWebhooks\x12$\n" + - "\rjustification\x18\x10 \x01(\tR\rjustification\x120\n" + + "\rjustification\x18\x14 \x01(\tR\rjustification\x120\n" + "\x14has_running_instance\x18\x11 \x01(\bR\x12hasRunningInstance\x12.\n" + "\x13has_queued_instance\x18\x12 \x01(\bR\x11hasQueuedInstance\x12>\n" + - "\x06groups\x18\x13 \x03(\v2&.olivetin.api.v1.ActionGroupMembershipR\x06groups\"q\n" + + "\x06groups\x18\x13 \x03(\v2&.olivetin.api.v1.ActionGroupMembershipR\x06groupsJ\x04\b\x10\x10\x11\"q\n" + "\x15ActionGroupMembership\x12\x12\n" + "\x04name\x18\x01 \x01(\tR\x04name\x12%\n" + "\x0emax_concurrent\x18\x02 \x01(\x05R\rmaxConcurrent\x12\x1d\n" + diff --git a/service/internal/api/api_justification.go b/service/internal/api/api_justification.go index 02135f0..56f1927 100644 --- a/service/internal/api/api_justification.go +++ b/service/internal/api/api_justification.go @@ -12,6 +12,7 @@ import ( "github.com/OliveTin/OliveTin/internal/entities" "github.com/OliveTin/OliveTin/internal/executor" "github.com/OliveTin/OliveTin/internal/tpl" + log "github.com/sirupsen/logrus" ) func validateJustificationRequired(action *config.Action, justification string, user *authpublic.AuthenticatedUser) error { @@ -58,6 +59,11 @@ func resolveJustificationFromTemplate(action *config.Action, binding *executor.A resolved, err := tpl.ParseTemplateWithActionContext(templateText, bindingEntity(binding), args) if err != nil { + log.WithFields(log.Fields{ + "template": templateText, + "entity": bindingEntity(binding), + "error": err, + }).Warn("Failed to resolve justification template") return fallback } diff --git a/service/internal/api/api_justification_test.go b/service/internal/api/api_justification_test.go index fc76f78..4758fd4 100644 --- a/service/internal/api/api_justification_test.go +++ b/service/internal/api/api_justification_test.go @@ -21,7 +21,7 @@ func TestStartActionRequiresJustificationForGuest(t *testing.T) { action := &config.Action{ Title: "Send email", ID: "send_email", - Justification: " ", + Justification: config.JustificationRequiredNoTemplate, Shell: "echo done", } cfg.Actions = append(cfg.Actions, action) @@ -85,7 +85,7 @@ func TestBuildActionExposesBlankRequiredJustification(t *testing.T) { action := &config.Action{ Title: "Audited action", ID: "audited", - Justification: " ", + Justification: config.JustificationRequiredNoTemplate, Shell: "echo hi", } cfg.Actions = append(cfg.Actions, action) @@ -101,7 +101,7 @@ func TestBuildActionExposesBlankRequiredJustification(t *testing.T) { }) require.NotNil(t, pb) - assert.Equal(t, " ", pb.Justification) + assert.Equal(t, config.JustificationRequiredNoTemplate, pb.Justification) } func TestResolveStartJustificationUsesTemplateWhenClientValueEmpty(t *testing.T) { @@ -168,7 +168,7 @@ func TestStartActionResolvesJustificationTemplateForGuest(t *testing.T) { func TestValidateJustificationRequiredAllowsSystemUser(t *testing.T) { cfg := config.DefaultConfig() - action := &config.Action{Title: "Cron job", Justification: " "} + action := &config.Action{Title: "Cron job", Justification: config.JustificationRequiredNoTemplate} err := validateJustificationRequired(action, "", auth.UserFromSystem(cfg, "cron")) require.NoError(t, err) diff --git a/service/internal/config/config.go b/service/internal/config/config.go index 02115fc..b0f91ab 100644 --- a/service/internal/config/config.go +++ b/service/internal/config/config.go @@ -7,6 +7,9 @@ import ( // ReservedArgumentNamePrefix is reserved for OliveTin-injected system arguments. const ReservedArgumentNamePrefix = "ot_" +// JustificationRequiredNoTemplate requires a manual justification with no prefilled template. +const JustificationRequiredNoTemplate = " " + // Action represents the core functionality of OliveTin - commands that show up // as buttons in the UI. type Action struct { @@ -43,7 +46,7 @@ func (action *Action) RequiresJustification() bool { } func (action *Action) JustificationTemplateText() string { - if action == nil || !action.RequiresJustification() { + if !action.RequiresJustification() { return "" } diff --git a/service/internal/config/config_reloader.go b/service/internal/config/config_reloader.go index b931e80..bc8631d 100644 --- a/service/internal/config/config_reloader.go +++ b/service/internal/config/config_reloader.go @@ -55,6 +55,7 @@ func unmarshalRoot(k *koanf.Koanf, cfg *Config) bool { DecoderConfig: &mapstructure.DecoderConfig{ DecodeHook: mapstructure.ComposeDecodeHookFunc( envDecodeHookFunc, + justificationDecodeHookFunc, mapstructure.StringToTimeDurationHookFunc(), mapstructure.TextUnmarshallerHookFunc(), ), @@ -259,6 +260,18 @@ func mergeFunc(src map[string]interface{}, dest map[string]interface{}) error { var envRegex = regexp.MustCompile(`\${{ *?(\S+) *?}}`) +func justificationDecodeHookFunc(from reflect.Type, to reflect.Type, data any) (any, error) { + if to.Kind() != reflect.String || from.Kind() != reflect.Bool { + return data, nil + } + + if data.(bool) { + return JustificationRequiredNoTemplate, nil + } + + return "", nil +} + func envDecodeHookFunc(from reflect.Type, to reflect.Type, data any) (any, error) { log.Debugf("envDecodeHookFunc called: from=%v, to=%v, data=%v", from, to, data) if from.Kind() != reflect.String { diff --git a/service/internal/config/justification_compat_test.go b/service/internal/config/justification_compat_test.go new file mode 100644 index 0000000..28908dc --- /dev/null +++ b/service/internal/config/justification_compat_test.go @@ -0,0 +1,58 @@ +package config + +import ( + "testing" + + "github.com/knadh/koanf/parsers/yaml" + "github.com/knadh/koanf/providers/rawbytes" + "github.com/knadh/koanf/v2" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestJustificationDecodeHookMigratesLegacyBooleanFalse(t *testing.T) { + cfg := loadJustificationCompatConfig(t, ` +actions: + - title: Legacy disabled + shell: echo hi + justification: false +`) + + require.Len(t, cfg.Actions, 1) + assert.Empty(t, cfg.Actions[0].Justification) +} + +func TestJustificationDecodeHookMigratesLegacyBooleanTrue(t *testing.T) { + cfg := loadJustificationCompatConfig(t, ` +actions: + - title: Legacy required + shell: echo hi + justification: true +`) + + require.Len(t, cfg.Actions, 1) + assert.Equal(t, JustificationRequiredNoTemplate, cfg.Actions[0].Justification) +} + +func TestSanitizeJustificationMigratesWeaklyTypedLegacyStrings(t *testing.T) { + action := &Action{Justification: "false"} + action.sanitizeJustification() + assert.Empty(t, action.Justification) + + action.Justification = "true" + action.sanitizeJustification() + assert.Equal(t, JustificationRequiredNoTemplate, action.Justification) +} + +func loadJustificationCompatConfig(t *testing.T, yamlBody string) *Config { + t.Helper() + + k := koanf.New(".") + require.NoError(t, k.Load(rawbytes.Provider([]byte(yamlBody)), yaml.Parser())) + + cfg := DefaultConfig() + require.True(t, unmarshalRoot(k, cfg)) + cfg.Sanitize() + + return cfg +} diff --git a/service/internal/config/sanitize.go b/service/internal/config/sanitize.go index 113d2d6..4d632ac 100644 --- a/service/internal/config/sanitize.go +++ b/service/internal/config/sanitize.go @@ -228,6 +228,7 @@ func (action *Action) sanitize(cfg *Config) { action.ID = getActionID(action) action.Icon = lookupHTMLIcon(action.Icon, cfg.DefaultIconForActions) migrateActionOnClick(action) + action.sanitizeJustification() action.OnClick = sanitizeOnClick(action.OnClick, cfg) action.PopupOnStart = action.OnClick @@ -469,6 +470,15 @@ func migrateActionOnClick(action *Action) { } } +func (action *Action) sanitizeJustification() { + switch action.Justification { + case "false": + action.Justification = "" + case "true": + action.Justification = JustificationRequiredNoTemplate + } +} + func shouldMigrateDefaultOnClickFromPopup(onClick, popupOnStart string) bool { if popupOnStart == "" { return false