Максимальное использование современных списков и библиотек

В этой статье рассматриваются способы получения максимального числа списков и библиотек при использовании современного пользовательского интерфейса в SharePoint.

Пока еще не удается преобразовать все списки и библиотеки в современный интерфейс, так как:

  • Некоторые типы списков и библиотек пока что не созданы командой разработчиков SharePoint для отображения в современном пользовательском интерфейсе, например список задач или список событий. Для таких случаев можно подождать реализации современной версии командой SharePoint или переключиться на эквивалентный вариант. Варианты включают использование Планировщика (Майкрософт) вместо классического списка задач или календаря группы Microsoft 365 вместо классического календаря списка событий SharePoint.

  • Определенные типы списков и библиотек могут отображаться в современном пользовательском интерфейсе, но блокируются из-за несовместимой конфигурации или настройки. Здесь потребуется ваше вмешательство.

Важно!

Средства модернизации и все остальные компоненты PnP — это инструменты с открытым исходным кодом, поддерживаемые активным сообществом, которое предоставляет для них поддержку. Со стороны официальных каналов поддержки Майкрософт отсутствуют соглашения об уровне обслуживания (SLA) для инструментов с открытым исходным кодом.

Шаблоны списков, доступные в современном пользовательском интерфейсе

Ниже перечислены наиболее часто используемые шаблоны списков, которые в настоящее время могут отображаться в современном пользовательском интерфейсе SharePoint (по состоянию на октябрь 2018 г.).

  • Список (100)
  • Библиотека документов (101)
  • Список ссылок (103)
  • Список объявлений (104)
  • Список контактов (105)
  • Библиотека изображений (109)
  • Библиотека форм (115)
  • Библиотека страниц сайта (119)
  • Настраиваемая сетка (120)
  • Список продвигаемых ссылок (170)
  • Библиотека страниц публикации (850)
  • Библиотека ресурсов (851)
  • Список отслеживания вопросов (1100)

В этом разделе вы узнаете, как определить списки, которые не отображаются как современный список, по какой причине это происходит и как это исправить (если это возможно). При это важно понимать, что для большинства клиентов большинство списков загружаются в современном интерфейсе без каких-либо оговорок. Списки, которые не загружаются в современном интерфейсе, остаются в классическом интерфейсе (например, список календаря или задач) или могут быть разблокированы с помощью их исправления, что рассматривается в этой серии статей. Списки, которые не загружаются как современный список, на 100% пригодны к использованию, полностью поддерживаются и не должны удерживать вас от включения современного интерфейса списков и библиотек для вашего клиента.

Важно!

SharePoint по умолчанию автоматически применяет современный интерфейс списков и библиотек, но при необходимости также автоматически возвращается к исходному интерфейсу. Это гарантирует, что все списки, которые могут использовать современный интерфейс, отображаются как современный список. А списки, которые не могут его использовать, просто переключаются в классический интерфейс при их применении.

Обнаружение списков и библиотек, которые недоступны в современном пользовательском интерфейсе

Чтобы определить, какие списки и библиотеки недоступны в современном пользовательском интерфейсе, рекомендуется запустить сканер модернизации SharePoint. Это средство выполняет подробный анализ всех списков и библиотек в клиенте, а затем создает отчеты, где указывается, какие списки и библиотеки не отображаются в современном пользовательском интерфейсе и (что еще важнее) почему. На основе выходных данных сканера вы можете разблокировать списки и библиотеки путем их исправления. В следующем разделе рассказывается, как это сделать.

Разблокировка списков и библиотек

Список может быть заблокирован по одной или нескольким причинам. Все они описываются в выходных данных сканера. Ниже перечислены типичные причины и способы их устранения.

Несовместимые настройки

Несовместимые настройки являются самой распространенной причиной, по которой списки не отображаются в современном интерфейсе, что обычно связано с одним из следующих действий:

  • Использование JSLink
  • Использование дополнительного действия пользователя, внедряющего JavaScript

Чтобы устранить эти препятствия, вы можете либо удалить настройку (если она больше не представляет ценности для бизнеса), либо создать альтернативное решение. Дополнительные сведения о создании настроек, которые совместимы с современным пользовательским интерфейсом списков и библиотек, см. в статье Модернизация настроек. Так как JSLink на уровне веб-части не предотвращает использование современного пользовательского интерфейса списков и библиотек, необходимо удалить эту конфигурацию. Это можно сделать вручную путем перевода страницы в режим редактирования посредством добавления ?ToolPaneView=2&pagemode=edit к URL-адресу страницы и последующего обновления свойств веб-части. Для выполнения этого программными средствами можно использовать получение веб-части с помощью класса LimitedWebPartManager и последующего обновления соответствующих свойств, как показано в следующем фрагменте. Для получения полного решения можно объединить этот фрагмент с более полным кодом, приведенным ниже на этой странице.

