Bug 1566011 Create sub component for manifestItem (part 2), r=ladybenko,fluent-reviewers,flod
☠☠ backed out by d359a7ccf597 ☠ ☠
authorOla Gasidlo <ogasidlo@mozilla.com>
Wed, 21 Aug 2019 08:39:11 +0000
changeset 489147 82634a1a23743a53cc38bee42e550cc01b76e1ca
parent 489146 e37925661bb44880b5d91455736fc7819d5bbb46
child 489148 de151ad69bd613efce11317b30c51bdeeb936f30
push id36465
push userdvarga@mozilla.com
push dateWed, 21 Aug 2019 16:47:43 +0000
treeherdermozilla-central@4ab60925635c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersladybenko, fluent-reviewers, flod
bugs1566011
milestone70.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1566011 Create sub component for manifestItem (part 2), r=ladybenko,fluent-reviewers,flod Differential Revision: https://phabricator.services.mozilla.com/D41909
devtools/client/application/application.css
devtools/client/application/src/base.css
devtools/client/application/src/components/manifest/ManifestItemIcon.js
devtools/client/application/src/components/manifest/ManifestItemText.js
devtools/client/application/src/components/manifest/ManifestItemWarning.js
devtools/client/application/src/components/manifest/ManifestPage.css
devtools/client/application/src/components/manifest/ManifestPage.js
devtools/client/application/src/components/manifest/ManifestView.css
devtools/client/application/src/components/manifest/ManifestView.js
devtools/client/application/src/components/manifest/ManifestViewEmpty.js
devtools/client/application/src/components/manifest/moz.build
devtools/client/application/src/components/routing/PageSwitcher.css
devtools/client/application/src/components/routing/moz.build
devtools/client/application/src/components/service-workers/WorkerListEmpty.css
devtools/client/application/src/components/service-workers/WorkerListEmpty.js
devtools/client/application/src/components/service-workers/WorkersPage.css
devtools/client/application/src/components/service-workers/WorkersPage.js
devtools/client/application/src/constants.js
devtools/client/application/test/components/manifest/__snapshots__/components_application_panel-ManifestPage.test.js.snap
devtools/client/application/test/components/manifest/__snapshots__/components_application_panel-ManifestView.test.js.snap
devtools/client/application/test/components/manifest/__snapshots__/components_application_panel-ManifestViewEmpty.test.js.snap
devtools/client/application/test/components/manifest/components_application_panel-ManifestView.test.js
devtools/client/application/test/components/manifest/components_application_panel-ManifestViewEmpty.test.js
devtools/client/application/test/components/service-workers/__snapshots__/components_application_panel-WorkerListEmpty.test.js.snap
devtools/client/application/test/components/service-workers/__snapshots__/components_application_panel-WorkersPage.test.js.snap
devtools/client/locales/en-US/application.ftl
--- a/devtools/client/application/application.css
+++ b/devtools/client/application/application.css
@@ -6,17 +6,18 @@
 * Global styles
 */
 @import "resource://devtools/client/application/src/base.css";
 
 /*
 * Components
 */
 @import "resource://devtools/client/application/src/components/App.css";
-@import "resource://devtools/client/application/src/components/manifest/ManifestPage.css";
+@import "resource://devtools/client/application/src/components/manifest/ManifestView.css";
+@import "resource://devtools/client/application/src/components/routing/PageSwitcher.css";
 @import "resource://devtools/client/application/src/components/service-workers/Worker.css";
 @import "resource://devtools/client/application/src/components/service-workers/WorkerList.css";
 @import "resource://devtools/client/application/src/components/service-workers/WorkerListEmpty.css";
 @import "resource://devtools/client/application/src/components/service-workers/WorkersPage.css";
 @import "resource://devtools/client/application/src/components/ui/UIButton.css";
 
 html,
 body,
--- a/devtools/client/application/src/base.css
+++ b/devtools/client/application/src/base.css
@@ -7,16 +7,18 @@
   /* See https://firefox-dev.tools/photon/visuals/typography.html */
   --caption-10-font-size: 11px;
   --caption-10-font-weight: 400;
   --body-10-font-size: 13px;
   --body-10-font-weight: 400;
   --body-20-font-size: 15px;
   --body-20-font-weight: 400;
   --body-20-font-weight-bold: 700;
