Commit 2be0ea5ffb64231d006e215ccbb6f630c3b752e6
1 parent
548f8bc3
各个节点绑定值 修改等bug
Showing
6 changed files
with
39 additions
and
58 deletions
yudao-ui-admin-vue3/src/components/bpmnProcessDesigner/package/penal/listeners/ElementListeners.vue
| @@ -9,14 +9,15 @@ | @@ -9,14 +9,15 @@ | ||
| 9 | show-overflow-tooltip | 9 | show-overflow-tooltip |
| 10 | :formatter="(row) => listenerTypeObject[row.listenerType]" | 10 | :formatter="(row) => listenerTypeObject[row.listenerType]" |
| 11 | /> | 11 | /> |
| 12 | - <el-table-column label="操作" width="130px"> | 12 | + <el-table-column label="操作" width="100px"> |
| 13 | <template #default="scope"> | 13 | <template #default="scope"> |
| 14 | - <el-button size="small" @click="openListenerForm(scope.row, scope.$index)" | 14 | + <el-button size="small" link @click="openListenerForm(scope.row, scope.$index)" |
| 15 | >编辑</el-button | 15 | >编辑</el-button |
| 16 | > | 16 | > |
| 17 | <el-divider direction="vertical" /> | 17 | <el-divider direction="vertical" /> |
| 18 | <el-button | 18 | <el-button |
| 19 | size="small" | 19 | size="small" |
| 20 | + link | ||
| 20 | style="color: #ff4d4f" | 21 | style="color: #ff4d4f" |
| 21 | @click="removeListener(scope.row, scope.$index)" | 22 | @click="removeListener(scope.row, scope.$index)" |
| 22 | >移除</el-button | 23 | >移除</el-button |
| @@ -26,7 +27,6 @@ | @@ -26,7 +27,6 @@ | ||
| 26 | </el-table> | 27 | </el-table> |
| 27 | <div class="element-drawer__button"> | 28 | <div class="element-drawer__button"> |
| 28 | <XButton | 29 | <XButton |
| 29 | - size="mini" | ||
| 30 | type="primary" | 30 | type="primary" |
| 31 | preIcon="ep:plus" | 31 | preIcon="ep:plus" |
| 32 | title="添加监听器" | 32 | title="添加监听器" |
| @@ -137,7 +137,7 @@ | @@ -137,7 +137,7 @@ | ||
| 137 | <el-divider /> | 137 | <el-divider /> |
| 138 | <p class="listener-filed__title"> | 138 | <p class="listener-filed__title"> |
| 139 | <span><Icon icon="ep:menu" />注入字段:</span> | 139 | <span><Icon icon="ep:menu" />注入字段:</span> |
| 140 | - <XButton type="primary" size="mini" @click="openListenerFieldForm(null)" title="添加字段" /> | 140 | + <XButton type="primary" @click="openListenerFieldForm(null)" title="添加字段" /> |
| 141 | </p> | 141 | </p> |
| 142 | <el-table | 142 | <el-table |
| 143 | :data="fieldsListOfListener" | 143 | :data="fieldsListOfListener" |
| @@ -163,16 +163,13 @@ | @@ -163,16 +163,13 @@ | ||
| 163 | /> | 163 | /> |
| 164 | <el-table-column label="操作" width="130px"> | 164 | <el-table-column label="操作" width="130px"> |
| 165 | <template #default="scope"> | 165 | <template #default="scope"> |
| 166 | - <el-button | ||
| 167 | - size="small" | ||
| 168 | - type="text" | ||
| 169 | - @click="openListenerFieldForm(scope.row, scope.$index)" | 166 | + <el-button size="small" link @click="openListenerFieldForm(scope.row, scope.$index)" |
| 170 | >编辑</el-button | 167 | >编辑</el-button |
| 171 | > | 168 | > |
| 172 | <el-divider direction="vertical" /> | 169 | <el-divider direction="vertical" /> |
| 173 | <el-button | 170 | <el-button |
| 174 | size="small" | 171 | size="small" |
| 175 | - type="text" | 172 | + link |
| 176 | style="color: #ff4d4f" | 173 | style="color: #ff4d4f" |
| 177 | @click="removeListenerField(scope.row, scope.$index)" | 174 | @click="removeListenerField(scope.row, scope.$index)" |
| 178 | >移除</el-button | 175 | >移除</el-button |
| @@ -293,9 +290,7 @@ const resetListenersList = () => { | @@ -293,9 +290,7 @@ const resetListenersList = () => { | ||
| 293 | otherExtensionList.value = [] | 290 | otherExtensionList.value = [] |
| 294 | console.log(bpmnElement.value, 'bpmnElement.value') | 291 | console.log(bpmnElement.value, 'bpmnElement.value') |
| 295 | bpmnElementListeners.value = | 292 | bpmnElementListeners.value = |
| 296 | - // bpmnElement.value.businessObject?.extensionElements?.filter( | ||
| 297 | - bpmnElement.value.businessObject?.extensionElements?.filter( | ||
| 298 | - // bpmnElement.value.businessObject?.extensionElements?.values?.filter( | 293 | + bpmnElement.value.businessObject?.extensionElements?.values?.filter( |
| 299 | (ex) => ex.$type === `${prefix}:ExecutionListener` | 294 | (ex) => ex.$type === `${prefix}:ExecutionListener` |
| 300 | ) ?? [] | 295 | ) ?? [] |
| 301 | elementListenersList.value = bpmnElementListeners.value.map((listener) => | 296 | elementListenersList.value = bpmnElementListeners.value.map((listener) => |
| @@ -396,8 +391,8 @@ const saveListenerConfig = async () => { | @@ -396,8 +391,8 @@ const saveListenerConfig = async () => { | ||
| 396 | // 保存其他配置 | 391 | // 保存其他配置 |
| 397 | console.log(bpmnElement.value, 'bpmnElement.value') | 392 | console.log(bpmnElement.value, 'bpmnElement.value') |
| 398 | otherExtensionList.value = | 393 | otherExtensionList.value = |
| 399 | - bpmnElement.value.businessObject?.extensionElements?.filter( | ||
| 400 | - // bpmnElement.value.businessObject?.extensionElements?.values?.filter( | 394 | + // bpmnElement.value.businessObject?.extensionElements?.filter( |
| 395 | + bpmnElement.value.businessObject?.extensionElements?.values?.filter( | ||
| 401 | (ex) => ex.$type !== `${prefix}:ExecutionListener` | 396 | (ex) => ex.$type !== `${prefix}:ExecutionListener` |
| 402 | ) ?? [] | 397 | ) ?? [] |
| 403 | console.log(bpmnElement.value, 'bpmnElement.value') | 398 | console.log(bpmnElement.value, 'bpmnElement.value') |
| @@ -406,20 +401,10 @@ const saveListenerConfig = async () => { | @@ -406,20 +401,10 @@ const saveListenerConfig = async () => { | ||
| 406 | otherExtensionList.value.concat(bpmnElementListeners.value), | 401 | otherExtensionList.value.concat(bpmnElementListeners.value), |
| 407 | 'otherExtensionList.value.concat(bpmnElementListeners.value).value' | 402 | 'otherExtensionList.value.concat(bpmnElementListeners.value).value' |
| 408 | ) | 403 | ) |
| 409 | - // updateElementExtensions( | ||
| 410 | - // bpmnElement.value, | ||
| 411 | - // // toRaw(bpmnElement.value), | ||
| 412 | - // otherExtensionList.value.concat(bpmnElementListeners.value) | ||
| 413 | - // // toRaw(otherExtensionList.value.concat(bpmnElementListeners.value)) | ||
| 414 | - // ) | ||
| 415 | - const extensions = window.bpmnInstances.moddle.create('bpmn:ExtensionElements', { | ||
| 416 | - values: otherExtensionList.value.concat(bpmnElementListeners.value) | ||
| 417 | - }) | ||
| 418 | - console.log(extensions, 'extensionsextensionsextensions') | ||
| 419 | - console.log(extensions.values, 'extensionsextensionsextensions') | ||
| 420 | - window.bpmnInstances.modeling.updateProperties(toRaw(bpmnElement.value), { | ||
| 421 | - extensionElements: extensions.values | ||
| 422 | - }) | 404 | + updateElementExtensions( |
| 405 | + bpmnElement.value, | ||
| 406 | + otherExtensionList.value.concat(bpmnElementListeners.value) | ||
| 407 | + ) | ||
| 423 | // 4. 隐藏侧边栏 | 408 | // 4. 隐藏侧边栏 |
| 424 | listenerFormModelVisible.value = false | 409 | listenerFormModelVisible.value = false |
| 425 | listenerForm.value = {} | 410 | listenerForm.value = {} |
yudao-ui-admin-vue3/src/components/bpmnProcessDesigner/package/penal/listeners/UserTaskListeners.vue
| @@ -17,13 +17,13 @@ | @@ -17,13 +17,13 @@ | ||
| 17 | /> | 17 | /> |
| 18 | <el-table-column label="操作" width="90px"> | 18 | <el-table-column label="操作" width="90px"> |
| 19 | <template #default="scope"> | 19 | <template #default="scope"> |
| 20 | - <el-button size="small" type="text" @click="openListenerForm(scope.row, scope.$index)" | 20 | + <el-button size="small" link @click="openListenerForm(scope.row, scope.$index)" |
| 21 | >编辑</el-button | 21 | >编辑</el-button |
| 22 | > | 22 | > |
| 23 | <el-divider direction="vertical" /> | 23 | <el-divider direction="vertical" /> |
| 24 | <el-button | 24 | <el-button |
| 25 | size="small" | 25 | size="small" |
| 26 | - type="text" | 26 | + link |
| 27 | style="color: #ff4d4f" | 27 | style="color: #ff4d4f" |
| 28 | @click="removeListener(scope.row, scope.$index)" | 28 | @click="removeListener(scope.row, scope.$index)" |
| 29 | >移除</el-button | 29 | >移除</el-button |
| @@ -204,16 +204,13 @@ | @@ -204,16 +204,13 @@ | ||
| 204 | /> | 204 | /> |
| 205 | <el-table-column label="操作" width="100px"> | 205 | <el-table-column label="操作" width="100px"> |
| 206 | <template #default="scope"> | 206 | <template #default="scope"> |
| 207 | - <el-button | ||
| 208 | - size="small" | ||
| 209 | - type="text" | ||
| 210 | - @click="openListenerFieldForm(scope.row, scope.$index)" | 207 | + <el-button size="small" link @click="openListenerFieldForm(scope.row, scope.$index)" |
| 211 | >编辑</el-button | 208 | >编辑</el-button |
| 212 | > | 209 | > |
| 213 | <el-divider direction="vertical" /> | 210 | <el-divider direction="vertical" /> |
| 214 | <el-button | 211 | <el-button |
| 215 | size="small" | 212 | size="small" |
| 216 | - type="text" | 213 | + link |
| 217 | style="color: #ff4d4f" | 214 | style="color: #ff4d4f" |
| 218 | @click="removeListenerField(scope.row, scope.$index)" | 215 | @click="removeListenerField(scope.row, scope.$index)" |
| 219 | >移除</el-button | 216 | >移除</el-button |
| @@ -338,8 +335,7 @@ const resetListenersList = () => { | @@ -338,8 +335,7 @@ const resetListenersList = () => { | ||
| 338 | bpmnElement.value = window.bpmnInstances.bpmnElement | 335 | bpmnElement.value = window.bpmnInstances.bpmnElement |
| 339 | otherExtensionList.value = [] | 336 | otherExtensionList.value = [] |
| 340 | bpmnElementListeners.value = | 337 | bpmnElementListeners.value = |
| 341 | - bpmnElement.value.businessObject?.extensionElements?.filter( | ||
| 342 | - // bpmnElement.value.businessObject?.extensionElements?.values.filter( | 338 | + bpmnElement.value.businessObject?.extensionElements?.values.filter( |
| 343 | (ex) => ex.$type === `${prefix}:TaskListener` | 339 | (ex) => ex.$type === `${prefix}:TaskListener` |
| 344 | ) ?? [] | 340 | ) ?? [] |
| 345 | elementListenersList.value = bpmnElementListeners.value.map((listener) => | 341 | elementListenersList.value = bpmnElementListeners.value.map((listener) => |
yudao-ui-admin-vue3/src/components/bpmnProcessDesigner/package/penal/listeners/template.js
| 1 | export const template = isTaskListener => { | 1 | export const template = isTaskListener => { |
| 2 | return ` | 2 | return ` |
| 3 | <div class="panel-tab__content"> | 3 | <div class="panel-tab__content"> |
| 4 | - <el-table :data="elementListenersList" size="mini" border> | 4 | + <el-table :data="elementListenersList" size="small" border> |
| 5 | <el-table-column label="序号" width="50px" type="index" /> | 5 | <el-table-column label="序号" width="50px" type="index" /> |
| 6 | <el-table-column label="事件类型" min-width="100px" prop="event" /> | 6 | <el-table-column label="事件类型" min-width="100px" prop="event" /> |
| 7 | <el-table-column label="监听器类型" min-width="100px" show-overflow-tooltip :formatter="row => listenerTypeObject[row.listenerType]" /> | 7 | <el-table-column label="监听器类型" min-width="100px" show-overflow-tooltip :formatter="row => listenerTypeObject[row.listenerType]" /> |
| 8 | <el-table-column label="操作" width="90px"> | 8 | <el-table-column label="操作" width="90px"> |
| 9 | <template #default="scope"> | 9 | <template #default="scope"> |
| 10 | - <el-button size="mini" type="text" @click="openListenerForm(scope, scope.$index)">编辑</el-button> | 10 | + <el-button size="small" type="text" @click="openListenerForm(scope, scope.$index)">编辑</el-button> |
| 11 | <el-divider direction="vertical" /> | 11 | <el-divider direction="vertical" /> |
| 12 | - <el-button size="mini" type="text" style="color: #ff4d4f" @click="removeListener(scope, scope.$index)">移除</el-button> | 12 | + <el-button size="small" type="text" style="color: #ff4d4f" @click="removeListener(scope, scope.$index)">移除</el-button> |
| 13 | </template> | 13 | </template> |
| 14 | </el-table-column> | 14 | </el-table-column> |
| 15 | </el-table> | 15 | </el-table> |
| 16 | <div class="element-drawer__button"> | 16 | <div class="element-drawer__button"> |
| 17 | - <el-button size="mini" type="primary" icon="el-icon-plus" @click="openListenerForm(null)">添加监听器</el-button> | 17 | + <el-button size="small" type="primary" icon="el-icon-plus" @click="openListenerForm(null)">添加监听器</el-button> |
| 18 | </div> | 18 | </div> |
| 19 | 19 | ||
| 20 | <!-- 监听器 编辑/创建 部分 --> | 20 | <!-- 监听器 编辑/创建 部分 --> |
| 21 | <el-drawer :visible.sync="listenerFormModelVisible" title="执行监听器" :size="width + 'px'" append-to-body destroy-on-close> | 21 | <el-drawer :visible.sync="listenerFormModelVisible" title="执行监听器" :size="width + 'px'" append-to-body destroy-on-close> |
| 22 | - <el-form size="mini" :model="listenerForm" label-width="96px" ref="listenerFormRef" @submit.native.prevent> | 22 | + <el-form size="small" :model="listenerForm" label-width="96px" ref="listenerFormRef" @submit.native.prevent> |
| 23 | <el-form-item label="事件类型" prop="event" :rules="{ required: true, trigger: ['blur', 'change'] }"> | 23 | <el-form-item label="事件类型" prop="event" :rules="{ required: true, trigger: ['blur', 'change'] }"> |
| 24 | <el-select v-model="listenerForm.event"> | 24 | <el-select v-model="listenerForm.event"> |
| 25 | <el-option label="start" value="start" /> | 25 | <el-option label="start" value="start" /> |
| @@ -115,31 +115,31 @@ export const template = isTaskListener => { | @@ -115,31 +115,31 @@ export const template = isTaskListener => { | ||
| 115 | <el-divider /> | 115 | <el-divider /> |
| 116 | <p class="listener-filed__title"> | 116 | <p class="listener-filed__title"> |
| 117 | <span><i class="el-icon-menu"></i>注入字段:</span> | 117 | <span><i class="el-icon-menu"></i>注入字段:</span> |
| 118 | - <el-button size="mini" type="primary" @click="openListenerFieldForm(null)">添加字段</el-button> | 118 | + <el-button size="small" type="primary" @click="openListenerFieldForm(null)">添加字段</el-button> |
| 119 | </p> | 119 | </p> |
| 120 | - <el-table :data="fieldsListOfListener" size="mini" max-height="240" border fit style="flex: none"> | 120 | + <el-table :data="fieldsListOfListener" size="small" max-height="240" border fit style="flex: none"> |
| 121 | <el-table-column label="序号" width="50px" type="index" /> | 121 | <el-table-column label="序号" width="50px" type="index" /> |
| 122 | <el-table-column label="字段名称" min-width="100px" prop="name" /> | 122 | <el-table-column label="字段名称" min-width="100px" prop="name" /> |
| 123 | <el-table-column label="字段类型" min-width="80px" show-overflow-tooltip :formatter="row => fieldTypeObject[row.fieldType]" /> | 123 | <el-table-column label="字段类型" min-width="80px" show-overflow-tooltip :formatter="row => fieldTypeObject[row.fieldType]" /> |
| 124 | <el-table-column label="字段值/表达式" min-width="100px" show-overflow-tooltip :formatter="row => row.string || row.expression" /> | 124 | <el-table-column label="字段值/表达式" min-width="100px" show-overflow-tooltip :formatter="row => row.string || row.expression" /> |
| 125 | <el-table-column label="操作" width="100px"> | 125 | <el-table-column label="操作" width="100px"> |
| 126 | <template #default="scope"> | 126 | <template #default="scope"> |
| 127 | - <el-button size="mini" type="text" @click="openListenerFieldForm(scope, scope.$index)">编辑</el-button> | 127 | + <el-button size="small" type="text" @click="openListenerFieldForm(scope, scope.$index)">编辑</el-button> |
| 128 | <el-divider direction="vertical" /> | 128 | <el-divider direction="vertical" /> |
| 129 | - <el-button size="mini" type="text" style="color: #ff4d4f" @click="removeListenerField(scope, scope.$index)">移除</el-button> | 129 | + <el-button size="small" type="text" style="color: #ff4d4f" @click="removeListenerField(scope, scope.$index)">移除</el-button> |
| 130 | </template> | 130 | </template> |
| 131 | </el-table-column> | 131 | </el-table-column> |
| 132 | </el-table> | 132 | </el-table> |
| 133 | 133 | ||
| 134 | <div class="element-drawer__button"> | 134 | <div class="element-drawer__button"> |
| 135 | - <el-button size="mini" @click="listenerFormModelVisible = false">取 消</el-button> | ||
| 136 | - <el-button size="mini" type="primary" @click="saveListenerConfig">保 存</el-button> | 135 | + <el-button size="small" @click="listenerFormModelVisible = false">取 消</el-button> |
| 136 | + <el-button size="small" type="primary" @click="saveListenerConfig">保 存</el-button> | ||
| 137 | </div> | 137 | </div> |
| 138 | </el-drawer> | 138 | </el-drawer> |
| 139 | 139 | ||
| 140 | <!-- 注入西段 编辑/创建 部分 --> | 140 | <!-- 注入西段 编辑/创建 部分 --> |
| 141 | <el-dialog title="字段配置" :visible.sync="listenerFieldFormModelVisible" width="600px" append-to-body destroy-on-close> | 141 | <el-dialog title="字段配置" :visible.sync="listenerFieldFormModelVisible" width="600px" append-to-body destroy-on-close> |
| 142 | - <el-form :model="listenerFieldForm" size="mini" label-width="96px" ref="listenerFieldFormRef" style="height: 136px" @submit.native.prevent> | 142 | + <el-form :model="listenerFieldForm" size="small" label-width="96px" ref="listenerFieldFormRef" style="height: 136px" @submit.native.prevent> |
| 143 | <el-form-item label="字段名称:" prop="name" :rules="{ required: true, trigger: ['blur', 'change'] }"> | 143 | <el-form-item label="字段名称:" prop="name" :rules="{ required: true, trigger: ['blur', 'change'] }"> |
| 144 | <el-input v-model="listenerFieldForm.name" clearable /> | 144 | <el-input v-model="listenerFieldForm.name" clearable /> |
| 145 | </el-form-item> | 145 | </el-form-item> |
| @@ -168,8 +168,8 @@ export const template = isTaskListener => { | @@ -168,8 +168,8 @@ export const template = isTaskListener => { | ||
| 168 | </el-form-item> | 168 | </el-form-item> |
| 169 | </el-form> | 169 | </el-form> |
| 170 | <template #footer> | 170 | <template #footer> |
| 171 | - <el-button size="mini" @click="listenerFieldFormModelVisible = false">取 消</el-button> | ||
| 172 | - <el-button size="mini" type="primary" @click="saveListenerFiled">确 定</el-button> | 171 | + <el-button size="small" @click="listenerFieldFormModelVisible = false">取 消</el-button> |
| 172 | + <el-button size="small" type="primary" @click="saveListenerFiled">确 定</el-button> | ||
| 173 | </template> | 173 | </template> |
| 174 | </el-dialog> | 174 | </el-dialog> |
| 175 | </div> | 175 | </div> |
yudao-ui-admin-vue3/src/components/bpmnProcessDesigner/package/penal/properties/ElementProperties.vue
| @@ -4,14 +4,15 @@ | @@ -4,14 +4,15 @@ | ||
| 4 | <el-table-column label="序号" width="50px" type="index" /> | 4 | <el-table-column label="序号" width="50px" type="index" /> |
| 5 | <el-table-column label="属性名" prop="name" min-width="100px" show-overflow-tooltip /> | 5 | <el-table-column label="属性名" prop="name" min-width="100px" show-overflow-tooltip /> |
| 6 | <el-table-column label="属性值" prop="value" min-width="100px" show-overflow-tooltip /> | 6 | <el-table-column label="属性值" prop="value" min-width="100px" show-overflow-tooltip /> |
| 7 | - <el-table-column label="操作" width="90px"> | 7 | + <el-table-column label="操作" width="110px"> |
| 8 | <template #default="scope"> | 8 | <template #default="scope"> |
| 9 | - <el-button type="text" @click="openAttributesForm(scope.row, scope.$index)" | 9 | + <el-button link @click="openAttributesForm(scope.row, scope.$index)" size="small" |
| 10 | >编辑</el-button | 10 | >编辑</el-button |
| 11 | > | 11 | > |
| 12 | <el-divider direction="vertical" /> | 12 | <el-divider direction="vertical" /> |
| 13 | <el-button | 13 | <el-button |
| 14 | - type="text" | 14 | + link |
| 15 | + size="small" | ||
| 15 | style="color: #ff4d4f" | 16 | style="color: #ff4d4f" |
| 16 | @click="removeAttributes(scope.row, scope.$index)" | 17 | @click="removeAttributes(scope.row, scope.$index)" |
| 17 | >移除</el-button | 18 | >移除</el-button |
| @@ -86,8 +87,8 @@ const resetAttributesList = () => { | @@ -86,8 +87,8 @@ const resetAttributesList = () => { | ||
| 86 | bpmnElement.value = window.bpmnInstances.bpmnElement | 87 | bpmnElement.value = window.bpmnInstances.bpmnElement |
| 87 | otherExtensionList.value = [] // 其他扩展配置 | 88 | otherExtensionList.value = [] // 其他扩展配置 |
| 88 | bpmnElementProperties.value = | 89 | bpmnElementProperties.value = |
| 89 | - bpmnElement.value.businessObject?.extensionElements?.filter((ex) => { | ||
| 90 | - // bpmnElement.value.businessObject?.extensionElements?.values.filter((ex) => { | 90 | + // bpmnElement.value.businessObject?.extensionElements?.filter((ex) => { |
| 91 | + bpmnElement.value.businessObject?.extensionElements?.values.filter((ex) => { | ||
| 91 | if (ex.$type !== `${prefix}:Properties`) { | 92 | if (ex.$type !== `${prefix}:Properties`) { |
| 92 | otherExtensionList.value.push(ex) | 93 | otherExtensionList.value.push(ex) |
| 93 | } | 94 | } |
yudao-ui-admin-vue3/src/components/bpmnProcessDesigner/package/penal/task/task-components/ReceiveTask.vue
yudao-ui-admin-vue3/src/components/bpmnProcessDesigner/package/utils.ts
| @@ -61,7 +61,7 @@ export function updateElementExtensions(element, extensionList) { | @@ -61,7 +61,7 @@ export function updateElementExtensions(element, extensionList) { | ||
| 61 | values: extensionList | 61 | values: extensionList |
| 62 | }) | 62 | }) |
| 63 | window.bpmnInstances.modeling.updateProperties(toRaw(element), { | 63 | window.bpmnInstances.modeling.updateProperties(toRaw(element), { |
| 64 | - extensionElements: extensions.values | 64 | + extensionElements: extensions |
| 65 | }) | 65 | }) |
| 66 | } | 66 | } |
| 67 | 67 |