⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 249213 in webkit


Ignore:
Timestamp:
Aug 28, 2019, 12:36:23 PM (7 years ago)
Author:
Jonathan Bedard
Message:

results.webkit.org: Move drawer to the right, open by default
https://bugs.webkit.org/show_bug.cgi?id=200977

Rubber-stamped by Aakash Jain.

The drawer was both unpopular and not discoverable. After feedback from bot watchers,
moving the drawer to the right side of the screen, opening it by default and have it displace
instead of hide the main content.

  • resultsdbpy/resultsdbpy/view/commit_view_unittest.py:

(CommitViewUnittest.test_drawer): Support new drawer style.
(CommitViewUnittest.test_range_slider): Ditto.
(CommitViewUnittest.test_one_line_switch): Ditto.
(CommitViewUnittest.test_branch_selection): Ditto.

  • resultsdbpy/resultsdbpy/view/static/css/drawer.css: Removed.
  • resultsdbpy/resultsdbpy/view/static/js/drawer.js:

(setEnableRecursive): Disable all elements underneath this one
(Drawer): Make drawer a sidebar.

  • resultsdbpy/resultsdbpy/view/static/library/css/webkit.css:

(.header>.title, .topbar>.title): Overflow of titles should be hidden.
(:root): Move boldInverseColor into webkit.css.
(@media (prefers-color-scheme: dark)):
(.sidebar): Sidebars on mobile should behave like drawers.
(.sidebar.hidden): Add concept of hidden sidebar.
(.mobile-sidebar-control): Add a control to collapse sidebar that only exists on mobile.
(.mobile-sidebar-control.display):
(.main.under-topbar-with-actions):
(@media screen and (min-width: 600px) and (orientation: landscape)):
(.sidebar.left.hidden):
(.sidebar.right.hidden):
(.main.right.hidden):
(.main.left.hidden):
(@media screen and (min-width: 768px) and (orientation: landscape)):
(.sidebar.right):
(a.disabled): Add ability to disable a link.
(.desktop-control): Add a control which only exists on desktop.

  • resultsdbpy/resultsdbpy/view/templates/base.html: Add hamburger drawer-button for mobile.
  • resultsdbpy/resultsdbpy/view/templates/commits.html: Use main since Drawer is now a sidebar.
  • resultsdbpy/resultsdbpy/view/templates/documentation.html: Ditto.
  • resultsdbpy/resultsdbpy/view/templates/search.html: Ditto.
  • resultsdbpy/resultsdbpy/view/templates/suite_results.html: Ditto.
  • resultsdbpy/resultsdbpy/view/view_routes_unittest.py:

(WebSiteTestCase.toggle_drawer): Support new drawer style.
(WebSiteTestCase.find_input_with_name): Ditto.

