From 4f3dfb360e3a7abb1e467c806a87448902ce7c34 Mon Sep 17 00:00:00 2001
From: Mart van Santen <mart@greenhost.nl>
Date: Wed, 15 Mar 2023 19:39:25 +0800
Subject: [PATCH] Better logo handling

---
 frontend/public/assets/email.svg              | 14 +++++
 frontend/public/assets/gitlab.svg             |  1 +
 frontend/public/assets/mattermost.svg         |  2 +
 frontend/public/assets/other.svg              |  1 +
 .../src/components/UserModal/UserModal.tsx    | 48 +++++++++++++++--
 frontend/src/components/UserModal/consts.ts   | 52 +++++++++++++++++++
 frontend/src/components/index.ts              |  1 +
 7 files changed, 116 insertions(+), 3 deletions(-)
 create mode 100644 frontend/public/assets/email.svg
 create mode 100644 frontend/public/assets/gitlab.svg
 create mode 100644 frontend/public/assets/mattermost.svg
 create mode 100644 frontend/public/assets/other.svg

diff --git a/frontend/public/assets/email.svg b/frontend/public/assets/email.svg
new file mode 100644
index 00000000..5fa1e9e3
--- /dev/null
+++ b/frontend/public/assets/email.svg
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
+<svg fill="#000000" height="800px" width="800px" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" 
+	 viewBox="0 0 75.294 75.294" xml:space="preserve">
+<g>
+	<path d="M66.097,12.089h-56.9C4.126,12.089,0,16.215,0,21.286v32.722c0,5.071,4.126,9.197,9.197,9.197h56.9
+		c5.071,0,9.197-4.126,9.197-9.197V21.287C75.295,16.215,71.169,12.089,66.097,12.089z M61.603,18.089L37.647,33.523L13.691,18.089
+		H61.603z M66.097,57.206h-56.9C7.434,57.206,6,55.771,6,54.009V21.457l29.796,19.16c0.04,0.025,0.083,0.042,0.124,0.065
+		c0.043,0.024,0.087,0.047,0.131,0.069c0.231,0.119,0.469,0.215,0.712,0.278c0.025,0.007,0.05,0.01,0.075,0.016
+		c0.267,0.063,0.537,0.102,0.807,0.102c0.001,0,0.002,0,0.002,0c0.002,0,0.003,0,0.004,0c0.27,0,0.54-0.038,0.807-0.102
+		c0.025-0.006,0.05-0.009,0.075-0.016c0.243-0.063,0.48-0.159,0.712-0.278c0.044-0.022,0.088-0.045,0.131-0.069
+		c0.041-0.023,0.084-0.04,0.124-0.065l29.796-19.16v32.551C69.295,55.771,67.86,57.206,66.097,57.206z"/>
+</g>
+</svg>
\ No newline at end of file
diff --git a/frontend/public/assets/gitlab.svg b/frontend/public/assets/gitlab.svg
new file mode 100644
index 00000000..95a22f10
--- /dev/null
+++ b/frontend/public/assets/gitlab.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 380 380"><defs><style>.cls-1{fill:#e24329;}.cls-2{fill:#fc6d26;}.cls-3{fill:#fca326;}</style></defs><g id="LOGO"><path class="cls-1" d="M282.83,170.73l-.27-.69-26.14-68.22a6.81,6.81,0,0,0-2.69-3.24,7,7,0,0,0-8,.43,7,7,0,0,0-2.32,3.52l-17.65,54H154.29l-17.65-54A6.86,6.86,0,0,0,134.32,99a7,7,0,0,0-8-.43,6.87,6.87,0,0,0-2.69,3.24L97.44,170l-.26.69a48.54,48.54,0,0,0,16.1,56.1l.09.07.24.17,39.82,29.82,19.7,14.91,12,9.06a8.07,8.07,0,0,0,9.76,0l12-9.06,19.7-14.91,40.06-30,.1-.08A48.56,48.56,0,0,0,282.83,170.73Z"/><path class="cls-2" d="M282.83,170.73l-.27-.69a88.3,88.3,0,0,0-35.15,15.8L190,229.25c19.55,14.79,36.57,27.64,36.57,27.64l40.06-30,.1-.08A48.56,48.56,0,0,0,282.83,170.73Z"/><path class="cls-3" d="M153.43,256.89l19.7,14.91,12,9.06a8.07,8.07,0,0,0,9.76,0l12-9.06,19.7-14.91S209.55,244,190,229.25C170.45,244,153.43,256.89,153.43,256.89Z"/><path class="cls-2" d="M132.58,185.84A88.19,88.19,0,0,0,97.44,170l-.26.69a48.54,48.54,0,0,0,16.1,56.1l.09.07.24.17,39.82,29.82s17-12.85,36.57-27.64Z"/></g></svg>
\ No newline at end of file
diff --git a/frontend/public/assets/mattermost.svg b/frontend/public/assets/mattermost.svg
new file mode 100644
index 00000000..9b055325
--- /dev/null
+++ b/frontend/public/assets/mattermost.svg
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
+<svg fill="#000000" width="800px" height="800px" viewBox="0 0 501 501" xmlns="http://www.w3.org/2000/svg" version="1"><path d="M236 .7C137.7 7.5 54 68.2 18.2 158.5c-32 81-19.6 172.8 33 242.5 39.8 53 97.2 87 164.3 97 16.5 2.7 48 3.2 63.5 1.2 48.7-6.3 92.2-24.6 129-54.2 13-10.5 33-31.2 42.2-43.7 26.4-35.5 42.8-75.8 49-120.3 1.6-12.3 1.6-48.7 0-61-4-28.3-12-54.8-24.2-79.5-12.8-26-26.5-45.3-46.8-65.8C417.8 64 400.2 49 398.4 49c-.6 0-.4 10.5.3 26l1.3 26 7 8.7c19 23.7 32.8 53.5 38.2 83 2.5 14 3 43 1 55.8-4.5 27.8-15.2 54-31 76.5-8.6 12.2-28 31.6-40.2 40.2-24 17-50 27.6-80 33-10 1.8-49 1.8-59 0-43-7.7-78.8-26-107.2-54.8-29.3-29.7-46.5-64-52.4-104.4-2-14-1.5-42 1-55C90 121.4 132 72 192 49.7c8-3 18.4-5.8 29.5-8.2 1.7-.4 34.4-38 35.3-40.6.3-1-10.2-1-20.8-.4z"/><path d="M322.2 24.6c-1.3.8-8.4 9.3-16 18.7-7.4 9.5-22.4 28-33.2 41.2-51 62.2-66 81.6-70.6 91-6 12-8.4 21-9 33-1.2 19.8 5 36 19 50C222 268 230 273 243 277.2c9 3 10.4 3.2 24 3.2 13.8 0 15 0 22.6-3 23.2-9 39-28.4 45-55.7 2-8.2 2-28.7.4-79.7l-2-72c-1-36.8-1.4-41.8-3-44-2-3-4.8-3.6-7.8-1.4z"/></svg>
\ No newline at end of file
diff --git a/frontend/public/assets/other.svg b/frontend/public/assets/other.svg
new file mode 100644
index 00000000..1a53b092
--- /dev/null
+++ b/frontend/public/assets/other.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="utf-8"?><svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 122.6 122.88" style="enable-background:new 0 0 122.6 122.88" xml:space="preserve"><g><path d="M110.6,72.58c0-3.19,2.59-5.78,5.78-5.78c3.19,0,5.78,2.59,5.78,5.78v33.19c0,4.71-1.92,8.99-5.02,12.09 c-3.1,3.1-7.38,5.02-12.09,5.02H17.11c-4.71,0-8.99-1.92-12.09-5.02c-3.1-3.1-5.02-7.38-5.02-12.09V17.19 C0,12.48,1.92,8.2,5.02,5.1C8.12,2,12.4,0.08,17.11,0.08h32.98c3.19,0,5.78,2.59,5.78,5.78c0,3.19-2.59,5.78-5.78,5.78H17.11 c-1.52,0-2.9,0.63-3.91,1.63c-1.01,1.01-1.63,2.39-1.63,3.91v88.58c0,1.52,0.63,2.9,1.63,3.91c1.01,1.01,2.39,1.63,3.91,1.63h87.95 c1.52,0,2.9-0.63,3.91-1.63s1.63-2.39,1.63-3.91V72.58L110.6,72.58z M112.42,17.46L54.01,76.6c-2.23,2.27-5.89,2.3-8.16,0.07 c-2.27-2.23-2.3-5.89-0.07-8.16l56.16-56.87H78.56c-3.19,0-5.78-2.59-5.78-5.78c0-3.19,2.59-5.78,5.78-5.78h26.5 c5.12,0,11.72-0.87,15.65,3.1c2.48,2.51,1.93,22.52,1.61,34.11c-0.08,3-0.15,5.29-0.15,6.93c0,3.19-2.59,5.78-5.78,5.78 c-3.19,0-5.78-2.59-5.78-5.78c0-0.31,0.08-3.32,0.19-7.24C110.96,30.94,111.93,22.94,112.42,17.46L112.42,17.46z"/></g></svg>
\ No newline at end of file
diff --git a/frontend/src/components/UserModal/UserModal.tsx b/frontend/src/components/UserModal/UserModal.tsx
index b6ceed73..083a6630 100644
--- a/frontend/src/components/UserModal/UserModal.tsx
+++ b/frontend/src/components/UserModal/UserModal.tsx
@@ -7,7 +7,7 @@ import { Input, Select } from 'src/components/Form';
 import { User, UserRole, useUsers } from 'src/services/users';
 import { useAuth } from 'src/services/auth';
 import { HIDDEN_APPS } from 'src/modules/dashboard/consts';
