Explorar el Código

Merge pull request #8799 from datalayer-contrib/remove-insensitive-terms

Use blocked/allowed extension naming in JupyterLab
Steven Silvester hace 4 años
padre
commit
67b270cb4c

+ 37 - 37
docs/source/user/extensions.rst

@@ -256,23 +256,23 @@ Listings
 When searching extensions, JupyterLab displays the complete search result and 
 the user is free to install any extension. This is the :ref:`default_mode`.
 
-To bring more security, you or your administrator can enable ``blacklists`` or ``whitelists``
+To bring more security, you or your administrator can enable ``blocked extensions`` or ``allowed extensions``
 mode. JupyterLab will check the extensions against the defined listings.
 
 .. warning::
 
     Only one mode at a time is allowed. If you or your server administrator configures
-    both black and white listings, the JupyterLab server will not start.
+    both blocked and allowed extensions listings, the JupyterLab server will not start.
 
 
-.. figure:: images/listings/simultaneous_black_white_listings.png
+.. figure:: images/listings/simultaneous_blocked_allowed_listings.png
    :align: center
    :class: jp-screenshot
 
-   **Figure:** Simultaneous black and white listings
+   **Figure:** Simultaneous blocked and allowed listings
 
 
-The following details the behavior for the :ref:`blacklist_mode` and the :ref:`whitelist_mode`.
+The following details the behavior for the :ref:`blocked_extension_mode` and the :ref:`allowed_extensions_mode`.
 The details to enable configure the listings can be read :ref:`listings_conf`. 
 
 .. _default_mode:
@@ -283,58 +283,58 @@ Default mode
 In the ``default`` mode, no listing is enabled and the search behavior is unchanged and
 is the one described previously.
 
-.. _blacklist_mode:
+.. _blocked_extension_mode:
 
-Blacklist mode
-^^^^^^^^^^^^^^
+Blocked Extension mode
+^^^^^^^^^^^^^^^^^^^^^^
 
 Extensions can be freely downloaded without going through a vetting process.
-However, users can add malicious extensions to a blacklist. The extension manager 
+However, users can add malicious extensions to a blocked extension. The extension manager 
 will show all extensions except for those that have 
-been explicitly added to the blacklist. Therfore, the extension manager 
-does not allow you to install blacklisted extensions.
+been explicitly added to the blocked extension. Therfore, the extension manager 
+does not allow you to install blocked extensioned extensions.
 
-If you, or your administrator, has enabled the blacklist mode,
-JupyterLab will use the blacklist and remove all blacklisted
+If you, or your administrator, has enabled the blocked extension mode,
+JupyterLab will use the blocked extension and remove all blocked extensioned
 extensions from your search result.
 
-If you have installed an extension before it has been blacklisted,
+If you have installed an extension before it has been blocked extensioned,
 the extension entry in the installed list will be highlighted
 in red. It is recommended that you uninstall it. You can move
 your mouse on the question mark icon to read the instructions.
 
-.. figure:: images/listings/installed_blacklisted.png
+.. figure:: images/listings/installed_blocked_extensions.png
    :align: center
    :class: jp-screenshot
 
-   **Figure:** Blacklisted installed extension which should be removed
+   **Figure:** Blocked Extension installed which should be removed
 
 
-.. _whitelist_mode:
+.. _allowed_extensions_mode:
 
-Whitelist mode
-^^^^^^^^^^^^^^
+Allowed Extensions mode
+^^^^^^^^^^^^^^^^^^^^^^^
 
-A whitelist maintains a set of approved extensions that users can freely 
+A allowed extensions listing maintains a set of approved extensions that users can freely 
 search and install. Extensions need to go through some sort of vetting process 
-before they are added to the whitelist. When using a whitelist, the extension manager 
-will only show extensions that have been explicitly added to the whitelist.
+before they are added to the allowed extensions. When using a allowed extensions, the extension manager 
+will only show extensions that have been explicitly added to the allowed extensions.
 
-If you, or your administrator, has enabled the whitelist mode
-JupyterLab will use the whitelist and only show extensions present
+If you, or your administrator, has enabled the allowed extensions mode
+JupyterLab will use the allowed extensions and only show extensions present
 in the withelist. The other extensions will not be show in the search result.
 
-If you have installed a whitelisted extension and at some point
-in time that extension is removed from the whitelist, the extension entry 
+If you have installed a allowed extensions extension and at some point
+in time that extension is removed from the allowed extensions, the extension entry 
 in the installed list will be highlighted in red. It is recommended that 
 you uninstall it. You can move your mouse on the question mark icon to
 read the instructions.
 
