From 21958eca1591d58f8a24522cea7424a80d10e02d Mon Sep 17 00:00:00 2001 From: metatroncubeswdev Date: Mon, 31 Aug 2026 15:21:49 -0400 Subject: [PATCH] Add SaaS workplace frontend --- addons/mcs_corporate_website/__manifest__.py | 3 + .../mcs_corporate_website/controllers/main.py | 200 ++++++++ .../data/workplace_data.xml | 29 ++ .../mcs_corporate_website/models/__init__.py | 2 + .../models/announcement.py | 37 ++ .../mcs_corporate_website/models/knowledge.py | 30 ++ .../security/ir.model.access.csv | 4 + .../static/src/scss/corporate_website.scss | 473 ++++++++++++++++++ .../views/workplace_backend_views.xml | 82 +++ .../views/workplace_templates.xml | 240 +++++++++ 10 files changed, 1100 insertions(+) create mode 100644 addons/mcs_corporate_website/data/workplace_data.xml create mode 100644 addons/mcs_corporate_website/models/announcement.py create mode 100644 addons/mcs_corporate_website/models/knowledge.py create mode 100644 addons/mcs_corporate_website/views/workplace_backend_views.xml create mode 100644 addons/mcs_corporate_website/views/workplace_templates.xml diff --git a/addons/mcs_corporate_website/__manifest__.py b/addons/mcs_corporate_website/__manifest__.py index 090f26a..fe29dcc 100644 --- a/addons/mcs_corporate_website/__manifest__.py +++ b/addons/mcs_corporate_website/__manifest__.py @@ -19,8 +19,11 @@ "security/security.xml", "security/ir.model.access.csv", "data/sequence_data.xml", + "data/workplace_data.xml", "views/support_ticket_views.xml", + "views/workplace_backend_views.xml", "views/website_templates.xml", + "views/workplace_templates.xml", "views/website_menus.xml", "data/website_data.xml", ], diff --git a/addons/mcs_corporate_website/controllers/main.py b/addons/mcs_corporate_website/controllers/main.py index 2bb0827..7867c53 100644 --- a/addons/mcs_corporate_website/controllers/main.py +++ b/addons/mcs_corporate_website/controllers/main.py @@ -13,6 +13,143 @@ class McsCorporateWebsite(http.Controller): ) return request.render(template, values) + def _workplace_render(self, template, values=None): + values = values or {} + values.update(self._workplace_context()) + return request.render(template, values) + + def _employee(self): + return request.env["hr.employee"].sudo().search([("user_id", "=", request.env.user.id)], limit=1) + + def _role(self): + user = request.env.user + if user.has_group("base.group_system"): + return "admin" + if user.has_group("mcs_corporate_website.group_mcs_website_support_user"): + return "support_agent" + if self._employee(): + return "employee" + return "client" + + def _workplace_context(self): + user = request.env.user + employee = self._employee() + role = self._role() + partner = user.partner_id.commercial_partner_id + return { + "wp_user": user, + "wp_role": role, + "wp_employee": employee, + "wp_first_name": (employee.name or user.name).split(" ")[0], + "wp_company_name": partner.name or user.company_id.name, + "wp_today": fields.Date.context_today(request.env.user), + "wp_nav": self._workplace_nav(role), + } + + def _workplace_nav(self, role): + if role == "client": + return [ + ("Dashboard", "/workplace", "dashboard"), + ("Support Tickets", "/workplace/tickets", "support"), + ("Create Ticket", "/workplace/tickets/new", "create"), + ("Knowledge Base", "/workplace/knowledge", "knowledge"), + ("Profile", "/workplace/profile", "profile"), + ] + items = [ + ("Dashboard", "/workplace", "dashboard"), + ("Attendance", "/workplace/attendance", "attendance"), + ("Leave", "/workplace/leave", "leave"), + ("Support", "/workplace/tickets", "support"), + ("Knowledge", "/workplace/knowledge", "knowledge"), + ("Announcements", "/workplace/announcements", "announcements"), + ] + if role in ("support_agent", "admin"): + items.insert(4, ("Queue", "/workplace/support-queue", "queue")) + return items + + def _ticket_domain(self, role): + if role in ("admin", "support_agent"): + return [] + return [("partner_id", "child_of", request.env.user.partner_id.commercial_partner_id.id)] + + def _ticket_values(self, tickets): + mapped = [] + for ticket in tickets: + mapped.append( + { + "id": ticket.id, + "number": ticket.name, + "subject": ticket.subject, + "priority": dict(ticket._fields["priority"].selection).get(ticket.priority), + "priority_key": ticket.priority, + "status": dict(ticket._fields["state"].selection).get(ticket.state), + "status_key": ticket.state, + "customer": ticket.partner_id.name or ticket.customer_name, + "assigned_team": dict(ticket._fields["service_area"].selection).get(ticket.service_area), + "created": ticket.create_date, + "updated": ticket.write_date, + "updated_label": fields.Datetime.to_string(ticket.write_date) if ticket.write_date else "", + } + ) + return mapped + + def _dashboard_values(self, role): + employee = self._employee() + today = fields.Date.context_today(request.env.user) + Ticket = request.env["mcs.support.ticket"].sudo() + tickets = Ticket.search(self._ticket_domain(role), order="write_date desc", limit=8) + values = { + "tickets": self._ticket_values(tickets), + "announcements": self._announcements(role, 3), + "articles": self._knowledge(role, 3), + "ticket_counts": { + "open": Ticket.search_count(self._ticket_domain(role) + [("state", "=", "new")]), + "in_progress": Ticket.search_count(self._ticket_domain(role) + [("state", "=", "in_progress")]), + "waiting": Ticket.search_count(self._ticket_domain(role) + [("state", "=", "waiting")]), + "resolved": Ticket.search_count(self._ticket_domain(role) + [("state", "in", ["resolved", "closed"])]), + }, + } + if employee and role != "client": + Attendance = request.env["hr.attendance"].sudo() + attendance = Attendance.search( + [("employee_id", "=", employee.id), ("check_in", ">=", fields.Datetime.to_string(today))], + order="check_in desc", + limit=1, + ) + month_start = today.replace(day=1) + values.update( + { + "attendance": attendance, + "worked_today": round(attendance.worked_hours, 2) if attendance else 0, + "month_present": Attendance.search_count( + [("employee_id", "=", employee.id), ("check_in", ">=", fields.Date.to_string(month_start))] + ), + "leave_balance": self._leave_balance(employee), + "recent_activity": self._recent_activity(employee), + } + ) + return values + + def _leave_balance(self, employee): + LeaveType = request.env["hr.leave.type"].sudo() + return [ + {"name": leave_type.name, "days": round(leave_type.with_context(employee_id=employee.id).virtual_remaining_leaves, 2)} + for leave_type in LeaveType.search([], limit=3) + ] + + def _recent_activity(self, employee): + Attendance = request.env["hr.attendance"].sudo() + records = Attendance.search([("employee_id", "=", employee.id)], order="check_in desc", limit=5) + return [{"label": "Attendance", "detail": record.check_in, "status": "Present" if record.check_out else "Open"} for record in records] + + def _knowledge(self, role, limit=12): + domain = [("active", "=", True), ("audience", "in", ["all", "client" if role == "client" else "employee"])] + return request.env["mcs.knowledge.article"].sudo().search(domain, limit=limit) + + def _announcements(self, role, limit=10): + domain = [("active", "=", True), ("audience", "in", ["all", "client" if role == "client" else "employee"])] + return request.env["mcs.announcement"].sudo().search(domain, order="date desc, id desc", limit=limit) + def _contact(self): return { "phone": "+1-647-679-7651", @@ -98,6 +235,69 @@ class McsCorporateWebsite(http.Controller): def privacy(self, **kwargs): return self._render("mcs_corporate_website.page_privacy") + @http.route(["/workplace"], type="http", auth="user", website=True) + def workplace_dashboard(self, **kwargs): + role = self._role() + template = "mcs_corporate_website.workplace_client_dashboard" if role == "client" else "mcs_corporate_website.workplace_employee_dashboard" + return self._workplace_render(template, self._dashboard_values(role)) + + @http.route(["/workplace/attendance"], type="http", auth="user", website=True) + def workplace_attendance(self, **kwargs): + employee = self._employee() + if not employee: + return request.redirect("/workplace") + today = fields.Date.context_today(request.env.user) + month_start = today.replace(day=1) + records = request.env["hr.attendance"].sudo().search( + [("employee_id", "=", employee.id), ("check_in", ">=", fields.Date.to_string(month_start))], + order="check_in desc", + limit=40, + ) + return self._workplace_render( + "mcs_corporate_website.workplace_attendance", + {"attendance_records": records, "attendance": records[:1], "worked_hours": round(sum(records.mapped("worked_hours")), 2)}, + ) + + @http.route(["/workplace/leave"], type="http", auth="user", website=True) + def workplace_leave(self, **kwargs): + employee = self._employee() + if not employee: + return request.redirect("/workplace") + leaves = request.env["hr.leave"].sudo().search([("employee_id", "=", employee.id)], order="request_date_from desc", limit=20) + return self._workplace_render("mcs_corporate_website.workplace_leave", {"leave_balance": self._leave_balance(employee), "leaves": leaves}) + + @http.route(["/workplace/tickets", "/workplace/support-queue"], type="http", auth="user", website=True) + def workplace_tickets(self, **kwargs): + role = self._role() + tickets = request.env["mcs.support.ticket"].sudo().search(self._ticket_domain(role), order="priority desc, write_date desc", limit=80) + template = "mcs_corporate_website.workplace_support_queue" if role in ("admin", "support_agent") and request.httprequest.path.endswith("support-queue") else "mcs_corporate_website.workplace_ticket_list" + return self._workplace_render(template, {"tickets": self._ticket_values(tickets)}) + + @http.route(["/workplace/tickets/new"], type="http", auth="user", website=True) + def workplace_ticket_new(self, **kwargs): + return self._workplace_render("mcs_corporate_website.workplace_ticket_new") + + @http.route(["/workplace/tickets/"], type="http", auth="user", website=True) + def workplace_ticket_detail(self, ticket_id, **kwargs): + role = self._role() + ticket = request.env["mcs.support.ticket"].sudo().search(self._ticket_domain(role) + [("id", "=", ticket_id)], limit=1) + if not ticket: + return request.not_found() + messages = ticket.message_ids.sorted(lambda item: item.date) + return self._workplace_render("mcs_corporate_website.workplace_ticket_detail", {"ticket": ticket, "messages": messages}) + + @http.route(["/workplace/knowledge"], type="http", auth="user", website=True) + def workplace_knowledge(self, **kwargs): + return self._workplace_render("mcs_corporate_website.workplace_knowledge", {"articles": self._knowledge(self._role())}) + + @http.route(["/workplace/announcements"], type="http", auth="user", website=True) + def workplace_announcements(self, **kwargs): + return self._workplace_render("mcs_corporate_website.workplace_announcements", {"announcements": self._announcements(self._role())}) + + @http.route(["/workplace/profile"], type="http", auth="user", website=True) + def workplace_profile(self, **kwargs): + return self._workplace_render("mcs_corporate_website.workplace_profile") + @http.route(["/support/submit"], type="http", auth="public", website=True, methods=["POST"]) def submit_support(self, **post): ticket = request.env["mcs.support.ticket"].sudo().create( diff --git a/addons/mcs_corporate_website/data/workplace_data.xml b/addons/mcs_corporate_website/data/workplace_data.xml new file mode 100644 index 0000000..80c1b0a --- /dev/null +++ b/addons/mcs_corporate_website/data/workplace_data.xml @@ -0,0 +1,29 @@ + + + Getting started with the workplace portal + getting_started + Use the dashboard to access attendance, leave, support, announcements, and profile information. + all + The workplace portal brings daily employee workflows and customer support into one authenticated Odoo-backed interface.

]]>
+
+ + How to raise a useful support ticket + technical + Include project name, affected page or module, priority, screenshots, and expected outcome. + all + Clear ticket details help the team triage, assign, and resolve issues faster.

]]>
+
+ + Billing and invoice support + billing + Create a support ticket for invoice questions, payment references, or account updates. + client + Billing queries are tracked through support tickets so communication remains attached to the customer account.

]]>
+
+ + Metatroncube Workplace portal update + company + all + The workplace portal now provides a cleaner dashboard for employee and customer support workflows.

]]>
+
+
diff --git a/addons/mcs_corporate_website/models/__init__.py b/addons/mcs_corporate_website/models/__init__.py index 17c91c3..9ae3e32 100644 --- a/addons/mcs_corporate_website/models/__init__.py +++ b/addons/mcs_corporate_website/models/__init__.py @@ -1,2 +1,4 @@ from . import support_ticket from . import website_setup +from . import knowledge +from . import announcement diff --git a/addons/mcs_corporate_website/models/announcement.py b/addons/mcs_corporate_website/models/announcement.py new file mode 100644 index 0000000..cb5366b --- /dev/null +++ b/addons/mcs_corporate_website/models/announcement.py @@ -0,0 +1,37 @@ +from odoo import fields, models + + +class McsAnnouncement(models.Model): + _name = "mcs.announcement" + _description = "Metatroncube Announcement" + _inherit = ["mail.thread", "mail.activity.mixin"] + _order = "date desc, id desc" + + name = fields.Char(string="Title", required=True, tracking=True) + author_id = fields.Many2one( + "res.users", + default=lambda self: self.env.user, + required=True, + tracking=True, + ) + date = fields.Date(default=fields.Date.context_today, required=True, tracking=True) + category = fields.Selection( + [ + ("company", "Company"), + ("hr", "HR"), + ("delivery", "Delivery"), + ("it", "Internal IT"), + ("client", "Client"), + ], + default="company", + required=True, + tracking=True, + ) + audience = fields.Selection( + [("all", "All"), ("employee", "Employees"), ("client", "Clients")], + default="employee", + required=True, + tracking=True, + ) + content = fields.Html(required=True) + active = fields.Boolean(default=True) diff --git a/addons/mcs_corporate_website/models/knowledge.py b/addons/mcs_corporate_website/models/knowledge.py new file mode 100644 index 0000000..5320865 --- /dev/null +++ b/addons/mcs_corporate_website/models/knowledge.py @@ -0,0 +1,30 @@ +from odoo import fields, models + + +class McsKnowledgeArticle(models.Model): + _name = "mcs.knowledge.article" + _description = "Metatroncube Knowledge Article" + _order = "sequence, name" + + name = fields.Char(required=True) + category = fields.Selection( + [ + ("getting_started", "Getting Started"), + ("account", "Account"), + ("billing", "Billing"), + ("website", "Website"), + ("technical", "Technical Support"), + ("internal_it", "Internal IT"), + ], + default="getting_started", + required=True, + ) + summary = fields.Char(required=True) + body = fields.Html() + audience = fields.Selection( + [("all", "All"), ("employee", "Employees"), ("client", "Clients")], + default="all", + required=True, + ) + sequence = fields.Integer(default=10) + active = fields.Boolean(default=True) diff --git a/addons/mcs_corporate_website/security/ir.model.access.csv b/addons/mcs_corporate_website/security/ir.model.access.csv index 756e9d3..8eae497 100644 --- a/addons/mcs_corporate_website/security/ir.model.access.csv +++ b/addons/mcs_corporate_website/security/ir.model.access.csv @@ -1,3 +1,7 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink access_mcs_support_ticket_user,mcs.support.ticket.user,model_mcs_support_ticket,mcs_corporate_website.group_mcs_website_support_user,1,1,1,0 access_mcs_support_ticket_manager,mcs.support.ticket.manager,model_mcs_support_ticket,mcs_corporate_website.group_mcs_website_support_manager,1,1,1,1 +access_mcs_knowledge_article_user,mcs.knowledge.article.user,model_mcs_knowledge_article,mcs_corporate_website.group_mcs_website_support_user,1,1,1,0 +access_mcs_knowledge_article_manager,mcs.knowledge.article.manager,model_mcs_knowledge_article,mcs_corporate_website.group_mcs_website_support_manager,1,1,1,1 +access_mcs_announcement_user,mcs.announcement.user,model_mcs_announcement,mcs_corporate_website.group_mcs_website_support_user,1,1,1,0 +access_mcs_announcement_manager,mcs.announcement.manager,model_mcs_announcement,mcs_corporate_website.group_mcs_website_support_manager,1,1,1,1 diff --git a/addons/mcs_corporate_website/static/src/scss/corporate_website.scss b/addons/mcs_corporate_website/static/src/scss/corporate_website.scss index 387b315..21e81c8 100644 --- a/addons/mcs_corporate_website/static/src/scss/corporate_website.scss +++ b/addons/mcs_corporate_website/static/src/scss/corporate_website.scss @@ -399,3 +399,476 @@ padding: 56px 0; } } + +.mcs-workplace { + --background: #F6F7F9; + --surface: #FFFFFF; + --sidebar: #101114; + --sidebar-hover: #1B1D21; + --text-primary: #17181B; + --text-secondary: #6B7280; + --border: #E6E8EC; + --accent: #1C4ED8; + --success: #16A34A; + --warning: #F59E0B; + --danger: #DC2626; + + min-height: calc(100vh - 76px); + display: grid; + grid-template-columns: 250px minmax(0, 1fr); + background: var(--background); + color: var(--text-primary); + font-family: Inter, Manrope, "Segoe UI", sans-serif; + + h1, + h2, + h3 { + letter-spacing: 0; + } +} + +.mcs-wp-sidebar { + position: sticky; + top: 0; + min-height: calc(100vh - 76px); + background: var(--sidebar); + padding: 22px 14px; + display: flex; + flex-direction: column; + gap: 26px; + + nav { + display: grid; + gap: 6px; + } +} + +.mcs-wp-brand { + display: flex; + gap: 10px; + align-items: center; + color: #fff; + text-decoration: none; + padding: 0 8px; + + img { + width: 42px; + height: 42px; + object-fit: contain; + } + + span { + display: grid; + font-size: 1.05rem; + font-weight: 800; + line-height: 1.1; + } + + small { + color: #9CA3AF; + font-size: 0.66rem; + letter-spacing: 0.16em; + margin-top: 3px; + } +} + +.mcs-wp-nav, +.mcs-wp-sidebar-bottom a { + color: #CBD5E1; + text-decoration: none; + border-radius: 10px; + padding: 11px 12px; + font-weight: 700; + + &:hover, + &.active { + color: #fff; + background: var(--sidebar-hover); + } +} + +.mcs-wp-sidebar-bottom { + margin-top: auto; + display: grid; + gap: 4px; +} + +.mcs-wp-main { + min-width: 0; +} + +.mcs-wp-topbar { + height: 72px; + background: var(--surface); + border-bottom: 1px solid var(--border); + display: flex; + align-items: center; + justify-content: space-between; + padding: 0 32px; +} + +.mcs-wp-kicker { + display: block; + color: var(--text-secondary); + font-size: 0.78rem; + font-weight: 800; + text-transform: uppercase; + letter-spacing: 0.12em; +} + +.mcs-wp-user { + display: flex; + align-items: center; + gap: 10px; + color: var(--text-secondary); + font-weight: 700; +} + +.mcs-avatar { + width: 36px; + height: 36px; + display: inline-grid; + place-items: center; + border-radius: 999px; + background: var(--accent); + color: #fff; + font-weight: 800; +} + +.mcs-avatar--lg { + width: 84px; + height: 84px; + font-size: 2rem; +} + +.mcs-wp-content { + max-width: 1500px; + margin: 0 auto; + padding: 34px; +} + +.mcs-wp-page-head { + display: flex; + align-items: center; + justify-content: space-between; + gap: 20px; + margin-bottom: 24px; + + p { + margin: 0 0 6px; + color: var(--text-secondary); + font-weight: 800; + text-transform: uppercase; + letter-spacing: 0.12em; + font-size: 0.78rem; + } + + h1 { + margin: 0; + font-size: 2.15rem; + line-height: 1.12; + font-weight: 820; + } +} + +.mcs-wp-grid { + display: grid; + gap: 18px; + margin-bottom: 22px; +} + +.mcs-wp-grid--2 { + grid-template-columns: repeat(2, minmax(0, 1fr)); +} + +.mcs-wp-grid--3 { + grid-template-columns: repeat(3, minmax(0, 1fr)); +} + +.mcs-wp-grid--4 { + grid-template-columns: repeat(4, minmax(0, 1fr)); +} + +.mcs-wp-two { + display: grid; + grid-template-columns: minmax(0, 1fr) 380px; + gap: 22px; + margin-bottom: 22px; + align-items: start; +} + +.mcs-wp-card { + background: var(--surface); + border: 1px solid var(--border); + border-radius: 14px; + padding: 22px; + box-shadow: 0 14px 38px rgba(17, 24, 39, 0.06); +} + +.mcs-metric { + display: grid; + gap: 8px; + + span { + color: var(--text-secondary); + font-weight: 800; + font-size: 0.82rem; + } + + strong { + font-size: 1.9rem; + line-height: 1; + } + + small { + color: var(--text-secondary); + } +} + +.mcs-card-head, +.mcs-list-row { + display: flex; + align-items: center; + justify-content: space-between; + gap: 14px; +} + +.mcs-card-head { + margin-bottom: 16px; + + h2 { + margin: 0; + font-size: 1.15rem; + font-weight: 820; + } +} + +.mcs-list-row { + padding: 13px 0; + border-top: 1px solid var(--border); + + span { + color: var(--text-secondary); + } +} + +.mcs-list-row--stack { + display: grid; + justify-content: start; +} + +.mcs-wp-btn { + display: inline-flex; + align-items: center; + justify-content: center; + border: 0; + border-radius: 10px; + padding: 11px 16px; + background: var(--accent); + color: #fff !important; + font-weight: 800; + text-decoration: none; + box-shadow: 0 10px 24px rgba(28, 78, 216, 0.2); +} + +.mcs-table-wrap { + width: 100%; + overflow-x: auto; +} + +.mcs-wp-table { + width: 100%; + border-collapse: collapse; + + th, + td { + padding: 13px 12px; + border-bottom: 1px solid var(--border); + white-space: nowrap; + text-align: left; + } + + th { + color: var(--text-secondary); + font-size: 0.78rem; + text-transform: uppercase; + letter-spacing: 0.08em; + } +} + +.mcs-status { + display: inline-flex; + align-items: center; + min-height: 26px; + border-radius: 999px; + padding: 4px 10px; + background: #EEF2FF; + color: #3730A3; + font-size: 0.78rem; + font-weight: 800; +} + +.mcs-ticket-in_progress, +.mcs-priority-1 { + background: #FEF3C7; + color: #92400E; +} + +.mcs-ticket-resolved, +.mcs-ticket-closed, +.mcs-att-present { + background: #DCFCE7; + color: #166534; +} + +.mcs-ticket-waiting { + background: #F3E8FF; + color: #6B21A8; +} + +.mcs-priority-2 { + background: #FEE2E2; + color: #991B1B; +} + +.mcs-filterbar { + display: flex; + gap: 8px; + flex-wrap: wrap; + margin-bottom: 16px; + + span { + border: 1px solid var(--border); + background: #fff; + border-radius: 999px; + padding: 8px 12px; + color: var(--text-secondary); + font-weight: 800; + } +} + +.mcs-calendar-strip { + display: flex; + gap: 8px; + overflow-x: auto; + margin-bottom: 16px; + + span { + min-width: 62px; + border: 1px solid var(--border); + border-radius: 10px; + padding: 10px; + display: grid; + text-align: center; + font-weight: 800; + } + + small { + color: var(--success); + font-size: 0.7rem; + } +} + +.mcs-wp-form { + display: grid; + gap: 15px; + + label { + display: grid; + gap: 7px; + color: var(--text-secondary); + font-weight: 800; + } + + input, + select, + textarea { + width: 100%; + border: 1px solid var(--border); + border-radius: 10px; + padding: 12px; + color: var(--text-primary); + background: #fff; + } + + textarea { + min-height: 160px; + } +} + +.mcs-search { + width: min(420px, 100%); + border: 1px solid var(--border); + border-radius: 10px; + padding: 12px 14px; +} + +.mcs-timeline { + display: grid; + gap: 12px; +} + +.mcs-message { + border: 1px solid var(--border); + border-radius: 14px; + padding: 16px; + background: #F9FAFB; +} + +.mcs-message--support { + background: #EFF6FF; + border-color: #BFDBFE; +} + +.mcs-reply { + display: grid; + gap: 12px; + margin-top: 16px; + + textarea { + min-height: 120px; + border: 1px solid var(--border); + border-radius: 10px; + padding: 12px; + } +} + +.mcs-empty { + padding: 24px; + color: var(--text-secondary); + text-align: center; +} + +.mcs-profile-card { + text-align: center; +} + +@media (max-width: 991.98px) { + .mcs-workplace { + grid-template-columns: 1fr; + } + + .mcs-wp-sidebar { + position: static; + min-height: auto; + } + + .mcs-wp-grid--2, + .mcs-wp-grid--3, + .mcs-wp-grid--4, + .mcs-wp-two { + grid-template-columns: 1fr; + } + + .mcs-wp-content { + padding: 22px; + } + + .mcs-wp-page-head, + .mcs-wp-topbar { + align-items: flex-start; + flex-direction: column; + height: auto; + padding: 20px; + } +} diff --git a/addons/mcs_corporate_website/views/workplace_backend_views.xml b/addons/mcs_corporate_website/views/workplace_backend_views.xml new file mode 100644 index 0000000..93ba8fc --- /dev/null +++ b/addons/mcs_corporate_website/views/workplace_backend_views.xml @@ -0,0 +1,82 @@ + + + mcs.knowledge.article.tree + mcs.knowledge.article + + + + + + + + + + + + mcs.knowledge.article.form + mcs.knowledge.article + +
+ + + + + + + + + + + +
+
+
+ + Knowledge Articles + mcs.knowledge.article + tree,form + + + + mcs.announcement.tree + mcs.announcement + + + + + + + + + + + + + mcs.announcement.form + mcs.announcement + +
+ + + + + + + + + + + + + +
+
+ + Announcements + mcs.announcement + tree,form + + + + +
diff --git a/addons/mcs_corporate_website/views/workplace_templates.xml b/addons/mcs_corporate_website/views/workplace_templates.xml new file mode 100644 index 0000000..4df6593 --- /dev/null +++ b/addons/mcs_corporate_website/views/workplace_templates.xml @@ -0,0 +1,240 @@ + + + + + + + + + + + + + + + + + + + + + + + +