webPart.Properties["JSLink"] = "";
webPart.SaveWebPartChanges();
cc.ExecuteQuery();

Наличие определенных типов полей

Некоторые типы полей (внешние данные BCS, Geolocation, OutcomeChoice в режиме редактирования, Image, Html и SummaryLinks) пока что не рассчитаны на работу в современном пользовательском интерфейсе. Исправить их можно следующими способами:

  • Удаление поля из представлений. Поле остается, поэтому для редактирования используется классический интерфейс, а для представлений — современный.
  • Перенос данных из этих полей в новое поле, совместимое с современным пользовательским интерфейсом.
  • Полное удаление поля (если оно не используется).

Блокирование современного пользовательского интерфейса списков и библиотек на уровне сайта или сети

Современный пользовательский интерфейс списков и библиотек может быть заблокирован для всего семейства веб-сайтов (на уровне сайтов) либо для одного или нескольких сайтов (на уровне сети). Это можно исправить, отключив соответствующие функции на уроне сайта или сети, как показано в приведенном ниже фрагменте кода PnP PowerShell.

$minimumVersion = New-Object System.Version("2.24.1803.0")
if (-not (Get-InstalledModule -Name SharePointPnPPowerShellOnline -MinimumVersion $minimumVersion -ErrorAction Ignore))
{
    Install-Module SharePointPnPPowerShellOnline -MinimumVersion $minimumVersion -Scope CurrentUser
}
Import-Module SharePointPnPPowerShellOnline -DisableNameChecking -MinimumVersion $minimumVersion

Connect-PnPOnline -Url "<your site url>"

# Disable the modern list site level blocking feature
Disable-PnPFeature -Identity "E3540C7D-6BEA-403C-A224-1A12EAFEE4C4" -Scope Site
# Disable the modern list web level blocking feature
Disable-PnPFeature -Identity "52E14B6F-B1BB-4969-B89B-C4FAA56745EF" -Scope Web

Примечание.

PnP PowerShell — это решение с открытым исходным кодом, поддержка которого предоставляется активным сообществом. Для инструментов с открытым исходным кодом не существует соглашения об уровне обслуживания в отношении поддержки корпорацией Майкрософт.

Блокирование современного пользовательского интерфейса списков и библиотек на уровне списка

Список может быть определен таким образом, чтобы всегда запускался классический пользовательский интерфейс на уровне списка (ListExperienceOptions, установленный на значение ClassicExperience). Чтобы отменить это, можно использовать следующий фрагмент кода:

// Load the list you want to update
var list = context.Web.Lists.GetByTitle(title);
context.Load(list);
context.ExecuteQuery();

// Possible options are Auto (= defaults to modern), NewExperience (= "modern") and ClassicExperience
list.ListExperienceOptions = ListExperience.Auto;

// Persist the changes
list.Update();
context.ExecuteQuery();

Списки, отображаемые с BaseTemplate = 0

Каждый список содержит базовый шаблон, но в некоторых случаях отображаются списки, содержащие значение 0 для базового шаблона в выходных данных сканера. Это связано с тем, что для этих списков либо нет представления, отмеченного как значение по умолчанию, либо вообще нет представления. Чтобы исправить эти списки, необходимо перейти к странице параметров списков (_layouts/15/listedit.aspx?List=%7B<list id>%7D) и установить представление для списка.

Специальные страницы для представления списков, содержащие не только список XSLTListViewWebPart

Пользователи могут изменять классические страницы для просмотра и редактирования списков, поэтому вы могли, к примеру, добавить веб-части на страницу представления списка. Если вы сделали это, то список больше не отображается в современном интерфейсе. Устранить эту проблему можно только путем удаления добавленных веб-частей со страниц списков. Вы можете вручную проверить эти случаи, перейдя в список и добавив ?ToolPaneView=2&pagemode=edit к URL-адресу списка. Это переведет страницу в режим правки, а также должно открыть дополнительные веб-части с возможностью их удаления. Если вы хотите сделать это программными средствами, указанный ниже фрагмент кода является подходящей отправной точкой. Этот фрагмент зависит от основной библиотеки PnP-сайтов, которую вы можете установить в своем проекте Visual Studio через пакет NuGet SharePointPnPCoreOnline.

using Microsoft.SharePoint.Client;
using Microsoft.SharePoint.Client.WebParts;
using OfficeDevPnP.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security;

