@pnp/cli-microsoft365
Version:
Manage Microsoft 365 and SharePoint Framework projects on any platform
169 lines • 9.07 kB
JavaScript
import { globalOptionsZod } from '../../../../Command.js';
import request from '../../../../request.js';
import { formatting } from '../../../../utils/formatting.js';
import { urlUtil } from '../../../../utils/urlUtil.js';
import { validation } from '../../../../utils/validation.js';
import SpoCommand from '../../../base/SpoCommand.js';
import commands from '../../commands.js';
import { z } from 'zod';
import { zod } from '../../../../utils/zod.js';
const options = globalOptionsZod
.extend({
webUrl: zod.alias('u', z.string()
.refine(url => validation.isValidSharePointUrl(url) === true, {
message: 'webUrl is not a valid SharePoint site URL.'
})),
listId: z.string()
.refine(id => validation.isValidGuid(id), id => ({
message: `'${id}' is not a valid GUID.`
})).optional(),
listTitle: z.string().optional(),
listUrl: z.string().optional(),
title: z.string().min(1, 'Cannot be empty.'),
fields: z.string().optional(),
viewQuery: z.string().optional(),
personal: z.boolean().optional(),
default: z.boolean().optional(),
paged: z.boolean().optional(),
rowLimit: z.number().int().positive().optional(),
customFormatter: z.string()
.refine(formatter => {
try {
JSON.parse(formatter);
return true;
}
catch {
return false;
}
}, {
message: 'Custom formatter must be a valid JSON string.'
})
.optional(),
type: z.enum(['list', 'calendar', 'gallery', 'kanban']).optional(),
calendarStartDateField: z.string().min(1, 'Cannot be empty.').optional(),
calendarEndDateField: z.string().min(1, 'Cannot be empty.').optional(),
calendarTitleField: z.string().min(1, 'Cannot be empty.').optional(),
calendarSubTitleField: z.string().min(1, 'Cannot be empty.').optional(),
calendarDefaultLayout: z.enum(['month', 'week', 'workWeek', 'day']).optional(),
kanbanBucketField: z.string().min(1, 'Cannot be empty.').optional()
})
.strict();
class SpoListViewAddCommand extends SpoCommand {
get name() {
return commands.LIST_VIEW_ADD;
}
get description() {
return 'Adds a new view to a SharePoint list';
}
get schema() {
return options;
}
getRefinedSchema(schema) {
return schema
.refine((options) => [options.listId, options.listTitle, options.listUrl].filter(o => o !== undefined).length === 1, {
message: 'Use one of the following options: listId, listTitle, or listUrl.'
})
.refine((options) => !options.personal || !options.default, {
message: 'Default view cannot be a personal view.'
})
.refine((options) => options.type !== 'calendar' || [options.calendarStartDateField, options.calendarEndDateField, options.calendarTitleField].filter(o => o === undefined).length === 0, {
message: 'When type is calendar, do specify calendarStartDateField, calendarEndDateField, and calendarTitleField.'
})
.refine((options) => options.type === 'calendar' || [options.calendarStartDateField, options.calendarEndDateField, options.calendarTitleField].filter(o => o === undefined).length === 3, {
message: 'When type is not calendar, do not specify calendarStartDateField, calendarEndDateField, and calendarTitleField.'
})
.refine((options) => options.type !== 'kanban' || options.kanbanBucketField !== undefined, {
message: 'When type is kanban, do specify kanbanBucketField.'
})
.refine((options) => options.type === 'kanban' || options.kanbanBucketField === undefined, {
message: 'When type is not kanban, do not specify kanbanBucketField.'
})
.refine((options) => options.type === 'calendar' || options.fields !== undefined, {
message: 'When type is not calendar, do specify fields.'
});
}
async commandAction(logger, args) {
try {
if (this.verbose) {
await logger.logToStderr(`Adding view '${args.options.title}' to list...`);
}
let apiUrl = `${args.options.webUrl}/_api/web/`;
if (args.options.listId) {
apiUrl += `lists(guid'${formatting.encodeQueryParameter(args.options.listId)}')`;
}
else if (args.options.listTitle) {
apiUrl += `lists/getByTitle('${formatting.encodeQueryParameter(args.options.listTitle)}')`;
}
else if (args.options.listUrl) {
apiUrl += `GetList('${formatting.encodeQueryParameter(urlUtil.getServerRelativePath(args.options.webUrl, args.options.listUrl))}')`;
}
apiUrl += '/views/add';
const requestOptions = {
url: apiUrl,
headers: {
'content-type': 'application/json;odata=verbose',
accept: 'application/json;odata=nometadata'
},
responseType: 'json',
data: {
parameters: {
Title: args.options.title,
ViewFields: {
results: args.options.fields?.split(',').map(f => f.trim()) ?? []
},
Query: args.options.viewQuery,
PersonalView: !!args.options.personal,
SetAsDefaultView: !!args.options.default,
Paged: args.options.paged ?? true,
RowLimit: args.options.rowLimit ?? 30,
CustomFormatter: args.options.customFormatter
}
}
};
this.setViewTypeSpecificParameters(args.options, requestOptions.data.parameters);
const result = await request.post(requestOptions);
await logger.log(result);
}
catch (err) {
this.handleRejectedODataJsonPromise(err);
}
}
setViewTypeSpecificParameters(options, requestBody) {
if (options.type === 'calendar') {
const defaultView = options.calendarDefaultLayout ?? 'month';
const titleField = options.calendarTitleField;
const subTitleField = options.calendarSubTitleField ?? '';
// Following fields are required for calendar view, order is important
const viewFields = [options.calendarStartDateField, options.calendarEndDateField, titleField, subTitleField].filter(field => field !== '');
// Add any additional fields specified by the user
const extraViewFields = requestBody.ViewFields.results.filter((field) => !viewFields.includes(field.trim()));
viewFields.push(...extraViewFields);
requestBody.CalendarViewStyles = `<CalendarViewStyle Title="Day" Type="day" Template="CalendarViewdayChrome" Sequence="1" Default="${String(defaultView === 'day').toUpperCase()}" /><CalendarViewStyle Title="Week" Type="week" Template="CalendarViewweekChrome" Sequence="2" Default="${String(defaultView === 'week').toUpperCase()}" /><CalendarViewStyle Title="Month" Type="month" Template="CalendarViewmonthChrome" Sequence="3" Default="${String(defaultView === 'month').toUpperCase()}" /><CalendarViewStyle Title="Work week" Type="workweek" Template="CalendarViewweekChrome" Sequence="4" Default="${String(defaultView === 'workWeek').toUpperCase()}" />`;
requestBody.Query = `<Where><DateRangesOverlap><FieldRef Name='${options.calendarStartDateField}' /><FieldRef Name='${options.calendarEndDateField}' /><Value Type='DateTime'><Month /></Value></DateRangesOverlap></Where>`;
requestBody.ViewData = `<FieldRef Name="${titleField}" Type="CalendarMonthTitle" /><FieldRef Name="${titleField}" Type="CalendarWeekTitle" /><FieldRef Name="${subTitleField}" Type="CalendarWeekLocation" /><FieldRef Name="${titleField}" Type="CalendarDayTitle" /><FieldRef Name="${subTitleField}" Type="CalendarDayLocation" />`;
requestBody.ViewFields.results = viewFields;
requestBody.ViewType2 = 'MODERNCALENDAR';
return;
}
if (options.type === 'gallery') {
requestBody.ViewType2 = 'TILES';
return;
}
if (options.type === 'kanban') {
// Add the bucket field to the view fields if it is not already included
const viewFields = requestBody.ViewFields.results;
if (!viewFields.includes(options.kanbanBucketField)) {
viewFields.push(options.kanbanBucketField);
}
if (!options.customFormatter) {
requestBody.CustomFormatter = '{}';
}
requestBody.ViewData = `<FieldRef Name="${options.kanbanBucketField}" Type="KanbanPivotColumn" />`;
requestBody.ViewType2 = 'KANBAN';
return;
}
}
;
}
export default new SpoListViewAddCommand();
//# sourceMappingURL=list-view-add.js.map