@servicenow/sdk-build-plugins 4.6.0 → 4.7.0
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/acl-plugin.js +3 -4
- package/dist/acl-plugin.js.map +1 -1
- package/dist/applicability-plugin.js +0 -2
- package/dist/applicability-plugin.js.map +1 -1
- package/dist/application-menu-plugin.js +0 -2
- package/dist/application-menu-plugin.js.map +1 -1
- package/dist/arrow-function-plugin.js +0 -1
- package/dist/arrow-function-plugin.js.map +1 -1
- package/dist/atf/test-plugin.js +6 -10
- package/dist/atf/test-plugin.js.map +1 -1
- package/dist/basic-syntax-plugin.js +10 -4
- package/dist/basic-syntax-plugin.js.map +1 -1
- package/dist/business-rule-plugin.js +0 -1
- package/dist/business-rule-plugin.js.map +1 -1
- package/dist/call-expression-plugin.js +0 -1
- package/dist/call-expression-plugin.js.map +1 -1
- package/dist/claims-plugin.js +0 -1
- package/dist/claims-plugin.js.map +1 -1
- package/dist/client-script-plugin.js +0 -1
- package/dist/client-script-plugin.js.map +1 -1
- package/dist/column-plugin.js +120 -49
- package/dist/column-plugin.js.map +1 -1
- package/dist/cross-scope-privilege-plugin.js +0 -1
- package/dist/cross-scope-privilege-plugin.js.map +1 -1
- package/dist/dashboard/dashboard-plugin.js +0 -2
- package/dist/dashboard/dashboard-plugin.js.map +1 -1
- package/dist/data-plugin.js +0 -1
- package/dist/data-plugin.js.map +1 -1
- package/dist/data-policy-plugin.d.ts +2 -0
- package/dist/data-policy-plugin.js +276 -0
- package/dist/data-policy-plugin.js.map +1 -0
- package/dist/email-notification-plugin.js +2 -3
- package/dist/email-notification-plugin.js.map +1 -1
- package/dist/flow/flow-logic/flow-logic-constants.d.ts +2 -0
- package/dist/flow/flow-logic/flow-logic-constants.js +6 -1
- package/dist/flow/flow-logic/flow-logic-constants.js.map +1 -1
- package/dist/flow/flow-logic/flow-logic-diagnostics.js +192 -56
- package/dist/flow/flow-logic/flow-logic-diagnostics.js.map +1 -1
- package/dist/flow/flow-logic/flow-logic-plugin-helpers.d.ts +2 -1
- package/dist/flow/flow-logic/flow-logic-plugin-helpers.js +44 -5
- package/dist/flow/flow-logic/flow-logic-plugin-helpers.js.map +1 -1
- package/dist/flow/flow-logic/flow-logic-plugin.js +279 -29
- package/dist/flow/flow-logic/flow-logic-plugin.js.map +1 -1
- package/dist/flow/flow-logic/flow-logic-shapes.d.ts +15 -0
- package/dist/flow/flow-logic/flow-logic-shapes.js +25 -1
- package/dist/flow/flow-logic/flow-logic-shapes.js.map +1 -1
- package/dist/flow/plugins/approval-rules-plugin.js +0 -1
- package/dist/flow/plugins/approval-rules-plugin.js.map +1 -1
- package/dist/flow/plugins/flow-action-definition-plugin.js +804 -205
- package/dist/flow/plugins/flow-action-definition-plugin.js.map +1 -1
- package/dist/flow/plugins/flow-data-pill-plugin.js +3 -5
- package/dist/flow/plugins/flow-data-pill-plugin.js.map +1 -1
- package/dist/flow/plugins/flow-definition-plugin.js +84 -17
- package/dist/flow/plugins/flow-definition-plugin.js.map +1 -1
- package/dist/flow/plugins/flow-diagnostics-plugin.js +65 -3
- package/dist/flow/plugins/flow-diagnostics-plugin.js.map +1 -1
- package/dist/flow/plugins/flow-instance-plugin.js +13 -5
- package/dist/flow/plugins/flow-instance-plugin.js.map +1 -1
- package/dist/flow/plugins/flow-trigger-instance-plugin.js +0 -1
- package/dist/flow/plugins/flow-trigger-instance-plugin.js.map +1 -1
- package/dist/flow/plugins/inline-script-plugin.js +0 -1
- package/dist/flow/plugins/inline-script-plugin.js.map +1 -1
- package/dist/flow/plugins/step-definition-plugin.js +0 -2
- package/dist/flow/plugins/step-definition-plugin.js.map +1 -1
- package/dist/flow/plugins/step-instance-plugin.js +216 -77
- package/dist/flow/plugins/step-instance-plugin.js.map +1 -1
- package/dist/flow/plugins/trigger-plugin.js +0 -2
- package/dist/flow/plugins/trigger-plugin.js.map +1 -1
- package/dist/flow/plugins/wfa-datapill-plugin.js +0 -1
- package/dist/flow/plugins/wfa-datapill-plugin.js.map +1 -1
- package/dist/flow/utils/datapill-transformer.js +9 -5
- package/dist/flow/utils/datapill-transformer.js.map +1 -1
- package/dist/flow/utils/flow-constants.d.ts +12 -0
- package/dist/flow/utils/flow-constants.js +17 -3
- package/dist/flow/utils/flow-constants.js.map +1 -1
- package/dist/flow/utils/flow-io-to-record.d.ts +1 -1
- package/dist/flow/utils/flow-io-to-record.js +21 -13
- package/dist/flow/utils/flow-io-to-record.js.map +1 -1
- package/dist/flow/utils/flow-pill-utils.d.ts +26 -0
- package/dist/flow/utils/flow-pill-utils.js +50 -0
- package/dist/flow/utils/flow-pill-utils.js.map +1 -0
- package/dist/flow/utils/flow-stage-processor.d.ts +138 -0
- package/dist/flow/utils/flow-stage-processor.js +665 -0
- package/dist/flow/utils/flow-stage-processor.js.map +1 -0
- package/dist/flow/utils/pill-string-parser.js +28 -43
- package/dist/flow/utils/pill-string-parser.js.map +1 -1
- package/dist/flow/utils/utils.d.ts +11 -6
- package/dist/flow/utils/utils.js +37 -28
- package/dist/flow/utils/utils.js.map +1 -1
- package/dist/form-plugin.js +4 -14
- package/dist/form-plugin.js.map +1 -1
- package/dist/html-import-plugin.js +0 -1
- package/dist/html-import-plugin.js.map +1 -1
- package/dist/import-sets-plugin.js +0 -2
- package/dist/import-sets-plugin.js.map +1 -1
- package/dist/inbound-email-action-plugin.js +0 -1
- package/dist/inbound-email-action-plugin.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/instance-scan-plugin.js +0 -7
- package/dist/instance-scan-plugin.js.map +1 -1
- package/dist/json-plugin.js +0 -1
- package/dist/json-plugin.js.map +1 -1
- package/dist/list-plugin.js +4 -1
- package/dist/list-plugin.js.map +1 -1
- package/dist/now-attach-plugin.js +0 -1
- package/dist/now-attach-plugin.js.map +1 -1
- package/dist/now-config-plugin.js +1 -1
- package/dist/now-config-plugin.js.map +1 -1
- package/dist/now-id-plugin.js +0 -1
- package/dist/now-id-plugin.js.map +1 -1
- package/dist/now-include-plugin.js +0 -1
- package/dist/now-include-plugin.js.map +1 -1
- package/dist/now-ref-plugin.js +0 -1
- package/dist/now-ref-plugin.js.map +1 -1
- package/dist/now-unresolved-plugin.js +0 -1
- package/dist/now-unresolved-plugin.js.map +1 -1
- package/dist/package-json-plugin.js +3 -2
- package/dist/package-json-plugin.js.map +1 -1
- package/dist/property-plugin.js +0 -2
- package/dist/property-plugin.js.map +1 -1
- package/dist/record-plugin.d.ts +2 -0
- package/dist/record-plugin.js +5 -4
- package/dist/record-plugin.js.map +1 -1
- package/dist/repack/lint/Rules.d.ts +1 -2
- package/dist/rest-api-plugin.js +6 -5
- package/dist/rest-api-plugin.js.map +1 -1
- package/dist/role-plugin.js +0 -1
- package/dist/role-plugin.js.map +1 -1
- package/dist/schedule-script/scheduled-script-plugin.js +5 -4
- package/dist/schedule-script/scheduled-script-plugin.js.map +1 -1
- package/dist/script-action-plugin.js +0 -2
- package/dist/script-action-plugin.js.map +1 -1
- package/dist/script-include-plugin.js +4 -4
- package/dist/script-include-plugin.js.map +1 -1
- package/dist/server-module-plugin/index.js +2 -3
- package/dist/server-module-plugin/index.js.map +1 -1
- package/dist/service-catalog/catalog-clientscript-plugin.js +2 -4
- package/dist/service-catalog/catalog-clientscript-plugin.js.map +1 -1
- package/dist/service-catalog/catalog-item-plugin.js +0 -2
- package/dist/service-catalog/catalog-item-plugin.js.map +1 -1
- package/dist/service-catalog/catalog-ui-policy-plugin.js +2 -4
- package/dist/service-catalog/catalog-ui-policy-plugin.js.map +1 -1
- package/dist/service-catalog/sc-record-producer-plugin.js +0 -2
- package/dist/service-catalog/sc-record-producer-plugin.js.map +1 -1
- package/dist/service-catalog/service-catalog-base.d.ts +2 -2
- package/dist/service-catalog/service-catalog-base.js +2 -2
- package/dist/service-catalog/service-catalog-base.js.map +1 -1
- package/dist/service-catalog/utils.js +1 -1
- package/dist/service-catalog/utils.js.map +1 -1
- package/dist/service-catalog/variable-set-plugin.js +0 -2
- package/dist/service-catalog/variable-set-plugin.js.map +1 -1
- package/dist/service-portal/angular-provider-plugin.js +0 -2
- package/dist/service-portal/angular-provider-plugin.js.map +1 -1
- package/dist/service-portal/dependency-plugin.js +3 -5
- package/dist/service-portal/dependency-plugin.js.map +1 -1
- package/dist/service-portal/header-footer-plugin.js +3 -5
- package/dist/service-portal/header-footer-plugin.js.map +1 -1
- package/dist/service-portal/menu-plugin.js +0 -1
- package/dist/service-portal/menu-plugin.js.map +1 -1
- package/dist/service-portal/page-plugin.js +0 -1
- package/dist/service-portal/page-plugin.js.map +1 -1
- package/dist/service-portal/page-route-map-plugin.js +0 -1
- package/dist/service-portal/page-route-map-plugin.js.map +1 -1
- package/dist/service-portal/portal-plugin.js +0 -2
- package/dist/service-portal/portal-plugin.js.map +1 -1
- package/dist/service-portal/theme-plugin.js +0 -2
- package/dist/service-portal/theme-plugin.js.map +1 -1
- package/dist/service-portal/widget-plugin.js +3 -5
- package/dist/service-portal/widget-plugin.js.map +1 -1
- package/dist/sla-plugin.js +0 -2
- package/dist/sla-plugin.js.map +1 -1
- package/dist/static-content-plugin.js +32 -3
- package/dist/static-content-plugin.js.map +1 -1
- package/dist/table-plugin.js +303 -66
- package/dist/table-plugin.js.map +1 -1
- package/dist/ui-action-plugin.js +26 -17
- package/dist/ui-action-plugin.js.map +1 -1
- package/dist/ui-page-plugin.js +159 -17
- package/dist/ui-page-plugin.js.map +1 -1
- package/dist/ui-policy-plugin.js +28 -97
- package/dist/ui-policy-plugin.js.map +1 -1
- package/dist/user-preference-plugin.js +0 -2
- package/dist/user-preference-plugin.js.map +1 -1
- package/dist/utils.d.ts +5 -9
- package/dist/utils.js +38 -11
- package/dist/utils.js.map +1 -1
- package/dist/ux-list-menu-config-plugin.js +0 -2
- package/dist/ux-list-menu-config-plugin.js.map +1 -1
- package/dist/view-plugin.js +0 -1
- package/dist/view-plugin.js.map +1 -1
- package/dist/workspace-plugin.js +0 -2
- package/dist/workspace-plugin.js.map +1 -1
- package/package.json +6 -6
- package/src/acl-plugin.ts +4 -5
- package/src/applicability-plugin.ts +0 -2
- package/src/application-menu-plugin.ts +0 -2
- package/src/arrow-function-plugin.ts +0 -1
- package/src/atf/test-plugin.ts +6 -11
- package/src/basic-syntax-plugin.ts +11 -4
- package/src/business-rule-plugin.ts +1 -2
- package/src/call-expression-plugin.ts +0 -1
- package/src/claims-plugin.ts +0 -1
- package/src/client-script-plugin.ts +1 -2
- package/src/column-plugin.ts +163 -76
- package/src/cross-scope-privilege-plugin.ts +1 -2
- package/src/dashboard/dashboard-plugin.ts +0 -2
- package/src/data-plugin.ts +0 -1
- package/src/data-policy-plugin.ts +333 -0
- package/src/email-notification-plugin.ts +8 -4
- package/src/flow/flow-logic/flow-logic-constants.ts +6 -0
- package/src/flow/flow-logic/flow-logic-diagnostics.ts +236 -58
- package/src/flow/flow-logic/flow-logic-plugin-helpers.ts +59 -6
- package/src/flow/flow-logic/flow-logic-plugin.ts +368 -38
- package/src/flow/flow-logic/flow-logic-shapes.ts +25 -0
- package/src/flow/plugins/approval-rules-plugin.ts +0 -1
- package/src/flow/plugins/flow-action-definition-plugin.ts +940 -208
- package/src/flow/plugins/flow-data-pill-plugin.ts +3 -5
- package/src/flow/plugins/flow-definition-plugin.ts +159 -26
- package/src/flow/plugins/flow-diagnostics-plugin.ts +89 -3
- package/src/flow/plugins/flow-instance-plugin.ts +26 -12
- package/src/flow/plugins/flow-trigger-instance-plugin.ts +0 -1
- package/src/flow/plugins/inline-script-plugin.ts +0 -1
- package/src/flow/plugins/step-definition-plugin.ts +0 -2
- package/src/flow/plugins/step-instance-plugin.ts +259 -65
- package/src/flow/plugins/trigger-plugin.ts +0 -2
- package/src/flow/plugins/wfa-datapill-plugin.ts +0 -1
- package/src/flow/utils/datapill-transformer.ts +13 -5
- package/src/flow/utils/flow-constants.ts +19 -1
- package/src/flow/utils/flow-io-to-record.ts +29 -19
- package/src/flow/utils/flow-pill-utils.ts +48 -0
- package/src/flow/utils/flow-stage-processor.ts +831 -0
- package/src/flow/utils/pill-string-parser.ts +29 -47
- package/src/flow/utils/utils.ts +39 -35
- package/src/form-plugin.ts +5 -15
- package/src/html-import-plugin.ts +0 -1
- package/src/import-sets-plugin.ts +0 -2
- package/src/inbound-email-action-plugin.ts +1 -2
- package/src/index.ts +7 -1
- package/src/instance-scan-plugin.ts +0 -7
- package/src/json-plugin.ts +0 -1
- package/src/list-plugin.ts +6 -2
- package/src/now-attach-plugin.ts +0 -1
- package/src/now-config-plugin.ts +1 -1
- package/src/now-id-plugin.ts +0 -1
- package/src/now-include-plugin.ts +0 -1
- package/src/now-ref-plugin.ts +0 -1
- package/src/now-unresolved-plugin.ts +0 -1
- package/src/package-json-plugin.ts +8 -3
- package/src/property-plugin.ts +0 -2
- package/src/record-plugin.ts +14 -6
- package/src/repack/lint/Rules.ts +1 -1
- package/src/rest-api-plugin.ts +7 -6
- package/src/role-plugin.ts +1 -2
- package/src/schedule-script/scheduled-script-plugin.ts +11 -5
- package/src/script-action-plugin.ts +0 -2
- package/src/script-include-plugin.ts +8 -4
- package/src/server-module-plugin/index.ts +2 -3
- package/src/service-catalog/catalog-clientscript-plugin.ts +2 -4
- package/src/service-catalog/catalog-item-plugin.ts +0 -2
- package/src/service-catalog/catalog-ui-policy-plugin.ts +2 -4
- package/src/service-catalog/sc-record-producer-plugin.ts +0 -2
- package/src/service-catalog/service-catalog-base.ts +2 -2
- package/src/service-catalog/utils.ts +1 -1
- package/src/service-catalog/variable-set-plugin.ts +0 -2
- package/src/service-portal/angular-provider-plugin.ts +0 -2
- package/src/service-portal/dependency-plugin.ts +0 -2
- package/src/service-portal/header-footer-plugin.ts +0 -2
- package/src/service-portal/menu-plugin.ts +1 -2
- package/src/service-portal/page-plugin.ts +1 -2
- package/src/service-portal/page-route-map-plugin.ts +1 -2
- package/src/service-portal/portal-plugin.ts +0 -2
- package/src/service-portal/theme-plugin.ts +0 -2
- package/src/service-portal/widget-plugin.ts +0 -2
- package/src/sla-plugin.ts +0 -2
- package/src/static-content-plugin.ts +37 -4
- package/src/table-plugin.ts +371 -92
- package/src/ui-action-plugin.ts +30 -17
- package/src/ui-page-plugin.ts +188 -20
- package/src/ui-policy-plugin.ts +33 -130
- package/src/user-preference-plugin.ts +0 -2
- package/src/utils.ts +48 -11
- package/src/ux-list-menu-config-plugin.ts +0 -2
- package/src/view-plugin.ts +0 -1
- package/src/workspace-plugin.ts +0 -2
package/src/ui-action-plugin.ts
CHANGED
|
@@ -6,13 +6,12 @@ import {
|
|
|
6
6
|
type Shape,
|
|
7
7
|
type StringShape,
|
|
8
8
|
} from '@servicenow/sdk-build-core'
|
|
9
|
+
import type { UiAction } from '@servicenow/sdk-core/runtime/ui'
|
|
9
10
|
import { NowIdShape } from './now-id-plugin'
|
|
10
11
|
import { ModuleFunctionShape } from './server-module-plugin'
|
|
11
|
-
import { createSdkDocEntry } from './utils'
|
|
12
12
|
|
|
13
13
|
export const UiActionPlugin = Plugin.create({
|
|
14
14
|
name: 'UiActionPlugin',
|
|
15
|
-
docs: [createSdkDocEntry('UiAction', ['sys_ui_action'])],
|
|
16
15
|
records: {
|
|
17
16
|
sys_ui_action: {
|
|
18
17
|
relationships: {
|
|
@@ -161,7 +160,7 @@ export const UiActionPlugin = Plugin.create({
|
|
|
161
160
|
order: $.map((o) => (o.ifString()?.getValue() === '' ? 100 : o))
|
|
162
161
|
.toNumber()
|
|
163
162
|
.def(100),
|
|
164
|
-
overrides: $.def(''),
|
|
163
|
+
overrides: $.from('sys_overrides').def(''),
|
|
165
164
|
showQuery: $.from('show_query').toBoolean().def(false),
|
|
166
165
|
showUpdate: $.from('show_update').toBoolean(),
|
|
167
166
|
showInsert: $.from('show_insert').toBoolean(),
|
|
@@ -195,6 +194,18 @@ export const UiActionPlugin = Plugin.create({
|
|
|
195
194
|
const arg = callExpression.getArgument(0).asObject()
|
|
196
195
|
const isClient = arg.get(['client', 'isClient'])
|
|
197
196
|
|
|
197
|
+
const form = arg.get('form')?.getValue() as UiAction<string>['form']
|
|
198
|
+
const isFormAction = form?.showButton || form?.showLink || form?.showContextMenu
|
|
199
|
+
|
|
200
|
+
const list = arg.get('list').getValue() as UiAction<string>['list']
|
|
201
|
+
const isListAction =
|
|
202
|
+
list?.showButton ||
|
|
203
|
+
list?.showBannerButton ||
|
|
204
|
+
list?.showContextMenu ||
|
|
205
|
+
list?.showListChoice ||
|
|
206
|
+
list?.showLink ||
|
|
207
|
+
list?.showSaveWithFormButton
|
|
208
|
+
|
|
198
209
|
const uiAction = await factory.createRecord({
|
|
199
210
|
source: callExpression,
|
|
200
211
|
table: 'sys_ui_action',
|
|
@@ -212,8 +223,8 @@ export const UiActionPlugin = Plugin.create({
|
|
|
212
223
|
? arg.get('messages').asArray().getValue().join('\n')
|
|
213
224
|
: arg.get('messages')
|
|
214
225
|
).def([]),
|
|
215
|
-
list_style: $.val(
|
|
216
|
-
form_style: $.val(
|
|
226
|
+
list_style: $.val(list?.style),
|
|
227
|
+
form_style: $.val(form?.style),
|
|
217
228
|
condition: $.def(''),
|
|
218
229
|
script: $.map(
|
|
219
230
|
(v) => v.if(ModuleFunctionShape)?.toString((n) => `${n}({{PARAMS}})`, ['current']) ?? v
|
|
@@ -222,24 +233,26 @@ export const UiActionPlugin = Plugin.create({
|
|
|
222
233
|
.toCdata(),
|
|
223
234
|
hint: $.def(''),
|
|
224
235
|
order: $.toNumber().def(100),
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
236
|
+
sys_overrides: $.from('overrides').def(''),
|
|
237
|
+
form_action: $.val(isFormAction).def(false),
|
|
238
|
+
list_action: $.val(isListAction).def(false),
|
|
239
|
+
form_button: $.val(form?.showButton).def(false),
|
|
240
|
+
list_button: $.val(list?.showButton).def(false),
|
|
241
|
+
form_link: $.val(form?.showLink).def(false),
|
|
242
|
+
list_link: $.val(list?.showLink).def(false),
|
|
243
|
+
form_context_menu: $.val(form?.showContextMenu).def(false),
|
|
244
|
+
list_context_menu: $.val(list?.showContextMenu).def(false),
|
|
232
245
|
show_query: $.from('showQuery').toBoolean().def(false),
|
|
233
246
|
show_insert: $.from('showInsert').toBoolean().def(false).def(true),
|
|
234
247
|
show_multiple_update: $.from('showMultipleUpdate').toBoolean().def(false),
|
|
235
248
|
show_update: $.from('showUpdate').toBoolean().def(true),
|
|
236
|
-
list_choice: $.val(
|
|
237
|
-
list_banner_button: $.val(
|
|
238
|
-
list_save_with_form_button: $.val(
|
|
249
|
+
list_choice: $.val(list?.showListChoice).def(false),
|
|
250
|
+
list_banner_button: $.val(list?.showBannerButton).def(false),
|
|
251
|
+
list_save_with_form_button: $.val(list?.showSaveWithFormButton).def(false),
|
|
239
252
|
isolate_script: $.from('isolateScript').toBoolean().def(false),
|
|
240
253
|
ui11_compatible: $.val(arg.get(['client', 'isUi11Compatible'])).def(false),
|
|
241
|
-
ui16_compatible: $.val(arg.get(['client', 'isUi16Compatible'])),
|
|
242
|
-
client_script_v2: $.val(arg.get(['workspace', 'clientScriptV2'])),
|
|
254
|
+
ui16_compatible: $.val(arg.get(['client', 'isUi16Compatible'])).def(false),
|
|
255
|
+
client_script_v2: $.val(arg.get(['workspace', 'clientScriptV2'])).toCdata(),
|
|
243
256
|
form_button_v2: $.val(arg.get(['workspace', 'showFormButtonV2'])).def(false),
|
|
244
257
|
form_menu_button_v2: $.val(arg.get(['workspace', 'showFormMenuButtonV2'])).def(false),
|
|
245
258
|
format_for_configurable_workspace: $.val(arg.get(['workspace', 'isConfigurableWorkspace'])).def(
|
package/src/ui-page-plugin.ts
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
isSNScope,
|
|
9
9
|
zipSync,
|
|
10
10
|
unzipSync,
|
|
11
|
+
ts,
|
|
11
12
|
type Logger,
|
|
12
13
|
type Diagnostics,
|
|
13
14
|
type Project,
|
|
@@ -21,9 +22,10 @@ import { parseDocument, DomUtils } from 'htmlparser2'
|
|
|
21
22
|
import { XMLParser, XMLBuilder, type X2jOptions, type XmlBuilderOptions } from 'fast-xml-parser'
|
|
22
23
|
import { create } from 'xmlbuilder2'
|
|
23
24
|
import { NowIdShape } from './now-id-plugin'
|
|
25
|
+
import { NowIncludeShape } from './now-include-plugin'
|
|
24
26
|
import { CHUNK_SIZE, chunkData, generateId } from './static-content-plugin'
|
|
25
27
|
import { sha256 } from './now-attach-plugin'
|
|
26
|
-
import {
|
|
28
|
+
import { TRANSLATIONS_SUFFIX } from '@servicenow/isomorphic-rollup'
|
|
27
29
|
|
|
28
30
|
const parserOptions: X2jOptions = {
|
|
29
31
|
ignoreAttributes: false,
|
|
@@ -157,6 +159,50 @@ const SOURCE_ARTIFACT_RELATIONSHIPS = {
|
|
|
157
159
|
|
|
158
160
|
const parser = new XMLParser(parserOptions)
|
|
159
161
|
|
|
162
|
+
const escapeHtml = (s: string): string => s.replace(/&/g, '&')
|
|
163
|
+
|
|
164
|
+
const escapeSingle = (s: string): string => escapeHtml(s).replace(/\\/g, '\\\\').replace(/'/g, "\\'")
|
|
165
|
+
|
|
166
|
+
const escapeDouble = (s: string): string => escapeHtml(s).replace(/\\/g, '\\\\').replace(/"/g, '\\"')
|
|
167
|
+
|
|
168
|
+
const getTranslationMessages = (
|
|
169
|
+
fs: FileSystem,
|
|
170
|
+
config: NowConfig,
|
|
171
|
+
rootDir: string,
|
|
172
|
+
htmlRelPathFromClientDir: string
|
|
173
|
+
): string[] => {
|
|
174
|
+
// The rollup plugin emits `<stem>.translations.json` next to each bundled html, preserving
|
|
175
|
+
// the html's subdirectory structure under clientDir. So a source html at
|
|
176
|
+
// `<clientDir>/admin/page.html` produces `<staticContentDir>/admin/page.translations.json`.
|
|
177
|
+
if (htmlRelPathFromClientDir.startsWith('..')) {
|
|
178
|
+
return []
|
|
179
|
+
}
|
|
180
|
+
const translationsRelPath = htmlRelPathFromClientDir.replace(/\.html$/, TRANSLATIONS_SUFFIX)
|
|
181
|
+
const translationsPath = path.join(rootDir, config.staticContentDir, translationsRelPath)
|
|
182
|
+
try {
|
|
183
|
+
fs.accessSync(translationsPath)
|
|
184
|
+
} catch {
|
|
185
|
+
return []
|
|
186
|
+
}
|
|
187
|
+
try {
|
|
188
|
+
const content = fs.readFileSync(translationsPath, { encoding: 'utf-8' })
|
|
189
|
+
const parsed = JSON.parse(content) as { messages: Array<string | { [key: string]: string }> }
|
|
190
|
+
return parsed.messages.map((entry) => (typeof entry === 'string' ? entry : (entry['code'] ?? '')))
|
|
191
|
+
} catch {
|
|
192
|
+
return []
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const translationsJellyScript = (scope: string, messages: string[]): string => `
|
|
197
|
+
<script type="text/javascript">
|
|
198
|
+
'use strict';
|
|
199
|
+
|
|
200
|
+
window.__TRANSLATIONS__ = {
|
|
201
|
+
${messages.map((message) => `'${escapeSingle(message)}': '\${NS,JS:sn_i18n.Message.getMessage("${escapeDouble(scope)}", "${escapeDouble(message)}")}'`).join(',\n ')}
|
|
202
|
+
};
|
|
203
|
+
</script>
|
|
204
|
+
`
|
|
205
|
+
|
|
160
206
|
// TODO: Remove this shim tag once we've shipped Glide support for this feature.
|
|
161
207
|
const nowUxGlobals = (themeId: string = POLARIS_APPSHELL_THEME_ID) => {
|
|
162
208
|
return parser.parse(`<!-- @sdk:now-ux-globals -->
|
|
@@ -216,7 +262,6 @@ const nodeTransformer = (nodes: any[]) => {
|
|
|
216
262
|
|
|
217
263
|
export const UiPagePlugin = Plugin.create({
|
|
218
264
|
name: 'UiPagePlugin',
|
|
219
|
-
docs: [createSdkDocEntry('UiPage', ['sys_ui_page'])],
|
|
220
265
|
records: {
|
|
221
266
|
sys_ui_page: {
|
|
222
267
|
composite: true,
|
|
@@ -271,7 +316,7 @@ export const UiPagePlugin = Plugin.create({
|
|
|
271
316
|
}
|
|
272
317
|
},
|
|
273
318
|
|
|
274
|
-
async toFile(uiPage, { config, descendants, transform }) {
|
|
319
|
+
async toFile(uiPage, { config, database, descendants, transform }) {
|
|
275
320
|
if (!uiPage.has('endpoint') && !uiPage.has('name')) {
|
|
276
321
|
return { success: false }
|
|
277
322
|
}
|
|
@@ -296,6 +341,7 @@ export const UiPagePlugin = Plugin.create({
|
|
|
296
341
|
|
|
297
342
|
const result = await serializeWithArtifact(uiPage, uiPagePropsToSerialize, {
|
|
298
343
|
config,
|
|
344
|
+
database,
|
|
299
345
|
descendants,
|
|
300
346
|
transform,
|
|
301
347
|
})
|
|
@@ -410,9 +456,29 @@ export const UiPagePlugin = Plugin.create({
|
|
|
410
456
|
diagnostics.error(endpoint.getOriginalNode(), 'endpoint must include a page name before .do')
|
|
411
457
|
return { success: false }
|
|
412
458
|
}
|
|
413
|
-
|
|
459
|
+
const htmlShape = arg.get('html')
|
|
460
|
+
let html = htmlShape.toString().getValue()
|
|
414
461
|
let sourceFilePaths: string[] = []
|
|
415
462
|
let assetNames: string[] = []
|
|
463
|
+
let vendorAssetNames: string[] = []
|
|
464
|
+
let htmlRelPathFromClientDir: string | undefined
|
|
465
|
+
|
|
466
|
+
const clientAbsDir = path.join(project.getRootDir(), config.clientDir)
|
|
467
|
+
const computeRelFromClientDir = (htmlIncludePath: string): string => {
|
|
468
|
+
const sourceFileDir = path.dirname(callExpression.getOriginalNode().getSourceFile().getFilePath())
|
|
469
|
+
const absoluteHtmlPath = path.resolve(sourceFileDir, htmlIncludePath)
|
|
470
|
+
return path.relative(clientAbsDir, absoluteHtmlPath).replace(/\\/g, '/')
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// `html: Now.include('../ui/hello.html')` resolves to a NowIncludeShape whose path
|
|
474
|
+
// we can read directly. The included content has no HTML_IMPORT_PREFIX, so detect
|
|
475
|
+
// this case before the prefix check below.
|
|
476
|
+
if (htmlShape.is(NowIncludeShape)) {
|
|
477
|
+
const includePath = htmlShape.as(NowIncludeShape).getPath()
|
|
478
|
+
if (includePath.endsWith('.html')) {
|
|
479
|
+
htmlRelPathFromClientDir = computeRelFromClientDir(includePath)
|
|
480
|
+
}
|
|
481
|
+
}
|
|
416
482
|
|
|
417
483
|
// HtmlImportPlugin (which runs before toRecord) resolves `html: _html` identifiers
|
|
418
484
|
// to the file content and prepends an HTML_IMPORT_PREFIX warning comment.
|
|
@@ -421,16 +487,23 @@ export const UiPagePlugin = Plugin.create({
|
|
|
421
487
|
// An inline string (e.g. `html: '<h1>...</h1>'`) never gets the prefix, so an
|
|
422
488
|
// unrelated `.html` import in the same file does NOT trigger artifact creation.
|
|
423
489
|
if (html.trimStart().startsWith(HTML_IMPORT_PREFIX)) {
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
//
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
)
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
490
|
+
// Resolve the import declaration from the specific identifier passed as the
|
|
491
|
+
// `html` argument — NOT the first .html import in the file. A single .now.ts
|
|
492
|
+
// may declare several UiPages with different html imports, and each one must
|
|
493
|
+
// pick up only the manifest/translations for the file it actually imports.
|
|
494
|
+
const htmlNode = htmlShape.getOriginalNode()
|
|
495
|
+
const moduleSpecifier = ts.Node.isIdentifier(htmlNode)
|
|
496
|
+
? htmlNode
|
|
497
|
+
.getSymbol()
|
|
498
|
+
?.getDeclarations()[0]
|
|
499
|
+
?.getParent()
|
|
500
|
+
?.asKind(ts.SyntaxKind.ImportDeclaration)
|
|
501
|
+
?.getModuleSpecifierValue()
|
|
502
|
+
: undefined
|
|
503
|
+
if (moduleSpecifier?.endsWith('.html')) {
|
|
504
|
+
htmlRelPathFromClientDir = computeRelFromClientDir(moduleSpecifier)
|
|
505
|
+
const sourceFileDir = path.dirname(htmlNode.getSourceFile().getFilePath())
|
|
506
|
+
const absoluteHtmlPath = path.resolve(sourceFileDir, moduleSpecifier)
|
|
434
507
|
const manifest = getUIPageSourceFilePaths(
|
|
435
508
|
absoluteHtmlPath,
|
|
436
509
|
fs,
|
|
@@ -440,6 +513,7 @@ export const UiPagePlugin = Plugin.create({
|
|
|
440
513
|
)
|
|
441
514
|
sourceFilePaths = manifest.files
|
|
442
515
|
assetNames = manifest.assetNames
|
|
516
|
+
vendorAssetNames = manifest.vendorAssetNames
|
|
443
517
|
}
|
|
444
518
|
}
|
|
445
519
|
|
|
@@ -458,6 +532,17 @@ export const UiPagePlugin = Plugin.create({
|
|
|
458
532
|
}
|
|
459
533
|
return { success: false }
|
|
460
534
|
}
|
|
535
|
+
if (htmlRelPathFromClientDir) {
|
|
536
|
+
const messages = getTranslationMessages(
|
|
537
|
+
fs,
|
|
538
|
+
config,
|
|
539
|
+
project.getRootDir(),
|
|
540
|
+
htmlRelPathFromClientDir
|
|
541
|
+
)
|
|
542
|
+
if (messages.length > 0) {
|
|
543
|
+
html += translationsJellyScript(config.scope, messages)
|
|
544
|
+
}
|
|
545
|
+
}
|
|
461
546
|
}
|
|
462
547
|
|
|
463
548
|
const record = await factory.createRecord({
|
|
@@ -503,6 +588,28 @@ export const UiPagePlugin = Plugin.create({
|
|
|
503
588
|
assetNames
|
|
504
589
|
)
|
|
505
590
|
|
|
591
|
+
// Link this page's source artifact to each vendor chunk it depends on.
|
|
592
|
+
// Emitted for both configuration and package builds: configuration
|
|
593
|
+
// deploys need the M2Ms so the platform knows which vendor chunks belong
|
|
594
|
+
// to this page; package builds need them so vendor refs are tracked in
|
|
595
|
+
// keys.ts and not flagged as deletes on the next sync.
|
|
596
|
+
if (vendorAssetNames.length > 0) {
|
|
597
|
+
const artifactRecord = sourceArtifactRecords.find(
|
|
598
|
+
(r) => r.getTable() === 'sn_glider_source_artifact'
|
|
599
|
+
)
|
|
600
|
+
if (artifactRecord) {
|
|
601
|
+
const vendorM2ms = await Promise.all(
|
|
602
|
+
vendorAssetNames.map((name) =>
|
|
603
|
+
createAssetArtifactM2mRecord(artifactRecord, name, record, {
|
|
604
|
+
factory,
|
|
605
|
+
config,
|
|
606
|
+
})
|
|
607
|
+
)
|
|
608
|
+
)
|
|
609
|
+
sourceArtifactRecords.push(...vendorM2ms)
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
|
|
506
613
|
if (sourceArtifactRecords.length > 0) {
|
|
507
614
|
record.with(...sourceArtifactRecords)
|
|
508
615
|
} else {
|
|
@@ -523,17 +630,18 @@ export const UiPagePlugin = Plugin.create({
|
|
|
523
630
|
})
|
|
524
631
|
|
|
525
632
|
/**
|
|
526
|
-
* Reads source file paths from the UI source manifest file.
|
|
633
|
+
* Reads source file paths and vendor asset names from the UI source manifest file.
|
|
527
634
|
*
|
|
528
635
|
* The manifest is generated by isomorphic-rollup's sourceManifest plugin during build.
|
|
529
|
-
* It's a JSON file with the structure:
|
|
636
|
+
* It's a JSON file with the structure:
|
|
637
|
+
* { html, entry, files: string[], vendors: [fileName, contentHash][] }
|
|
530
638
|
*
|
|
531
639
|
* @param htmlFilePath - Path to the HTML file
|
|
532
640
|
* @param fs - File system interface
|
|
533
641
|
* @param logger - Logger for diagnostics
|
|
534
642
|
* @param config - NowConfig with staticContentDir
|
|
535
643
|
* @param rootDir - Project root directory
|
|
536
|
-
* @returns
|
|
644
|
+
* @returns Source file paths, entry asset names, and vendor asset names
|
|
537
645
|
*/
|
|
538
646
|
const getUIPageSourceFilePaths = (
|
|
539
647
|
htmlFilePath: string,
|
|
@@ -541,8 +649,8 @@ const getUIPageSourceFilePaths = (
|
|
|
541
649
|
logger: Logger,
|
|
542
650
|
config: NowConfig,
|
|
543
651
|
rootDir: string
|
|
544
|
-
): { files: string[]; assetNames: string[] } => {
|
|
545
|
-
const empty = { files: [], assetNames: [] }
|
|
652
|
+
): { files: string[]; assetNames: string[]; vendorAssetNames: string[] } => {
|
|
653
|
+
const empty = { files: [], assetNames: [], vendorAssetNames: [] }
|
|
546
654
|
try {
|
|
547
655
|
// Derive manifest path from HTML path by mirroring the directory structure
|
|
548
656
|
// from clientDir into staticContentDir and swapping the extension.
|
|
@@ -596,7 +704,30 @@ const getUIPageSourceFilePaths = (
|
|
|
596
704
|
// no source map in this build output — skip
|
|
597
705
|
}
|
|
598
706
|
|
|
599
|
-
|
|
707
|
+
// Derive vendor asset names from the manifest's vendors field.
|
|
708
|
+
// Each vendor entry is [fileName, contentHash], e.g.
|
|
709
|
+
// ["vendor-react-dom--d217b640.jsdbx", "d217b640"]
|
|
710
|
+
// The asset name mirrors static-content-plugin's formula:
|
|
711
|
+
// path.join(scope, fileNameWithoutExt)
|
|
712
|
+
const vendorAssetNames: string[] = []
|
|
713
|
+
const vendors: [string, string][] = manifest.vendors ?? []
|
|
714
|
+
for (const [fileName] of vendors) {
|
|
715
|
+
const ext = path.extname(fileName)
|
|
716
|
+
const nameWithoutExt = fileName.substring(0, fileName.length - ext.length)
|
|
717
|
+
const vendorAssetName = path.join(config.scope, nameWithoutExt).replace(/\\/g, '/')
|
|
718
|
+
vendorAssetNames.push(vendorAssetName)
|
|
719
|
+
|
|
720
|
+
// Check for vendor sourcemap
|
|
721
|
+
const vendorMapPath = path.join(staticContentAbsDir, `${nameWithoutExt}.jsdbx.map`)
|
|
722
|
+
try {
|
|
723
|
+
fs.accessSync(vendorMapPath)
|
|
724
|
+
vendorAssetNames.push(path.join(config.scope, `${nameWithoutExt}.js.map`).replace(/\\/g, '/'))
|
|
725
|
+
} catch {
|
|
726
|
+
// no sourcemap for this vendor chunk
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
return { files: manifest.files, assetNames, vendorAssetNames }
|
|
600
731
|
} catch (error) {
|
|
601
732
|
logger.warn(`Failed to read source manifest: ${error}`)
|
|
602
733
|
return empty
|
|
@@ -1114,6 +1245,7 @@ async function serializeWithArtifact(
|
|
|
1114
1245
|
metadataRecord: Record,
|
|
1115
1246
|
metadataProps: string[],
|
|
1116
1247
|
context: {
|
|
1248
|
+
database: Database
|
|
1117
1249
|
descendants: { query: (table: string) => Record[] }
|
|
1118
1250
|
config: { scope: string; scopeId: string }
|
|
1119
1251
|
transform: Transform
|
|
@@ -1293,6 +1425,42 @@ async function serializeWithArtifact(
|
|
|
1293
1425
|
? `sys_attachment.table_sys_id=${artifactId}^sys_idNOT IN${currentDocIds.join(',')}`
|
|
1294
1426
|
: `sys_attachment.table_sys_id=${artifactId}`
|
|
1295
1427
|
recordUpdate.ele('sys_attachment_doc', { action: 'delete_multiple', query: docQuery })
|
|
1428
|
+
|
|
1429
|
+
// Clean up stale source-artifact M2Ms for this artifact (e.g. when a vendor
|
|
1430
|
+
// chunk hash changes, the M2M to the prior vendor asset must be removed).
|
|
1431
|
+
//
|
|
1432
|
+
// Query the full database, not page descendants: asset M2Ms are descendants
|
|
1433
|
+
// of their sys_ux_lib_asset records, not of the page, so the page's
|
|
1434
|
+
// descendants only have the page M2M. The NOT IN list must include every
|
|
1435
|
+
// current-build M2M for this artifact, otherwise the sweep would also
|
|
1436
|
+
// delete live entry/vendor M2Ms inserted by the asset XMLs.
|
|
1437
|
+
//
|
|
1438
|
+
// Skip DELETE-action rows: on a same-project package rebuild,
|
|
1439
|
+
// generateRecordsFromDeletedKeys inserts DELETE rows for keys no longer
|
|
1440
|
+
// registered (e.g. the prior vendor M2M). Adding their sys_ids to NOT IN
|
|
1441
|
+
// would protect the stale rows on the platform — defeating the sweep.
|
|
1442
|
+
const currentM2mIds = context.database
|
|
1443
|
+
.query('sn_glider_source_artifact_m2m')
|
|
1444
|
+
.filter((m2m) => {
|
|
1445
|
+
if (m2m.isDeleted()) {
|
|
1446
|
+
return false
|
|
1447
|
+
}
|
|
1448
|
+
const srcArtifact = m2m.get('source_artifact')
|
|
1449
|
+
const srcId = srcArtifact.isRecord()
|
|
1450
|
+
? srcArtifact.asRecord().getId().getValue()
|
|
1451
|
+
: srcArtifact.toString().getValue()
|
|
1452
|
+
return srcId === artifactId
|
|
1453
|
+
})
|
|
1454
|
+
.map((m2m) => m2m.getId().getValue())
|
|
1455
|
+
|
|
1456
|
+
const m2mQuery =
|
|
1457
|
+
currentM2mIds.length > 0
|
|
1458
|
+
? `source_artifact=${artifactId}^sys_idNOT IN${currentM2mIds.join(',')}`
|
|
1459
|
+
: `source_artifact=${artifactId}`
|
|
1460
|
+
recordUpdate.ele('sn_glider_source_artifact_m2m', {
|
|
1461
|
+
action: 'delete_multiple',
|
|
1462
|
+
query: m2mQuery,
|
|
1463
|
+
})
|
|
1296
1464
|
})
|
|
1297
1465
|
|
|
1298
1466
|
return {
|
package/src/ui-policy-plugin.ts
CHANGED
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
type Record,
|
|
9
9
|
type Shape,
|
|
10
10
|
} from '@servicenow/sdk-build-core'
|
|
11
|
-
import {
|
|
11
|
+
import { validateClientSideScript } from './utils'
|
|
12
12
|
import { NowIdShape } from './now-id-plugin'
|
|
13
13
|
|
|
14
14
|
// Define table names as constants since they're not exported from the core tables
|
|
@@ -93,7 +93,6 @@ const validateScriptProperty = (
|
|
|
93
93
|
|
|
94
94
|
export const UiPolicyPlugin = Plugin.create({
|
|
95
95
|
name: 'UiPolicyPlugin',
|
|
96
|
-
docs: [createSdkDocEntry('UiPolicy', ['sys_ui_policy'])],
|
|
97
96
|
records: {
|
|
98
97
|
[SYS_UI_POLICY]: {
|
|
99
98
|
coalesce: ['table', 'short_description'],
|
|
@@ -108,128 +107,35 @@ export const UiPolicyPlugin = Plugin.create({
|
|
|
108
107
|
},
|
|
109
108
|
},
|
|
110
109
|
toShape(record, { descendants }) {
|
|
111
|
-
const actions = descendants
|
|
112
|
-
.
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
fieldMessage?: string
|
|
128
|
-
fieldMessageType?: string
|
|
129
|
-
valueAction?: string
|
|
130
|
-
} = {
|
|
131
|
-
field: fieldValue,
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Convert ServiceNow string format to boolean | 'ignore'
|
|
135
|
-
const visible = stringToBoolean(action.get('visible')?.ifString()?.getValue())
|
|
136
|
-
const disabled = stringToBoolean(action.get('disabled')?.ifString()?.getValue())
|
|
137
|
-
const mandatory = stringToBoolean(action.get('mandatory')?.ifString()?.getValue())
|
|
138
|
-
|
|
139
|
-
// Only include visible if it's not 'ignore'
|
|
140
|
-
if (visible !== undefined && visible !== 'ignore') {
|
|
141
|
-
actionObj.visible = visible
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// Convert 'disabled' to 'readOnly'
|
|
145
|
-
// Only include 'readOnly' if it's not 'ignore'
|
|
146
|
-
if (disabled !== undefined && disabled !== 'ignore') {
|
|
147
|
-
actionObj.readOnly = disabled
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// Only include mandatory if it's not 'ignore'
|
|
151
|
-
if (mandatory !== undefined && mandatory !== 'ignore') {
|
|
152
|
-
actionObj.mandatory = mandatory
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
const cleared = action.get('cleared')?.ifBoolean()?.getValue()
|
|
156
|
-
if (cleared) {
|
|
157
|
-
actionObj.cleared = cleared
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// Add new optional fields - only if they have meaningful values
|
|
161
|
-
const table = action.get('table')?.ifString()?.getValue()
|
|
162
|
-
const parentTable = record.get('table')?.ifString()?.getValue()
|
|
163
|
-
// Only include table if it's different from the parent policy's table
|
|
164
|
-
if (table && table !== parentTable) {
|
|
165
|
-
actionObj.table = table
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
const value = action.get('value')?.ifString()?.getValue()
|
|
169
|
-
if (value) {
|
|
170
|
-
actionObj.value = value
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
const fieldMessage = action.get('field_message')?.ifString()?.getValue()
|
|
174
|
-
if (fieldMessage) {
|
|
175
|
-
actionObj.fieldMessage = fieldMessage
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
const fieldMessageType = action.get('field_message_type')?.ifString()?.getValue()
|
|
179
|
-
// Only include if it's not the default value 'none'
|
|
180
|
-
if (fieldMessageType && fieldMessageType !== 'none') {
|
|
181
|
-
actionObj.fieldMessageType = fieldMessageType
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
const valueAction = action.get('value_action')?.ifString()?.getValue()
|
|
185
|
-
// Only include if it's not the default value 'ignore'
|
|
186
|
-
if (valueAction && valueAction !== 'ignore') {
|
|
187
|
-
actionObj.valueAction = valueAction
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// Skip actions that have no meaningful properties (all are 'ignore')
|
|
191
|
-
if (Object.keys(actionObj).length === 1) {
|
|
192
|
-
return null // Only 'field' property exists, skip this action
|
|
193
|
-
}
|
|
110
|
+
const actions = descendants.query(SYS_UI_POLICY_ACTION).map((action) => {
|
|
111
|
+
return action.transform(({ $ }) => ({
|
|
112
|
+
field: $,
|
|
113
|
+
visible: $.map((v) => stringToBoolean(v?.asString()?.getValue())).def('ignore'),
|
|
114
|
+
readOnly: $.from('disabled')
|
|
115
|
+
.map((v) => stringToBoolean(v?.asString()?.getValue()))
|
|
116
|
+
.def('ignore'),
|
|
117
|
+
mandatory: $.map((v) => stringToBoolean(v?.asString()?.getValue())).def('ignore'),
|
|
118
|
+
cleared: $.toBoolean().def(false),
|
|
119
|
+
table: $.def(''),
|
|
120
|
+
value: $.def(''),
|
|
121
|
+
fieldMessage: $.from('field_message').def(''),
|
|
122
|
+
fieldMessageType: $.from('field_message_type').def('none'),
|
|
123
|
+
valueAction: $.from('value_action').def('ignore'),
|
|
124
|
+
}))
|
|
125
|
+
})
|
|
194
126
|
|
|
195
|
-
|
|
196
|
-
})
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
.query(SYS_UI_POLICY_RL_ACTION)
|
|
202
|
-
.map((rlAction) => {
|
|
203
|
-
const rlActionObj: {
|
|
204
|
-
list?: string
|
|
205
|
-
visible?: boolean | 'ignore'
|
|
206
|
-
} = {}
|
|
207
|
-
|
|
208
|
-
const listValue = rlAction.get('list')?.ifString()?.getValue()
|
|
209
|
-
if (listValue) {
|
|
210
|
-
// Strip REL: prefix if present (transform ServiceNow → Fluent)
|
|
211
|
-
// Users write plain GUIDs or table.field format in Fluent code
|
|
212
|
-
if (listValue.startsWith('REL:')) {
|
|
213
|
-
rlActionObj.list = listValue.substring(4) // Remove 'REL:' prefix
|
|
214
|
-
} else {
|
|
215
|
-
rlActionObj.list = listValue
|
|
127
|
+
const relatedListActions = descendants.query(SYS_UI_POLICY_RL_ACTION).map((rlAction) =>
|
|
128
|
+
rlAction.transform(({ $ }) => ({
|
|
129
|
+
list: $.map((v) => {
|
|
130
|
+
if (v?.ifString()?.ifDefined()) {
|
|
131
|
+
const listVal = v.asString().getValue()
|
|
132
|
+
return listVal.startsWith('REL:') ? listVal.substring(4) : listVal
|
|
216
133
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
rlActionObj.visible = visible
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
// Skip if no meaningful properties (only $id exists)
|
|
226
|
-
if (Object.keys(rlActionObj).length === 0) {
|
|
227
|
-
return null
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
return rlActionObj
|
|
231
|
-
})
|
|
232
|
-
.filter((rlAction) => rlAction !== null) // Remove null actions
|
|
134
|
+
return ''
|
|
135
|
+
}).def(''),
|
|
136
|
+
visible: $.map((v) => stringToBoolean(v?.asString()?.getValue())).def('ignore'),
|
|
137
|
+
}))
|
|
138
|
+
)
|
|
233
139
|
|
|
234
140
|
return {
|
|
235
141
|
success: true,
|
|
@@ -278,7 +184,7 @@ export const UiPolicyPlugin = Plugin.create({
|
|
|
278
184
|
order: $.from('order').toNumber().def(100),
|
|
279
185
|
setValues: $.from('set_values').def(''),
|
|
280
186
|
view: $.from('view').def(''),
|
|
281
|
-
actions: $.val(actions.
|
|
187
|
+
actions: $.val(actions).def([]),
|
|
282
188
|
relatedListActions: $.val(
|
|
283
189
|
relatedListActions.length > 0 ? relatedListActions : undefined
|
|
284
190
|
),
|
|
@@ -401,11 +307,10 @@ export const UiPolicyPlugin = Plugin.create({
|
|
|
401
307
|
const hasClearedProp = action.get('cleared')?.isBoolean() || false
|
|
402
308
|
|
|
403
309
|
if (!hasVisibleProp && !hasReadOnlyProp && !hasMandatoryProp && !hasClearedProp) {
|
|
404
|
-
diagnostics.
|
|
310
|
+
diagnostics.hint(
|
|
405
311
|
action,
|
|
406
|
-
`Action at index ${i}
|
|
312
|
+
`Action at index ${i} has no effect — consider specifying at least one of: visible, readOnly, mandatory, or cleared`
|
|
407
313
|
)
|
|
408
|
-
continue
|
|
409
314
|
}
|
|
410
315
|
|
|
411
316
|
const actionRecord = await factory.createRecord({
|
|
@@ -475,14 +380,12 @@ export const UiPolicyPlugin = Plugin.create({
|
|
|
475
380
|
}
|
|
476
381
|
}
|
|
477
382
|
|
|
478
|
-
// At least one property must be specified (visible or list)
|
|
479
383
|
const hasVisibleProp = isValidActionValue(rlAction.get('visible'))
|
|
480
384
|
if (!hasVisibleProp && !listValue) {
|
|
481
|
-
diagnostics.
|
|
385
|
+
diagnostics.hint(
|
|
482
386
|
rlAction,
|
|
483
|
-
`Related list action at index ${i}
|
|
387
|
+
`Related list action at index ${i} has no effect — consider specifying at least one of: list or visible`
|
|
484
388
|
)
|
|
485
|
-
continue
|
|
486
389
|
}
|
|
487
390
|
|
|
488
391
|
const rlActionRecord = await factory.createRecord({
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { CallExpressionShape, Plugin } from '@servicenow/sdk-build-core'
|
|
2
2
|
import { NowIdShape } from './now-id-plugin'
|
|
3
|
-
import { createSdkDocEntry } from './utils'
|
|
4
3
|
|
|
5
4
|
/**
|
|
6
5
|
* Creates a User Preference (sys_user_preference).
|
|
@@ -17,7 +16,6 @@ import { createSdkDocEntry } from './utils'
|
|
|
17
16
|
*/
|
|
18
17
|
export const UserPreferencePlugin = Plugin.create({
|
|
19
18
|
name: 'UserPreferencePlugin',
|
|
20
|
-
docs: [createSdkDocEntry('UserPreference', ['sys_user_preference'])],
|
|
21
19
|
records: {
|
|
22
20
|
sys_user_preference: {
|
|
23
21
|
toShape(record) {
|