fix(desktop): fixes to app switcher inside desk

This commit is contained in:
Rushabh Mehta 2024-09-23 15:19:09 +05:30
parent f88c508c23
commit 4da1f70eaf
13 changed files with 4798 additions and 276 deletions

View file

@ -165,29 +165,40 @@ def load_desktop_data(bootinfo):
if has_permission and not frappe.get_attr(has_permission)():
continue
workspaces = [
r[0]
for r in (
frappe.qb.from_(Workspace)
.inner_join(Module)
.on(Workspace.module == Module.name)
.select(Workspace.name)
.where(Module.app_name == app_name)
.run()
)
if r[0] in allowed_pages
]
bootinfo.app_data.append(
dict(
app_name=app_info.get("name") or app_name,
app_title=app_info.get("title")
or frappe.get_hooks("app_title", app_name=app_name)
or (
frappe.get_hooks("app_title", app_name=app_name)
and frappe.get_hooks("app_title", app_name=app_name)[0]
or ""
)
or app_name,
app_route=app_info.get("route") or frappe.get_hooks("app_home", app_name=app_name),
app_route=(
frappe.get_hooks("app_home", app_name=app_name)
and frappe.get_hooks("app_home", app_name=app_name)[0]
)
or (workspaces and "/app/" + frappe.utils.slug(workspaces[0]))
or "",
app_logo_url=app_info.get("logo")
or frappe.get_hooks("app_logo_url", app_name=app_name)
or frappe.get_hooks("app_logo_url", app_name="frappe"),
modules=[m.name for m in frappe.get_all("Module Def", dict(app_name=app_name))],
workspaces=[
r[0]
for r in (
frappe.qb.from_(Workspace)
.inner_join(Module)
.on(Workspace.module == Module.name)
.select(Workspace.name)
.where(Module.app_name == app_name)
.run()
)
if r[0] in allowed_pages
],
workspaces=workspaces,
)
)

View file

@ -473,6 +473,9 @@ def get_workspace_sidebar_items():
if page["name"] in workspace_visibilty:
page["visibility"] = workspace_visibilty[page["name"]]
if not page["app"] and page["module"]:
page["app"] = frappe.db.get_value("Module Def", page["module"], "app_name")
except frappe.PermissionError:
pass
if private_pages:

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 743 KiB

View file

@ -6,9 +6,11 @@ Instructions:
3. Don't set stroke, fill colour
4. Use viewport 24 24
Tip: use lucide.svg in /icons for all downloaded icons
-->
<svg id="frappe-symbols" aria-hidden="true" style="display: none;" class="es-icon" xmlns="http://www.w3.org/2000/svg">
<svg id="frappe-symbols" aria-hidden="true" style="display: none;" class="icon" xmlns="http://www.w3.org/2000/svg">
<symbol viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" id="icon-up-line">
<path d="M13 10.5L8 5.5L3 10.5" stroke-linecap="round" stroke-linejoin="round"/>
</symbol>
@ -329,6 +331,14 @@ Instructions:
<path d="M7.9 20A9 9 0 1 0 4 16.1L2 22Z"/>
</symbol>
<symbol viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" id="icon-home">
<path d="M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8"/><path d="M3 10a2 2 0 0 1 .709-1.528l7-5.999a2 2 0 0 1 2.582 0l7 5.999A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>
</symbol>
<symbol viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" id="icon-grid">
<rect width="7" height="7" x="3" y="3" rx="1"/><rect width="7" height="7" x="14" y="3" rx="1"/><rect width="7" height="7" x="14" y="14" rx="1"/><rect width="7" height="7" x="3" y="14" rx="1"/>
</symbol>
<symbol viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" id="icon-refresh">
<path d="M13.644 8.43a5.571 5.571 0 1 1-.876-3.001M12.787 2v3.429H9.358" stroke-linecap="round" stroke-linejoin="round"></path>
</symbol>

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 86 KiB

View file