-import { appAccessList, initialUserForm } from './consts';
+import { appAccessList, appExternalAccessList, initialUserForm } from './consts';
 import { UserModalProps } from './types';
 
 export const UserModal = ({ open, onClose, userId, setUserId }: UserModalProps) => {
@@ -165,6 +165,48 @@ export const UserModal = ({ open, onClose, userId, setUserId }: UserModalProps)
     );
   };
 
+  // Given an item, find the object with the meta data (logo, label etc) for
+  // this app and return that object. It first searches the default included
+  // list, then the external application list and a fall back on the 'other'
+  // object
+  const fetchAppObject = (item: any) => {
+    let obj = _.find(appAccessList, ['name', item.name!]);
+    if (obj) {
+      return obj;
+    }
+    // Check if slug shows up in external list
+    let slug = item.name.toLowerCase();
+
+    // Strip ext from the slug, the ext prefix is advised in the documentation
+    // for external applications, however, we no not need it to match it with
+    // our application list
+    slug = slug.replace(/^ext-/, '');
+    slug = slug.replace(/^ext/, '');
+    obj = _.find(appExternalAccessList, ['name', slug!]);
+    if (obj) {
+      return obj;
+    }
+
+    obj = _.find(appExternalAccessList, ['name', 'other'!]);
+    return obj;
+  };
+
+  // Return logo of app, if not found, return a generic default
+  const fetchAppImage = (item: any) => {
+    const obj = fetchAppObject(item);
+    return obj?.image;
+  };
+
+  // Return name of app
+  const fetchAppLabel = (item: any) => {
+    const obj = fetchAppObject(item);
+    if (obj?.label === '') {
+      // Object not found, so we use the name, with capatilized first char
+      return item.name.charAt(0).toUpperCase() + item.name.slice(1);
+    }
+    return obj?.label;
+  };
+
   return (
     <>
       <Modal
@@ -275,11 +317,11 @@ export const UserModal = ({ open, onClose, userId, setUserId }: UserModalProps)
                                 <div className="flex-shrink-0 flex-1 flex items-center">
                                   <img
                                     className="h-10 w-10 rounded-md overflow-hidden"
-                                    src={_.find(appAccessList, ['name', item.name!])?.image}
+                                    src={fetchAppImage(item)}
                                     alt={item.name ?? 'Image'}
                                   />
                                   <h3 className="ml-4 text-md leading-6 font-medium text-gray-900">
-                                    {_.find(appAccessList, ['name', item.name!])?.label}
+                                    {fetchAppLabel(item)}
                                   </h3>
                                 </div>
                                 <div>
diff --git a/frontend/src/components/UserModal/consts.ts b/frontend/src/components/UserModal/consts.ts
index 95cbbf08..0f316f67 100644
--- a/frontend/src/components/UserModal/consts.ts
+++ b/frontend/src/components/UserModal/consts.ts
@@ -33,6 +33,58 @@ export const appAccessList = [
   },
 ];
 