Location:
trunk/Tools
Files:
1 deleted
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/Tools/ChangeLog

    r249208 r249213  
     12019-08-28  Jonathan Bedard  <jbedard@apple.com>
     2
     3        results.webkit.org: Move drawer to the right, open by default
     4        https://bugs.webkit.org/show_bug.cgi?id=200977
     5
     6        Rubber-stamped by Aakash Jain.
     7
     8        The drawer was both unpopular and not discoverable. After feedback from bot watchers,
     9        moving the drawer to the right side of the screen, opening it by default and have it displace
     10        instead of hide the main content.
     11
     12        * resultsdbpy/resultsdbpy/view/commit_view_unittest.py:
     13        (CommitViewUnittest.test_drawer): Support new drawer style.
     14        (CommitViewUnittest.test_range_slider): Ditto.
     15        (CommitViewUnittest.test_one_line_switch): Ditto.
     16        (CommitViewUnittest.test_branch_selection): Ditto.
     17        * resultsdbpy/resultsdbpy/view/static/css/drawer.css: Removed.
     18        * resultsdbpy/resultsdbpy/view/static/js/drawer.js:
     19        (setEnableRecursive): Disable all elements underneath this one
     20        (Drawer): Make drawer a sidebar.
     21        * resultsdbpy/resultsdbpy/view/static/library/css/webkit.css:
     22        (.header>.title, .topbar>.title): Overflow of titles should be hidden.
     23        (:root): Move boldInverseColor into webkit.css.
     24        (@media (prefers-color-scheme: dark)):
     25        (.sidebar): Sidebars on mobile should behave like drawers.
     26        (.sidebar.hidden): Add concept of hidden sidebar.
     27        (.mobile-sidebar-control): Add a control to collapse sidebar that only exists on mobile.
     28        (.mobile-sidebar-control.display):
     29        (.main.under-topbar-with-actions):
     30        (@media screen and (min-width: 600px) and (orientation: landscape)):
     31        (.sidebar.left.hidden):
     32        (.sidebar.right.hidden):
     33        (.main.right.hidden):
     34        (.main.left.hidden):
     35        (@media screen and (min-width: 768px) and (orientation: landscape)):
     36        (.sidebar.right):
     37        (a.disabled): Add ability to disable a link.
     38        (.desktop-control): Add a control which only exists on desktop.
     39        * resultsdbpy/resultsdbpy/view/templates/base.html: Add hamburger drawer-button for mobile.
     40        * resultsdbpy/resultsdbpy/view/templates/commits.html: Use main since Drawer is now a sidebar.
     41        * resultsdbpy/resultsdbpy/view/templates/documentation.html: Ditto.
     42        * resultsdbpy/resultsdbpy/view/templates/search.html: Ditto.
     43        * resultsdbpy/resultsdbpy/view/templates/suite_results.html: Ditto.
     44        * resultsdbpy/resultsdbpy/view/view_routes_unittest.py:
     45        (WebSiteTestCase.toggle_drawer): Support new drawer style.
     46        (WebSiteTestCase.find_input_with_name): Ditto.
     47
    1482019-08-28  Keith Rollin  <krollin@apple.com>
    249
  • trunk/Tools/resultsdbpy/resultsdbpy/view/commit_view_unittest.py

    r247628 r249213  
    6565        driver.get(self.URL + '/commits')
    6666        time.sleep(.2)
    67         self.assertNotIn('display', driver.find_element_by_class_name('drawer').get_attribute('class'))
    68 
     67        self.assertNotIn('hidden', driver.find_element_by_class_name('sidebar').get_attribute('class'))
     68
     69        self.toggle_drawer(driver, assert_displayed=False)
    6970        self.toggle_drawer(driver, assert_displayed=True)
    70         self.toggle_drawer(driver, assert_displayed=False)
    7171
    7272    @WaitForDockerTestCase.mock_if_no_docker(mock_redis=FakeStrictRedis, mock_cassandra=MockCassandraContext)
     
    159159        self.assertEqual(5, len(commits['webkit']))
    160160
    161         self.toggle_drawer(driver, assert_displayed=True)
    162 
    163161        controls = self.find_input_with_name(driver, 'Limit:').find_elements_by_tag_name('input')
    164162        self.assertEqual(3, len(controls))
     
    199197        changelog = commits['safari'][0].find_element_by_tag_name('div')
    200198        self.assertEqual(line_1, changelog.text)
    201 
    202         self.toggle_drawer(driver, assert_displayed=True)
    203199
    204200        controls = self.find_input_with_name(driver, 'One-line:').find_elements_by_tag_name('span')
     
    236232        self.assertEqual(5, len(commits['webkit']))
    237233
    238         self.toggle_drawer(driver, assert_displayed=True)
    239 
    240234        controls = self.find_input_with_name(driver, 'Branch').find_elements_by_tag_name('select')
    241235        self.assertEqual(1, len(controls))
  • trunk/Tools/resultsdbpy/resultsdbpy/view/static/js/drawer.js

    r248995 r249213  
    2626import {Configuration} from '/assets/js/configuration.js'
    2727
     28function setEnableRecursive(element, state) {
     29    element.disabled = !state;
     30    if (!state)
     31        element.classList.add("disabled");
     32    else
     33        element.classList.remove("disabled");
     34
     35    for (let node of element.children)
     36        setEnableRecursive(node, state);
     37}
     38
    2839function Drawer(controls = []) {
    29     const COLLAPSED = false;
    30     const EXTENDED = true;
    31     var drawerState = COLLAPSED;
     40    const HIDDEN = false;
     41    const VISIBLE = true;
     42    let drawerState = VISIBLE;
     43    let main = null;
     44
     45    const sidebarControl = document.getElementsByClassName('mobile-sidebar-control')[0];
     46    sidebarControl.classList.add('display');
    3247
    3348    const drawerRef = REF.createRef({
    3449        state: drawerState,
    3550        onStateUpdate: (element, state) => {
    36             if (state)
    37                 element.classList.add("display");
    38             else
    39                 element.classList.remove("display");
     51            if (state) {
     52                element.classList.remove("hidden");
     53                if (main)
     54                    main.classList.remove("hidden");
     55            } else {
     56                element.classList.add("hidden");
     57                if (main)
     58                    main.classList.add("hidden");
     59            }
     60
     61            for (let node of element.children) {
     62                if (node.classList.contains("list"))
     63                    setEnableRecursive(node, state);
     64            }
     65        },
     66        onElementMount: (element) => {
     67            let candidates = document.getElementsByClassName("main");
     68            if (candidates.length)
     69                main = candidates[0];
     70
     71            sidebarControl.onclick = () => {
     72                if (element.style.display)
     73                    element.style.display = null;
     74                else
     75                    element.style.display = 'block';
     76            }
    4077        }
    4178    });
     79
    4280    const drawerControllerRef = REF.createRef({
    4381        state: drawerState,
    4482        onStateUpdate: (element, state) => {
    4583            if (state) {
    46                 element.classList.remove("collapsed");
    47                 element.classList.add("extended");
    48             } else {
    49                 element.classList.remove("extended");
    50                 element.classList.add("collapsed");
     84                element.innerHTML = 'Collapse &gt';
     85                element.style.textAlign = 'center';
     86            }
     87            else{
     88                element.innerHTML = '&lt';
     89                element.style.textAlign = 'left';
    5190            }
    5291        },
     
    6099    });
    61100
    62     return `<div class="drawer left under-topbar-with-actions unselectable" ref="${drawerRef}">
     101    return `<div class="sidebar right under-topbar-with-actions unselectable" ref="${drawerRef}">
     102            <button class="button desktop-control" ref="${drawerControllerRef}" style="width:96%; margin: 10px 2% 10px 2%;"></button>
    63103            ${controls.map(control => {
    64104                return `<div class="list">
     
    66106                    </div>`;
    67107                }).join('')}
    68         </div>
    69         <button class="drawer-control collapsed" ref="${drawerControllerRef}"><div></div></button>`;
     108        </div>`;
    70109}
    71110
  • trunk/Tools/resultsdbpy/resultsdbpy/view/static/library/css/webkit.css

    r249161 r249213  
    9292  --formLabelPadding: 14px;
    9393  --topZIndex: 100;
     94  --boldInverseColor: var(--black);
    9495}
    9596
     
    123124    --borderColorSection: var(--blackDark);
    124125    --borderColorHard: var(--blackDarker);
     126    --boldInverseColor: var(--white);
    125127  }
    126128}
     
    227229  font-weight: 400;
    228230  flex: auto;
     231  overflow: hidden;
    229232}
    230233
     
    916919  border-right: 1px solid var(--borderColorSection);
    917920  overflow-y: auto;
     921  min-width: 250px;
     922  background-color: var(--blurBackgroundColor);
     923  -webkit-backdrop-filter: blur(5px) brightness(88%);
     924  backdrop-filter: blur(5px) brightness(88%);
     925  z-index: var(--topZIndex);
     926  right: 0;
     927}
     928.sidebar.hidden {
     929  display: none;
    918930}
    919931
     
    929941}
    930942
     943.mobile-sidebar-control {
     944  display: none;
     945  float: right;
     946}
     947.mobile-sidebar-control.display {
     948  display: block;
     949}
     950
    931951@media (prefers-color-scheme: dark) {
    932952  .sidebar {
     
    954974}
    955975
     976.main.under-topbar-with-actions {
     977  margin-top: calc(12px * 2  + var(--largeSize) * 1.3 + var(--smallSize) * 1.3 + 12px * 2);
     978}
     979
    956980@media screen and (min-width: 600px) and (orientation: landscape) {
    957981  .sidebar {
     982    display: block;
    958983    width: 299px;
     984    z-index: 0;
     985    left: 0;
     986    right: unset;
     987  }
     988  .sidebar.left.hidden {
    959989    display: block;
     990    left: -249px;
     991  }
     992  .sidebar.right.hidden {
     993    display: block;
     994    right: -249px;
    960995  }
    961996  .sidebar.under-topbar-with-actions {
     
    964999  }
    9651000
     1001  .mobile-sidebar-control.display {
     1002    display: none;
     1003  }
     1004
    9661005  .main {
    9671006    margin-left: 299px;
     
    9731012    margin-right: 299px;
    9741013  }
     1014  .main.right.hidden {
     1015    margin-left: 50px;
     1016    width: calc(100% - 50px);
     1017  }
     1018  .main.left.hidden {
     1019    margin-left: 0;
     1020    margin-right: 50px;
     1021    width: calc(100% - 50px);
     1022  }
    9751023
    9761024  .main.under-topbar-with-actions {
     
    9811029@media screen and (min-width: 768px) and (orientation: landscape) {
    9821030  .sidebar {
     1031    display: block;
    9831032    width: 310px;
     1033    z-index: 0;
     1034    left: 0;
     1035    right: unset;
     1036  }
     1037  .sidebar.left.hidden {
    9841038    display: block;
     1039    left: -260px;
     1040  }
     1041  .sidebar.right.hidden {
     1042    display: block;
     1043    right: -260px;
    9851044  }
    9861045  .sidebar.under-topbar-with-actions {
     
    10051064
    10061065.sidebar.right {
    1007   border-right: 0px;
    1008   border-left: 1px;
     1066  left: unset;
    10091067  right: 0;
    10101068}
     
    17521810    color: var(--grey);
    17531811  }
     1812}
     1813
     1814a.disabled {
     1815  color: var(--grey);
     1816  pointer-events: none;
    17541817}
    17551818
     
    25952658  user-select: none;
    25962659}
     2660
     2661.desktop-control {
     2662  display: none;
     2663}
     2664
     2665@media screen and (min-width: 600px) and (orientation: landscape) {
     2666  .desktop-control {
     2667    display: block;
     2668  }
     2669}
  • trunk/Tools/resultsdbpy/resultsdbpy/view/templates/base.html

    r249124 r249213  
    3636<div class="header fixed">
    3737    <div class="title">
    38         <div class="text large block">{{site_title}}</div>
     38        <div class="text large block" style="width: calc(100% - 44px); overflow: hidden; white-space: nowrap; text-overflow: ellipsis;">
     39            {{site_title}}
     40        </div>
     41        <button style="width: 44px" class="button mobile-sidebar-control">☰</button>
    3942    </div>
    4043    <div class="actions">
  • trunk/Tools/resultsdbpy/resultsdbpy/view/templates/commits.html

    r247664 r249213  
    2727{% block head %}
    2828<link rel="stylesheet" type="text/css" href="assets/css/commit.css">
    29 <link rel="stylesheet" type="text/css" href="assets/css/drawer.css">
    3029
    3130<script type="module">
     
    105104    OneLineSwitch(),
    106105    BranchSelector(() => {table.reload()}),
    107 ])} ${table}`);
     106])}
     107<div class="main left under-topbar-with-actions">
     108    <div class="content">${table}</div>
     109</div>`);
    108110
    109111</script>
     
    112114{% block content %}
    113115
    114 <div class="content" id="app">
     116<div id="app">
    115117</div>
    116118
  • trunk/Tools/resultsdbpy/resultsdbpy/view/templates/documentation.html

    r247664 r249213  
    2525{% extends "base.html" %}
    2626{% block head %}
    27 <link rel="stylesheet" type="text/css" href="assets/css/drawer.css">
    2827
    2928<script type="module">
    3029
    31 import {DOM} from '/library/js/Ref.js';
     30import {DOM, REF} from '/library/js/Ref.js';
    3231import {Expectations} from '/assets/js/timeline.js';
    3332
     
    496495}
    497496
     497const sidebarControl = document.getElementsByClassName('mobile-sidebar-control')[0];
     498sidebarControl.classList.add('display');
     499
     500const sidebarRef = REF.createRef({
     501    onElementMount: (element) => {
     502        sidebarControl.onclick = () => {
     503            if (element.style.display)
     504                element.style.display = null;
     505            else
     506                element.style.display = 'block';
     507        }
     508    }
     509});
     510
    498511DOM.inject(
    499512    document.getElementById('app'),
    500     `<div class="sidebar under-topbar-with-actions">
     513    `<div class="sidebar under-topbar-with-actions" ref="${sidebarRef}">
    501514        <div class="list">
    502515        ${Object.keys(documentation).map((primary) => {
  • trunk/Tools/resultsdbpy/resultsdbpy/view/templates/search.html

    r248910 r249213  
    2626{% extends "base.html" %}
    2727{% block head %}
    28 <link rel="stylesheet" type="text/css" href="assets/css/drawer.css">
    2928<link rel="stylesheet" type="text/css" href="assets/css/search.css">
    3029<link rel="stylesheet" type="text/css" href="assets/css/timeline.css">
     
    228227    ])}
    229228
    230     ${SearchBar(function () {
    231         const splitURL = document.URL.split('?');
    232         let params = queryToParams(splitURL[1]);
    233         if (!params.suite)
    234             params.suite = [];
    235         if (!params.test)
    236             params.test = [];
    237 
    238         for (let i = 0; i < arguments.length; i++) {
    239             let needToAdd = true;
    240             if (!needToAdd)
    241                 continue;
    242 
    243             let child = {
    244                 suite: arguments[i].suite,
    245                 test: arguments[i].test,
    246                 timeline: new TimelineFromEndpoint(`api/results/${arguments[i].suite}/${arguments[i].test}`),
    247             }
    248 
    249             view.ref.setState({prepending: [child]});
    250             params.suite.push(child.suite);
    251             params.test.push(child.test);
    252         }
    253         const queryString = paramsToQuery(params);
    254         window.history.pushState(queryString, '', splitURL[0] + '?' + queryString);
    255     }, SUITES)}
    256     ${view}`
     229    <div class="main left under-topbar-with-actions">
     230        <div class="content">
     231            ${SearchBar(function () {
     232                const splitURL = document.URL.split('?');
     233                let params = queryToParams(splitURL[1]);
     234                if (!params.suite)
     235                    params.suite = [];
     236                if (!params.test)
     237                    params.test = [];
     238
     239                for (let i = 0; i < arguments.length; i++) {
     240                    let needToAdd = true;
     241                    if (!needToAdd)
     242                        continue;
     243
     244                    let child = {
     245                        suite: arguments[i].suite,
     246                        test: arguments[i].test,
     247                        timeline: new TimelineFromEndpoint(`api/results/${arguments[i].suite}/${arguments[i].test}`),
     248                    }
     249
     250                    view.ref.setState({prepending: [child]});
     251                    params.suite.push(child.suite);
     252                    params.test.push(child.test);
     253                }
     254                const queryString = paramsToQuery(params);
     255                window.history.pushState(queryString, '', splitURL[0] + '?' + queryString);
     256            }, SUITES)}
     257            ${view}
     258        </div>
     259    </div>`
    257260);
    258261
     
    262265{% block content %}
    263266
    264 <div class="content" id="app">
     267<div id="app">
    265268</div>
    266269
  • trunk/Tools/resultsdbpy/resultsdbpy/view/templates/suite_results.html

    r248910 r249213  
    2626{% extends "base.html" %}
    2727{% block head %}
    28 <link rel="stylesheet" type="text/css" href="assets/css/drawer.css">
    2928<link rel="stylesheet" type="text/css" href="assets/css/search.css">
    3029<link rel="stylesheet" type="text/css" href="assets/css/timeline.css">
     
    171170    ConfigurationSelectors(() => {view.reload()}),
    172171])}
    173 ${view}
    174 `);
     172<div class="main left under-topbar-with-actions">
     173    <div class="content">
     174        ${view}
     175    </div>
     176</div>`);
    175177
    176178</script>
     
    179181{% block content %}
    180182
    181 <div class="content" id="app">
     183<div id="app">
    182184</div>
    183185
  • trunk/Tools/resultsdbpy/resultsdbpy/view/view_routes_unittest.py

    r247869 r249213  
    4242
    4343    def toggle_drawer(self, driver, assert_displayed=None):
    44         driver.find_element_by_class_name('drawer-control').click()
     44        sidebar = driver.find_element_by_class_name('sidebar')
     45        sidebar.find_elements_by_tag_name('button')[0].click()
    4546        time.sleep(.5)
    4647        if assert_displayed:
    47             self.assertIn('display', driver.find_element_by_class_name('drawer').get_attribute('class'))
     48            self.assertNotIn('hidden', sidebar.get_attribute('class'))
    4849        elif assert_displayed is False:
    49             self.assertNotIn('display', driver.find_element_by_class_name('drawer').get_attribute('class'))
     50            self.assertIn('hidden', sidebar.get_attribute('class'))
    5051
    5152    def find_input_with_name(self, driver, name):
    52         control = [label.parent for label in driver.find_element_by_class_name('drawer').find_elements_by_tag_name('div') if label.find_element_by_tag_name('label').text == name][0]
     53        control = [label.parent for label in driver.find_element_by_class_name('sidebar').find_elements_by_tag_name('div') if label.find_element_by_tag_name('label').text == name][0]
    5354        self.assertIsNotNone(control)
    5455        return control
     
    103104        self.assertEqual(driver.title, 'Results Database')
    104105        title = driver.find_element_by_class_name('title').find_element_by_tag_name('div')
    105         self.assertEqual(title.text, 'Results Database')
     106        self.assertEqual(title.text.lstrip().rstrip(), 'Results Database')
    106107
    107108    @WaitForDockerTestCase.mock_if_no_docker(mock_redis=FakeStrictRedis, mock_cassandra=MockCassandraContext)
Note: See TracChangeset for help on using the changeset viewer.