namespace MultipleWebPartFixer
{
    class Program
    {
        static void Main(string[] args)
        {
            string siteUrl = "https://contoso.sharepoint.com/sites/demo";
            string userName = "joe@contoso.onmicrosoft.com";
            AuthenticationManager am = new AuthenticationManager();
            using (var cc = am.GetSharePointOnlineAuthenticatedContextTenant(siteUrl, userName, GetSecureString("Password")))
            {
                // Grab the list
                var list = cc.Web.Lists.GetByTitle("listtofix");
                list.EnsureProperties(l => l.RootFolder, l => l.Id);

                bool isNoScriptSite = cc.Web.IsNoScriptSite();

                if (isNoScriptSite)
                {
                    throw new Exception("You don't have the needed permissions to apply this fix!");
                }

                // get the current (allitems) form
                var files = list.RootFolder.FindFiles("allitems.aspx");
                var allItemsForm = files.FirstOrDefault();
                if (allItemsForm != null)
                {
                    // Load web part manager and web parts
                    var limitedWPManager = allItemsForm.GetLimitedWebPartManager(PersonalizationScope.Shared);
                    cc.Load(limitedWPManager);

                    // Load the web parts on the page
                    IEnumerable<WebPartDefinition> webParts = cc.LoadQuery(limitedWPManager.WebParts.IncludeWithDefaultProperties(wp => wp.Id, wp => wp.ZoneId, wp => wp.WebPart.ExportMode, wp => wp.WebPart.Title, wp => wp.WebPart.ZoneIndex, wp => wp.WebPart.IsClosed, wp => wp.WebPart.Hidden, wp => wp.WebPart.Properties));
                    cc.ExecuteQueryRetry();

                    List<WebPartDefinition> webPartsToDelete = new List<WebPartDefinition>();
                    if (webParts.Count() > 1)
                    {
                        // List all except the XsltListView web part(s)
                        foreach (var webPart in webParts)
                        {
                            if (GetTypeFromProperties(webPart.WebPart.Properties) != "XsltListView")
                            {
                                webPartsToDelete.Add(webPart);
                            }
                        }

                        if (webPartsToDelete.Count == webParts.Count() - 1)
                        {
                            foreach(var webPart in webPartsToDelete)
                            {
                                webPart.DeleteWebPart();
                            }
                            cc.ExecuteQueryRetry();
                            Console.WriteLine("List fixed!");
                        }
                        else
                        {
                            // Special case...investigation needed. Go to list and append ?ToolPaneView=2&pagemode=edit to the list url to check the page
                            Console.WriteLine("Go to list and append ?ToolPaneView=2&pagemode=edit to the list url to check this page");
                        }
                    }
                }
            }

            Console.WriteLine("Press enter to continue...");
            Console.ReadLine();
        }

        public static string GetTypeFromProperties(PropertyValues properties)
        {
            // Check for XSLTListView web part
            string[] xsltWebPart = new string[] { "ListUrl", "ListId", "Xsl", "JSLink", "ShowTimelineIfAvailable" };
            if (CheckWebPartProperties(xsltWebPart, properties))
            {
                return "XsltListView";
            }

            return "";
        }
        private static bool CheckWebPartProperties(string[] propertiesToCheck, PropertyValues properties)
        {
            bool isWebPart = true;
            foreach (var wpProp in propertiesToCheck)
            {
                if (!properties.FieldValues.ContainsKey(wpProp))
                {
                    isWebPart = false;
                    break;
                }
            }

            return isWebPart;
        }

        private static SecureString GetSecureString(string label)
        {
            SecureString sStrPwd = new SecureString();
            try
            {
                Console.Write(String.Format("{0}: ", label));

                for (ConsoleKeyInfo keyInfo = Console.ReadKey(true); keyInfo.Key != ConsoleKey.Enter; keyInfo = Console.ReadKey(true))
                {
                    if (keyInfo.Key == ConsoleKey.Backspace)
                    {
                        if (sStrPwd.Length > 0)
                        {
                            sStrPwd.RemoveAt(sStrPwd.Length - 1);
                            Console.SetCursorPosition(Console.CursorLeft - 1, Console.CursorTop);
                            Console.Write(" ");
                            Console.SetCursorPosition(Console.CursorLeft - 1, Console.CursorTop);
                        }
                    }
                    else if (keyInfo.Key != ConsoleKey.Enter)
                    {
                        Console.Write("*");
                        sStrPwd.AppendChar(keyInfo.KeyChar);
                    }

                }
                Console.WriteLine("");
            }
            catch (Exception e)
            {
                sStrPwd = null;
                Console.WriteLine(e.Message);
            }

            return sStrPwd;
        }
    }
}

См. также