-.. figure:: images/listings/installed_whitelisted.png
+.. figure:: images/listings/installed_allowed_extensions.png
    :align: center
    :class: jp-screenshot
 
-   **Figure:** The second of the installed extensions was removed from the whitelist and should be removed
+   **Figure:** The second of the installed extensions was removed from the allowed extensions and should be removed
 
 .. _listings_conf:
 
@@ -343,12 +343,12 @@ Listing Configuration
 
 You or your administrator can use the following traits to define the listings loading.
 
-- ``blacklist_uris``: A list of comma-separated URIs to fetch a blacklist file from
-- ``whitelist_uris``: A list of comma-separated URIs to fetch a whitelist file from
+- ``blocked_extension_uris``: A list of comma-separated URIs to fetch a blocked extension file from
+- ``allowed_extensions_uris``: A list of comma-separated URIs to fetch a allowed extensions file from
 - ``listings_refresh_seconds``: The interval delay in seconds to refresh the lists
 - ``listings_request_options``: The optional kwargs to use for the listings HTTP requests
 
-For example, to enable blacklist, launch the server with ``--LabServerApp.blacklist_uris=http://example.com/blacklist.json`` where ``http://example.com/blacklist.json`` is a blacklist JSON file as described below.
+For example, to enable blocked extension, launch the server with ``--LabServerApp.blocked_extension_uris=http://example.com/blocked extension.json`` where ``http://example.com/blocked extension.json`` is a blocked extension JSON file as described below.
 
 The details for the listings_request_options are listed
 on `this page <https://2.python-requests.org/en/v2.7.0/api/#requests.request>`__  
@@ -362,16 +362,16 @@ The ``name`` attribute supports regular expressions.
 Optionally, you can also add some more fields for your records (``type``, ``reason``, ``creation_date``,
 ``last_update_date``). These optional fields are not used in the user interface.
 