+// List of external application which are not part of zulip. This is to
+// load nice icons and labels. Because in the future translations are planned
+// this list is included in the frontend and do not rely on the information
+// provides by the baccken.
+export const appExternalAccessList = [
+  // 3 Possible names for email
+  {
+    name: 'email',
+    image: '/assets/email.svg',
+    label: 'E-mail',
+    documentationUrl: '',
+  },
+  {
+    name: 'mail',
+    image: '/assets/email.svg',
+    label: 'E-mail',
+    documentationUrl: '',
+  },
+  {
+    name: 'zimbra',
+    image: '/assets/zimbra.svg',
+    label: 'E-mail',
+    documentationUrl: '',
+  },
+  // Other common applications
+  {
+    name: 'gitlab',
+    image: '/assets/gitlab.svg',
+    label: 'GitLab',
+    documentationUrl: '',
+  },
+  {
+    name: 'mattermost',
+    image: '/assets/mattermost.svg',
+    label: 'Mattermost',
+    documentationUrl: '',
+  },
+  {
+    name: 'vpn',
+    image: '/assets/vpn.svg',
+    label: 'VPN',
+    documentationUrl: '',
+  },
+  // This is used for all other
+  {
+    name: 'other',
+    image: '/assets/other.svg',
+    label: '',
+    documentationUrl: '',
+  },
+];
+
 export const allAppAccessList = [
   {
     name: 'dashboard',
diff --git a/frontend/src/components/index.ts b/frontend/src/components/index.ts
index 64e430d5..30927d83 100644
--- a/frontend/src/components/index.ts
+++ b/frontend/src/components/index.ts
@@ -6,3 +6,4 @@ export { Tabs } from './Tabs';
 export { Modal, ConfirmationModal, InfoModal, StepsModal } from './Modal';
 export { UserModal } from './UserModal';
 export { ProgressSteps } from './ProgressSteps';
+export { AppAccess } from './AppAccess';
-- 
GitLab