@ -101,13 +101,12 @@ frappe.ui.Sidebar = class Sidebar {
<a>
<div class="sidebar-item-icon">
<img
style="margin-right: var(--margin-sm);"
class="app-logo"
src="${app.app_logo_url}"
alt="${__("App Logo")}"
>
</div>
<span>${app.app_title}</span>
<span class="app-item-title">${app.app_title}</span>
</a>
</div>`).appendTo(app_switcher_menu);
}

View file

@ -171,11 +171,6 @@ footer {
float: right;
}
img {
max-width: 100%;
height: auto;
}
.missing-image {
background-color: var(--bg-light-gray);
line-height: 140px;

View file

@ -268,6 +268,13 @@ body {
text-decoration: none;
display: flex;
align-items: center;
gap: var(--margin-sm);
}
.app-item-title {
text-overflow: ellipsis;
text-wrap: nowrap;
overflow: hidden;
}
}

View file

@ -30,7 +30,6 @@
@import "navbar";
@import "footer";
@import "error-state";
@import "my_account";
.ql-editor.read-mode {
padding: 0;

View file

@ -1,91 +0,0 @@
@include media-breakpoint-down(sm) {
#page-me {
.side-list {
.list-group {
display: none;
}
}
}
}
.my-account-header {
color: var(--gray-900);
margin-bottom: var(--margin-lg);
font-weight: bold;
@include media-breakpoint-down(sm) {
margin-left: -1rem;
}
}
.my-account-container {
max-width: 800px;
margin: auto;
margin-bottom: 4rem;
}
.account-info {
background-color: var(--fg-color);
border: 1px solid var(--border-color);
border-radius: var(--border-radius-md);
padding: var(--padding-sm) 25px;
@include media-breakpoint-down(sm) {
padding: 0;
}
.my-account-name,
.my-account-item {
color: var(--gray-900);
font-weight: var(--weight-medium);
}
.my-account-avatar {
.avatar {
height: 60px;
width: 60px;
}
}
.my-account-item-desc {
color: var(--gray-700);
@include get_textstyle("base", "regular");
}
.my-account-item-link {
@include get_textstyle("base", "regular");
a {
text-decoration: none;
.edit-profile-icon {
stroke: var(--blue-500);
}
}
.right-icon {
@include media-breakpoint-up(sm) {
display: none;
}
}
.item-link-text {
@include media-breakpoint-down(sm) {
display: none;
}
}
}
.col {
padding: var(--padding-md) 0;
border-bottom: 1px solid var(--border-color);
.form-group {
margin-right: var(--margin-lg);
}
}
:last-child {
border: 0;
}
}

View file

@ -5,3 +5,76 @@
color: $body-color;
}
}
.portal-container {
max-width: 540px;
margin: 3rem auto;
padding: var(--padding-2xl);
border-radius: var(--border-radius-lg);
background-color: var(--bg-color);
/* border: 1px solid var(--border-color); */
box-shadow: var(--shadow-lg);
}
.portal-items {
border: 1px solid var(--border-color);
border-radius: var(--border-radius);
.portal-section {
padding: 10px;
border-bottom: 1px solid var(--border-color);
&:last-child {
border-bottom: none;
}
}
}
.portal-section {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 0;
&.head {
padding: 0;
padding-bottom: var(--padding-lg);
margin-top: -10px;
border-bottom: none;
}
a {
text-decoration: none;
}
.item-link-text {
padding-left: var(--padding-sm);
color: var(--text-light);
}
.title {
font-weight: var(--weight-semibold);
font-size: var(--text-lg);
color: var(--text-color);
}
}
.icon-md {
margin-top: -3px;
}
.icon {
stroke: var(--text-light);
}
.portal-footer {
margin: var(--margin-md) auto;
display: flex;
justify-content: center;
gap: var(--margin-xl);
a {
color: var(--text-light);
text-decoration: none;
}
}

View file

@ -13,77 +13,10 @@
background-color: var(--subtle-fg);
font-size: var(--text-base);
}
.me-container {
max-width: 540px;
margin: 3rem auto;
padding: var(--padding-2xl);
border-radius: var(--border-radius-lg);
background-color: var(--bg-color);
/* border: 1px solid var(--border-color); */
box-shadow: var(--shadow-lg);
}
.me-items {
border: 1px solid var(--border-color);
border-radius: var(--border-radius);
}
.me-section {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px;
border-bottom: 1px solid var(--border-color);
}
.me-section.head {
padding: 0;
padding-bottom: var(--padding-lg);
margin-top: -10px;
border-bottom: none;
}
.me-section:last-child {
border-bottom: none;
}
.icon-md {
margin-top: -3px;
}
.icon {
stroke: var(--text-light);
}
.me-section a {
text-decoration: none;
}
.item-link-text {
padding-left: var(--padding-sm);
color: var(--text-light);
}
.title {
font-weight: var(--weight-semibold);
font-size: var(--text-lg);
color: var(--text-color);
}
.me-logout {
margin: var(--margin-md) auto;
text-align: center;
}
.me-logout a {
color: var(--text-light);
}
</style>
<div class="me-container">
<div class="me-section head">
<div class="portal-container">
<div class="portal-section head">
<div class="title">{{_("Settings")}}</div>
<div>
<span class="my-account-avatar">
@ -94,8 +27,8 @@
</span>
</div>
</div>
<div class="me-items">
<div class="me-section">
<div class="portal-items">
<div class="portal-section">
<span class="my-account-item-link">
<a href="/update-profile/{{ user }}">
<svg class="edit-profile-icon icon icon-md">
@ -108,7 +41,7 @@
</span>
</div>
<div class="me-section">
<div class="portal-section">
<span class="my-account-item-link">
<a href="/update-password">
<svg class="right-icon icon icon-md"><use href="#icon-lock"></use></svg>
@ -116,7 +49,7 @@
</a>
</span>
</div>
<div class="me-section">
<div class="portal-section">
<span class="my-account-item-link">
<a href="/third_party_apps">
<svg class="right-icon icon icon-md"><use href="#icon-web"></use></svg>
@ -137,7 +70,15 @@
</div>
</div>
<div class="me-logout">
<div class="portal-footer">
<a href="/">
<svg class="right-icon icon icon-md"><use href="#icon-home"></use></svg>
{{ _("Home") }}
</a>
<a href="/apps">
<svg class="right-icon icon icon-md"><use href="#icon-grid"></use></svg>
{{ _("Apps") }}
</a>
<a href="/logout">
<svg class="right-icon icon icon-md"><use href="#icon-logout"></use></svg>
{{ _("Logout") }}

View file

@ -2,89 +2,82 @@
{% block title %} {{ _("Third Party Apps") }} {% endblock %}
{% block page_sidebar %}
{% include "templates/includes/web_sidebar.html" %}
{% endblock %}
{% block navbar %}{% endblock %}
{% block footer %}{% endblock %}
{% block style %}
{% endblock %}
{% block style %}{% endblock %}
{% block page_content %}
<h3 class="my-account-header">{{ _("Third Party Apps") }}</h3>
<div class="third-party-wrapper">
{% if app %}
<h4>{{ app.app_name }}</h4>
<div class="web-list-item">
<div class="row">
<div class="col-xs-12">
<div class="well">
<div class="text-muted">{{ _("This will log out {0} from all other devices").format(app.app_name) }}</div>
<div class="padding"></div>
<div class="text-right">
<button class="btn btn-default" onclick="location.href = '/third_party_apps';">Cancel</button>
<button class="btn btn-danger btn-delete-app" data-client_id="{{ app.client_id }}">Revoke</button>
<div class="portal-container">
<div class="portal-section head">
<div class="title">{{ _("Third Party Apps") }}</div>
</div>
<div class="third-party-wrapper portal-items">
{% if app %}
<h4>{{ app.app_name }}</h4>
<div class="web-list-item portal-section">
<div class="row">
<div class="col-xs-12">
<div class="well">
<div class="text-muted">{{ _("This will log out {0} from all other devices").format(app.app_name) }}</div>
<div class="padding"></div>
<div class="text-right">
<button class="btn btn-default" onclick="location.href = '/third_party_apps';">Cancel</button>
<button class="btn btn-danger btn-delete-app" data-client_id="{{ app.client_id }}">Revoke</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% elif apps|length > 0 %}
<h4>{{ _("Active Sessions") }}</h4>
{% for app in apps %}
<div class="web-list-item">
<div class="row">
<div class="col-xs-6">
{{ app.app_name }}
{% elif apps|length > 0 %}
<h4>{{ _("Active Sessions") }}</h4>
{% for app in apps %}
<div class="web-list-item portal-section">
<div class="row">
<div class="col-xs-6">
{{ app.app_name }}
</div>
<div class="col-xs-4 text-right text-muted">
<small class="text-right">
{{ _("logged in") }}&nbsp;{{ frappe.utils.pretty_date(app.creation) }}
</small>
</div>
<div class="col-xs-2 text-right small text-muted">
<a class="btn btn-sm btn-link" href="/third_party_apps?app={{ app.name }}">{{ _("Revoke") }}</a>
</div>
</div>
</div>
<div class="col-xs-4 text-right text-muted">
<small class="text-right">
{{ _("logged in") }}&nbsp;{{ frappe.utils.pretty_date(app.creation) }}
</small>
{% endfor %}
{% else %}
<div class="empty-apps-state">
<img src="/assets/frappe/images/ui-states/empty-app-state.svg"/>
<div class="font-weight-bold mt-4">
{{ _("No Active Sessions")}}
</div>
<div class="col-xs-2 text-right small text-muted">
<a class="btn btn-sm btn-link" href="/third_party_apps?app={{ app.name }}">{{ _("Revoke") }}</a>
<div class="text-muted mt-2">
{{ _("Looks like you havent added any third party apps.")}}
</div>
</div>
{% endif %}
</div>
{% endfor %}
{% else %}
<div class="empty-apps-state">
<img src="/assets/frappe/images/ui-states/empty-app-state.svg"/>
<div class="font-weight-bold mt-4">
{{ _("No Active Sessions")}}
</div>
<div class="text-muted mt-2">
{{ _("Looks like you havent added any third party apps.")}}
</div>
</div>
{% endif %}
</div>
<script>
{% include "templates/includes/integrations/third_party_apps.js" %}
</script>
<style>
body {
background-color: var(--bg-color);
}
.my-account-header, .third-party-wrapper {
max-width: 800px;
margin: auto;
}
.my-account-header {
margin-top: 3rem;
margin-bottom: 1rem;
background-color: var(--subtle-fg);
font-size: var(--text-base);
}
.third-party-wrapper {
background-color: var(--fg-color);
border-radius: var(--border-radius-md);
border: 1px solid var(--border-color);
padding: var(--padding-md);
}
.empty-apps-state {
width: 100%;
display: flex;
flex-direction: column;
justify-content: center;

View file

@ -1,15 +1,25 @@
{% extends "templates/web.html" %}
{% block title %} {{_("Reset Password")}} {% endblock %}
{% block head_include %}
{% endblock %}
{% block navbar %}{% endblock %}
{% block footer %}{% endblock %}
{% block head_include %}{% endblock %}
{% block page_content %}
<section class="for-reset-password d-block">
<div class="page-card-head">
<h4 class="reset-password-heading">{{ _("Reset Password") if frappe.db.get_default('company') else _("Set Password")}}</h4>
<style>
body {
background-color: var(--subtle-fg);
font-size: var(--text-base);
}
</style>
<div class="portal-container">
<div class="portal-section head">
<div class="title">{{ _("Reset Password") if frappe.db.get_default('company') else _("Set Password")}}</div>
</div>
<div class="page-card">
<form id="reset-password">
<div class="portal-section pb-0">
<form id="reset-password" style="width: 100%">
<div class="form-group">
<input id="old_password" type="password"
class="form-control mb-4" placeholder="{{ _('Old Password') }}" autocomplete="current-password">
@ -21,7 +31,7 @@
</div>
<div class="form-group">
<input id="confirm_password" type="password"
class="form-control" placeholder="{{ _('Confirm Password') }}" autocomplete="new-password">
class="form-control mb-4" placeholder="{{ _('Confirm Password') }}" autocomplete="new-password">
</div>
<p class="password-mismatch-message text-muted small hidden mt-2"></p>
@ -36,28 +46,7 @@
</div>
{%- endif -%}
</div>
</section>
<style>
.page-card-head {
padding: max(5vh, 30px) 0 14px 0px;
margin: 0 auto;
text-align: center;
font-size: var(--text-xl);
font-weight: 600;
}
.page-card-head img {
max-height: 42px;
}
.page-card-head h4 {
margin-top: 1rem;
font-size: var(--text-xl);
font-weight: var(--weight-semibold);
letter-spacing: 0.01em;
color: var(--text-color);
}
</style>
</div>
<script>