mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-24 04:04:06 -08:00
feat(ServiceNow Node): Add basicAuth support and fix getColumns loadOptions (#2712)
* ✨ Support basic auth for ServiceNow * 🐛 Support ServiceNow sysparm_fields as string * ⚡ credential test for basic auth * fix(Google Tasks Node): Fix "Show Completed" option and hide title field where not needed (#2741) * 🐛 Google Tasks: Fix showCompleted * ⚡ Improvements Co-authored-by: ricardo <ricardoespinoza105@gmail.com> * feat(Mocean Node): Add "Delivery Report URL" option and credential tests (#3075) * add dlr url column add dlr url(delivery report URl) column. Allow user set the endpoint to receive the report * update update delivery report url description * ⚡ fixed nodelinter issues, added credential test, replaced icon * ⚡ Improvements Co-authored-by: d3no <d3no520@gmail.com> Co-authored-by: Michael Kret <michael.k@radency.com> * feat(Emelia Node): Add Campaign > Duplicate functionality (#3000) * feat(Emelia Node): Add campaign duplication feature * ⚡ small ui fixes, added credential test, fixed nodelinter issues * ⚡ Improvements * ⚡ Updated wording for Number operations on IF-Node (#3065) * fix(Google Tasks Node): Fix "Show Completed" option and hide title field where not needed (#2741) * 🐛 Google Tasks: Fix showCompleted * ⚡ Improvements Co-authored-by: ricardo <ricardoespinoza105@gmail.com> * feat(Mocean Node): Add "Delivery Report URL" option and credential tests (#3075) * add dlr url column add dlr url(delivery report URl) column. Allow user set the endpoint to receive the report * update update delivery report url description * ⚡ fixed nodelinter issues, added credential test, replaced icon * ⚡ Improvements Co-authored-by: d3no <d3no520@gmail.com> Co-authored-by: Michael Kret <michael.k@radency.com> * ⚡ Normalize name Co-authored-by: Michael Kret <michael.k@radency.com> Co-authored-by: ricardo <ricardoespinoza105@gmail.com> Co-authored-by: Jonathan Bennetts <jonathan.bennetts@gmail.com> Co-authored-by: Tom <19203795+that-one-tom@users.noreply.github.com> Co-authored-by: Ricardo Espinoza <ricardo@n8n.io> Co-authored-by: d3no <d3no520@gmail.com> Co-authored-by: Jan Oberhauser <jan.oberhauser@gmail.com> * ⚡ fix nodelinter issues, added hint to field option * fix(GraphQL Node)!: Correctly report errors returned by the API (#3071) * upstream merge * ⚡ graphql node will throw error when response has errors property * 🔨 updated changelog * ⚡ Improvements * ⚡ Improvements * ⚡ Add package-lock.json back Co-authored-by: ricardo <ricardoespinoza105@gmail.com> * feat(FTP Node): Add option to recursively create directories on rename (#3001) * Recursively Make Directories on SFTP Rename * Linting * ⚡ Improvement * ⚡ Rename "Move" to "Create Directories" * Change "Create Directories" description Co-authored-by: ricardo <ricardoespinoza105@gmail.com> * feat(Microsoft Teams Node): Add chat message support (#2635) * ✨ Add chat messages to MS Teams node * Updated credentials to include missing scope * ⚡ Small improvements Co-authored-by: Jonathan Bennetts <jonathan.bennetts@gmail.com> Co-authored-by: ricardo <ricardoespinoza105@gmail.com> * feat(Mautic Node): Add credential test and allow trailing slash in host (#3080) * Updated Mautic to stop trailing slashes from causing an issue * Fixed oauth failing when there is a trailing slash in the mautic host * Added credential test * test: Fix randomly failing UM tests (#3061) * ⚡ Declutter test logs * 🐛 Fix random passwords length * 🐛 Fix password hashing in test user creation * 🐛 Hash leftover password * ⚡ Improve error message for `compare` * ⚡ Restore `randomInvalidPassword` contant * ⚡ Mock Telemetry module to prevent `--forceExit` * ⚡ Silence logger * ⚡ Simplify condition * ⚡ Unhash password in payload * fix(NocoDB Node): Fix pagination (#3081) * feat(Strava Node): Add "Get Streams" operation (#2582) * Strava node: adding getStreams operation * Changed the keys to use multiOptions Co-authored-by: Jonathan Bennetts <jonathan.bennetts@gmail.com> * ⚡ Improvements * fix(core): Fix crash on webhook when last node did not return data * fix(Salesforce Node): Fix issue that "status" did not get used for Case => Create & Update (#2212) * bugfix for salesforce case create and update case not picking status * 🐛 Fix issue with package-lock.json Co-authored-by: ricardo <ricardoespinoza105@gmail.com> * 🐛 Fix issue with credentials * ⚡ Fix basicAuth * ⚡ Reset default Co-authored-by: Michael Kret <michael.k@radency.com> Co-authored-by: Tom <19203795+that-one-tom@users.noreply.github.com> Co-authored-by: ricardo <ricardoespinoza105@gmail.com> Co-authored-by: Ricardo Espinoza <ricardo@n8n.io> Co-authored-by: d3no <d3no520@gmail.com> Co-authored-by: Charles Lecalier <charles.lecalier@gmail.com> Co-authored-by: Jonathan Bennetts <jonathan.bennetts@gmail.com> Co-authored-by: Jan Oberhauser <jan.oberhauser@gmail.com> Co-authored-by: Michael Kret <88898367+michael-radency@users.noreply.github.com> Co-authored-by: Rhys Williams <me@rhyswilliams.co.za> Co-authored-by: Iván Ovejero <ivov.src@gmail.com> Co-authored-by: Luis Cipriani <37157+lfcipriani@users.noreply.github.com> Co-authored-by: Ketan Somvanshi <ketan.somvanshi@plivo.com>
This commit is contained in:
parent
1018146f21
commit
2c72584b55
|
@ -0,0 +1,35 @@
|
|||
import {
|
||||
IAuthenticateBasicAuth,
|
||||
ICredentialType,
|
||||
INodeProperties,
|
||||
ICredentialTestRequest,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class ServiceNowBasicApi implements ICredentialType {
|
||||
name = 'serviceNowBasicApi';
|
||||
extends = [
|
||||
'httpBasicAuth'
|
||||
];
|
||||
displayName = 'ServiceNow Basic Auth API';
|
||||
documentationUrl = 'serviceNow';
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Subdomain',
|
||||
name: 'subdomain',
|
||||
type: 'string',
|
||||
default: '',
|
||||
hint: 'The subdomain can be extracted from the URL. If the URL is: https://dev99890.service-now.com the subdomain is dev99890',
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
authenticate: IAuthenticateBasicAuth = {
|
||||
type: 'basicAuth',
|
||||
properties: {},
|
||||
};
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL: '=https://{{$credentials?.subdomain}}.service-now.com',
|
||||
url: '/api/now/table/sys_user_role',
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,8 +16,7 @@ export class ServiceNowOAuth2Api implements ICredentialType {
|
|||
name: 'subdomain',
|
||||
type: 'string',
|
||||
default: '',
|
||||
placeholder: 'n8n',
|
||||
description: 'The subdomain of your ServiceNow environment',
|
||||
hint: 'The subdomain can be extracted from the URL. If the URL is: https://dev99890.service-now.com the subdomain is dev99890',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
|
|
|
@ -7,6 +7,7 @@ export const businessServiceOperations: INodeProperties[] = [
|
|||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
|
@ -44,7 +45,7 @@ export const businessServiceFields: INodeProperties[] = [
|
|||
},
|
||||
},
|
||||
default: false,
|
||||
description: 'If all results should be returned or only up to a given limit',
|
||||
description: 'Whether to return all results or only up to a given limit',
|
||||
},
|
||||
{
|
||||
displayName: 'Limit',
|
||||
|
@ -99,17 +100,19 @@ export const businessServiceFields: INodeProperties[] = [
|
|||
name: 'sysparm_fields',
|
||||
type: 'multiOptions',
|
||||
typeOptions: {
|
||||
// nodelinter-ignore-next-line
|
||||
loadOptionsMethod: 'getColumns',
|
||||
},
|
||||
default: '',
|
||||
default: [],
|
||||
description: 'A list of fields to return',
|
||||
hint: 'String of comma separated values or an array of strings can be set in an expression',
|
||||
},
|
||||
{
|
||||
displayName: 'Filter',
|
||||
name: 'sysparm_query',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'An encoded query string used to filter the results. <a href="https://developer.servicenow.com/dev.do#!/learn/learning-plans/quebec/servicenow_application_developer/app_store_learnv2_rest_quebec_more_about_query_parameters">More info</a>',
|
||||
description: 'An encoded query string used to filter the results. <a href="https://developer.servicenow.com/dev.do#!/learn/learning-plans/quebec/servicenow_application_developer/app_store_learnv2_rest_quebec_more_about_query_parameters">More info</a>.',
|
||||
},
|
||||
{
|
||||
displayName: 'Return Values',
|
||||
|
|
|
@ -7,6 +7,7 @@ export const configurationItemsOperations: INodeProperties[] = [
|
|||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
|
@ -44,7 +45,7 @@ export const configurationItemsFields: INodeProperties[] = [
|
|||
},
|
||||
},
|
||||
default: false,
|
||||
description: 'If all results should be returned or only up to a given limit',
|
||||
description: 'Whether to return all results or only up to a given limit',
|
||||
},
|
||||
{
|
||||
displayName: 'Limit',
|
||||
|
@ -68,7 +69,7 @@ export const configurationItemsFields: INodeProperties[] = [
|
|||
maxValue: 500,
|
||||
},
|
||||
default: 50,
|
||||
description: 'The max number of results to return',
|
||||
description: 'Max number of results to return',
|
||||
},
|
||||
{
|
||||
displayName: 'Options',
|
||||
|
@ -99,17 +100,19 @@ export const configurationItemsFields: INodeProperties[] = [
|
|||
name: 'sysparm_fields',
|
||||
type: 'multiOptions',
|
||||
typeOptions: {
|
||||
// nodelinter-ignore-next-line
|
||||
loadOptionsMethod: 'getColumns',
|
||||
},
|
||||
default: '',
|
||||
default: [],
|
||||
description: 'A list of fields to return',
|
||||
hint: 'String of comma separated values or an array of strings can be set in an expression',
|
||||
},
|
||||
{
|
||||
displayName: 'Filter',
|
||||
name: 'sysparm_query',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'An encoded query string used to filter the results. <a href="https://developer.servicenow.com/dev.do#!/learn/learning-plans/quebec/servicenow_application_developer/app_store_learnv2_rest_quebec_more_about_query_parameters">More info</a>',
|
||||
description: 'An encoded query string used to filter the results. <a href="https://developer.servicenow.com/dev.do#!/learn/learning-plans/quebec/servicenow_application_developer/app_store_learnv2_rest_quebec_more_about_query_parameters">More info</a>.',
|
||||
},
|
||||
{
|
||||
displayName: 'Return Values',
|
||||
|
|
|
@ -7,6 +7,7 @@ export const departmentOperations: INodeProperties[] = [
|
|||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
|
@ -44,7 +45,7 @@ export const departmentFields: INodeProperties[] = [
|
|||
},
|
||||
},
|
||||
default: false,
|
||||
description: 'If all results should be returned or only up to a given limit',
|
||||
description: 'Whether to return all results or only up to a given limit',
|
||||
},
|
||||
{
|
||||
displayName: 'Limit',
|
||||
|
@ -99,17 +100,19 @@ export const departmentFields: INodeProperties[] = [
|
|||
name: 'sysparm_fields',
|
||||
type: 'multiOptions',
|
||||
typeOptions: {
|
||||
// nodelinter-ignore-next-line
|
||||
loadOptionsMethod: 'getColumns',
|
||||
},
|
||||
default: '',
|
||||
default: [],
|
||||
description: 'A list of fields to return',
|
||||
hint: 'String of comma separated values or an array of strings can be set in an expression',
|
||||
},
|
||||
{
|
||||
displayName: 'Filter',
|
||||
name: 'sysparm_query',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'An encoded query string used to filter the results. <a href="https://developer.servicenow.com/dev.do#!/learn/learning-plans/quebec/servicenow_application_developer/app_store_learnv2_rest_quebec_more_about_query_parameters">More info</a>',
|
||||
description: 'An encoded query string used to filter the results. <a href="https://developer.servicenow.com/dev.do#!/learn/learning-plans/quebec/servicenow_application_developer/app_store_learnv2_rest_quebec_more_about_query_parameters">More info</a>.',
|
||||
},
|
||||
{
|
||||
displayName: 'Return Values',
|
||||
|
|
|
@ -7,6 +7,7 @@ export const dictionaryOperations: INodeProperties[] = [
|
|||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
|
@ -44,7 +45,7 @@ export const dictionaryFields: INodeProperties[] = [
|
|||
},
|
||||
},
|
||||
default: false,
|
||||
description: 'If all results should be returned or only up to a given limit',
|
||||
description: 'Whether to return all results or only up to a given limit',
|
||||
},
|
||||
{
|
||||
displayName: 'Limit',
|
||||
|
@ -99,17 +100,19 @@ export const dictionaryFields: INodeProperties[] = [
|
|||
name: 'sysparm_fields',
|
||||
type: 'multiOptions',
|
||||
typeOptions: {
|
||||
// nodelinter-ignore-next-line
|
||||
loadOptionsMethod: 'getColumns',
|
||||
},
|
||||
default: '',
|
||||
default: [],
|
||||
description: 'A list of fields to return',
|
||||
hint: 'String of comma separated values or an array of strings can be set in an expression',
|
||||
},
|
||||
{
|
||||
displayName: 'Filter',
|
||||
name: 'sysparm_query',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'An encoded query string used to filter the results. <a href="https://developer.servicenow.com/dev.do#!/learn/learning-plans/quebec/servicenow_application_developer/app_store_learnv2_rest_quebec_more_about_query_parameters">More info</a>',
|
||||
description: 'An encoded query string used to filter the results. <a href="https://developer.servicenow.com/dev.do#!/learn/learning-plans/quebec/servicenow_application_developer/app_store_learnv2_rest_quebec_more_about_query_parameters">More info</a>.',
|
||||
},
|
||||
{
|
||||
displayName: 'Return Values',
|
||||
|
|
|
@ -10,15 +10,25 @@ import {
|
|||
import {
|
||||
IDataObject,
|
||||
INodePropertyOptions,
|
||||
JsonObject,
|
||||
NodeApiError,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export async function serviceNowApiRequest(this: IExecuteFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
|
||||
|
||||
const credentials = await this.getCredentials('serviceNowOAuth2Api');
|
||||
const headers = {} as IDataObject;
|
||||
const authenticationMethod = this.getNodeParameter('authentication', 0, 'oAuth2') as string;
|
||||
|
||||
let credentials;
|
||||
|
||||
if (authenticationMethod === 'basicAuth') {
|
||||
credentials = await this.getCredentials('serviceNowBasicApi');
|
||||
} else {
|
||||
credentials = await this.getCredentials('serviceNowOAuth2Api');
|
||||
}
|
||||
|
||||
const options: OptionsWithUri = {
|
||||
headers: {},
|
||||
headers,
|
||||
method,
|
||||
qs,
|
||||
body,
|
||||
|
@ -38,11 +48,11 @@ export async function serviceNowApiRequest(this: IExecuteFunctions | ILoadOption
|
|||
}
|
||||
|
||||
try {
|
||||
|
||||
return await this.helpers.requestOAuth2!.call(this, 'serviceNowOAuth2Api', options);
|
||||
const credentialType = authenticationMethod === 'oAuth2' ? 'serviceNowOAuth2Api' : 'serviceNowBasicApi';
|
||||
return await this.helpers.requestWithAuthentication.call(this, credentialType, options);
|
||||
|
||||
} catch (error) {
|
||||
throw new NodeApiError(this.getNode(), error);
|
||||
throw new NodeApiError(this.getNode(), (error as JsonObject));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ export const incidentOperations: INodeProperties[] = [
|
|||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
|
@ -85,19 +86,21 @@ export const incidentFields: INodeProperties[] = [
|
|||
name: 'assigned_to',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
// nodelinter-ignore-next-line
|
||||
loadOptionsMethod: 'getUsers',
|
||||
loadOptionsDependsOn: [
|
||||
'additionalFields.assignment_group',
|
||||
],
|
||||
},
|
||||
default: '',
|
||||
description: 'Which user is the incident assigned to. Requires the selection of an assignment group',
|
||||
description: 'Which user is the incident assigned to. Requires the selection of an assignment group.',
|
||||
},
|
||||
{
|
||||
displayName: 'Assignment Group',
|
||||
name: 'assignment_group',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
// nodelinter-ignore-next-line
|
||||
loadOptionsMethod: 'getAssignmentGroups',
|
||||
},
|
||||
default: '',
|
||||
|
@ -108,6 +111,7 @@ export const incidentFields: INodeProperties[] = [
|
|||
name: 'business_service',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
// nodelinter-ignore-next-line
|
||||
loadOptionsMethod: 'getBusinessServices',
|
||||
},
|
||||
default: '',
|
||||
|
@ -125,6 +129,7 @@ export const incidentFields: INodeProperties[] = [
|
|||
name: 'category',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
// nodelinter-ignore-next-line
|
||||
loadOptionsMethod: 'getIncidentCategories',
|
||||
},
|
||||
default: '',
|
||||
|
@ -142,9 +147,10 @@ export const incidentFields: INodeProperties[] = [
|
|||
name: 'cmdb_ci',
|
||||
type: 'multiOptions',
|
||||
typeOptions: {
|
||||
// nodelinter-ignore-next-line
|
||||
loadOptionsMethod: 'getConfigurationItems',
|
||||
},
|
||||
default: '',
|
||||
default: [],
|
||||
description: 'Configuration Items, \'cmdb_ci\' in metadata',
|
||||
},
|
||||
{
|
||||
|
@ -197,7 +203,7 @@ export const incidentFields: INodeProperties[] = [
|
|||
value: 1,
|
||||
},
|
||||
],
|
||||
default: '',
|
||||
default: 1,
|
||||
description: 'The impact of the incident',
|
||||
},
|
||||
{
|
||||
|
@ -205,16 +211,18 @@ export const incidentFields: INodeProperties[] = [
|
|||
name: 'close_code',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
// nodelinter-ignore-next-line
|
||||
loadOptionsMethod: 'getIncidentResolutionCodes',
|
||||
},
|
||||
default: '',
|
||||
description: 'The resolution code of the incident. \'close_code\' in metadata',
|
||||
description: 'The resolution code of the incident, \'close_code\' in metadata',
|
||||
},
|
||||
{
|
||||
displayName: 'State',
|
||||
name: 'state',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
// nodelinter-ignore-next-line
|
||||
loadOptionsMethod: 'getIncidentStates',
|
||||
},
|
||||
default: '',
|
||||
|
@ -225,6 +233,7 @@ export const incidentFields: INodeProperties[] = [
|
|||
name: 'subcategory',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
// nodelinter-ignore-next-line
|
||||
loadOptionsMethod: 'getIncidentSubcategories',
|
||||
loadOptionsDependsOn: [
|
||||
'additionalFields.category',
|
||||
|
@ -251,7 +260,7 @@ export const incidentFields: INodeProperties[] = [
|
|||
value: 1,
|
||||
},
|
||||
],
|
||||
default: '',
|
||||
default: 1,
|
||||
description: 'The urgency of the incident',
|
||||
},
|
||||
],
|
||||
|
@ -275,7 +284,7 @@ export const incidentFields: INodeProperties[] = [
|
|||
},
|
||||
},
|
||||
default: false,
|
||||
description: 'If all results should be returned or only up to a given limit',
|
||||
description: 'Whether to return all results or only up to a given limit',
|
||||
},
|
||||
{
|
||||
displayName: 'Limit',
|
||||
|
@ -330,17 +339,19 @@ export const incidentFields: INodeProperties[] = [
|
|||
name: 'sysparm_fields',
|
||||
type: 'multiOptions',
|
||||
typeOptions: {
|
||||
// nodelinter-ignore-next-line
|
||||
loadOptionsMethod: 'getColumns',
|
||||
},
|
||||
default: '',
|
||||
default: [],
|
||||
description: 'A list of fields to return',
|
||||
hint: 'String of comma separated values or an array of strings can be set in an expression',
|
||||
},
|
||||
{
|
||||
displayName: 'Filter',
|
||||
name: 'sysparm_query',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'An encoded query string used to filter the results. <a href="https://developer.servicenow.com/dev.do#!/learn/learning-plans/quebec/servicenow_application_developer/app_store_learnv2_rest_quebec_more_about_query_parameters">More info</a>',
|
||||
description: 'An encoded query string used to filter the results. <a href="https://developer.servicenow.com/dev.do#!/learn/learning-plans/quebec/servicenow_application_developer/app_store_learnv2_rest_quebec_more_about_query_parameters">More info</a>.',
|
||||
},
|
||||
{
|
||||
displayName: 'Return Values',
|
||||
|
@ -417,10 +428,12 @@ export const incidentFields: INodeProperties[] = [
|
|||
name: 'sysparm_fields',
|
||||
type: 'multiOptions',
|
||||
typeOptions: {
|
||||
// nodelinter-ignore-next-line
|
||||
loadOptionsMethod: 'getColumns',
|
||||
},
|
||||
default: '',
|
||||
default: [],
|
||||
description: 'A list of fields to return',
|
||||
hint: 'String of comma separated values or an array of strings can be set in an expression',
|
||||
},
|
||||
{
|
||||
displayName: 'Return Values',
|
||||
|
@ -489,19 +502,21 @@ export const incidentFields: INodeProperties[] = [
|
|||
name: 'assigned_to',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
// nodelinter-ignore-next-line
|
||||
loadOptionsMethod: 'getUsers',
|
||||
loadOptionsDependsOn: [
|
||||
'additionalFields.assignment_group',
|
||||
],
|
||||
},
|
||||
default: '',
|
||||
description: 'Which user is the incident assigned to. Requires the selection of an assignment group',
|
||||
description: 'Which user is the incident assigned to. Requires the selection of an assignment group.',
|
||||
},
|
||||
{
|
||||
displayName: 'Assignment Group',
|
||||
name: 'assignment_group',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
// nodelinter-ignore-next-line
|
||||
loadOptionsMethod: 'getAssignmentGroups',
|
||||
},
|
||||
default: '',
|
||||
|
@ -512,6 +527,7 @@ export const incidentFields: INodeProperties[] = [
|
|||
name: 'business_service',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
// nodelinter-ignore-next-line
|
||||
loadOptionsMethod: 'getBusinessServices',
|
||||
},
|
||||
default: '',
|
||||
|
@ -529,6 +545,7 @@ export const incidentFields: INodeProperties[] = [
|
|||
name: 'category',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
// nodelinter-ignore-next-line
|
||||
loadOptionsMethod: 'getIncidentCategories',
|
||||
},
|
||||
default: '',
|
||||
|
@ -546,9 +563,10 @@ export const incidentFields: INodeProperties[] = [
|
|||
name: 'cmdb_ci',
|
||||
type: 'multiOptions',
|
||||
typeOptions: {
|
||||
// nodelinter-ignore-next-line
|
||||
loadOptionsMethod: 'getConfigurationItems',
|
||||
},
|
||||
default: '',
|
||||
default: [],
|
||||
description: 'Configuration Items, \'cmdb_ci\' in metadata',
|
||||
},
|
||||
{
|
||||
|
@ -601,7 +619,7 @@ export const incidentFields: INodeProperties[] = [
|
|||
value: 1,
|
||||
},
|
||||
],
|
||||
default: '',
|
||||
default: 1,
|
||||
description: 'The impact of the incident',
|
||||
},
|
||||
{
|
||||
|
@ -609,9 +627,11 @@ export const incidentFields: INodeProperties[] = [
|
|||
name: 'close_code',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
// nodelinter-ignore-next-line
|
||||
loadOptionsMethod: 'getIncidentResolutionCodes',
|
||||
},
|
||||
default: '',
|
||||
// nodelinter-ignore-next-line
|
||||
description: 'The resolution code of the incident. \'close_code\' in metadata',
|
||||
},
|
||||
{
|
||||
|
@ -619,6 +639,7 @@ export const incidentFields: INodeProperties[] = [
|
|||
name: 'hold_reason',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
// nodelinter-ignore-next-line
|
||||
loadOptionsMethod: 'getIncidentHoldReasons',
|
||||
},
|
||||
default: '',
|
||||
|
@ -629,6 +650,7 @@ export const incidentFields: INodeProperties[] = [
|
|||
name: 'state',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
// nodelinter-ignore-next-line
|
||||
loadOptionsMethod: 'getIncidentStates',
|
||||
},
|
||||
default: '',
|
||||
|
@ -639,6 +661,7 @@ export const incidentFields: INodeProperties[] = [
|
|||
name: 'subcategory',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
// nodelinter-ignore-next-line
|
||||
loadOptionsMethod: 'getIncidentSubcategories',
|
||||
loadOptionsDependsOn: [
|
||||
'additionalFields.category',
|
||||
|
@ -665,7 +688,7 @@ export const incidentFields: INodeProperties[] = [
|
|||
value: 1,
|
||||
},
|
||||
],
|
||||
default: '',
|
||||
default: 1,
|
||||
description: 'The urgency of the incident',
|
||||
},
|
||||
],
|
||||
|
|
|
@ -9,6 +9,7 @@ import {
|
|||
INodePropertyOptions,
|
||||
INodeType,
|
||||
INodeTypeDescription,
|
||||
JsonObject,
|
||||
NodeOperationError,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
|
@ -82,13 +83,49 @@ export class ServiceNow implements INodeType {
|
|||
{
|
||||
name: 'serviceNowOAuth2Api',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
authentication: [
|
||||
'oAuth2',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'serviceNowBasicApi',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
authentication: [
|
||||
'basicAuth',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
properties: [
|
||||
{
|
||||
displayName: 'Authentication',
|
||||
name: 'authentication',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Basic Auth',
|
||||
value: 'basicAuth',
|
||||
},
|
||||
{
|
||||
name: 'OAuth2',
|
||||
value: 'oAuth2',
|
||||
},
|
||||
],
|
||||
default: 'oAuth2',
|
||||
description: 'Authentication method to use',
|
||||
},
|
||||
{
|
||||
displayName: 'Resource',
|
||||
name: 'resource',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
options: [
|
||||
{
|
||||
name: 'Business Service',
|
||||
|
@ -427,7 +464,7 @@ export class ServiceNow implements INodeType {
|
|||
const returnAll = this.getNodeParameter('returnAll', i) as boolean;
|
||||
qs = this.getNodeParameter('options', i) as IDataObject;
|
||||
|
||||
if (qs.sysparm_fields) {
|
||||
if (qs.sysparm_fields && typeof qs.sysparm_fields !== 'string') {
|
||||
qs.sysparm_fields = (qs.sysparm_fields as string[]).join(',');
|
||||
}
|
||||
|
||||
|
@ -448,7 +485,7 @@ export class ServiceNow implements INodeType {
|
|||
const returnAll = this.getNodeParameter('returnAll', i) as boolean;
|
||||
qs = this.getNodeParameter('options', i) as IDataObject;
|
||||
|
||||
if (qs.sysparm_fields) {
|
||||
if (qs.sysparm_fields && typeof qs.sysparm_fields !== 'string') {
|
||||
qs.sysparm_fields = (qs.sysparm_fields as string[]).join(',');
|
||||
}
|
||||
|
||||
|
@ -469,7 +506,7 @@ export class ServiceNow implements INodeType {
|
|||
const returnAll = this.getNodeParameter('returnAll', i) as boolean;
|
||||
qs = this.getNodeParameter('options', i) as IDataObject;
|
||||
|
||||
if (qs.sysparm_fields) {
|
||||
if (qs.sysparm_fields && typeof qs.sysparm_fields !== 'string') {
|
||||
qs.sysparm_fields = (qs.sysparm_fields as string[]).join(',');
|
||||
}
|
||||
|
||||
|
@ -490,7 +527,7 @@ export class ServiceNow implements INodeType {
|
|||
const returnAll = this.getNodeParameter('returnAll', i) as boolean;
|
||||
qs = this.getNodeParameter('options', i) as IDataObject;
|
||||
|
||||
if (qs.sysparm_fields) {
|
||||
if (qs.sysparm_fields && typeof qs.sysparm_fields !== 'string') {
|
||||
qs.sysparm_fields = (qs.sysparm_fields as string[]).join(',');
|
||||
}
|
||||
|
||||
|
@ -529,7 +566,7 @@ export class ServiceNow implements INodeType {
|
|||
const id = this.getNodeParameter('id', i) as string;
|
||||
qs = this.getNodeParameter('options', i) as IDataObject;
|
||||
|
||||
if (qs.sysparm_fields) {
|
||||
if (qs.sysparm_fields && typeof qs.sysparm_fields !== 'string') {
|
||||
qs.sysparm_fields = (qs.sysparm_fields as string[]).join(',');
|
||||
}
|
||||
|
||||
|
@ -541,7 +578,7 @@ export class ServiceNow implements INodeType {
|
|||
const returnAll = this.getNodeParameter('returnAll', i) as boolean;
|
||||
qs = this.getNodeParameter('options', i) as IDataObject;
|
||||
|
||||
if (qs.sysparm_fields) {
|
||||
if (qs.sysparm_fields && typeof qs.sysparm_fields !== 'string') {
|
||||
qs.sysparm_fields = (qs.sysparm_fields as string[]).join(',');
|
||||
}
|
||||
|
||||
|
@ -604,7 +641,7 @@ export class ServiceNow implements INodeType {
|
|||
const id = this.getNodeParameter('id', i) as string;
|
||||
qs = this.getNodeParameter('options', i) as IDataObject;
|
||||
|
||||
if (qs.sysparm_fields) {
|
||||
if (qs.sysparm_fields && typeof qs.sysparm_fields !== 'string') {
|
||||
qs.sysparm_fields = (qs.sysparm_fields as string[]).join(',');
|
||||
}
|
||||
|
||||
|
@ -617,7 +654,7 @@ export class ServiceNow implements INodeType {
|
|||
const returnAll = this.getNodeParameter('returnAll', i) as boolean;
|
||||
qs = this.getNodeParameter('options', i) as IDataObject;
|
||||
|
||||
if (qs.sysparm_fields) {
|
||||
if (qs.sysparm_fields && typeof qs.sysparm_fields !== 'string') {
|
||||
qs.sysparm_fields = (qs.sysparm_fields as string[]).join(',');
|
||||
}
|
||||
|
||||
|
@ -679,7 +716,7 @@ export class ServiceNow implements INodeType {
|
|||
const getOption = this.getNodeParameter('getOption', i) as string;
|
||||
qs = this.getNodeParameter('options', i) as IDataObject;
|
||||
|
||||
if (qs.sysparm_fields) {
|
||||
if (qs.sysparm_fields && typeof qs.sysparm_fields !== 'string') {
|
||||
qs.sysparm_fields = (qs.sysparm_fields as string[]).join(',');
|
||||
}
|
||||
|
||||
|
@ -700,7 +737,7 @@ export class ServiceNow implements INodeType {
|
|||
const returnAll = this.getNodeParameter('returnAll', i) as boolean;
|
||||
qs = this.getNodeParameter('options', i) as IDataObject;
|
||||
|
||||
if (qs.sysparm_fields) {
|
||||
if (qs.sysparm_fields && typeof qs.sysparm_fields !== 'string') {
|
||||
qs.sysparm_fields = (qs.sysparm_fields as string[]).join(',');
|
||||
}
|
||||
|
||||
|
@ -730,7 +767,7 @@ export class ServiceNow implements INodeType {
|
|||
const returnAll = this.getNodeParameter('returnAll', i) as boolean;
|
||||
qs = this.getNodeParameter('options', i) as IDataObject;
|
||||
|
||||
if (qs.sysparm_fields) {
|
||||
if (qs.sysparm_fields && typeof qs.sysparm_fields !== 'string') {
|
||||
qs.sysparm_fields = (qs.sysparm_fields as string[]).join(',');
|
||||
}
|
||||
|
||||
|
@ -751,7 +788,7 @@ export class ServiceNow implements INodeType {
|
|||
const returnAll = this.getNodeParameter('returnAll', i) as boolean;
|
||||
qs = this.getNodeParameter('options', i) as IDataObject;
|
||||
|
||||
if (qs.sysparm_fields) {
|
||||
if (qs.sysparm_fields && typeof qs.sysparm_fields !== 'string') {
|
||||
qs.sysparm_fields = (qs.sysparm_fields as string[]).join(',');
|
||||
}
|
||||
|
||||
|
@ -771,7 +808,7 @@ export class ServiceNow implements INodeType {
|
|||
}
|
||||
} catch (error) {
|
||||
if (this.continueOnFail()) {
|
||||
returnData.push({ error: error.message });
|
||||
returnData.push({ error: (error as JsonObject).message });
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ export const tableRecordOperations: INodeProperties[] = [
|
|||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
|
@ -71,7 +72,7 @@ export const tableRecordFields: INodeProperties[] = [
|
|||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Auto-map Input Data to Columns',
|
||||
name: 'Auto-Map Input Data to Columns',
|
||||
value: 'mapInput',
|
||||
description: 'Use when node input names match destination field names',
|
||||
},
|
||||
|
@ -117,7 +118,7 @@ export const tableRecordFields: INodeProperties[] = [
|
|||
},
|
||||
default: '',
|
||||
required: false,
|
||||
description: 'List of input properties to avoid sending, separated by commas. Leave empty to send all inputs',
|
||||
description: 'List of input properties to avoid sending, separated by commas. Leave empty to send all inputs.',
|
||||
},
|
||||
{
|
||||
displayName: 'Fields to Send',
|
||||
|
@ -208,7 +209,7 @@ export const tableRecordFields: INodeProperties[] = [
|
|||
},
|
||||
},
|
||||
default: false,
|
||||
description: 'If all results should be returned or only up to a given limit',
|
||||
description: 'Whether to return all results or only up to a given limit',
|
||||
},
|
||||
{
|
||||
displayName: 'Limit',
|
||||
|
@ -268,15 +269,16 @@ export const tableRecordFields: INodeProperties[] = [
|
|||
'tableName',
|
||||
],
|
||||
},
|
||||
default: '',
|
||||
default: [],
|
||||
description: 'A list of fields to return',
|
||||
hint: 'String of comma separated values or an array of strings can be set in an expression',
|
||||
},
|
||||
{
|
||||
displayName: 'Filter',
|
||||
name: 'sysparm_query',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'An encoded query string used to filter the results. <a href="https://developer.servicenow.com/dev.do#!/learn/learning-plans/quebec/servicenow_application_developer/app_store_learnv2_rest_quebec_more_about_query_parameters">More info</a>',
|
||||
description: 'An encoded query string used to filter the results. <a href="https://developer.servicenow.com/dev.do#!/learn/learning-plans/quebec/servicenow_application_developer/app_store_learnv2_rest_quebec_more_about_query_parameters">More info</a>.',
|
||||
},
|
||||
{
|
||||
displayName: 'Return Values',
|
||||
|
@ -380,8 +382,9 @@ export const tableRecordFields: INodeProperties[] = [
|
|||
'tableName',
|
||||
],
|
||||
},
|
||||
default: '',
|
||||
default: [],
|
||||
description: 'A list of fields to return',
|
||||
hint: 'String of comma separated values or an array of strings can be set in an expression',
|
||||
},
|
||||
{
|
||||
displayName: 'Return Values',
|
||||
|
@ -455,7 +458,7 @@ export const tableRecordFields: INodeProperties[] = [
|
|||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Auto-map Input Data to Columns',
|
||||
name: 'Auto-Map Input Data to Columns',
|
||||
value: 'mapInput',
|
||||
description: 'Use when node input names match destination field names',
|
||||
},
|
||||
|
@ -501,7 +504,7 @@ export const tableRecordFields: INodeProperties[] = [
|
|||
},
|
||||
default: '',
|
||||
required: false,
|
||||
description: 'List of input properties to avoid sending, separated by commas. Leave empty to send all inputs',
|
||||
description: 'List of input properties to avoid sending, separated by commas. Leave empty to send all inputs.',
|
||||
},
|
||||
{
|
||||
displayName: 'Fields to Send',
|
||||
|
|
|
@ -7,6 +7,7 @@ export const userOperations: INodeProperties[] = [
|
|||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
|
@ -84,7 +85,7 @@ export const userFields: INodeProperties[] = [
|
|||
displayName: 'Active',
|
||||
name: 'active',
|
||||
type: 'boolean',
|
||||
default: '',
|
||||
default: false,
|
||||
description: 'Whether to activate the user',
|
||||
},
|
||||
{
|
||||
|
@ -196,7 +197,7 @@ export const userFields: INodeProperties[] = [
|
|||
displayName: 'Password Needs Reset',
|
||||
name: 'password_needs_reset',
|
||||
type: 'boolean',
|
||||
default: '',
|
||||
default: false,
|
||||
description: 'Whether to require a password reset when the user logs in',
|
||||
},
|
||||
{
|
||||
|
@ -213,7 +214,7 @@ export const userFields: INodeProperties[] = [
|
|||
typeOptions: {
|
||||
loadOptionsMethod: 'getUserRoles',
|
||||
},
|
||||
default: '',
|
||||
default: [],
|
||||
description: 'Roles of the user',
|
||||
},
|
||||
{
|
||||
|
@ -242,6 +243,7 @@ export const userFields: INodeProperties[] = [
|
|||
name: 'user_name',
|
||||
type: 'string',
|
||||
default: '',
|
||||
// nodelinter-ignore-next-line
|
||||
description: 'A username associated with the user (e.g. user_name.123)',
|
||||
},
|
||||
{
|
||||
|
@ -272,7 +274,7 @@ export const userFields: INodeProperties[] = [
|
|||
},
|
||||
},
|
||||
default: false,
|
||||
description: 'If all results should be returned or only up to a given limit',
|
||||
description: 'Whether to return all results or only up to a given limit',
|
||||
},
|
||||
{
|
||||
displayName: 'Limit',
|
||||
|
@ -332,15 +334,16 @@ export const userFields: INodeProperties[] = [
|
|||
'operation',
|
||||
],
|
||||
},
|
||||
default: '',
|
||||
default: [],
|
||||
description: 'A list of fields to return',
|
||||
hint: 'String of comma separated values or an array of strings can be set in an expression',
|
||||
},
|
||||
{
|
||||
displayName: 'Filter',
|
||||
name: 'sysparm_query',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'An encoded query string used to filter the results. <a href="https://developer.servicenow.com/dev.do#!/learn/learning-plans/quebec/servicenow_application_developer/app_store_learnv2_rest_quebec_more_about_query_parameters">More info</a>',
|
||||
description: 'An encoded query string used to filter the results. <a href="https://developer.servicenow.com/dev.do#!/learn/learning-plans/quebec/servicenow_application_developer/app_store_learnv2_rest_quebec_more_about_query_parameters">More info</a>.',
|
||||
},
|
||||
{
|
||||
displayName: 'Return Values',
|
||||
|
@ -491,8 +494,9 @@ export const userFields: INodeProperties[] = [
|
|||
'operation',
|
||||
],
|
||||
},
|
||||
default: '',
|
||||
default: [],
|
||||
description: 'A list of fields to return',
|
||||
hint: 'String of comma separated values or an array of strings can be set in an expression',
|
||||
},
|
||||
{
|
||||
displayName: 'Return Values',
|
||||
|
@ -560,7 +564,7 @@ export const userFields: INodeProperties[] = [
|
|||
displayName: 'Active',
|
||||
name: 'active',
|
||||
type: 'boolean',
|
||||
default: '',
|
||||
default: false,
|
||||
description: 'Whether to activate the user',
|
||||
},
|
||||
{
|
||||
|
@ -672,7 +676,7 @@ export const userFields: INodeProperties[] = [
|
|||
displayName: 'Password Needs Reset',
|
||||
name: 'password_needs_reset',
|
||||
type: 'boolean',
|
||||
default: '',
|
||||
default: false,
|
||||
description: 'Whether to require a password reset when the user logs in',
|
||||
},
|
||||
{
|
||||
|
@ -689,7 +693,7 @@ export const userFields: INodeProperties[] = [
|
|||
typeOptions: {
|
||||
loadOptionsMethod: 'getUserRoles',
|
||||
},
|
||||
default: '',
|
||||
default: [],
|
||||
description: 'Roles of the user',
|
||||
},
|
||||
{
|
||||
|
@ -718,6 +722,7 @@ export const userFields: INodeProperties[] = [
|
|||
name: 'user_name',
|
||||
type: 'string',
|
||||
default: '',
|
||||
// nodelinter-ignore-next-line
|
||||
description: 'A username associated with the user (e.g. user_name.123)',
|
||||
},
|
||||
{
|
||||
|
|
|
@ -7,6 +7,7 @@ export const userGroupOperations: INodeProperties[] = [
|
|||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
|
@ -44,7 +45,7 @@ export const userGroupFields: INodeProperties[] = [
|
|||
},
|
||||
},
|
||||
default: false,
|
||||
description: 'If all results should be returned or only up to a given limit',
|
||||
description: 'Whether to return all results or only up to a given limit',
|
||||
},
|
||||
{
|
||||
displayName: 'Limit',
|
||||
|
@ -101,15 +102,16 @@ export const userGroupFields: INodeProperties[] = [
|
|||
typeOptions: {
|
||||
loadOptionsMethod: 'getColumns',
|
||||
},
|
||||
default: '',
|
||||
default: [],
|
||||
description: 'A list of fields to return',
|
||||
hint: 'String of comma separated values or an array of strings can be set in an expression',
|
||||
},
|
||||
{
|
||||
displayName: 'Filter',
|
||||
name: 'sysparm_query',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'An encoded query string used to filter the results. <a href="https://developer.servicenow.com/dev.do#!/learn/learning-plans/quebec/servicenow_application_developer/app_store_learnv2_rest_quebec_more_about_query_parameters">More info</a>',
|
||||
description: 'An encoded query string used to filter the results. <a href="https://developer.servicenow.com/dev.do#!/learn/learning-plans/quebec/servicenow_application_developer/app_store_learnv2_rest_quebec_more_about_query_parameters">More info</a>.',
|
||||
},
|
||||
{
|
||||
displayName: 'Return Values',
|
||||
|
|
|
@ -7,6 +7,7 @@ export const userRoleOperations: INodeProperties[] = [
|
|||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
|
@ -44,7 +45,7 @@ export const userRoleFields: INodeProperties[] = [
|
|||
},
|
||||
},
|
||||
default: false,
|
||||
description: 'If all results should be returned or only up to a given limit',
|
||||
description: 'Whether to return all results or only up to a given limit',
|
||||
},
|
||||
{
|
||||
displayName: 'Limit',
|
||||
|
@ -101,15 +102,16 @@ export const userRoleFields: INodeProperties[] = [
|
|||
typeOptions: {
|
||||
loadOptionsMethod: 'getColumns',
|
||||
},
|
||||
default: '',
|
||||
default: [],
|
||||
description: 'A list of fields to return',
|
||||
hint: 'String of comma separated values or an array of strings can be set in an expression',
|
||||
},
|
||||
{
|
||||
displayName: 'Filter',
|
||||
name: 'sysparm_query',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'An encoded query string used to filter the results. <a href="https://developer.servicenow.com/dev.do#!/learn/learning-plans/quebec/servicenow_application_developer/app_store_learnv2_rest_quebec_more_about_query_parameters">More info</a>',
|
||||
description: 'An encoded query string used to filter the results. <a href="https://developer.servicenow.com/dev.do#!/learn/learning-plans/quebec/servicenow_application_developer/app_store_learnv2_rest_quebec_more_about_query_parameters">More info</a>.',
|
||||
},
|
||||
{
|
||||
displayName: 'Return Values',
|
||||
|
|
|
@ -258,6 +258,7 @@
|
|||
"dist/credentials/SentryIoOAuth2Api.credentials.js",
|
||||
"dist/credentials/SentryIoServerApi.credentials.js",
|
||||
"dist/credentials/ServiceNowOAuth2Api.credentials.js",
|
||||
"dist/credentials/ServiceNowBasicApi.credentials.js",
|
||||
"dist/credentials/Sftp.credentials.js",
|
||||
"dist/credentials/ShopifyApi.credentials.js",
|
||||
"dist/credentials/Signl4Api.credentials.js",
|
||||
|
|
Loading…
Reference in a new issue