-This is an example of a blacklist file.
+This is an example of a blocked extension file.
 
 .. code:: json
 
    {
-   "blacklist": [
+   "blocked extension": [
       {
          "name": "@jupyterlab-examples/launcher",
          "type": "jupyterlab",
-         "reason": "@jupyterlab-examples/launcher is blacklisted for test purpose - Do NOT take this for granted!!!",
+         "reason": "@jupyterlab-examples/launcher is blocked extensioned for test purpose - Do NOT take this for granted!!!",
          "creation_date": "2020-03-11T03:28:56.782Z",
          "last_update_date":  "2020-03-11T03:28:56.782Z"
       }
@@ -379,17 +379,17 @@ This is an example of a blacklist file.
    }
 
 
-In the following whitelist example a ``@jupyterlab/*`` will whitelist 
+In the following allowed extensions example a ``@jupyterlab/*`` will allowed extensions 
 all jupyterlab organization extensions.
 
 .. code:: json
 
    {
-   "whitelist": [
+   "allowed extensions": [
       {
          "name": "@jupyterlab/*",
          "type": "jupyterlab",
-         "reason": "All @jupyterlab org extensions are whitelisted, of course...",
+         "reason": "All @jupyterlab org extensions are allowed extensions, of course...",
          "creation_date": "2020-03-11T03:28:56.782Z",
          "last_update_date":  "2020-03-11T03:28:56.782Z"
       }

+ 0 - 0
docs/source/user/images/listings/installed_whitelisted.png → docs/source/user/images/listings/installed_allowed_extensions.png


+ 0 - 0
docs/source/user/images/listings/installed_blacklisted.png → docs/source/user/images/listings/installed_blocked_extensions.png


+ 0 - 0
docs/source/user/images/listings/simultaneous_black_white_listings.png → docs/source/user/images/listings/simultaneous_blocked_allowed_listings.png


+ 10 - 10
packages/extensionmanager-extension/examples/listings/Makefile

@@ -1,13 +1,13 @@
-export BLACK_LIST_URIS="https://raw.githubusercontent.com/datalayer-jupyterlab/jupyterlab-listings-example/master/blacklist_simple.json"
-# export BLACK_LIST_URIS=""
-# export WHITE_LIST_URIS="https://raw.githubusercontent.com/datalayer-jupyterlab/jupyterlab-listings-example/master/whitelist_only_jlab.json"
-export WHITE_LIST_URIS=""
+export BLOCKED_EXTENSIONS_URIS="https://raw.githubusercontent.com/datalayer-jupyterlab/jupyterlab-listings-example/master/blockedExtensions_simple.json"
+# export BLOCKED_EXTENSIONS_URIS=""
+# export ALLOWED_EXTENSIONS_URIS="https://raw.githubusercontent.com/datalayer-jupyterlab/jupyterlab-listings-example/master/allowedExtensions_only_jlab.json"
+export ALLOWED_EXTENSIONS_URIS=""
 export LISTINGS_REFRESH_SECONDS=120
 export LISTINGS_REQUEST_OPTS="{'timeout': 10}"
 
 listings-uris:
-	@exec echo Using blacklist URIs: ${BLACK_LIST_URIS}
-	@exec echo Using whitelist URIs: ${WHITE_LIST_URIS}
+	@exec echo Using blockedExtensions URIs: ${BLOCKED_EXTENSIONS_URIS}
+	@exec echo Using allowedExtensions URIs: ${ALLOWED_EXTENSIONS_URIS}
 	@exec echo Refreshing lists every ${LISTINGS_REFRESH_SECONDS} seconds
 	@exec echo Using ${LISTINGS_REQUEST_OPTS} for the HTTP requests
 
@@ -15,8 +15,8 @@ dev: listings-uris
 	@exec python main.py \
 	  --dev \
 	  --no-browser \
-	  --LabServerApp.blacklist_uris=${BLACK_LIST_URIS} \
-	  --LabServerApp.whitelist_uris=${WHITE_LIST_URIS} \
+	  --LabServerApp.blocked_extensions_uris=${BLOCKED_EXTENSIONS_URIS} \
+	  --LabServerApp.allowed_extensions_uris=${ALLOWED_EXTENSIONS_URIS} \
 	  --LabServerApp.listings_refresh_seconds=${LISTINGS_REFRESH_SECONDS} \
 	  --LabServerApp.listings_request_options=${LISTINGS_REQUEST_OPTS}
 
@@ -25,7 +25,7 @@ watch: listings-uris
 	  --dev \
 	  --no-browser \
 	  --watch \
-	  --LabServerApp.blacklist_uris=${BLACK_LIST_URIS} \
-	  --LabServerApp.whitelist_uris=${WHITE_LIST_URIS} \
+	  --LabServerApp.blocked_extensions_uris=${BLOCKED_EXTENSIONS_URIS} \
+	  --LabServerApp.allowed_extensions_uris=${ALLOWED_EXTENSIONS_URIS} \
 	  --LabServerApp.listings_refresh_seconds=${LISTINGS_REFRESH_SECONDS} \
 	  --LabServerApp.listings_request_options=${LISTINGS_REQUEST_OPTS}

+ 1 - 1
packages/extensionmanager-extension/examples/listings/list/whitelist.json → packages/extensionmanager-extension/examples/listings/list/allowed_extensions.json

@@ -1,5 +1,5 @@
 {
-  "whitelist": [
+  "allowed_extensions": [
     {
       "name": "@jupyterlab/*",
       "type": "jupyterlab",

+ 1 - 1
packages/extensionmanager-extension/examples/listings/list/blacklist.json → packages/extensionmanager-extension/examples/listings/list/blocked_extensions.json

@@ -1,5 +1,5 @@
 {
-  "blacklist": [
+  "blocked_extensions": [
     {
       "name": "@jupyterlab-examples/launcher",
       "type": "jupyterlab",

+ 18 - 13
packages/extensionmanager/src/listings.ts

@@ -33,16 +33,16 @@ export interface IListEntry {
  *
  */
 export type ListResult = null | {
-  mode: 'white' | 'black' | 'default' | 'invalid';
+  mode: 'block' | 'allow' | 'default' | 'invalid';
   uris: string[];
   entries: IListEntry[];
 };
 
 export interface IListingApi {
-  blacklist_uris: string[];
-  whitelist_uris: string[];
-  blacklist: IListEntry[];
-  whitelist: IListEntry[];
+  blocked_extensions_uris: string[];
+  allowed_extensions_uris: string[];
+  blocked_extensions: IListEntry[];
+  allowed_extensions: IListEntry[];
 }
 
 /**
@@ -62,7 +62,10 @@ export class Lister {
           uris: [],
           entries: []
         };
-        if (data.blacklist_uris.length > 0 && data.whitelist_uris.length > 0) {
+        if (
+          data.blocked_extensions_uris.length > 0 &&
+          data.allowed_extensions_uris.length > 0
+        ) {
           console.warn('Simultaneous black and white list are not allowed.');
           this._listings = {
             mode: 'invalid',
@@ -70,17 +73,19 @@ export class Lister {
             entries: []
           };
         } else if (
-          data.blacklist_uris.length > 0 ||
-          data.whitelist_uris.length > 0
+          data.blocked_extensions_uris.length > 0 ||
+          data.allowed_extensions_uris.length > 0
         ) {
           this._listings = {
-            mode: data.blacklist_uris.length > 0 ? 'black' : 'white',
+            mode: data.blocked_extensions_uris.length > 0 ? 'block' : 'allow',
             uris:
-              data.blacklist_uris.length > 0
-                ? data.blacklist_uris
-                : data.whitelist_uris,
+              data.blocked_extensions_uris.length > 0
+                ? data.blocked_extensions_uris
+                : data.allowed_extensions_uris,
             entries:
-              data.blacklist_uris.length > 0 ? data.blacklist : data.whitelist
+              data.blocked_extensions_uris.length > 0
+                ? data.blocked_extensions
+                : data.allowed_extensions
           };
         }
         this._listingsLoaded.emit(this._listings);

+ 48 - 34
packages/extensionmanager/src/model.ts

@@ -74,9 +74,9 @@ export interface IEntry {
    */
   installed_version: string;
 
-  blacklistEntry: IListEntry | undefined;
+  blockedExtensionsEntry: IListEntry | undefined;
 
-  whitelistEntry: IListEntry | undefined;
+  allowedExtensionsEntry: IListEntry | undefined;
 }
 
 /**
@@ -175,10 +175,10 @@ export class ListModel extends VDomModel {
 
   private _listingIsLoaded(_: Lister, listings: ListResult) {
     this._listMode = listings!.mode;
-    this._blacklistArray = new Array<IListEntry>();
-    if (this._listMode === 'black') {
+    this._blockedExtensionsArray = new Array<IListEntry>();
+    if (this._listMode === 'block') {
       listings!.entries.map(e => {
-        this._blacklistArray.push({
+        this._blockedExtensionsArray.push({
           name: e.name,
           regexp: new RegExp(e.name),
           type: e.type,
@@ -188,10 +188,10 @@ export class ListModel extends VDomModel {
         });
       });
     }
-    this._whitelistArray = new Array<IListEntry>();
-    if (this._listMode === 'white') {
+    this._allowedExtensionsArray = new Array<IListEntry>();
+    if (this._listMode === 'allow') {
       listings!.entries.map(e => {
-        this._whitelistArray.push({
+        this._allowedExtensionsArray.push({
           name: e.name,
           regexp: new RegExp(e.name),
           type: e.type,
@@ -273,22 +273,22 @@ export class ListModel extends VDomModel {
   /**
    * The list mode.
    */
-  get listMode(): 'black' | 'white' | 'default' | 'invalid' {
+  get listMode(): 'block' | 'allow' | 'default' | 'invalid' {
     return this._listMode;
   }
 
   /**
-   * The total number of blacklisted results in the current search.
+   * The total number of blockedExtensions results in the current search.
    */
-  get totalBlacklistedFound(): number {
-    return this._totalBlacklistedFound;
+  get totalblockedExtensionsFound(): number {
+    return this._totalblockedExtensionsFound;
   }
 
   /**
-   * The total number of whitelisted results in the current search.
+   * The total number of allowedExtensions results in the current search.
    */
-  get totalWhitelistedFound(): number {
-    return this._totalWhitelistedFound;
+  get totalallowedExtensionsFound(): number {
+    return this._totalallowedExtensionsFound;
   }
 
   /**
@@ -474,8 +474,8 @@ export class ListModel extends VDomModel {
     res: Promise<ISearchResult>
   ): Promise<{ [key: string]: IEntry }> {
     const entries: { [key: string]: IEntry } = {};
-    this._totalBlacklistedFound = 0;
-    this._totalWhitelistedFound = 0;
+    this._totalblockedExtensionsFound = 0;
+    this._totalallowedExtensionsFound = 0;
     this._totalEntries = 0;
     for (const obj of (await res).objects) {
       const pkg = obj.package;
@@ -483,13 +483,21 @@ export class ListModel extends VDomModel {
         continue;
       }
       this._totalEntries = this._totalEntries + 1;
-      const isBlacklisted = this.isListed(pkg.name, this._blacklistArray);
-      if (isBlacklisted) {
-        this._totalBlacklistedFound = this._totalBlacklistedFound + 1;
+      const isblockedExtensions = this.isListed(
+        pkg.name,
+        this._blockedExtensionsArray
+      );
+      if (isblockedExtensions) {
+        this._totalblockedExtensionsFound =
+          this._totalblockedExtensionsFound + 1;
       }
-      const isWhitelisted = this.isListed(pkg.name, this._whitelistArray);
-      if (isWhitelisted) {
-        this._totalWhitelistedFound = this._totalWhitelistedFound + 1;
+      const isallowedExtensions = this.isListed(
+        pkg.name,
+        this._allowedExtensionsArray
+      );
+      if (isallowedExtensions) {
+        this._totalallowedExtensionsFound =
+          this._totalallowedExtensionsFound + 1;
       }
       entries[pkg.name] = {
         name: pkg.name,
@@ -505,8 +513,8 @@ export class ListModel extends VDomModel {
         status: null,
         latest_version: pkg.version,
         installed_version: '',
-        blacklistEntry: isBlacklisted,
-        whitelistEntry: isWhitelisted
+        blockedExtensionsEntry: isblockedExtensions,
+        allowedExtensionsEntry: isallowedExtensions
       };
     }
     return entries;
@@ -534,8 +542,14 @@ export class ListModel extends VDomModel {
             status: pkg.status,
             latest_version: pkg.latest_version,
             installed_version: pkg.installed_version,
-            blacklistEntry: this.isListed(pkg.name, this._blacklistArray),
-            whitelistEntry: this.isListed(pkg.name, this._whitelistArray)
+            blockedExtensionsEntry: this.isListed(
+              pkg.name,
+              this._blockedExtensionsArray
+            ),
+            allowedExtensionsEntry: this.isListed(
+              pkg.name,
+              this._allowedExtensionsArray
+            )
           };
         })
       );
@@ -760,7 +774,7 @@ export class ListModel extends VDomModel {
   /**
    * Contains an error message if an error occurred when searching for lists.
    */
-  blacklistError: string | null = null;
+  blockedExtensionsError: string | null = null;
 
   /**
    * Contains an error message if an error occurred when querying the server extension.
@@ -810,11 +824,11 @@ export class ListModel extends VDomModel {
   private _pendingActions: Promise<any>[] = [];
   private _debouncedUpdate: Debouncer<void, void>;
 
-  private _listMode: 'black' | 'white' | 'default' | 'invalid';
-  private _blacklistArray: Array<IListEntry>;
-  private _whitelistArray: Array<IListEntry>;
-  private _totalBlacklistedFound: number = 0;
-  private _totalWhitelistedFound: number = 0;
+  private _listMode: 'block' | 'allow' | 'default' | 'invalid';
+  private _blockedExtensionsArray: Array<IListEntry>;
+  private _allowedExtensionsArray: Array<IListEntry>;
+  private _totalblockedExtensionsFound: number = 0;
+  private _totalallowedExtensionsFound: number = 0;
 }
 
 let _isDisclaimed = false;
@@ -849,7 +863,7 @@ export namespace ListModel {
  */
 namespace Private {
   /**
-   * A comparator function that sorts whitelisted orgs to the top.
+   * A comparator function that sorts allowedExtensions orgs to the top.
    */
   export function comparator(a: IEntry, b: IEntry): number {
     if (a.name === b.name) {

+ 1 - 1
packages/extensionmanager/src/npm.ts

@@ -297,6 +297,6 @@ export function isJupyterOrg(name: string): boolean {
     parts.length > 1 && // Has a first part
     !!first && // with a finite length
     first[0] === '@' && // corresponding to an org name
-    jupyterOrg.indexOf(first.slice(1)) !== -1 // in the org whitelist.
+    jupyterOrg.indexOf(first.slice(1)) !== -1 // in the org allowedExtensions.
   );
 }

+ 17 - 17
packages/extensionmanager/src/widget.tsx

@@ -177,23 +177,23 @@ function ListEntry(props: ListEntry.IProperties): React.ReactElement<any> {
   }
   const githubUser = getExtensionGitHubUser(entry);
   if (
-    listMode === 'black' &&
-    entry.blacklistEntry &&
+    listMode === 'block' &&
+    entry.blockedExtensionsEntry &&
     viewType === 'searchResult'
   ) {
     return <li></li>;
   }
   if (
-    listMode === 'white' &&
-    !entry.whitelistEntry &&
+    listMode === 'allow' &&
+    !entry.allowedExtensionsEntry &&
     viewType === 'searchResult'
   ) {
     return <li></li>;
   }
-  if (listMode === 'black' && entry.blacklistEntry?.name) {
+  if (listMode === 'block' && entry.blockedExtensionsEntry?.name) {
     flagClasses.push(`jp-extensionmanager-entry-should-be-uninstalled`);
   }
-  if (listMode === 'white' && !entry.whitelistEntry) {
+  if (listMode === 'allow' && !entry.allowedExtensionsEntry) {
     flagClasses.push(`jp-extensionmanager-entry-should-be-uninstalled`);
   }
   return (
@@ -220,10 +220,10 @@ function ListEntry(props: ListEntry.IProperties): React.ReactElement<any> {
               {entry.name}
             </a>
           </div>
-          {entry.blacklistEntry && (
+          {entry.blockedExtensionsEntry && (
             <ToolbarButtonComponent
               icon={listingsInfoIcon}
-              iconLabel={`${entry.name} extension has been blacklisted since install. Please uninstall immediately and contact your blacklist administrator.`}
+              iconLabel={`${entry.name} extension has been blockedExtensions since install. Please uninstall immediately and contact your blockedExtensions administrator.`}
               onClick={() =>
                 window.open(
                   'https://jupyterlab.readthedocs.io/en/stable/user/extensions.html'
@@ -231,12 +231,12 @@ function ListEntry(props: ListEntry.IProperties): React.ReactElement<any> {
               }
             />
           )}
-          {!entry.whitelistEntry &&
+          {!entry.allowedExtensionsEntry &&
             viewType === 'installed' &&
-            listMode === 'white' && (
+            listMode === 'allow' && (
               <ToolbarButtonComponent
                 icon={listingsInfoIcon}
-                iconLabel={`${entry.name} extension has been removed from the whitelist since installation. Please uninstall immediately and contact your whitelist administrator.`}
+                iconLabel={`${entry.name} extension has been removed from the allowedExtensions since installation. Please uninstall immediately and contact your allowedExtensions administrator.`}
                 onClick={() =>
                   window.open(
                     'https://jupyterlab.readthedocs.io/en/stable/user/extensions.html'
@@ -259,8 +259,8 @@ function ListEntry(props: ListEntry.IProperties): React.ReactElement<any> {
           </div>
           <div className="jp-extensionmanager-entry-buttons">
             {!entry.installed &&
-              !entry.blacklistEntry &&
-              !(!entry.whitelistEntry && listMode === 'white') &&
+              !entry.blockedExtensionsEntry &&
+              !(!entry.allowedExtensionsEntry && listMode === 'allow') &&
               ListModel.isDisclaimed() && (
                 <Button
                   onClick={() => props.performAction('install', entry)}
@@ -271,8 +271,8 @@ function ListEntry(props: ListEntry.IProperties): React.ReactElement<any> {
                 </Button>
               )}
             {ListModel.entryHasUpdate(entry) &&
-              !entry.blacklistEntry &&
-              !(!entry.whitelistEntry && listMode === 'white') &&
+              !entry.blockedExtensionsEntry &&
+              !(!entry.allowedExtensionsEntry && listMode === 'allow') &&
               ListModel.isDisclaimed() && (
                 <Button
                   onClick={() => props.performAction('install', entry)}
@@ -329,7 +329,7 @@ export namespace ListEntry {
     /**
      * The list mode to apply.
      */
-    listMode: 'black' | 'white' | 'default' | 'invalid';
+    listMode: 'block' | 'allow' | 'default' | 'invalid';
 
     /**
      * The requested view type.
@@ -415,7 +415,7 @@ export namespace ListView {
     /**
      * The list mode to apply.
      */
-    listMode: 'black' | 'white' | 'default' | 'invalid';
+    listMode: 'block' | 'allow' | 'default' | 'invalid';
 
     /**
      * The requested view type.

+ 1 - 1
setup.py

@@ -151,7 +151,7 @@ setup_args = dict(
 setup_args['install_requires'] = [
     'ipython',
     'tornado!=6.0.0, !=6.0.1, !=6.0.2',
-    'jupyterlab_server>=2.0.0a3',
+    'jupyterlab_server>=2.0.0a4',
     'jupyter_server>=1.0.0rc5',
     'nbclassic>=0.2.0rc3',
     'jinja2>=2.10'