diff --git a/core/modules/field_ui/field_ui.module b/core/modules/field_ui/field_ui.module
index b9d1a1c..751343c 100644
--- a/core/modules/field_ui/field_ui.module
+++ b/core/modules/field_ui/field_ui.module
@@ -67,6 +67,11 @@ function field_ui_menu() {
     'type' => MENU_NORMAL_ITEM,
     'file' => 'field_ui.admin.inc',
   );
+  $items['admin/reports/fields/list'] = array(
+    'title' => 'List',
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+    'weight' => -10,
+  );
 
   // Create tabs for all possible bundles.
   foreach (entity_get_info() as $entity_type => $entity_info) {
diff --git a/core/modules/views/lib/Drupal/views/Tests/UI/DefaultViewsTest.php b/core/modules/views/lib/Drupal/views/Tests/UI/DefaultViewsTest.php
index 3ce171b..2780e40 100644
--- a/core/modules/views/lib/Drupal/views/Tests/UI/DefaultViewsTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/UI/DefaultViewsTest.php
@@ -41,7 +41,7 @@ function testDefaultViews() {
 
     // Enable the front page view, and make sure it is now visible on the main
     // listing page.
-    $this->drupalGet('admin/structure/views/templates');
+    $this->drupalGet('admin/structure/views');
     $this->clickViewsOperationLink(t('Enable'), '/frontpage/');
     $this->assertUrl('admin/structure/views');
     $this->assertLinkByHref($edit_href);
@@ -64,7 +64,7 @@ function testDefaultViews() {
 
     // Save another view in the UI.
     $this->drupalPost('admin/structure/views/nojs/display/archive/page_1/title', array(), t('Apply'));
-    $this->drupalPost('admin/structure/views/view/archive/page_1', array(), t('Save'));
+    $this->drupalPost('admin/structure/views/view/archive/edit/page_1', array(), t('Save'));
 
     // Check there is an enable link. i.e. The view has not been enabled after
     // editing.
@@ -107,7 +107,7 @@ function testDefaultViews() {
     // $this->assertNoLinkByHref($edit_href);
     // The easiest way to verify it appears on the disabled views listing page
     // is to try to click the "enable" link from there again.
-    $this->drupalGet('admin/structure/views/templates');
+    $this->drupalGet('admin/structure/views');
     $this->clickViewsOperationLink(t('Enable'), '/frontpage/');
     $this->assertUrl('admin/structure/views');
     $this->assertLinkByHref($edit_href);
diff --git a/core/modules/views/lib/Drupal/views/Tests/UI/StorageTest.php b/core/modules/views/lib/Drupal/views/Tests/UI/StorageTest.php
index 1fbec1f..c740132 100644
--- a/core/modules/views/lib/Drupal/views/Tests/UI/StorageTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/UI/StorageTest.php
@@ -36,14 +36,13 @@ public function testDetails() {
     $view_name = 'test_view';
     $view = views_get_view($view_name);
 
-    $path = "admin/structure/views/nojs/edit-details/$view_name";
     $edit = array(
       'human_name' => $this->randomName(),
       'tag' => $this->randomName(),
       'description' => $this->randomName(30),
     );
 
-    $this->drupalPost($path, $edit, t('Apply'));
+    $this->drupalPost("admin/structure/views/nojs/edit-details/$view_name/default", $edit, t('Apply'));
     $this->drupalPost(NULL, array(), t('Save'));
 
     $view = views_get_view($view_name);
diff --git a/core/modules/views/lib/Drupal/views/Tests/UI/TagTest.php b/core/modules/views/lib/Drupal/views/Tests/UI/TagTest.php
index e5cac15..1ed5178 100644
--- a/core/modules/views/lib/Drupal/views/Tests/UI/TagTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/UI/TagTest.php
@@ -14,6 +14,13 @@
  */
 class TagTest extends ViewUnitTestBase {
 
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('views', 'views_ui');
+
   public static function getInfo() {
     return array(
       'name' => 'Tag',
@@ -38,12 +45,16 @@ public function testViewsUiAutocompleteTag() {
     }
 
     // Make sure just ten results are returns.
-    $result = views_ui_autocomplete_tag('autocomplete_tag_test');
+    $controller = $this->container->get('views_ui.controller');
+    $request = $this->container->get('request');
+    $request->query->set('q', 'autocomplete_tag_test');
+    $result = $controller->autocompleteTag();
     $matches = (array) json_decode($result->getContent());
     $this->assertEqual(count($matches), 10, 'Make sure the maximum amount of tag results is 10.');
 
     // Make sure that matching by a certain prefix works.
-    $result = views_ui_autocomplete_tag('autocomplete_tag_test_even');
+    $request->query->set('q', 'autocomplete_tag_test_even');
+    $result = $controller->autocompleteTag();
     $matches = (array) json_decode($result->getContent());
     $this->assertEqual(count($matches), 8, 'Make sure that only a subset is returned.');
     foreach ($matches as $tag) {
@@ -51,7 +62,8 @@ public function testViewsUiAutocompleteTag() {
     }
 
     // Make sure an invalid result doesn't return anything.
-    $result = views_ui_autocomplete_tag($this->randomName());
+    $request->query->set('q', $this->randomName());
+    $result = $controller->autocompleteTag();
     $matches = (array) json_decode($result->getContent());
     $this->assertEqual(count($matches), 0, "Make sure an invalid tag doesn't return anything.");
   }
diff --git a/core/modules/views/views_ui/admin.inc b/core/modules/views/views_ui/admin.inc
index 9e9f1ba..857fb19 100644
--- a/core/modules/views/views_ui/admin.inc
+++ b/core/modules/views/views_ui/admin.inc
@@ -8,6 +8,7 @@
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Core\Database\Database;
 use Symfony\Component\HttpFoundation\JsonResponse;
+use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
 use Drupal\views_ui\ViewUI;
 use Drupal\views_ui\ViewFormControllerBase;
 use Drupal\views\Analyzer;
@@ -15,25 +16,6 @@
 use Drupal\views\Plugin\views\wizard\WizardException;
 
 /**
- * Returns the results of the live preview.
- */
-function views_ui_preview(ViewUI $view, $display_id) {
-  // Pass along any other arguments.
-  $args = func_get_args();
-  unset($args[0], $args[1]);
-  return $view->renderPreview($display_id, $args);
-}
-
-/**
- * Page callback to add a new view.
- */
-function views_ui_add_page() {
-  drupal_set_title(t('Add new view'));
-  $view = entity_create('view', array());
-  return entity_get_form($view, 'add');
-}
-
-/**
  * Converts a form element in the add view wizard to be AJAX-enabled.
  *
  * This function takes a form element and adds AJAX behaviors to it such that
@@ -317,22 +299,6 @@ function views_ui_edit_page(ViewUI $view, $display_id = NULL) {
 }
 
 /**
- * Page callback for rendering the preview form and the preview of the view.
- *
- * @param \Drupal\views_ui\ViewUI $view
- *   The view UI object to preview.
- * @param string $display_id
- *   The display ID to preview.
- *
- * @return array
- *   The form array of the full preview form.
- */
-function views_ui_build_preview(ViewUI $view, $display_id) {
-  $view->displayID = $display_id;
-  return entity_get_form($view, 'preview');
-}
-
-/**
  * Move form elements into details for presentation purposes.
  *
  * Many views forms use #tree = TRUE to keep their values in a hierarchy for
@@ -564,7 +530,7 @@ function views_ui_ajax_form($js, $key, ViewUI $view, $display_id = '') {
 
   $form = views_ui_ajax_forms($key);
   if (empty($form)) {
-    return MENU_NOT_FOUND;
+    throw new NotFoundHttpException();
   }
 
   views_include('ajax');
@@ -725,7 +691,11 @@ function views_ui_edit_details_form_submit($form, &$form_state) {
       $view->set($key, $value);
     }
   }
-  $form_state['#page_title'] = views_ui_edit_page_title($view);
+  $bases = views_fetch_base_tables();
+  $form_state['#page_title'] = $view->getHumanName();
+  if (isset($bases[$view->get('base_table')])) {
+    $form_state['#page_title'] .= ' (' . $bases[$view->get('base_table')]['title'] . ')';
+  }
   views_ui_cache_set($view);
 }
 
@@ -2066,29 +2036,6 @@ function views_ui_edit_display_form_change_theme($form, &$form_state) {
   $form_state['rebuild'] = TRUE;
 }
 
-/**
- * Page callback for views tag autocomplete
- */
-function views_ui_autocomplete_tag($string = NULL) {
-  $matches = array();
-  if (!isset($string)) {
-    $string = drupal_container()->get('request')->query->get('q');
-  }
-  // get matches from default views:
-  $views = views_get_all_views();
-  foreach ($views as $view) {
-    $tag = $view->get('tag');
-    if ($tag && strpos($tag, $string) === 0) {
-      $matches[$tag] = $tag;
-      if (count($matches) >= 10) {
-        break;
-      }
-    }
-  }
-
-  return new JsonResponse($matches);
-}
-
 function _views_sort_types($a, $b) {
   $a_group = drupal_strtolower($a['group']);
   $b_group = drupal_strtolower($b['group']);
@@ -2246,85 +2193,3 @@ function views_ui_form_button_was_clicked($element, &$form_state) {
   }
   return $element;
 }
-
-/**
- * List all instances of fields on any views.
- *
- * Therefore it builds up a table of each field which is used in any view.
- *
- * @see field_ui_fields_list()
- */
-function views_ui_field_list() {
-  $views = views_get_all_views();
-  $data = drupal_container()->get('views.views_data');
-
-  // Fetch all fieldapi fields which are used in views
-  // Therefore search in all views, displays and handler-types.
-  $fields = array();
-  $handler_types = ViewExecutable::viewsHandlerTypes();
-  foreach ($views as $view) {
-    $executable = $view->get('executable');
-    $executable->initDisplay();
-    foreach ($executable->displayHandlers as $display_id => $display) {
-      if ($executable->setDisplay($display_id)) {
-        foreach ($handler_types as $type => $info) {
-          foreach ($executable->getItems($type, $display_id) as $item) {
-            $table_data = $data->get($item['table']);
-            if (isset($table_data[$item['field']]) && isset($table_data[$item['field']][$type])
-              && $field_data = $table_data[$item['field']][$type]) {
-              // The final check that we have a fieldapi field now.
-              if (isset($field_data['field_name'])) {
-                $fields[$field_data['field_name']][$view->id()] = $view->id();
-              }
-            }
-          }
-        }
-      }
-    }
-  }
-
-  $header = array(t('Field name'), t('Used in'));
-  $rows = array();
-  foreach ($fields as $field_name => $views) {
-
-    $rows[$field_name]['data'][0] = check_plain($field_name);
-    foreach ($views as $view) {
-      $rows[$field_name]['data'][1][] = l($view, "admin/structure/views/view/$view");
-    }
-    $rows[$field_name]['data'][1] = implode(', ', $rows[$field_name]['data'][1]);
-  }
-
-  // Sort rows by field name.
-  ksort($rows);
-  $output = array(
-    '#theme' => 'table',
-    '#header' => $header,
-    '#rows' => $rows,
-    '#empty' => t('No fields have been used in views yet.'),
-  );
-
-  return $output;
-}
-
-/**
- * Lists all plugins and what enabled Views use them.
- */
-function views_ui_plugin_list() {
-  $rows = views_plugin_list();
-  foreach ($rows as &$row) {
-    // Link each view name to the view itself.
-    foreach ($row['views'] as $row_name => $view) {
-      $row['views'][$row_name] = l($view, "admin/structure/views/view/$view");
-    }
-    $row['views'] = implode(', ', $row['views']);
-  }
-
-  // Sort rows by field name.
-  ksort($rows);
-  return array(
-    '#theme' => 'table',
-    '#header' => array(t('Type'), t('Name'), t('Provided by'), t('Used in')),
-    '#rows' => $rows,
-    '#empty' => t('There are no enabled views.'),
-  );
-}
diff --git a/core/modules/views/views_ui/lib/Drupal/views_ui/Routing/ViewsUIController.php b/core/modules/views/views_ui/lib/Drupal/views_ui/Routing/ViewsUIController.php
new file mode 100644
index 0000000..0d55ae7
--- /dev/null
+++ b/core/modules/views/views_ui/lib/Drupal/views_ui/Routing/ViewsUIController.php
@@ -0,0 +1,463 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\views_ui\Routing\ViewsUIController.
+ */
+
+namespace Drupal\views_ui\Routing;
+
+use Drupal\views\ViewExecutable;
+use Drupal\views\ViewStorageInterface;
+use Drupal\views_ui\ViewUI;
+use Drupal\views\ViewsDataCache;
+use Drupal\user\TempStoreFactory;
+use Drupal\Core\Entity\EntityManager;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\JsonResponse;
+use Symfony\Component\HttpFoundation\RedirectResponse;
+use Drupal\Core\Ajax\AjaxResponse;
+use Drupal\Core\Ajax\ReplaceCommand;
+
+/**
+ * Returns responses for Views UI routes.
+ */
+class ViewsUIController {
+
+  /**
+   * Stores the Entity manager.
+   *
+   * @var \Drupal\Core\Entity\EntityManager
+   */
+  protected $entityManager;
+
+  /**
+   * Stores the Views data cache object.
+   *
+   * @var \Drupal\views\ViewsDataCache
+   */
+  protected $viewsData;
+
+  /**
+   * Stores the user tempstore.
+   *
+   * @var \Drupal\user\TempStore
+   */
+  protected $tempStore;
+
+  /**
+   * Constructs a new \Drupal\views_ui\Routing\ViewsUIController object.
+   *
+   * @param \Drupal\Core\Entity\EntityManager $entity_manager
+   *   The Entity manager.
+   * @param \Drupal\views\ViewsDataCache views_data
+   *   The Views data cache object.
+   * @param \Drupal\user\TempStoreFactory $temp_store_factory
+   *   The factory for the temp store object.
+   */
+  public function __construct(EntityManager $entity_manager, ViewsDataCache $views_data, TempStoreFactory $temp_store_factory) {
+    $this->entityManager = $entity_manager;
+    $this->viewsData = $views_data;
+    $this->tempStore = $temp_store_factory->get('views');
+  }
+
+  /**
+   * Lists all of the views.
+   *
+   * @return array
+   *   The Views listing page.
+   */
+  public function listing() {
+    return $this->entityManager->getListController('view')->render();
+  }
+
+  /**
+   * Returns the form to add a new view.
+   *
+   * @return array
+   *   The Views add form.
+   */
+  public function add() {
+    drupal_set_title(t('Add new view'));
+
+    $entity = $this->entityManager->getStorageController('view')->create(array());
+    return entity_get_form($entity, 'add');
+  }
+
+  /**
+   * Form builder for the admin display defaults page.
+   *
+   * @return array
+   *   The Views basic settings form.
+   */
+  public function settingsBasic() {
+    // @todo Remove the need for this.
+    module_load_include('inc', 'views_ui', 'admin');
+    return drupal_get_form('views_ui_admin_settings_basic');
+  }
+
+  /**
+   * Form builder for the advanced admin settings page.
+   *
+   * @return array
+   *   The Views advanced settings form.
+   */
+  public function settingsAdvanced() {
+    // @todo Remove the need for this.
+    module_load_include('inc', 'views_ui', 'admin');
+    return drupal_get_form('views_ui_admin_settings_advanced');
+  }
+
+  /**
+   * Lists all instances of fields on any views.
+   *
+   * @return array
+   *   The Views fields report page.
+   */
+  public function reportFields() {
+    $views = $this->entityManager->getStorageController('view')->load();
+
+    // Fetch all fieldapi fields which are used in views
+    // Therefore search in all views, displays and handler-types.
+    $fields = array();
+    $handler_types = ViewExecutable::viewsHandlerTypes();
+    foreach ($views as $view) {
+      $executable = $view->get('executable');
+      $executable->initDisplay();
+      foreach ($executable->displayHandlers as $display_id => $display) {
+        if ($executable->setDisplay($display_id)) {
+          foreach ($handler_types as $type => $info) {
+            foreach ($executable->getItems($type, $display_id) as $item) {
+              $table_data = $this->viewsData->get($item['table']);
+              if (isset($table_data[$item['field']]) && isset($table_data[$item['field']][$type])
+                && $field_data = $table_data[$item['field']][$type]) {
+                // The final check that we have a fieldapi field now.
+                if (isset($field_data['field_name'])) {
+                  $fields[$field_data['field_name']][$view->id()] = $view->id();
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+
+    $header = array(t('Field name'), t('Used in'));
+    $rows = array();
+    foreach ($fields as $field_name => $views) {
+      $rows[$field_name]['data'][0] = check_plain($field_name);
+      foreach ($views as $view) {
+        $rows[$field_name]['data'][1][] = l($view, "admin/structure/views/view/$view");
+      }
+      $rows[$field_name]['data'][1] = implode(', ', $rows[$field_name]['data'][1]);
+    }
+
+    // Sort rows by field name.
+    ksort($rows);
+    $output = array(
+      '#theme' => 'table',
+      '#header' => $header,
+      '#rows' => $rows,
+      '#empty' => t('No fields have been used in views yet.'),
+    );
+
+    return $output;
+  }
+
+  /**
+   * Lists all plugins and what enabled Views use them.
+   *
+   * @return array
+   *   The Views plugins report page.
+   */
+  public function reportPlugins() {
+    $rows = views_plugin_list();
+    foreach ($rows as &$row) {
+      // Link each view name to the view itself.
+      foreach ($row['views'] as $row_name => $view) {
+        $row['views'][$row_name] = l($view, "admin/structure/views/view/$view");
+      }
+      $row['views'] = implode(', ', $row['views']);
+    }
+
+    // Sort rows by field name.
+    ksort($rows);
+    return array(
+      '#theme' => 'table',
+      '#header' => array(t('Type'), t('Name'), t('Provided by'), t('Used in')),
+      '#rows' => $rows,
+      '#empty' => t('There are no enabled views.'),
+    );
+  }
+
+  /**
+   * Calls a method on a view and reloads the listing page.
+   *
+   * @param string|\Drupal\views\ViewStorageInterface $view
+   *   The view being acted upon.
+   * @param string $op
+   *   The operation to perform, e.g., 'enable' or 'disable'.
+   *
+   * @return \Drupal\Core\Ajax\AjaxResponse|\Symfony\Component\HttpFoundation\RedirectResponse
+   *   Either returns a rebuilt listing page as an AJAX response, or redirects
+   *   back to the listing page.
+   */
+  public function ajaxOperation($view, $op, Request $request) {
+    // @todo Remove this when http://drupal.org/node/1798214 is in.
+    $view = $this->upcastView($view);
+
+    // Perform the operation.
+    $view->$op();
+
+    // If the request is via AJAX, return the rendered list as JSON.
+    if ($request->request->get('js')) {
+      $list = $this->entityManager->getListController('view')->render();
+      $response = new AjaxResponse();
+      $response->addCommand(new ReplaceCommand('#views-entity-list', drupal_render($list)));
+      return $response;
+    }
+
+    // Otherwise, redirect back to the page.
+    // @todo Remove url() wrapper once http://drupal.org/node/1668866 is in.
+    return new RedirectResponse(url('admin/structure/views', array('absolute' => TRUE)));
+  }
+
+  /**
+   * Returns the form to clone a view.
+   *
+   * @param string|\Drupal\views\ViewStorageInterface $view
+   *   The view being cloned.
+   *
+   * @return array
+   *   The Views clone form.
+   */
+  public function cloneForm($view) {
+    // @todo Remove this when http://drupal.org/node/1798214 is in.
+    $view = $this->upcastView($view);
+
+    drupal_set_title(t('Clone of @human_name', array('@human_name' => $view->getHumanName())));
+
+    return entity_get_form($view, 'clone');
+  }
+
+  /**
+   * Returns the form to delete a view.
+   *
+   * @param string|\Drupal\views\ViewStorageInterface $view
+   *   The view being deleted.
+   *
+   * @return array
+   *   The Views delete form.
+   */
+  public function deleteForm($view) {
+    // @todo Remove this when http://drupal.org/node/1798214 is in.
+    $view = $this->upcastView($view);
+
+    return drupal_get_form('views_ui_confirm_delete', $view);
+  }
+
+  /**
+   * Menu callback for Views tag autocompletion.
+   *
+   * Like other autocomplete functions, this function inspects the 'q' query
+   * parameter for the string to use to search for suggestions.
+   *
+   * @return \Symfony\Component\HttpFoundation\JsonResponse
+   *   A JSON response containing the autocomplete suggestions for Views tags.
+   */
+  public function autocompleteTag(Request $request) {
+    $matches = array();
+    $string = $request->query->get('q');
+    // Get matches from default views.
+    $views = $this->entityManager->getStorageController('view')->load();
+    foreach ($views as $view) {
+      $tag = $view->get('tag');
+      if ($tag && strpos($tag, $string) === 0) {
+        $matches[$tag] = $tag;
+        if (count($matches) >= 10) {
+          break;
+        }
+      }
+    }
+
+    return new JsonResponse($matches);
+  }
+
+  /**
+   * Returns the form to edit a view.
+   *
+   * @param string|\Drupal\views_ui\ViewUI $views_ui
+   *   The view being deleted.
+   * @param string|null $display_id
+   *   (optional) The display ID being edited. Defaults to NULL, which will load
+   *   the first available display.
+   *
+   * @return array
+   *   An array containing the Views edit and preview forms.
+   */
+  public function edit($views_ui, $display_id = NULL) {
+    // @todo Replace with proper upcasting.
+    $view = $this->getViewUI($views_ui);
+
+    $name = $view->getHumanName();
+    $data = $this->viewsData->get($view->get('base_table'));
+    if (isset($data['table']['base']['title'])) {
+      $name .= ' (' . $data['table']['base']['title'] . ')';
+    }
+    drupal_set_title($name);
+
+    $view->displayID = $display_id;
+    $build['edit'] = entity_get_form($view, 'edit');
+    $build['preview'] = entity_get_form($view, 'preview');
+    return $build;
+  }
+
+  /**
+   * Returns the form to preview a view.
+   *
+   * @param string|\Drupal\views_ui\ViewUI $views_ui
+   *   The view being deleted.
+   * @param string|null $display_id
+   *   (optional) The display ID being edited. Defaults to NULL, which will
+   *   load the first available display.
+   *
+   * @return array
+   *   The Views preview form.
+   */
+  public function preview($views_ui, $display_id = NULL) {
+    // @todo Replace with proper upcasting.
+    $view = $this->getViewUI($views_ui);
+
+    $view->displayID = $display_id;
+    return entity_get_form($view, 'preview');
+  }
+
+  /**
+   * Returns the form to break the lock of an edited view.
+   *
+   * @param string|\Drupal\views_ui\ViewUI $views_ui
+   *   The locked view.
+   *
+   * @return array
+   *   The Views 'break lock' form.
+   */
+  public function breakLock($views_ui) {
+    // @todo Remove the need for this.
+    module_load_include('inc', 'views_ui', 'admin');
+
+    // @todo Replace with proper upcasting.
+    $view = $this->getViewUI($views_ui);
+
+    return drupal_get_form('views_ui_break_lock_confirm', $view);
+  }
+
+  /**
+   * Provides a generic entry point to handle AJAX forms.
+   *
+   * @param string $js
+   *   If this is an AJAX form, it will be the string 'ajax'. Otherwise, it will
+   *   be 'nojs'. This determines the response.
+   * @param string $key
+   *   A string representing a section of the Views UI. Available keys are in
+   *   views_ui_ajax_forms().
+   * @param \Drupal\views_ui\ViewUI $views_ui
+   *   The view being edited.
+   * @param string|null $display_id
+   *   The display ID being edited, or NULL to load the first available display.
+   * @param string|null $type
+   *   If $key is 'add-item' or 'config-item', this is the type of handler being
+   *   edited. Otherwise, it is the subsection of the Views UI. For example, the
+   *   'display' section has 'access' as a subsection, or the 'config-item' has
+   *   'style' as a handler type. NULL if the section has no subsections.
+   * @param string|null $id
+   *   If $key is 'config-item', then this will be the plugin ID of the handler.
+   *   Otherwise it will be NULL.
+   *
+   * @return array
+   *   An form for a specific operation in the Views UI, or an array of AJAX
+   *   commands to render a form.
+   *
+   * @todo When http://drupal.org/node/1843224 is in, this will return
+   *   \Drupal\Core\Ajax\AjaxResponse instead of the array of AJAX commands.
+   *
+   * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
+   */
+  public function ajaxForm($js, $key, $views_ui, $display_id, $type, $id) {
+    // Determine if this is an AJAX submission.
+    $js = $js == 'ajax';
+
+    // @todo Remove the need for this.
+    module_load_include('inc', 'views_ui', 'admin');
+
+    // @todo Replace with proper upcasting.
+    $view = $this->getViewUI($views_ui);
+
+    return views_ui_ajax_form($js, $key, $view, $display_id, $type, $id);
+  }
+
+  /**
+   * Provides upcasting for View entities until there is generic handling.
+   *
+   * @param string|\Drupal\views\ViewStorageInterface $view
+   *   The view being loaded.
+   *
+   * @return \Drupal\views\ViewStorageInterface
+   *   The loaded View.
+   *
+   * @todo Remove this when http://drupal.org/node/1798214 is committed.
+   */
+  protected function upcastView($view) {
+    if ($view instanceof ViewStorageInterface) {
+      return $view;
+    }
+
+    $results = $this->entityManager->getStorageController('view')->load(array($view));
+    $entity = reset($results);
+    if (!($entity instanceof ViewStorageInterface)) {
+      throw new \Exception(format_string("Could not load view '@view'.", array('@view' => $view)));
+    }
+    return $entity;
+  }
+
+  /**
+   * Loads a view, first checking for a view being currently edited.
+   *
+   * @param string $name
+   *   The machine name of the view.
+   *
+   * @return \Drupal\views_ui\ViewUI|false
+   *   Either the view object, with a 'locked' property indicating whether or
+   *   not someone else is already editing the view, or FALSE if the view could
+   *   not be loaded.
+   */
+  public function getViewUI($name) {
+    $view = $this->tempStore->get($name);
+    $results = $this->entityManager->getStorageController('view')->load(array($name));
+    $original_view = !empty($results) ? new ViewUI(reset($results)) : NULL;
+
+    if (empty($view)) {
+      $view = $original_view;
+      if (!empty($view)) {
+        // Check to see if someone else is already editing this view.
+        // Set a flag to indicate that this view is being edited.
+        // This flag will be used e.g. to determine whether strings
+        // should be localized.
+        $view->editing = TRUE;
+      }
+    }
+    else {
+      // Keep disabled/enabled status real.
+      if ($original_view) {
+        $view->set('disabled', $original_view->get('disabled'));
+      }
+    }
+
+    if (empty($view)) {
+      return FALSE;
+    }
+    $view->locked = $this->tempStore->getMetadata($view->id());
+
+    return $view;
+  }
+
+}
diff --git a/core/modules/views/views_ui/lib/Drupal/views_ui/ViewEditFormController.php b/core/modules/views/views_ui/lib/Drupal/views_ui/ViewEditFormController.php
index a43d3ce..196dc85 100644
--- a/core/modules/views/views_ui/lib/Drupal/views_ui/ViewEditFormController.php
+++ b/core/modules/views/views_ui/lib/Drupal/views_ui/ViewEditFormController.php
@@ -643,7 +643,7 @@ public function renderDisplayTop(ViewUI $view) {
       '#links' => array(
         'edit-details' => array(
           'title' => t('edit view name/description'),
-          'href' => "admin/structure/views/nojs/edit-details/{$view->id()}",
+          'href' => "admin/structure/views/nojs/edit-details/{$view->id()}/$display_id",
           'attributes' => array('class' => array('views-ajax-link')),
         ),
         'analyze' => array(
diff --git a/core/modules/views/views_ui/lib/Drupal/views_ui/ViewFormControllerBase.php b/core/modules/views/views_ui/lib/Drupal/views_ui/ViewFormControllerBase.php
index e9ed64f..61eb153 100644
--- a/core/modules/views/views_ui/lib/Drupal/views_ui/ViewFormControllerBase.php
+++ b/core/modules/views/views_ui/lib/Drupal/views_ui/ViewFormControllerBase.php
@@ -18,6 +18,16 @@
 abstract class ViewFormControllerBase extends EntityFormController {
 
   /**
+   * Overrides \Drupal\Core\Entity\EntityFormController::init().
+   */
+  protected function init(array &$form_state, EntityInterface $entity) {
+    parent::init($form_state, $entity);
+
+    // @todo Remove the need for this.
+    form_load_include($form_state, 'inc', 'views_ui', 'admin');
+  }
+
+  /**
    * Overrides Drupal\Core\Entity\EntityFormController::prepareForm().
    */
   protected function prepareEntity(EntityInterface $view) {
diff --git a/core/modules/views/views_ui/lib/Drupal/views_ui/ViewPreviewFormController.php b/core/modules/views/views_ui/lib/Drupal/views_ui/ViewPreviewFormController.php
index f6798fe..8d8ca11 100644
--- a/core/modules/views/views_ui/lib/Drupal/views_ui/ViewPreviewFormController.php
+++ b/core/modules/views/views_ui/lib/Drupal/views_ui/ViewPreviewFormController.php
@@ -82,7 +82,7 @@ protected function actions(array $form, array &$form_state) {
         '#submit' => array(array($this, 'submitPreview')),
         '#id' => 'preview-submit',
         '#ajax' => array(
-          'path' => 'admin/structure/views/view/' . $view->id() . '/preview/' . $view->displayID . '/ajax',
+          'path' => 'admin/structure/views/view/' . $view->id() . '/preview/' . $view->displayID,
           'wrapper' => 'views-preview-wrapper',
           'event' => 'click',
           'progress' => array('type' => 'throbber'),
@@ -98,7 +98,7 @@ protected function actions(array $form, array &$form_state) {
   public function submitPreview($form, &$form_state) {
     // Rebuild the form with a pristine $view object.
     $view = $this->getEntity($form_state);
-    $form_state['build_info']['args'][0] = views_ui_cache_load($view->id());
+    $form_state['build_info']['args'][0] = drupal_container()->get('views_ui.controller')->getViewUI($view->id());
     $view->renderPreview = TRUE;
     $form_state['show_preview'] = TRUE;
     $form_state['rebuild'] = TRUE;
diff --git a/core/modules/views/views_ui/lib/Drupal/views_ui/ViewUI.php b/core/modules/views/views_ui/lib/Drupal/views_ui/ViewUI.php
index d161c97..6931054 100644
--- a/core/modules/views/views_ui/lib/Drupal/views_ui/ViewUI.php
+++ b/core/modules/views/views_ui/lib/Drupal/views_ui/ViewUI.php
@@ -630,7 +630,7 @@ public function renderPreview($display_id, $args = array()) {
       }
 
       // Make view links come back to preview.
-      $this->override_path = 'admin/structure/views/nojs/preview/' . $this->id() . '/' . $display_id;
+      $this->override_path = 'admin/structure/views/view/' . $this->id() . '/preview/' . $display_id;
 
       // Also override the current path so we get the pager.
       $original_path = current_path();
diff --git a/core/modules/views/views_ui/lib/Drupal/views_ui/ViewsUiBundle.php b/core/modules/views/views_ui/lib/Drupal/views_ui/ViewsUiBundle.php
new file mode 100644
index 0000000..9459721
--- /dev/null
+++ b/core/modules/views/views_ui/lib/Drupal/views_ui/ViewsUiBundle.php
@@ -0,0 +1,29 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\views_ui\ViewsBundle.
+ */
+
+namespace Drupal\views_ui;
+
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\HttpKernel\Bundle\Bundle;
+use Symfony\Component\DependencyInjection\Reference;
+
+/**
+ * Views UI dependency injection container.
+ */
+class ViewsUiBundle extends Bundle {
+
+  /**
+   * Overrides \Symfony\Component\HttpKernel\Bundle\Bundle::build().
+   */
+  public function build(ContainerBuilder $container) {
+    $container->register('views_ui.controller', 'Drupal\views_ui\Routing\ViewsUIController')
+      ->addArgument(new Reference('plugin.manager.entity'))
+      ->addArgument(new Reference('views.views_data'))
+      ->addArgument(new Reference('user.tempstore'));
+  }
+
+}
diff --git a/core/modules/views/views_ui/views_ui.module b/core/modules/views/views_ui/views_ui.module
index 8ab01be..59ec9ad 100644
--- a/core/modules/views/views_ui/views_ui.module
+++ b/core/modules/views/views_ui/views_ui.module
@@ -6,11 +6,9 @@
  */
 
 use Drupal\views\ViewExecutable;
-use Drupal\views\Plugin\Core\Entity\View;
+use Drupal\views\ViewStorageInterface;
 use Drupal\views_ui\ViewUI;
 use Drupal\views\Analyzer;
-use Drupal\Core\Entity\EntityInterface;
-use Symfony\Component\HttpFoundation\JsonResponse;
 
 /**
  * Implements hook_menu().
@@ -18,177 +16,100 @@
 function views_ui_menu() {
   $items = array();
 
-  // Minor code reduction technique.
-  $base = array(
-    'access callback' => 'user_access',
-    'access arguments' => array('administer views'),
-    'file' => 'admin.inc',
-  );
-  // Set up the base for AJAX callbacks.
-  $ajax_base = array(
-    'page callback' => 'views_ui_ajax_callback',
-    'page arguments' => array(4, 5),
-    'type' => MENU_CALLBACK,
-  ) + $base;
-
   // Top-level Views module pages (not tied to a particular View).
   $items['admin/structure/views/add'] = array(
     'title' => 'Add new view',
-    'page callback' => 'views_ui_add_page',
+    'page callback' => 'NOT_USED',
     'type' => MENU_LOCAL_ACTION,
-  ) + $base;
+    'access arguments' => array('administer views'),
+  );
 
   $items['admin/structure/views'] = array(
     'title' => 'Views',
     'description' => 'Manage customized lists of content.',
-    'page callback' => 'views_ui_list_page',
-  ) + $base;
+    'page callback' => 'NOT_USED',
+    'access arguments' => array('administer views'),
+  );
 
   $items['admin/structure/views/list'] = array(
     'title' => 'List',
     'weight' => -10,
     'type' => MENU_DEFAULT_LOCAL_TASK,
-  ) + $base;
-
-  $items['admin/structure/views/view/%views_ui_cache/clone'] = array(
-    'title callback' => 'views_ui_clone_title',
-    'title arguments' => array(4),
-    'page callback' => 'entity_get_form',
-    'page arguments' => array(4, 'clone'),
-    'type' => MENU_CALLBACK,
-  ) + $base;
-
-  $items['admin/structure/views/view/%views_ui/enable'] = array(
-    'title' => 'Enable a view',
-  ) + $ajax_base;
-
-  $items['admin/structure/views/view/%views_ui/disable'] = array(
-    'title' => 'Disable a view',
-  ) + $ajax_base;
-
-  $items['admin/structure/views/view/%views_ui/delete'] = array(
-    'title' => 'Delete a view',
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('views_ui_confirm_delete', 4),
-    'type' => MENU_CALLBACK,
-  ) + $base;
+    'access arguments' => array('administer views'),
+  );
 
   $items['admin/structure/views/settings'] = array(
     'title' => 'Settings',
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('views_ui_admin_settings_basic'),
+    'page callback' => 'NOT_USED',
     'type' => MENU_LOCAL_TASK,
-  ) + $base;
+    'access arguments' => array('administer views'),
+  );
   $items['admin/structure/views/settings/basic'] = array(
     'title' => 'Basic',
-    'page arguments' => array('views_ui_admin_settings_basic'),
     'type' => MENU_DEFAULT_LOCAL_TASK,
-  ) + $base;
+    'access arguments' => array('administer views'),
+  );
   $items['admin/structure/views/settings/advanced'] = array(
     'title' => 'Advanced',
-    'page arguments' => array('views_ui_admin_settings_advanced'),
     'type' => MENU_LOCAL_TASK,
     'weight' => 1,
-  ) + $base;
+    'access arguments' => array('administer views'),
+  );
 
   // The primary Edit View page. Secondary tabs for each Display are added in
   // views_ui_menu_local_tasks_alter().
-  $items['admin/structure/views/view/%views_ui_cache'] = array(
-    'title callback' => 'views_ui_edit_page_title',
-    'title arguments' => array(4),
-    'page callback' => 'views_ui_edit_page',
-    'page arguments' => array(4),
-  ) + $base;
-  $items['admin/structure/views/view/%views_ui_cache/edit'] = array(
+  $items['admin/structure/views/view/%'] = array(
+    'page callback' => 'NOT_USED',
+    'access arguments' => array('administer views'),
+  );
+  $items['admin/structure/views/view/%/edit'] = array(
     'title' => 'Edit view',
     'type' => MENU_DEFAULT_LOCAL_TASK,
     'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
     'weight' => -10,
-    'theme callback' => 'ajax_base_page_theme',
-  ) + $base;
-  $items['admin/structure/views/view/%views_ui_cache/edit/%/ajax'] = array(
-    'page callback' => 'views_ui_ajax_get_form',
-    'page arguments' => array('views_ui_edit_form', 4, 6),
-    'delivery callback' => 'ajax_deliver',
-    'theme callback' => 'ajax_base_page_theme',
-    'type' => MENU_CALLBACK,
-  ) + $base;
-  $items['admin/structure/views/view/%views_ui_cache/preview/%'] = array(
-    'page callback' => 'views_ui_build_preview',
-    'page arguments' => array(4, 6),
+    'access arguments' => array('administer views'),
+  );
+  $items['admin/structure/views/view/%/preview/%'] = array(
+    'page callback' => 'NOT_USED',
     'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
     'type' => MENU_VISIBLE_IN_BREADCRUMB,
-  ) + $base;
-  $items['admin/structure/views/view/%views_ui_cache/preview/%/ajax'] = array(
-    'page callback' => 'views_ui_build_preview',
-    'page arguments' => array(4, 6),
-    'delivery callback' => 'ajax_deliver',
-    'theme callback' => 'ajax_base_page_theme',
-    'type' => MENU_CALLBACK,
-  ) + $base;
+    'access arguments' => array('administer views'),
+  );
 
   // Additional pages for acting on a View.
 
-  $items['admin/structure/views/view/%views_ui_cache/break-lock'] = array(
+  $items['admin/structure/views/view/%/break-lock'] = array(
     'title' => 'Break lock',
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('views_ui_break_lock_confirm', 4),
+    'page callback' => 'NOT_USED',
     'type' => MENU_VISIBLE_IN_BREADCRUMB,
-  ) + $base;
+    'access arguments' => array('administer views'),
+  );
 
   // NoJS/AJAX callbacks that can use the default Views AJAX form system.
-  $items['admin/structure/views/nojs/%/%views_ui_cache'] = array(
-    'page callback' => 'views_ui_ajax_form',
-    'page arguments' => array(FALSE, 4, 5),
-    'type' => MENU_CALLBACK,
-  ) + $base;
-  $items['admin/structure/views/ajax/%/%views_ui_cache'] = array(
-    'page callback' => 'views_ui_ajax_form',
-    'page arguments' => array(TRUE, 4, 5),
-    'delivery callback' => 'ajax_deliver',
-    'type' => MENU_CALLBACK,
-  ) + $base;
-
-  $items['admin/structure/views/nojs/preview/%views_ui_cache/%'] = array(
-    'page callback' => 'views_ui_preview',
-    'page arguments' => array(5, 6),
-  ) + $base;
-  $items['admin/structure/views/ajax/preview/%views_ui_cache/%'] = array(
-    'page callback' => 'views_ui_preview',
-    'page arguments' => array(5, 6),
-    'delivery callback' => 'ajax_deliver',
-  ) + $base;
-
-  // Autocomplete callback for tagging a View.
-  // Views module uses admin/views/... instead of admin/structure/views/... for
-  // autocomplete paths, so be consistent with that.
-  // @todo Change to admin/structure/views/... when the change can be made to
-  //   Views module as well.
-  $items['admin/views/ajax/autocomplete/tag'] = array(
-    'page callback' => 'views_ui_autocomplete_tag',
-    'type' => MENU_CALLBACK,
-  ) + $base;
+  $items['admin/structure/views/nojs/%/%'] = array(
+    'page callback' => 'NOT_USED',
+    'type' => MENU_VISIBLE_IN_BREADCRUMB,
+    'access arguments' => array('administer views'),
+  );
+
 
   // A page in the Reports section to show usage of fields in all views
-  $items['admin/reports/fields/list'] = array(
-    'title' => 'List',
-    'type' => MENU_DEFAULT_LOCAL_TASK,
-    'weight' => -10,
-  );
   $items['admin/reports/fields/views-fields'] = array(
     'title' => 'Used in views',
     'description' => 'Overview of fields used in all views.',
-    'page callback' => 'views_ui_field_list',
+    'page callback' => 'NOT_USED',
     'type' => MENU_LOCAL_TASK,
     'weight' => 0,
-  ) + $base;
+    'access arguments' => array('administer views'),
+  );
 
   // A page in the Reports section to show usage of plugins in all views.
   $items['admin/reports/views-plugins'] = array(
     'title' => 'Views plugins',
     'description' => 'Overview of plugins used in all views.',
-    'page callback' => 'views_ui_plugin_list',
-  ) + $base;
+    'page callback' => 'NOT_USED',
+    'access arguments' => array('administer views'),
+  );
 
   return $items;
 }
@@ -301,61 +222,6 @@ function views_ui_library_info() {
 }
 
 /**
- * Page title callback for the Edit View page.
- */
-function views_ui_edit_page_title(ViewUI $view) {
-  module_load_include('inc', 'views_ui', 'admin');
-  $bases = views_fetch_base_tables();
-  $name = $view->getHumanName();
-  if (isset($bases[$view->get('base_table')])) {
-    $name .= ' (' . $bases[$view->get('base_table')]['title'] . ')';
-  }
-
-  return $name;
-}
-
-/**
- * Specialized menu callback to load a view and check its locked status.
- *
- * @param $name
- *   The machine name of the view.
- *
- * @return
- *   The view object, with a "locked" property indicating whether or not
- *   someone else is already editing the view.
- */
-function views_ui_cache_load($name) {
-  $views_temp_store = drupal_container()->get('user.tempstore')->get('views');
-  $view = $views_temp_store->get($name);
-  $storage = entity_load('view', $name);
-  $original_view = $storage ? new ViewUI($storage) : NULL;
-
-  if (empty($view)) {
-    $view = $original_view;
-    if (!empty($view)) {
-      // Check to see if someone else is already editing this view.
-      // Set a flag to indicate that this view is being edited.
-      // This flag will be used e.g. to determine whether strings
-      // should be localized.
-      $view->editing = TRUE;
-    }
-  }
-  else {
-    // Keep disabled/enabled status real.
-    if ($original_view) {
-      $view->set('disabled', $original_view->get('disabled'));
-    }
-  }
-
-  if (empty($view)) {
-    return FALSE;
-  }
-  $view->locked = $views_temp_store->getMetadata($view->id());
-
-  return $view;
-}
-
-/**
  * Specialized cache function to add a flag to our view, include an appropriate
  * include, and cache more easily.
  */
@@ -383,16 +249,6 @@ function views_ui_cache_set(ViewUI $view) {
 }
 
 /**
- * Title callback for the views clone form.
- *
- * @param \Drupal\views\ViewExecutable $view
- *   The view to clone.
- */
-function views_ui_clone_title(ViewUI $view) {
-  return t('Clone of @human_name', array('@human_name' => $view->getHumanName()));
-}
-
-/**
  * Theme preprocess for views-view.tpl.php.
  */
 function views_ui_preprocess_views_view(&$vars) {
@@ -557,50 +413,6 @@ function views_ui_contextual_links_suppress_pop() {
 }
 
 /**
- * Menu callback; handles AJAX form submissions similar to ajax_form_callback(), but can be used for uncached forms.
- *
- * ajax_form_callback(), the menu callback for the system/ajax path, requires
- * the form to be retrievable from the form cache, because it lacks a trusted
- * $form_id argument with which to call drupal_retrieve_form(). When AJAX is
- * wanted on a non-cacheable form, #ajax['path'] can be set to a path whose
- * menu router item's 'page callback' is this function, and whose
- * 'page arguments' is the form id, optionally followed by additional build
- * arguments, as expected by drupal_get_form().
- *
- * The same caution must be used when defining a hook_menu() entry with this
- * page callback as is used when defining a hook_menu() entry with the
- * 'drupal_get_form' page callback: a 'page arguments' must be specified with a
- * literal value as the first argument, because $form_id determines which form
- * builder function gets called, so must be safe from user tampering.
- *
- * @see drupal_get_form()
- * @see ajax_form_callback()
- * @see http://drupal.org/node/774876
- */
-function views_ui_ajax_get_form($form_id) {
-  // @see ajax_get_form()
-  $form_state = array(
-    'no_redirect' => TRUE,
-  );
-  $form_state['rebuild_info']['copy']['#build_id'] = TRUE;
-  $form_state['rebuild_info']['copy']['#action'] = TRUE;
-
-  // @see drupal_get_form()
-  $args = func_get_args();
-  array_shift($args);
-  $form_state['build_info']['args'] = $args;
-  $form = drupal_build_form($form_id, $form_state);
-
-  // @see ajax_form_callback()
-  if (!empty($form_state['triggering_element'])) {
-    $callback = $form_state['triggering_element']['#ajax']['callback'];
-  }
-  if (!empty($callback) && function_exists($callback)) {
-    return $callback($form, $form_state);
-  }
-}
-
-/**
  * This is part of a patch to address a jQueryUI bug.  The bug is responsible
  * for the inability to scroll a page when a modal dialog is active. If the content
  * of the dialog extends beyond the bottom of the viewport, the user is only able
@@ -677,35 +489,6 @@ function views_ui_load($name) {
 }
 
 /**
- * Page callback: Calls a method on a view and reloads the listing page.
- *
- * @param Drupal\views\ViewExectuable $view
- *   The config entity being acted upon.
- * @param string $op
- *   The operation to perform, e.g., 'enable' or 'disable'.
- *
- * @return mixed
- *   Either returns the listing page as JSON, or calls drupal_goto() to
- *   redirect back to the listing page.
- */
-function views_ui_ajax_callback(ViewExecutable $view, $op) {
-  // Perform the operation.
-  $view->storage->$op();
-
-  // If the request is via AJAX, return the rendered list as JSON.
-  if (drupal_container()->get('request')->request->get('js')) {
-    $list = views_ui_list_page();
-    $commands = array(ajax_command_replace('#views-entity-list', drupal_render($list)));
-    return new JsonResponse(ajax_render($commands));
-  }
-  // Otherwise, redirect back to the page.
-  else {
-    $entity_info = entity_get_info('view');
-    drupal_goto('admin/structure/views');
-  }
-}
-
-/**
  * Form constructor for the View deletion form.
  *
  * @param \Drupal\views\ViewExectuable $view
@@ -713,10 +496,10 @@ function views_ui_ajax_callback(ViewExecutable $view, $op) {
  *
  * @see views_ui_confirm_delete_submit()
  */
-function views_ui_confirm_delete($form, &$form_state, ViewExecutable $view) {
+function views_ui_confirm_delete($form, &$form_state, ViewStorageInterface $view) {
   $form['view'] = array('#type' => 'value', '#value' => $view);
   return confirm_form($form,
-    t('Are you sure you want to delete the %name view?', array('%name' => $view->storage->getHumanName())),
+    t('Are you sure you want to delete the %name view?', array('%name' => $view->getHumanName())),
     'admin/structure/views',
     t('This action cannot be undone.'),
     t('Delete'),
@@ -728,20 +511,6 @@ function views_ui_confirm_delete($form, &$form_state, ViewExecutable $view) {
  * Form submission handler for views_ui_confirm_delete().
  */
 function views_ui_confirm_delete_submit($form, &$form_state) {
-  $form_state['values']['view']->storage->delete();
+  $form_state['values']['view']->delete();
   $form_state['redirect'] = 'admin/structure/views';
 }
-
-/**
- * Page callback: Lists all of the views.
- *
- * @return array
- *   A render array for a page containing a list of views.
- *
- * @see views_ui_menu()
- */
-function views_ui_list_page() {
-  return drupal_container()->get('plugin.manager.entity')
-    ->getListController('view')
-    ->render();
-}
diff --git a/core/modules/views/views_ui/views_ui.routing.yml b/core/modules/views/views_ui/views_ui.routing.yml
new file mode 100644
index 0000000..6a2f32c
--- /dev/null
+++ b/core/modules/views/views_ui/views_ui.routing.yml
@@ -0,0 +1,111 @@
+views_ui.list:
+  pattern: '/admin/structure/views'
+  defaults:
+    _controller: 'views_ui.controller:listing'
+  requirements:
+    _permission: 'administer views'
+
+views_ui.add:
+  pattern: '/admin/structure/views/add'
+  defaults:
+    _controller: 'views_ui.controller:add'
+  requirements:
+    _permission: 'administer views'
+
+views_ui.settings.basic:
+  pattern: '/admin/structure/views/settings'
+  defaults:
+    _controller: 'views_ui.controller:settingsBasic'
+  requirements:
+    _permission: 'administer views'
+
+views_ui.settings.advanced:
+  pattern: '/admin/structure/views/settings/advanced'
+  defaults:
+    _controller: 'views_ui.controller:settingsAdvanced'
+  requirements:
+    _permission: 'administer views'
+
+views_ui.reports.fields:
+  pattern: '/admin/reports/fields/views-fields'
+  defaults:
+    _controller: 'views_ui.controller:reportFields'
+  requirements:
+    _permission: 'administer views'
+
+views_ui.reports.plugins:
+  pattern: '/admin/reports/views-plugins'
+  defaults:
+    _controller: 'views_ui.controller:reportPlugins'
+  requirements:
+    _permission: 'administer views'
+
+views_ui.operation:
+  pattern: '/admin/structure/views/view/{view}/{op}'
+  defaults:
+    _controller: 'views_ui.controller:ajaxOperation'
+  requirements:
+    _permission: 'administer views'
+    op: 'enable|disable'
+
+views_ui.clone:
+  pattern: '/admin/structure/views/view/{view}/clone'
+  defaults:
+    _controller: 'views_ui.controller:cloneForm'
+  requirements:
+    _permission: 'administer views'
+
+views_ui.delete:
+  pattern: '/admin/structure/views/view/{view}/delete'
+  defaults:
+    _controller: 'views_ui.controller:deleteForm'
+  requirements:
+    _permission: 'administer views'
+
+views_ui.autocomplete:
+  pattern: '/admin/views/ajax/autocomplete/tag'
+  defaults:
+    _controller: 'views_ui.controller:autocompleteTag'
+  requirements:
+    _permission: 'administer views'
+
+views_ui.edit:
+  pattern: '/admin/structure/views/view/{views_ui}'
+  defaults:
+    _controller: 'views_ui.controller:edit'
+  requirements:
+    _permission: 'administer views'
+
+views_ui.edit.display:
+  pattern: '/admin/structure/views/view/{views_ui}/edit/{display_id}'
+  defaults:
+    _controller: 'views_ui.controller:edit'
+    display_id: NULL
+  requirements:
+    _permission: 'administer views'
+
+views_ui.preview:
+  pattern: '/admin/structure/views/view/{views_ui}/preview/{display_id}'
+  defaults:
+    _controller: 'views_ui.controller:preview'
+    display_id: NULL
+  requirements:
+    _permission: 'administer views'
+
+views_ui.breakLock:
+  pattern: '/admin/structure/views/view/{views_ui}/break-lock'
+  defaults:
+    _controller: 'views_ui.controller:breakLock'
+    display_id: NULL
+  requirements:
+    _permission: 'administer views'
+
+views_ui.ajaxForm:
+  pattern: '/admin/structure/views/{js}/{key}/{views_ui}/{display_id}/{type}/{id}'
+  defaults:
+    _controller: 'views_ui.controller:ajaxForm'
+    type: NULL
+    id: NULL
+  requirements:
+    _permission: 'administer views'
+    js: 'nojs|ajax'
