@gitlab/duo-ui 15.19.0 → 15.19.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/agentic_chat/components/agentic_tool_approval_flow/agentic_tool_approval_flow.js +4 -0
- package/dist/components/agentic_chat/components/agentic_tool_approval_flow/agentic_tool_approval_modal/agentic_tool_approval_modal.js +25 -4
- package/dist/components/chat/components/duo_chat_message_tool_approval/message_tool_approval.js +35 -5
- package/package.json +1 -1
- package/src/components/agentic_chat/components/agentic_tool_approval_flow/agentic_tool_approval_flow.vue +4 -0
- package/src/components/agentic_chat/components/agentic_tool_approval_flow/agentic_tool_approval_modal/agentic_tool_approval_modal.vue +47 -22
- package/src/components/chat/components/duo_chat_message_tool_approval/message_tool_approval.vue +61 -27
|
@@ -58,6 +58,7 @@ var script = {
|
|
|
58
58
|
* @property {string} text - Display text for button/dropdown
|
|
59
59
|
* @property {boolean} primary - Mark as primary action (exactly one required)
|
|
60
60
|
* @property {boolean} disabled - Disable this option (passed through to GitLab UI)
|
|
61
|
+
* @property {string} [secondaryText] - Secondary text shown below the option (e.g., reason for disabled state)
|
|
61
62
|
*/
|
|
62
63
|
approvalOptions: {
|
|
63
64
|
type: Array,
|
|
@@ -88,6 +89,9 @@ var script = {
|
|
|
88
89
|
if (option.primary === true && option.disabled === true) {
|
|
89
90
|
return false;
|
|
90
91
|
}
|
|
92
|
+
if ('secondaryText' in option && typeof option.secondaryText !== 'string') {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
91
95
|
return true;
|
|
92
96
|
});
|
|
93
97
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { GlModal, GlButton,
|
|
1
|
+
import { GlModal, GlButton, GlButtonGroup, GlDisclosureDropdown } from '@gitlab/ui';
|
|
2
2
|
import { translate } from '../../../../../utils/i18n';
|
|
3
3
|
import { acceptedApproveToolPayloads } from '../../../../chat/constants';
|
|
4
4
|
import __vue_normalize__ from 'vue-runtime-helpers/dist/normalize-component.js';
|
|
@@ -18,8 +18,8 @@ var script = {
|
|
|
18
18
|
components: {
|
|
19
19
|
GlModal,
|
|
20
20
|
GlButton,
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
GlButtonGroup,
|
|
22
|
+
GlDisclosureDropdown
|
|
23
23
|
},
|
|
24
24
|
props: {
|
|
25
25
|
/**
|
|
@@ -79,6 +79,25 @@ var script = {
|
|
|
79
79
|
showSplitButton() {
|
|
80
80
|
return this.safeApprovalOptions.length > 1;
|
|
81
81
|
},
|
|
82
|
+
approvalDropdownItems() {
|
|
83
|
+
return this.additionalApprovalOptions.map(option => ({
|
|
84
|
+
text: option.text,
|
|
85
|
+
...(option.secondaryText ? {
|
|
86
|
+
secondaryText: option.secondaryText
|
|
87
|
+
} : {}),
|
|
88
|
+
extraAttrs: {
|
|
89
|
+
...(option.disabled ? {
|
|
90
|
+
disabled: true
|
|
91
|
+
} : {}),
|
|
92
|
+
'data-testid': 'approve-dropdown-item'
|
|
93
|
+
},
|
|
94
|
+
action: () => {
|
|
95
|
+
var _this$$refs$approvalD;
|
|
96
|
+
(_this$$refs$approvalD = this.$refs.approvalDropdown) === null || _this$$refs$approvalD === void 0 ? void 0 : _this$$refs$approvalD.close();
|
|
97
|
+
this.handleDropdownSelection(option);
|
|
98
|
+
}
|
|
99
|
+
}));
|
|
100
|
+
},
|
|
82
101
|
denyAction() {
|
|
83
102
|
return {
|
|
84
103
|
text: this.$options.i18n.DENY_TEXT,
|
|
@@ -152,7 +171,9 @@ var script = {
|
|
|
152
171
|
const __vue_script__ = script;
|
|
153
172
|
|
|
154
173
|
/* template */
|
|
155
|
-
var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('gl-modal',{attrs:{"visible":_vm.visible,"modal-id":"agentic-tool-approval-modal","title":_vm.$options.i18n.TITLE,"action-primary":null,"action-cancel":null,"no-close-on-backdrop":true,"no-close-on-esc":true,"data-testid":"agentic-tool-approval-modal"},on:{"hide":_vm.handleModalHide},scopedSlots:_vm._u([{key:"modal-footer",fn:function(){return [_c('div',{staticClass:"gl-flex gl-justify-end gl-gap-3"},[_c('gl-button',_vm._b({on:{"click":_vm.handleDeny}},'gl-button',_vm.denyAction.attributes,false),[_vm._v("\n "+_vm._s(_vm.denyAction.text)+"\n ")]),_vm._v(" "),(_vm.showSplitButton)?_c('gl-
|
|
174
|
+
var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('gl-modal',{attrs:{"visible":_vm.visible,"modal-id":"agentic-tool-approval-modal","title":_vm.$options.i18n.TITLE,"action-primary":null,"action-cancel":null,"no-close-on-backdrop":true,"no-close-on-esc":true,"data-testid":"agentic-tool-approval-modal"},on:{"hide":_vm.handleModalHide},scopedSlots:_vm._u([{key:"modal-footer",fn:function(){return [_c('div',{staticClass:"gl-flex gl-justify-end gl-gap-3"},[_c('gl-button',_vm._b({on:{"click":_vm.handleDeny}},'gl-button',_vm.denyAction.attributes,false),[_vm._v("\n "+_vm._s(_vm.denyAction.text)+"\n ")]),_vm._v(" "),(_vm.showSplitButton)?_c('gl-button-group',{attrs:{"data-testid":"approve-dropdown"}},[_c('gl-button',{attrs:{"variant":"confirm","size":"small","disabled":_vm.primaryApprovalOption.disabled,"data-testid":"approve-dropdown-primary"},on:{"click":_vm.handlePrimaryApprove}},[_vm._v("\n "+_vm._s(_vm.primaryApprovalOption.text)+"\n ")]),_vm._v(" "),_c('gl-disclosure-dropdown',{ref:"approvalDropdown",attrs:{"variant":"confirm","category":"primary","size":"small","no-caret":"","icon":"chevron-down","toggle-text":"More approval options","text-sr-only":"","placement":"bottom-end","disabled":_vm.primaryApprovalOption.disabled,"items":_vm.approvalDropdownItems},scopedSlots:_vm._u([{key:"list-item",fn:function(ref){
|
|
175
|
+
var item = ref.item;
|
|
176
|
+
return [_c('span',[_vm._v(_vm._s(item.text))]),_vm._v(" "),(item.secondaryText)?_c('span',{staticClass:"gl-block gl-text-sm gl-text-subtle"},[_vm._v("\n "+_vm._s(item.secondaryText)+"\n ")]):_vm._e()]}}],null,false,1049862671)})],1):_c('gl-button',{attrs:{"variant":"confirm","size":"small","disabled":_vm.primaryApprovalOption.disabled,"data-testid":"approve-button"},on:{"click":_vm.handlePrimaryApprove}},[_vm._v("\n "+_vm._s(_vm.primaryApprovalOption.text)+"\n ")])],1)]},proxy:true}])},[_c('div',{staticClass:"gl-mb-4"},[_c('p',{staticClass:"gl-mb-3",attrs:{"data-testid":"approval-description"}},[_vm._v("\n "+_vm._s(_vm.description)+"\n ")]),_vm._v(" "),(_vm.toolDetails)?_c('div',{staticClass:"gl-mb-3 gl-rounded-base gl-bg-gray-10 gl-p-3",attrs:{"data-testid":"tool-details"}},[_c('strong',[_vm._v(_vm._s(_vm.$options.i18n.TOOL_LABEL)+" "+_vm._s(_vm.toolName))]),_vm._v(" "),(_vm.toolDetails.parameters)?_c('pre',{staticClass:"gl-mb-0 gl-mt-2 gl-text-inherit",attrs:{"data-testid":"tool-parameters"}},[_vm._v(_vm._s(JSON.stringify(_vm.toolDetails.parameters, null, 2)))]):_vm._e()]):_vm._e()])])};
|
|
156
177
|
var __vue_staticRenderFns__ = [];
|
|
157
178
|
|
|
158
179
|
/* style */
|
package/dist/components/chat/components/duo_chat_message_tool_approval/message_tool_approval.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { GlButton, GlCard, GlFormTextarea, GlFormGroup, GlBadge,
|
|
1
|
+
import { GlButton, GlButtonGroup, GlCard, GlFormTextarea, GlFormGroup, GlBadge, GlDisclosureDropdown } from '@gitlab/ui';
|
|
2
2
|
import { capitalize, startCase } from 'lodash-es';
|
|
3
3
|
import { translate } from '../../../../utils/i18n';
|
|
4
4
|
import { convertKeysToCamelCase } from '../../../../utils/object';
|
|
@@ -48,12 +48,12 @@ var script = {
|
|
|
48
48
|
name: 'MessageToolApproval',
|
|
49
49
|
components: {
|
|
50
50
|
GlButton,
|
|
51
|
+
GlButtonGroup,
|
|
51
52
|
GlCard,
|
|
52
53
|
GlFormTextarea,
|
|
53
54
|
GlFormGroup,
|
|
54
55
|
GlBadge,
|
|
55
|
-
|
|
56
|
-
GlDropdownItem,
|
|
56
|
+
GlDisclosureDropdown,
|
|
57
57
|
CreateCommitToolParams,
|
|
58
58
|
DefaultToolParams,
|
|
59
59
|
RunCommandToolParams
|
|
@@ -84,6 +84,7 @@ var script = {
|
|
|
84
84
|
* @property {string} text - The display text for the option
|
|
85
85
|
* @property {boolean} primary - Whether this is the primary option (appears as main button)
|
|
86
86
|
* @property {boolean} disabled - Whether this option is disabled
|
|
87
|
+
* @property {string} [secondaryText] - Secondary text shown below the option (e.g., reason for disabled state)
|
|
87
88
|
*/
|
|
88
89
|
approvalOptions: {
|
|
89
90
|
type: Array,
|
|
@@ -96,7 +97,15 @@ var script = {
|
|
|
96
97
|
validator(value) {
|
|
97
98
|
if (!Array.isArray(value)) return false;
|
|
98
99
|
// Must have at least one approve-tool-once option
|
|
99
|
-
|
|
100
|
+
if (!value.some(option => option.type === acceptedApproveToolPayloads.APPROVE_TOOL_ONCE)) {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
return value.every(option => {
|
|
104
|
+
if ('secondaryText' in option && typeof option.secondaryText !== 'string') {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
return true;
|
|
108
|
+
});
|
|
100
109
|
}
|
|
101
110
|
}
|
|
102
111
|
},
|
|
@@ -202,6 +211,25 @@ var script = {
|
|
|
202
211
|
},
|
|
203
212
|
showSplitButton() {
|
|
204
213
|
return this.safeApprovalOptions.length > 1;
|
|
214
|
+
},
|
|
215
|
+
approvalDropdownItems() {
|
|
216
|
+
return this.additionalApprovalOptions.map(option => ({
|
|
217
|
+
text: option.text,
|
|
218
|
+
...(option.secondaryText ? {
|
|
219
|
+
secondaryText: option.secondaryText
|
|
220
|
+
} : {}),
|
|
221
|
+
extraAttrs: {
|
|
222
|
+
...(option.disabled ? {
|
|
223
|
+
disabled: true
|
|
224
|
+
} : {}),
|
|
225
|
+
'data-testid': 'approve-dropdown-item'
|
|
226
|
+
},
|
|
227
|
+
action: () => {
|
|
228
|
+
var _this$$refs$approvalD;
|
|
229
|
+
(_this$$refs$approvalD = this.$refs.approvalDropdown) === null || _this$$refs$approvalD === void 0 ? void 0 : _this$$refs$approvalD.close();
|
|
230
|
+
this.handleDropdownSelection(option);
|
|
231
|
+
}
|
|
232
|
+
}));
|
|
205
233
|
}
|
|
206
234
|
},
|
|
207
235
|
watch: {
|
|
@@ -265,7 +293,9 @@ var script = {
|
|
|
265
293
|
const __vue_script__ = script;
|
|
266
294
|
|
|
267
295
|
/* template */
|
|
268
|
-
var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('gl-card',{staticClass:"gl-w-full",class:{ 'message-tool-approval-collapsed': _vm.collapsed },attrs:{"header-class":{ 'message-tool-approval-collapsed-header': _vm.collapsed },"body-class":{ 'gl-hidden': _vm.collapsed }},scopedSlots:_vm._u([{key:"header",fn:function(){return [_c('div',{staticClass:"gl-flex gl-items-center gl-justify-between gl-gap-3"},[_c('span',{staticClass:"gl-inline-flex gl-items-center gl-gap-2"},[(_vm.collapsible)?_c('gl-button',_vm._b({attrs:{"variant":"default","category":"tertiary","size":"small","data-testid":"toggle-details-button"},on:{"click":function($event){_vm.collapsed = !_vm.collapsed;}}},'gl-button',_vm.collapseButtonProps,false)):_vm._e(),_vm._v(" "),_c('span',[_vm._v("\n "+_vm._s(_vm.toolApprovalTitle)+"\n ")])],1),_vm._v(" "),_c('gl-badge',{attrs:{"variant":_vm.toolStatusVariant}},[_vm._v("\n "+_vm._s(_vm.toolStatusLabel)+"\n ")])],1)]},proxy:true},(!_vm.isApproved)?{key:"footer",fn:function(){return [(!_vm.showDenialReason)?_c('div',{staticClass:"gl-flex gl-gap-2"},[(_vm.showSplitButton)?_c('gl-
|
|
296
|
+
var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('gl-card',{staticClass:"gl-w-full",class:{ 'message-tool-approval-collapsed': _vm.collapsed },attrs:{"header-class":{ 'message-tool-approval-collapsed-header': _vm.collapsed },"body-class":{ 'gl-hidden': _vm.collapsed }},scopedSlots:_vm._u([{key:"header",fn:function(){return [_c('div',{staticClass:"gl-flex gl-items-center gl-justify-between gl-gap-3"},[_c('span',{staticClass:"gl-inline-flex gl-items-center gl-gap-2"},[(_vm.collapsible)?_c('gl-button',_vm._b({attrs:{"variant":"default","category":"tertiary","size":"small","data-testid":"toggle-details-button"},on:{"click":function($event){_vm.collapsed = !_vm.collapsed;}}},'gl-button',_vm.collapseButtonProps,false)):_vm._e(),_vm._v(" "),_c('span',[_vm._v("\n "+_vm._s(_vm.toolApprovalTitle)+"\n ")])],1),_vm._v(" "),_c('gl-badge',{attrs:{"variant":_vm.toolStatusVariant}},[_vm._v("\n "+_vm._s(_vm.toolStatusLabel)+"\n ")])],1)]},proxy:true},(!_vm.isApproved)?{key:"footer",fn:function(){return [(!_vm.showDenialReason)?_c('div',{staticClass:"gl-flex gl-gap-2"},[(_vm.showSplitButton)?_c('gl-button-group',{attrs:{"data-testid":"approve-dropdown"}},[_c('gl-button',{attrs:{"variant":"confirm","size":"small","disabled":_vm.buttonsDisabled || _vm.primaryApprovalOption.disabled,"loading":_vm.isApproving,"data-testid":"approve-dropdown-primary"},on:{"click":_vm.handlePrimaryApprove}},[_vm._v("\n "+_vm._s(_vm.primaryApprovalOption.text)+"\n ")]),_vm._v(" "),_c('gl-disclosure-dropdown',{ref:"approvalDropdown",attrs:{"variant":"confirm","category":"primary","size":"small","no-caret":"","icon":"chevron-down","toggle-text":"More approval options","text-sr-only":"","placement":"bottom-end","disabled":_vm.buttonsDisabled || _vm.primaryApprovalOption.disabled,"items":_vm.approvalDropdownItems},scopedSlots:_vm._u([{key:"list-item",fn:function(ref){
|
|
297
|
+
var item = ref.item;
|
|
298
|
+
return [_c('span',[_vm._v(_vm._s(item.text))]),_vm._v(" "),(item.secondaryText)?_c('span',{staticClass:"gl-block gl-text-sm gl-text-subtle"},[_vm._v("\n "+_vm._s(item.secondaryText)+"\n ")]):_vm._e()]}}],null,false,1049862671)})],1):_c('gl-button',{attrs:{"variant":"confirm","size":"small","data-testid":"approve-tool-inline","disabled":_vm.buttonsDisabled || _vm.primaryApprovalOption.disabled,"loading":_vm.isApproving},on:{"click":_vm.handlePrimaryApprove}},[_vm._v("\n "+_vm._s(_vm.primaryApprovalOption.text)+"\n ")]),_vm._v(" "),_c('gl-button',{attrs:{"size":"small","data-testid":"deny-tool-inline","disabled":_vm.buttonsDisabled,"loading":_vm.isDenying},on:{"click":_vm.handleDeny}},[_vm._v("\n "+_vm._s(_vm.denyButtonText)+"\n ")])],1):_c('div',[_c('gl-form-group',{staticClass:"gl-mb-3",attrs:{"label":_vm.$options.i18n.DENIAL_REASON_LABEL,"label-for":"inline-rejection-reason","optional":true}},[_c('gl-form-textarea',{attrs:{"id":"inline-rejection-reason","placeholder":_vm.$options.i18n.DENIAL_REASON_PLACEHOLDER,"rows":2,"no-resize":true,"submit-on-enter":false,"disabled":_vm.buttonsDisabled,"data-testid":"denial-reason-textarea","autofocus":""},on:{"submit":_vm.submitDenial},model:{value:(_vm.denialReason),callback:function ($$v) {_vm.denialReason=$$v;},expression:"denialReason"}})],1),_vm._v(" "),_c('div',{staticClass:"gl-flex gl-gap-3"},[_c('gl-button',{attrs:{"size":"small","data-testid":"submit-denial","variant":"confirm","disabled":_vm.buttonsDisabled,"loading":_vm.isDenying},on:{"click":_vm.submitDenial}},[_vm._v("\n "+_vm._s(_vm.denyButtonText)+"\n ")]),_vm._v(" "),_c('gl-button',{attrs:{"size":"small","data-testid":"cancel-denial","disabled":_vm.buttonsDisabled},on:{"click":_vm.cancelDenial}},[_vm._v("\n "+_vm._s(_vm.$options.i18n.CANCEL_TEXT)+"\n ")])],1)],1)]},proxy:true}:null],null,true)},[_vm._v(" "),_vm._l((_vm.messages),function(toolMsg,index){return _c('div',{key:toolMsg.id || index},[_c(_vm.getToolParamsComponent(toolMsg.tool_info && toolMsg.tool_info.name),_vm._b({tag:"component",class:['gl-leading-20', { 'gl-border-t gl-mt-3 gl-border-gray-100 gl-pt-3': index > 0 }],attrs:{"tool-name":toolMsg.tool_info && toolMsg.tool_info.name,"tool-params":_vm.convertKeysToCamelCase((toolMsg.tool_info && toolMsg.tool_info.args) || {}),"tool-response":toolMsg.tool_info && toolMsg.tool_info.tool_response,"working-directory":_vm.workingDirectory}},'component',_vm.convertKeysToCamelCase((toolMsg.tool_info && toolMsg.tool_info.args) || {}),false))],1)})],2)};
|
|
269
299
|
var __vue_staticRenderFns__ = [];
|
|
270
300
|
|
|
271
301
|
/* style */
|
package/package.json
CHANGED
|
@@ -66,6 +66,7 @@ export default {
|
|
|
66
66
|
* @property {string} text - Display text for button/dropdown
|
|
67
67
|
* @property {boolean} primary - Mark as primary action (exactly one required)
|
|
68
68
|
* @property {boolean} disabled - Disable this option (passed through to GitLab UI)
|
|
69
|
+
* @property {string} [secondaryText] - Secondary text shown below the option (e.g., reason for disabled state)
|
|
69
70
|
*/
|
|
70
71
|
approvalOptions: {
|
|
71
72
|
type: Array,
|
|
@@ -99,6 +100,9 @@ export default {
|
|
|
99
100
|
if (option.primary === true && option.disabled === true) {
|
|
100
101
|
return false;
|
|
101
102
|
}
|
|
103
|
+
if ('secondaryText' in option && typeof option.secondaryText !== 'string') {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
102
106
|
return true;
|
|
103
107
|
});
|
|
104
108
|
},
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script>
|
|
2
|
-
import { GlModal, GlButton,
|
|
2
|
+
import { GlModal, GlButton, GlButtonGroup, GlDisclosureDropdown } from '@gitlab/ui';
|
|
3
3
|
import { translate } from '../../../../../utils/i18n';
|
|
4
4
|
import { acceptedApproveToolPayloads } from '../../../../chat/constants';
|
|
5
5
|
|
|
@@ -25,8 +25,8 @@ export default {
|
|
|
25
25
|
components: {
|
|
26
26
|
GlModal,
|
|
27
27
|
GlButton,
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
GlButtonGroup,
|
|
29
|
+
GlDisclosureDropdown,
|
|
30
30
|
},
|
|
31
31
|
props: {
|
|
32
32
|
/**
|
|
@@ -88,6 +88,20 @@ export default {
|
|
|
88
88
|
showSplitButton() {
|
|
89
89
|
return this.safeApprovalOptions.length > 1;
|
|
90
90
|
},
|
|
91
|
+
approvalDropdownItems() {
|
|
92
|
+
return this.additionalApprovalOptions.map((option) => ({
|
|
93
|
+
text: option.text,
|
|
94
|
+
...(option.secondaryText ? { secondaryText: option.secondaryText } : {}),
|
|
95
|
+
extraAttrs: {
|
|
96
|
+
...(option.disabled ? { disabled: true } : {}),
|
|
97
|
+
'data-testid': 'approve-dropdown-item',
|
|
98
|
+
},
|
|
99
|
+
action: () => {
|
|
100
|
+
this.$refs.approvalDropdown?.close();
|
|
101
|
+
this.handleDropdownSelection(option);
|
|
102
|
+
},
|
|
103
|
+
}));
|
|
104
|
+
},
|
|
91
105
|
denyAction() {
|
|
92
106
|
return {
|
|
93
107
|
text: this.$options.i18n.DENY_TEXT,
|
|
@@ -190,26 +204,37 @@ export default {
|
|
|
190
204
|
</gl-button>
|
|
191
205
|
|
|
192
206
|
<!-- Split button when multiple options available -->
|
|
193
|
-
<gl-dropdown
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
207
|
+
<gl-button-group v-if="showSplitButton" data-testid="approve-dropdown">
|
|
208
|
+
<gl-button
|
|
209
|
+
variant="confirm"
|
|
210
|
+
size="small"
|
|
211
|
+
:disabled="primaryApprovalOption.disabled"
|
|
212
|
+
data-testid="approve-dropdown-primary"
|
|
213
|
+
@click="handlePrimaryApprove"
|
|
214
|
+
>
|
|
215
|
+
{{ primaryApprovalOption.text }}
|
|
216
|
+
</gl-button>
|
|
217
|
+
<gl-disclosure-dropdown
|
|
218
|
+
ref="approvalDropdown"
|
|
219
|
+
variant="confirm"
|
|
220
|
+
category="primary"
|
|
221
|
+
size="small"
|
|
222
|
+
no-caret
|
|
223
|
+
icon="chevron-down"
|
|
224
|
+
toggle-text="More approval options"
|
|
225
|
+
text-sr-only
|
|
226
|
+
placement="bottom-end"
|
|
227
|
+
:disabled="primaryApprovalOption.disabled"
|
|
228
|
+
:items="approvalDropdownItems"
|
|
209
229
|
>
|
|
210
|
-
{
|
|
211
|
-
|
|
212
|
-
|
|
230
|
+
<template #list-item="{ item }">
|
|
231
|
+
<span>{{ item.text }}</span>
|
|
232
|
+
<span v-if="item.secondaryText" class="gl-block gl-text-sm gl-text-subtle">
|
|
233
|
+
{{ item.secondaryText }}
|
|
234
|
+
</span>
|
|
235
|
+
</template>
|
|
236
|
+
</gl-disclosure-dropdown>
|
|
237
|
+
</gl-button-group>
|
|
213
238
|
|
|
214
239
|
<!-- Simple button when only one option -->
|
|
215
240
|
<gl-button
|
package/src/components/chat/components/duo_chat_message_tool_approval/message_tool_approval.vue
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import {
|
|
3
3
|
GlButton,
|
|
4
|
+
GlButtonGroup,
|
|
4
5
|
GlFormTextarea,
|
|
5
6
|
GlFormGroup,
|
|
6
7
|
GlCard,
|
|
7
8
|
GlBadge,
|
|
8
|
-
|
|
9
|
-
GlDropdownItem,
|
|
9
|
+
GlDisclosureDropdown,
|
|
10
10
|
} from '@gitlab/ui';
|
|
11
11
|
import { startCase, capitalize } from 'lodash-es';
|
|
12
12
|
import { translate } from '../../../../utils/i18n';
|
|
@@ -79,12 +79,12 @@ export default {
|
|
|
79
79
|
name: 'MessageToolApproval',
|
|
80
80
|
components: {
|
|
81
81
|
GlButton,
|
|
82
|
+
GlButtonGroup,
|
|
82
83
|
GlCard,
|
|
83
84
|
GlFormTextarea,
|
|
84
85
|
GlFormGroup,
|
|
85
86
|
GlBadge,
|
|
86
|
-
|
|
87
|
-
GlDropdownItem,
|
|
87
|
+
GlDisclosureDropdown,
|
|
88
88
|
CreateCommitToolParams,
|
|
89
89
|
DefaultToolParams,
|
|
90
90
|
RunCommandToolParams,
|
|
@@ -115,6 +115,7 @@ export default {
|
|
|
115
115
|
* @property {string} text - The display text for the option
|
|
116
116
|
* @property {boolean} primary - Whether this is the primary option (appears as main button)
|
|
117
117
|
* @property {boolean} disabled - Whether this option is disabled
|
|
118
|
+
* @property {string} [secondaryText] - Secondary text shown below the option (e.g., reason for disabled state)
|
|
118
119
|
*/
|
|
119
120
|
approvalOptions: {
|
|
120
121
|
type: Array,
|
|
@@ -129,9 +130,17 @@ export default {
|
|
|
129
130
|
validator(value) {
|
|
130
131
|
if (!Array.isArray(value)) return false;
|
|
131
132
|
// Must have at least one approve-tool-once option
|
|
132
|
-
|
|
133
|
-
(option) => option.type === acceptedApproveToolPayloads.APPROVE_TOOL_ONCE
|
|
134
|
-
)
|
|
133
|
+
if (
|
|
134
|
+
!value.some((option) => option.type === acceptedApproveToolPayloads.APPROVE_TOOL_ONCE)
|
|
135
|
+
) {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
return value.every((option) => {
|
|
139
|
+
if ('secondaryText' in option && typeof option.secondaryText !== 'string') {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
return true;
|
|
143
|
+
});
|
|
135
144
|
},
|
|
136
145
|
},
|
|
137
146
|
},
|
|
@@ -231,6 +240,20 @@ export default {
|
|
|
231
240
|
showSplitButton() {
|
|
232
241
|
return this.safeApprovalOptions.length > 1;
|
|
233
242
|
},
|
|
243
|
+
approvalDropdownItems() {
|
|
244
|
+
return this.additionalApprovalOptions.map((option) => ({
|
|
245
|
+
text: option.text,
|
|
246
|
+
...(option.secondaryText ? { secondaryText: option.secondaryText } : {}),
|
|
247
|
+
extraAttrs: {
|
|
248
|
+
...(option.disabled ? { disabled: true } : {}),
|
|
249
|
+
'data-testid': 'approve-dropdown-item',
|
|
250
|
+
},
|
|
251
|
+
action: () => {
|
|
252
|
+
this.$refs.approvalDropdown?.close();
|
|
253
|
+
this.handleDropdownSelection(option);
|
|
254
|
+
},
|
|
255
|
+
}));
|
|
256
|
+
},
|
|
234
257
|
},
|
|
235
258
|
watch: {
|
|
236
259
|
approvalStatus(newVal) {
|
|
@@ -333,27 +356,38 @@ export default {
|
|
|
333
356
|
<template v-if="!isApproved" #footer>
|
|
334
357
|
<div v-if="!showDenialReason" class="gl-flex gl-gap-2">
|
|
335
358
|
<!-- Split button when multiple approval options available -->
|
|
336
|
-
<gl-dropdown
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
<gl-dropdown
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
359
|
+
<gl-button-group v-if="showSplitButton" data-testid="approve-dropdown">
|
|
360
|
+
<gl-button
|
|
361
|
+
variant="confirm"
|
|
362
|
+
size="small"
|
|
363
|
+
:disabled="buttonsDisabled || primaryApprovalOption.disabled"
|
|
364
|
+
:loading="isApproving"
|
|
365
|
+
data-testid="approve-dropdown-primary"
|
|
366
|
+
@click="handlePrimaryApprove"
|
|
367
|
+
>
|
|
368
|
+
{{ primaryApprovalOption.text }}
|
|
369
|
+
</gl-button>
|
|
370
|
+
<gl-disclosure-dropdown
|
|
371
|
+
ref="approvalDropdown"
|
|
372
|
+
variant="confirm"
|
|
373
|
+
category="primary"
|
|
374
|
+
size="small"
|
|
375
|
+
no-caret
|
|
376
|
+
icon="chevron-down"
|
|
377
|
+
toggle-text="More approval options"
|
|
378
|
+
text-sr-only
|
|
379
|
+
placement="bottom-end"
|
|
380
|
+
:disabled="buttonsDisabled || primaryApprovalOption.disabled"
|
|
381
|
+
:items="approvalDropdownItems"
|
|
353
382
|
>
|
|
354
|
-
{
|
|
355
|
-
|
|
356
|
-
|
|
383
|
+
<template #list-item="{ item }">
|
|
384
|
+
<span>{{ item.text }}</span>
|
|
385
|
+
<span v-if="item.secondaryText" class="gl-block gl-text-sm gl-text-subtle">
|
|
386
|
+
{{ item.secondaryText }}
|
|
387
|
+
</span>
|
|
388
|
+
</template>
|
|
389
|
+
</gl-disclosure-dropdown>
|
|
390
|
+
</gl-button-group>
|
|
357
391
|
|
|
358
392
|
<!-- Simple button when only one approval option -->
|
|
359
393
|
<gl-button
|