+  --title-10-font-size: 13px;
+  --title-10-font-weight: 400;
   --title-20-font-size: 17px;
   --title-20-font-weight: 600;
   --title-30-font-size: 22px;
   --title-30-font-weight: 300;
 
   /* Global styles */
   --base-font-size: var(--body-10-font-size);
   --base-font-weight: var(--body-10-font-weight);
new file mode 100644
--- /dev/null
+++ b/devtools/client/application/src/components/manifest/ManifestItemIcon.js
@@ -0,0 +1,36 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
+const { PureComponent } = require("devtools/client/shared/vendor/react");
+const {
+  tr,
+  td,
+  th,
+} = require("devtools/client/shared/vendor/react-dom-factories");
+
+/**
+ * This component
+ */
+class ManifestItemIcon extends PureComponent {
+  static get propTypes() {
+    return {
+      icon: PropTypes.object.isRequired,
+    };
+  }
+  render() {
+    const { icon } = this.props;
+
+    return tr(
+      { className: "manifest-view__row" },
+      th({ className: "manifest-view__col-label", scope: "row" }, icon.size),
+      td({ className: "manifest-view__col-value" }, icon.src)
+    );
+  }
+}
+
+// Exports
+module.exports = ManifestItemIcon;
new file mode 100644
--- /dev/null
+++ b/devtools/client/application/src/components/manifest/ManifestItemText.js
@@ -0,0 +1,37 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
+const { PureComponent } = require("devtools/client/shared/vendor/react");
+const {
+  tr,
+  td,
+  th,
+} = require("devtools/client/shared/vendor/react-dom-factories");
+
+/**
+ * This component
+ */
+class ManifestItemText extends PureComponent {
+  static get propTypes() {
+    return {
+      name: PropTypes.string.isRequired,
+      val: PropTypes.string.isRequired,
+    };
+  }
+  render() {
+    const { name, val } = this.props;
+
+    return tr(
+      { className: "manifest-view__row" },
+      th({ className: "manifest-view__col-label", scope: "row" }, name),
+      td({ className: "manifest-view__col-value" }, val)
+    );
+  }
+}
+
+// Exports
+module.exports = ManifestItemText;
new file mode 100644
--- /dev/null
+++ b/devtools/client/application/src/components/manifest/ManifestItemWarning.js
@@ -0,0 +1,43 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
+const { PureComponent } = require("devtools/client/shared/vendor/react");
+const {
+  tr,
+  td,
+  th,
+  img,
+} = require("devtools/client/shared/vendor/react-dom-factories");
+
+/**
+ * This component
+ */
+class ManifestItemWarning extends PureComponent {
+  static get propTypes() {
+    return {
+      warning: PropTypes.object.isRequired,
+    };
+  }
+  render() {
+    const { warning } = this.props;
+
+    return tr(
+      { className: "manifest-view__row manifest-view__row-error" },
+      th(
+        { className: "manifest-view__col-label", scope: "row" },
+        img({
+          src: "chrome://global/skin/icons/warning.svg",
+          alt: "Warning icon",
+        })
+      ),
+      td({ className: "manifest-view__col-value" }, warning.warn)
+    );
+  }
+}
+
+// Exports
+module.exports = ManifestItemWarning;
deleted file mode 100644
--- a/devtools/client/application/src/components/manifest/ManifestPage.css
+++ /dev/null
@@ -1,16 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-.manifest-page {
-	height: 100vh;
-  padding: 0 2rem;
-  display: grid;
-  -moz-user-select: none;
-
-  /* slipt up in components in https://bugzilla.mozilla.org/show_bug.cgi?id=1566011 */
-  align-items: center;
-  justify-content: center;
-  font-size: var(--title-10-font-size);
-  color: var(--theme-toolbar-color);
-}
--- a/devtools/client/application/src/components/manifest/ManifestPage.js
+++ b/devtools/client/application/src/components/manifest/ManifestPage.js
@@ -9,16 +9,53 @@ const {
   PureComponent,
 } = require("devtools/client/shared/vendor/react");
 const {
   section,
 } = require("devtools/client/shared/vendor/react-dom-factories");
 
 const ManifestLoader = createFactory(require("../manifest/ManifestLoader"));
 
+const ManifestView = createFactory(require("./ManifestView"));
+const ManifestViewEmpty = createFactory(require("./ManifestViewEmpty"));
+
+const { MANIFEST_DATA } = require("../../constants");
+
 class ManifestPage extends PureComponent {
   render() {
-    return section({ className: `manifest-page` }, ManifestLoader({}));
+    const isManifestViewEmpty = !MANIFEST_DATA;
+
+    // needs to be replaced with data from ManifestLoader
+    const data = {
+      warnings: MANIFEST_DATA.moz_validation,
+      icons: MANIFEST_DATA.icons,
+      identity: {
+        name: MANIFEST_DATA.name,
+        short_name: MANIFEST_DATA.short_name,
+      },
+      presentation: {
+        display: MANIFEST_DATA.display,
+        orientation: MANIFEST_DATA.orientation,
+        start_url: MANIFEST_DATA.start_url,
+        theme_color: MANIFEST_DATA.theme_color,
+        background_color: MANIFEST_DATA.background_color,
+      },
+    };
+
+    return section(
+      {
+        className: `app-page ${isManifestViewEmpty ? "app-page--empty" : ""}`,
+      },
+      ManifestLoader({}),
+      isManifestViewEmpty
+        ? ManifestViewEmpty({})
+        : ManifestView({
+            identity: data.identity,
+            warnings: data.warnings,
+            icons: data.icons,
+            presentation: data.presentation,
+          })
+    );
   }
 }
 
 // Exports
 module.exports = ManifestPage;
new file mode 100644
--- /dev/null
+++ b/devtools/client/application/src/components/manifest/ManifestView.css
@@ -0,0 +1,41 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+.manifest-view {
+  padding: calc(var(--base-unit) * 2) calc(var(--base-unit) * 4);
+  border-bottom: 1px solid var(--grey-20);
+  display: table;
+  width: 100%;
+}
+
+.manifest-view:last-child {
+  border-bottom: 0;
+}
+
+.manifest-view__title {
+	font-size: var(--title-10-font-size);
+  font-weight: var(--title-20-font-weight);
+  text-align: left;
+  padding: calc(var(--base-unit) * 2) 0;
+}
+
+.manifest-view__row {
+  vertical-align: top;
+}
+
+.manifest-view__col-label {
+	color: var(--grey-50);
+  font-weight: var(--title-30-font-weight);
+  width: calc(var(--base-unit) * 28);
+  text-align: right;
+}
+
+.manifest-view__col-value {
+  word-break: break-all;
+}
+
+.manifest-view__row-error .manifest-view__col-label {
+  width: calc(var(--base-unit) * 6);
+  text-align: left;
+}
new file mode 100644
--- /dev/null
+++ b/devtools/client/application/src/components/manifest/ManifestView.js
@@ -0,0 +1,106 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
+const {
+  createFactory,
+  PureComponent,
+} = require("devtools/client/shared/vendor/react");
+const {
+  article,
+  caption,
+  h1,
+  table,
+  tbody,
+} = require("devtools/client/shared/vendor/react-dom-factories");
+
+const FluentReact = require("devtools/client/shared/vendor/fluent-react");
+const Localized = createFactory(FluentReact.Localized);
+
+const ManifestItemIcon = createFactory(require("./ManifestItemIcon"));
+const ManifestItemText = createFactory(require("./ManifestItemText"));
+const ManifestItemWarning = createFactory(require("./ManifestItemWarning"));
+/**
+ * This component
+ */
+class ManifestView extends PureComponent {
+  static get propTypes() {
+    return {
+      identity: PropTypes.object.isRequired,
+      warnings: PropTypes.array.isRequired,
+      icons: PropTypes.array.isRequired,
+      presentation: PropTypes.object.isRequired,
+    };
+  }
+  render() {
+    const { identity, warnings, icons, presentation } = this.props;
+
+    return article(
+      {},
+      Localized(
+        {
+          id: "manifest-view-header",
+        },
+        h1({ className: "app-page__title" })
+      ),
+      table(
+        { className: "manifest-view", key: "errors-and-warnings" },
+        Localized(
+          { id: "manifest-item-warnings" },
+          caption({ className: "manifest-view__title" })
+        ),
+        tbody(
+          {},
+          warnings.map((warning, index) =>
+            ManifestItemWarning({ warning, key: `warning-${index}` })
+          )
+        )
+      ),
+      table(
+        { className: "manifest-view", key: "identity" },
+        Localized(
+          { id: "manifest-item-identity" },
+          caption({ className: "manifest-view__title" })
+        ),
+        tbody(
+          {},
+          Object.entries(identity).map(([key, value]) =>
+            ManifestItemText({ name: key, val: value, key: `${key}` })
+          )
+        )
+      ),
+      table(
+        { className: "manifest-view", key: "presentation" },
+        Localized(
+          { id: "manifest-item-presentation" },
+          caption({ className: "manifest-view__title" })
+        ),
+        tbody(
+          {},
+          Object.entries(presentation).map(([key, value]) =>
+            ManifestItemText({ name: key, val: value, key: `${key}` })
+          )
+        )
+      ),
+      table(
+        { className: "manifest-view", key: "icons" },
+        Localized(
+          { id: "manifest-item-icons" },
+          caption({ className: "manifest-view__title" })
+        ),
+        tbody(
+          {},
+          icons.map((icon, index) =>
+            ManifestItemIcon({ icon, key: `warning-${index}` })
+          )
+        )
+      )
+    );
+  }
+}
+
+// Exports
+module.exports = ManifestView;
new file mode 100644
--- /dev/null
+++ b/devtools/client/application/src/components/manifest/ManifestViewEmpty.js
@@ -0,0 +1,40 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const {
+  createFactory,
+  PureComponent,
+} = require("devtools/client/shared/vendor/react");
+const {
+  article,
+  h1,
+  p,
+} = require("devtools/client/shared/vendor/react-dom-factories");
+
+const FluentReact = require("devtools/client/shared/vendor/fluent-react");
+const Localized = createFactory(FluentReact.Localized);
+
+/**
+ * This component displays help information when no manifest is found for the
+ * current target.
+ */
+class ManifestViewEmpty extends PureComponent {
+  render() {
+    return article(
+      { className: "manifest-view-empty" },
+      Localized(
+        {
+          id: "manifest-view-header",
+        },
+        h1({ className: "app-page__title" })
+      ),
+      Localized({ id: "manifest-empty-intro" }, p({}))
+    );
+  }
+}
+
+// Exports
+module.exports = ManifestViewEmpty;
--- a/devtools/client/application/src/components/manifest/moz.build
+++ b/devtools/client/application/src/components/manifest/moz.build
@@ -1,9 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 DevToolsModules(
+	'ManifestItemIcon.js',
+	'ManifestItemText.js',
+	'ManifestItemWarning.js',
     'ManifestLoader.js',
-    'ManifestPage.css',
-    'ManifestPage.js'
+    'ManifestPage.js',
+    'ManifestView.css',
+    'ManifestView.js',
+    'ManifestViewEmpty.js'
 )
new file mode 100644
--- /dev/null
+++ b/devtools/client/application/src/components/routing/PageSwitcher.css
@@ -0,0 +1,29 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+
+/*
+ * Page container for worker + manifest views
+ */
+
+.app-page {
+  height: 100vh;
+  padding: 0 2rem;
+  display: grid;
+  grid-template-rows: 1fr auto;
+  -moz-user-select: none;
+}
+
+.app-page--empty {
+  align-items: center;
+  justify-content: center;
+  font-size: var(--body-10-font-size);
+  color: var(--theme-toolbar-color);
+}
+
+.app-page__title {
+  font-size: var(--title-30-font-size);
+  font-weight: var(--title-30-font-weight);
+  margin: 0;
+}
--- a/devtools/client/application/src/components/routing/moz.build
+++ b/devtools/client/application/src/components/routing/moz.build
@@ -1,7 +1,8 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 DevToolsModules(
+    'PageSwitcher.css',
     'PageSwitcher.js',
 )
--- a/devtools/client/application/src/components/service-workers/WorkerListEmpty.css
+++ b/devtools/client/application/src/components/service-workers/WorkerListEmpty.css
@@ -1,27 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-.worker-list-empty {
-  max-width: calc(var(--base-unit) * 179);
-  font-size: var(--body-10-font-size);
-  color: var(--theme-toolbar-color);
+.app-page__title .external-link {
+  font-weight: var(--title-30-font-weight);
 }
 
-.worker-list-empty__title {
-  font-size: var(--title-20-font-size);
-  font-weight: var(--title-20-font-weight);
-}
-
-.worker-list-empty__title .external-link {
-  font-weight: var(--title-30-font-weight);
-} 
-
 .worker-list-empty__tips {
   margin-inline-start: 2rem;
 }
 
 .worker-list-empty__tips__item {
   margin-block-start: 0.5rem;
   margin-block-end: 0.5rem;
 }
--- a/devtools/client/application/src/components/service-workers/WorkerListEmpty.js
+++ b/devtools/client/application/src/components/service-workers/WorkerListEmpty.js
@@ -7,16 +7,17 @@
 const { openDocLink, openTrustedLink } = require("devtools/client/shared/link");
 const {
   createFactory,
   PureComponent,
 } = require("devtools/client/shared/vendor/react");
 const {
   a,
   article,
+  h1,
   li,
   p,
   ul,
 } = require("devtools/client/shared/vendor/react-dom-factories");
 
 const FluentReact = require("devtools/client/shared/vendor/fluent-react");
 const Localized = createFactory(FluentReact.Localized);
 
@@ -53,17 +54,17 @@ class WorkerListEmpty extends PureCompon
       Localized(
         {
           id: "serviceworker-empty-intro",
           a: a({
             className: "external-link",
             onClick: () => this.openDocumentation(),
           }),
         },
-        p({ className: "worker-list-empty__title" })
+        h1({ className: "app-page__title" })
       ),
       Localized({ id: "serviceworker-empty-suggestions" }, p({})),
       ul(
         { className: "worker-list-empty__tips" },
         Localized(
           {
             id: "serviceworker-empty-suggestions-console",
             a: a({ className: "link", onClick: () => this.switchToConsole() }),
--- a/devtools/client/application/src/components/service-workers/WorkersPage.css
+++ b/devtools/client/application/src/components/service-workers/WorkersPage.css
@@ -10,23 +10,8 @@
  *  +---------------------------------------------+
  *  | Service worker 1                            |
  *  |   (...)                                     |
  *  | Service worker N           (see Worker.css) |
  *  +---------------------------------------------+
  *  |                     Link to about:debugging |
  *  +---------------------------------------------+
  */
-.workers-page {
-  height: 100vh;
-  padding: 0 2rem;
-  display: grid;
-  -moz-user-select: none;
-}
-
-.workers-page--empty {
-  align-items: center;
-  justify-content: center;
-}
-
-.workers-page:not(.workers-page--empty) {
-  grid-template-rows: 1fr auto;
-}
--- a/devtools/client/application/src/components/service-workers/WorkersPage.js
+++ b/devtools/client/application/src/components/service-workers/WorkersPage.js
@@ -33,19 +33,17 @@ class WorkersPage extends PureComponent 
     // Filter out workers from other domains
     const domainWorkers = workers.filter(
       x => new URL(x.url).hostname === domain
     );
     const isWorkerListEmpty = domainWorkers.length === 0;
 
     return section(
       {
-        className: `workers-page ${
-          isWorkerListEmpty ? "workers-page--empty" : ""
-        }`,
+        className: `app-page ${isWorkerListEmpty ? "app-page--empty" : ""}`,
       },
       isWorkerListEmpty
         ? WorkerListEmpty({})
         : WorkerList({
             canDebugWorkers,
             workers: domainWorkers,
           })
     );
--- a/devtools/client/application/src/constants.js
+++ b/devtools/client/application/src/constants.js
@@ -18,10 +18,56 @@ const actionTypes = {
 
 const PAGE_TYPES = {
   MANIFEST: "manifest",
   SERVICE_WORKERS: "service-workers",
 };
 
 const DEFAULT_PAGE = PAGE_TYPES.MANIFEST;
 
+const MANIFEST_DATA = {
+  background_color: "#F9D",
+  dir: "auto",
+  display: "browser",
+  icons: [
+    {
+      src:
+        "https://design.firefox.com/icons/icons/desktop/default-browser-16.svg",
+      type: "type/png",
+      size: "16x16",
+    },
+    {
+      src:
+        "https://design.firefox.com/icons/icons/desktop/default-browser-16.svg",
+      type: "type/png",
+      size: "32x32",
+    },
+    {
+      src:
+        "https://design.firefox.com/icons/icons/desktop/default-browser-16.svg",
+      type: "type/png",
+      size: "64x64",
+    },
+  ],
+  lang: "en-US",
+  moz_manifest_url: "",
+  moz_validation: [
+    { warn: "Icons item at index 0 is invalid." },
+    {
+      warn:
+        "Icons item at index 2 is invalid. Icons item at index 2 is invalid. Icons item at index 2 is invalid. Icons item at index 2 is invalid.",
+    },
+  ],
+  name:
+    "Name is a verrry long name and the name is longer tha you thinnk because it is loooooooooooooooooooooooooooooooooooooooooooooooong",
+  orientation: "landscape",
+  scope: "./",
+  short_name: "Na",
+  start_url: "root",
+  theme_color: "#345",
+};
+
 // flatten constants
-module.exports = Object.assign({}, { DEFAULT_PAGE, PAGE_TYPES }, actionTypes);
+module.exports = Object.assign(
+  {},
+  { DEFAULT_PAGE, PAGE_TYPES, MANIFEST_DATA },
+  actionTypes
+);
--- a/devtools/client/application/test/components/manifest/__snapshots__/components_application_panel-ManifestPage.test.js.snap
+++ b/devtools/client/application/test/components/manifest/__snapshots__/components_application_panel-ManifestPage.test.js.snap
@@ -1,9 +1,55 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`ManifestPage renders the expected snapshot 1`] = `
 <section
-  className="manifest-page"
+  className="app-page "
 >
   <Connect(ManifestLoader) />
+  <ManifestView
+    icons={
+      Array [
+        Object {
+          "size": "16x16",
+          "src": "https://design.firefox.com/icons/icons/desktop/default-browser-16.svg",
+          "type": "type/png",
+        },
+        Object {
+          "size": "32x32",
+          "src": "https://design.firefox.com/icons/icons/desktop/default-browser-16.svg",
+          "type": "type/png",
+        },
+        Object {
+          "size": "64x64",
+          "src": "https://design.firefox.com/icons/icons/desktop/default-browser-16.svg",
+          "type": "type/png",
+        },
+      ]
+    }
+    identity={
+      Object {
+        "name": "Name is a verrry long name and the name is longer tha you thinnk because it is loooooooooooooooooooooooooooooooooooooooooooooooong",
+        "short_name": "Na",
+      }
+    }
+    presentation={
+      Object {
+        "background_color": "#F9D",
+        "display": "browser",
+        "orientation": "landscape",
+        "start_url": "root",
+        "theme_color": "#345",
+      }
+    }
+    warnings={
+      Array [
+        Object {
+          "warn": "Icons item at index 0 is invalid.",
+        },
+        Object {
+          "warn": "Icons item at index 2 is invalid. Icons item at index 2 is invalid. Icons item at index 2 is invalid. Icons item at index 2 is invalid.",
+        },
+      ]
+    }
+  />
 </section>
 `;
new file mode 100644
--- /dev/null
+++ b/devtools/client/application/test/components/manifest/__snapshots__/components_application_panel-ManifestView.test.js.snap
@@ -0,0 +1,150 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`ManifestView renders the expected snapshot 1`] = `
+<article>
+  <Localized
+    id="manifest-view-header"
+  >
+    <h1
+      className="app-page__title"
+    />
+  </Localized>
+  <table
+    className="manifest-view"
+    key="errors-and-warnings"
+  >
+    <Localized
+      id="manifest-item-warnings"
+    >
+      <caption
+        className="manifest-view__title"
+      />
+    </Localized>
+    <tbody>
+      <ManifestItemWarning
+        key="warning-0"
+        warning={
+          Object {
+            "warn": "Icons item at index 0 is invalid.",
+          }
+        }
+      />
+      <ManifestItemWarning
+        key="warning-1"
+        warning={
+          Object {
+            "warn": "Icons item at index 2 is invalid. Icons item at index 2 is invalid. Icons item at index 2 is invalid. Icons item at index 2 is invalid.",
+          }
+        }
+      />
+    </tbody>
+  </table>
+  <table
+    className="manifest-view"
+    key="identity"
+  >
+    <Localized
+      id="manifest-item-identity"
+    >
+      <caption
+        className="manifest-view__title"
+      />
+    </Localized>
+    <tbody>
+      <ManifestItemText
+        key="name"
+        name="name"
+        val="Name is a verrry long name and the name is longer tha you thinnk because it is loooooooooooooooooooooooooooooooooooooooooooooooong"
+      />
+      <ManifestItemText
+        key="short_name"
+        name="short_name"
+        val="Na"
+      />
+    </tbody>
+  </table>
+  <table
+    className="manifest-view"
+    key="presentation"
+  >
+    <Localized
+      id="manifest-item-presentation"
+    >
+      <caption
+        className="manifest-view__title"
+      />
+    </Localized>
+    <tbody>
+      <ManifestItemText
+        key="display"
+        name="display"
+        val="browser"
+      />
+      <ManifestItemText
+        key="orientation"
+        name="orientation"
+        val="landscape"
+      />
+      <ManifestItemText
+        key="start_url"
+        name="start_url"
+        val="root"
+      />
+      <ManifestItemText
+        key="theme_color"
+        name="theme_color"
+        val="#345"
+      />
+      <ManifestItemText
+        key="background_color"
+        name="background_color"
+        val="#F9D"
+      />
+    </tbody>
+  </table>
+  <table
+    className="manifest-view"
+    key="icons"
+  >
+    <Localized
+      id="manifest-item-icons"
+    >
+      <caption
+        className="manifest-view__title"
+      />
+    </Localized>
+    <tbody>
+      <ManifestItemIcon
+        icon={
+          Object {
+            "size": "16x16",
+            "src": "https://design.firefox.com/icons/icons/desktop/default-browser-16.svg",
+            "type": "type/png",
+          }
+        }
+        key="warning-0"
+      />
+      <ManifestItemIcon
+        icon={
+          Object {
+            "size": "32x32",
+            "src": "https://design.firefox.com/icons/icons/desktop/default-browser-16.svg",
+            "type": "type/png",
+          }
+        }
+        key="warning-1"
+      />
+      <ManifestItemIcon
+        icon={
+          Object {
+            "size": "64x64",
+            "src": "https://design.firefox.com/icons/icons/desktop/default-browser-16.svg",
+            "type": "type/png",
+          }
+        }
+        key="warning-2"
+      />
+    </tbody>
+  </table>
+</article>
+`;
new file mode 100644
--- /dev/null
+++ b/devtools/client/application/test/components/manifest/__snapshots__/components_application_panel-ManifestViewEmpty.test.js.snap
@@ -0,0 +1,20 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`ManifestViewEmpty renders the expected snapshot 1`] = `
+<article
+  className="manifest-view-empty"
+>
+  <Localized
+    id="manifest-view-header"
+  >
+    <h1
+      className="app-page__title"
+    />
+  </Localized>
+  <Localized
+    id="manifest-empty-intro"
+  >
+    <p />
+  </Localized>
+</article>
+`;
new file mode 100644
--- /dev/null
+++ b/devtools/client/application/test/components/manifest/components_application_panel-ManifestView.test.js
@@ -0,0 +1,49 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Import libs
+const { shallow } = require("enzyme");
+const { createFactory } = require("react");
+
+const ManifestView = createFactory(
+  require("devtools/client/application/src/components/manifest/ManifestView")
+);
+
+const { MANIFEST_DATA } = require("../../../src/constants");
+
+// needs to move to reducer
+const data = {
+  warnings: MANIFEST_DATA.moz_validation,
+  icons: MANIFEST_DATA.icons,
+  identity: {
+    name: MANIFEST_DATA.name,
+    short_name: MANIFEST_DATA.short_name,
+  },
+  presentation: {
+    display: MANIFEST_DATA.display,
+    orientation: MANIFEST_DATA.orientation,
+    start_url: MANIFEST_DATA.start_url,
+    theme_color: MANIFEST_DATA.theme_color,
+    background_color: MANIFEST_DATA.background_color,
+  },
+};
+
+/**
+ * Test for ManifestView.js component
+ */
+
+describe("ManifestView", () => {
+  it("renders the expected snapshot", () => {
+    const wrapper = shallow(
+      ManifestView({
+        identity: data.identity,
+        warnings: data.warnings,
+        icons: data.icons,
+        presentation: data.presentation,
+      })
+    );
+    expect(wrapper).toMatchSnapshot();
+  });
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/application/test/components/manifest/components_application_panel-ManifestViewEmpty.test.js
@@ -0,0 +1,23 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Import libs
+const { shallow } = require("enzyme");
+const { createFactory } = require("react");
+
+const ManifestViewEmpty = createFactory(
+  require("devtools/client/application/src/components/manifest/ManifestViewEmpty")
+);
+
+/**
+ * Test for ManifestPage.js component
+ */
+
+describe("ManifestViewEmpty", () => {
+  it("renders the expected snapshot", () => {
+    const wrapper = shallow(ManifestViewEmpty({}));
+    expect(wrapper).toMatchSnapshot();
+  });
+});
--- a/devtools/client/application/test/components/service-workers/__snapshots__/components_application_panel-WorkerListEmpty.test.js.snap
+++ b/devtools/client/application/test/components/service-workers/__snapshots__/components_application_panel-WorkerListEmpty.test.js.snap
@@ -8,18 +8,18 @@ exports[`WorkerListEmpty renders the exp
     a={
       <a
         className="external-link"
         onClick={[Function]}
       />
     }
     id="serviceworker-empty-intro"
   >
-    <p
-      className="worker-list-empty__title"
+    <h1
+      className="app-page__title"
     />
   </Localized>
   <Localized
     id="serviceworker-empty-suggestions"
   >
     <p />
   </Localized>
   <ul
--- a/devtools/client/application/test/components/service-workers/__snapshots__/components_application_panel-WorkersPage.test.js.snap
+++ b/devtools/client/application/test/components/service-workers/__snapshots__/components_application_panel-WorkersPage.test.js.snap
@@ -1,13 +1,13 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`WorkersPage filters out workers from diferent domains 1`] = `
 <section
-  className="workers-page "
+  className="app-page "
 >
   <WorkerList
     canDebugWorkers={true}
     workers={
       Array [
         Object {
           "active": true,
           "name": "worker1",
@@ -27,25 +27,25 @@ exports[`WorkersPage filters out workers
       ]
     }
   />
 </section>
 `;
 
 exports[`WorkersPage filters out workers from different domains and renders an empty list when there is none left 1`] = `
 <section
-  className="workers-page workers-page--empty"
+  className="app-page app-page--empty"
 >
   <WorkerListEmpty />
 </section>
 `;
 
 exports[`WorkersPage it renders a list with a single element if there's just 1 worker 1`] = `
 <section
-  className="workers-page "
+  className="app-page "
 >
   <WorkerList
     canDebugWorkers={true}
     workers={
       Array [
         Object {
           "active": true,
           "name": "worker1",
@@ -57,17 +57,17 @@ exports[`WorkersPage it renders a list w
       ]
     }
   />
 </section>
 `;
 
 exports[`WorkersPage renders a list with multiple elements when there are multiple workers 1`] = `
 <section
-  className="workers-page "
+  className="app-page "
 >
   <WorkerList
     canDebugWorkers={true}
     workers={
       Array [
         Object {
           "active": true,
           "name": "worker1",
@@ -95,13 +95,13 @@ exports[`WorkersPage renders a list with
       ]
     }
   />
 </section>
 `;
 
 exports[`WorkersPage renders an empty list if there are no workers 1`] = `
 <section
-  className="workers-page workers-page--empty"
+  className="app-page app-page--empty"
 >
   <WorkerListEmpty />
 </section>
 `;
--- a/devtools/client/locales/en-US/application.ftl
+++ b/devtools/client/locales/en-US/application.ftl
@@ -75,19 +75,38 @@ serviceworker-empty-suggestions-console 
 # Suggestion to use the debugger to investigate why a service worker is not registered.
 # Clicking on the link will switch from the Application panel to the debugger.
 serviceworker-empty-suggestions-debugger = Step through your Service Worker registration and look for exceptions. <a>Open the Debugger</a>
 
 # Suggestion to go to about:debugging in order to see Service Workers for all domains.
 # Clicking on the link will open about:debugging in a new tab.
 serviceworker-empty-suggestions-aboutdebugging = Inspect Service Workers from other domains. <a>Open about:debugging</a>
 
+# Header for the view of Manifest displayed in the application panel for the current page.
+manifest-view-header = App Manifest
+
+# Header for the Errors and Warnings section of Manifest inspection displayed in the application panel.
+manifest-item-warnings = Errors and Warnings
+
+# Header for the Identity section of Manifest inspection displayed in the application panel.
+manifest-item-identity = Identity
+
+# Header for the Presentation section of Manifest inspection displayed in the application panel.
+manifest-item-presentation = Presentation
+
+# Header for the Icon section of Manifest inspection displayed in the application panel.
+manifest-item-icons = Icons
+
+# Text displayed when no manifest was found for the current page.
+manifest-empty-intro = No manifest found to inspect.
+
 # Text displayed while we are loading the manifest file
 manifest-loading = Loading manifest…
 
 # Text displayed when the manifest has been successfully loaded
 manifest-loaded-ok = Manifest loaded.
 
 # Text displayed when there has been an error while trying to load the manifest
 manifest-loaded-error = There was an error while loading the manifest:
 
 # Text displayed when the page has no manifest available
 manifest-non-existing = No manifest found to inspect.
+