Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
80eac55b63 | ||
|
|
b1c4ac7ede | ||
|
|
05f9c3053d |
@@ -1,11 +1,41 @@
|
||||
class SuperAdmin::DashboardController < SuperAdmin::ApplicationController
|
||||
include ActionView::Helpers::NumberHelper
|
||||
|
||||
ALLOWED_CHART_DAYS = [7, 30].freeze
|
||||
|
||||
def index
|
||||
@data = Conversation.unscoped.group_by_day(:created_at, range: 30.days.ago..2.seconds.ago).count.to_a
|
||||
@accounts_count = number_with_delimiter(Account.count)
|
||||
@users_count = number_with_delimiter(User.count)
|
||||
@inboxes_count = number_with_delimiter(Inbox.count)
|
||||
@conversations_count = number_with_delimiter(Conversation.count)
|
||||
@chart_days = parse_chart_days
|
||||
@data = conversations_by_day
|
||||
@accounts_count = format_count(Account.count)
|
||||
@users_count = format_count(User.count)
|
||||
@inboxes_count = format_count(Inbox.count)
|
||||
@conversations_count = format_count(recent_conversations.count)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def parse_chart_days
|
||||
days = params[:chart_period].to_i
|
||||
ALLOWED_CHART_DAYS.include?(days) ? days : 7
|
||||
end
|
||||
|
||||
def chart_date_range
|
||||
(@chart_days - 1).days.ago.beginning_of_day..Time.current
|
||||
end
|
||||
|
||||
def last_30_days
|
||||
29.days.ago.beginning_of_day..Time.current
|
||||
end
|
||||
|
||||
def recent_conversations
|
||||
Conversation.unscoped.where(created_at: last_30_days)
|
||||
end
|
||||
|
||||
def conversations_by_day
|
||||
Conversation.unscoped.group_by_day(:created_at, range: chart_date_range, default_value: 0).count.to_a
|
||||
end
|
||||
|
||||
def format_count(count)
|
||||
number_with_delimiter(count)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -31,8 +31,8 @@ class AccountDashboard < Administrate::BaseDashboard
|
||||
updated_at: Field::DateTime,
|
||||
users: CountField,
|
||||
conversations: CountField,
|
||||
locale: Field::Select.with_options(collection: LANGUAGES_CONFIG.map { |_x, y| y[:iso_639_1_code] }),
|
||||
status: Field::Select.with_options(collection: [%w[Active active], %w[Suspended suspended]]),
|
||||
locale: LocaleField,
|
||||
status: StatusField,
|
||||
account_users: Field::HasMany,
|
||||
custom_attributes: Field::String
|
||||
}.merge(enterprise_attribute_types).freeze
|
||||
@@ -45,10 +45,9 @@ class AccountDashboard < Administrate::BaseDashboard
|
||||
COLLECTION_ATTRIBUTES = %i[
|
||||
id
|
||||
name
|
||||
locale
|
||||
users
|
||||
conversations
|
||||
status
|
||||
users
|
||||
locale
|
||||
].freeze
|
||||
|
||||
# SHOW_PAGE_ATTRIBUTES
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
require 'administrate/field/base'
|
||||
|
||||
class LocaleField < Administrate::Field::Base
|
||||
def to_s
|
||||
language = LANGUAGES_CONFIG.find { |_key, val| val[:iso_639_1_code] == data }
|
||||
language ? language[1][:name] : data
|
||||
end
|
||||
|
||||
def selectable_options
|
||||
LANGUAGES_CONFIG.map { |_key, val| [val[:name], val[:iso_639_1_code]] }
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,15 @@
|
||||
require 'administrate/field/base'
|
||||
|
||||
class StatusField < Administrate::Field::Base
|
||||
def to_s
|
||||
data.to_s.capitalize
|
||||
end
|
||||
|
||||
def active?
|
||||
data.to_s == 'active'
|
||||
end
|
||||
|
||||
def selectable_options
|
||||
[%w[Active active], %w[Suspended suspended]]
|
||||
end
|
||||
end
|
||||
@@ -9,7 +9,7 @@ module SuperAdmin::NavigationHelper
|
||||
end
|
||||
|
||||
# Add general at the beginning
|
||||
general_feature = [['general', { 'config_key' => 'general', 'name' => 'General' }]]
|
||||
general_feature = [['general', { 'config_key' => 'general', 'name' => 'General', 'icon' => 'icon-gear' }]]
|
||||
|
||||
general_feature + features.to_a
|
||||
end
|
||||
|
||||
@@ -13,28 +13,30 @@ defineProps({
|
||||
|
||||
<template>
|
||||
<header
|
||||
class="flex items-center px-8 py-4 bg-white border-b border-slate-100"
|
||||
class="sticky top-0 z-10 bg-n-background border-b border-n-weak"
|
||||
role="banner"
|
||||
>
|
||||
<a :href="responseSourcePath" class="text-woot-500 hover:underline mr-4">
|
||||
{{ 'Back' }}
|
||||
</a>
|
||||
<div
|
||||
class="border border-solid border-slate-100 text-slate-700 mr-4 p-2 rounded-full"
|
||||
>
|
||||
<svg width="24" height="24"><use xlink:href="#icon-mist-fill" /></svg>
|
||||
</div>
|
||||
<div class="flex flex-col h-14 justify-center">
|
||||
<h1 id="page-title" class="text-base font-medium text-slate-900">
|
||||
{{ 'Robin AI playground' }}
|
||||
</h1>
|
||||
<p class="text-sm text-slate-600">
|
||||
{{ 'Chat with the source' }}
|
||||
<span class="font-medium">
|
||||
{{ responseSourceName }}
|
||||
</span>
|
||||
{{ 'and evaluate it’s efficiency.' }}
|
||||
</p>
|
||||
<div class="flex items-center h-16 mx-auto max-w-[60rem]">
|
||||
<a :href="responseSourcePath" class="text-woot-500 hover:underline mr-4">
|
||||
Back
|
||||
</a>
|
||||
<div
|
||||
class="border border-solid border-n-weak text-n-slate-11 mr-4 p-2 rounded-full"
|
||||
>
|
||||
<svg width="24" height="24"><use xlink:href="#icon-mist-fill" /></svg>
|
||||
</div>
|
||||
<div class="flex flex-col justify-center">
|
||||
<h1 id="page-title" class="text-lg font-medium text-n-slate-12">
|
||||
Robin AI playground
|
||||
</h1>
|
||||
<p class="text-sm text-n-slate-11">
|
||||
Chat with the source
|
||||
<span class="font-medium text-n-slate-12">
|
||||
{{ responseSourceName }}
|
||||
</span>
|
||||
and evaluate it's efficiency.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
</template>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<script setup>
|
||||
import { computed } from 'vue';
|
||||
/* eslint-disable vue/no-bare-strings-in-template */
|
||||
import { computed, ref } from 'vue';
|
||||
import BarChart from 'shared/components/charts/BarChart.vue';
|
||||
|
||||
const props = defineProps({
|
||||
componentData: {
|
||||
type: Object,
|
||||
@@ -8,11 +10,32 @@ const props = defineProps({
|
||||
},
|
||||
});
|
||||
|
||||
const chartFilterOptions = [
|
||||
{ value: '7', label: 'Last 7d' },
|
||||
{ value: '30', label: 'Last 30d' },
|
||||
];
|
||||
|
||||
const selectedChartFilter = ref(
|
||||
props.componentData.chartDays?.toString() || '7'
|
||||
);
|
||||
|
||||
const onChartFilterChange = event => {
|
||||
const period = event.target.value;
|
||||
const url = new URL(window.location.href);
|
||||
url.searchParams.set('chart_period', period);
|
||||
window.location.href = url.toString();
|
||||
};
|
||||
|
||||
const formatDate = dateString => {
|
||||
const date = new Date(dateString);
|
||||
return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
|
||||
};
|
||||
|
||||
const prepareData = sourceData => {
|
||||
var labels = [];
|
||||
var data = [];
|
||||
const labels = [];
|
||||
const data = [];
|
||||
sourceData.forEach(item => {
|
||||
labels.push(item[0]);
|
||||
labels.push(formatDate(item[0]));
|
||||
data.push(item[1]);
|
||||
});
|
||||
return {
|
||||
@@ -38,38 +61,98 @@ const { accountsCount, usersCount, inboxesCount, conversationsCount } =
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="w-full h-full">
|
||||
<header class="main-content__header" role="banner">
|
||||
<h1 id="page-title" class="main-content__page-title">
|
||||
{{ 'Admin Dashboard' }}
|
||||
</h1>
|
||||
</header>
|
||||
|
||||
<section class="main-content__body main-content__body--flush">
|
||||
<div class="report--list">
|
||||
<div class="report-card">
|
||||
<div class="metric">{{ accountsCount }}</div>
|
||||
<div>{{ 'Accounts' }}</div>
|
||||
</div>
|
||||
<div class="report-card">
|
||||
<div class="metric">{{ usersCount }}</div>
|
||||
<div>{{ 'Users' }}</div>
|
||||
</div>
|
||||
<div class="report-card">
|
||||
<div class="metric">{{ inboxesCount }}</div>
|
||||
<div>{{ 'Inboxes' }}</div>
|
||||
</div>
|
||||
<div class="report-card">
|
||||
<div class="metric">{{ conversationsCount }}</div>
|
||||
<div>{{ 'Conversations' }}</div>
|
||||
<section class="flex flex-col w-full h-full">
|
||||
<header
|
||||
class="sticky top-0 z-10 bg-n-background border-b border-n-weak"
|
||||
role="banner"
|
||||
>
|
||||
<div
|
||||
class="flex items-center justify-between w-full h-16 mx-auto max-w-[60rem]"
|
||||
>
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="border border-n-weak p-2 rounded-full text-n-slate-11">
|
||||
<svg width="24" height="24">
|
||||
<use xlink:href="#icon-layout-dashboard" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="flex flex-col justify-center">
|
||||
<h1
|
||||
id="page-title"
|
||||
class="text-base font-medium tracking-tight text-n-slate-12"
|
||||
>
|
||||
Admin Dashboard
|
||||
</h1>
|
||||
<p class="text-xs text-n-slate-11 m-0">
|
||||
Accounts, users, and conversation metrics
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- eslint-disable vue/no-static-inline-styles -->
|
||||
<BarChart
|
||||
class="p-8 w-full"
|
||||
:collection="chartData"
|
||||
style="max-height: 500px"
|
||||
/>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="flex-1 px-6 overflow-y-auto">
|
||||
<div class="w-full mx-auto max-w-[60rem] py-8">
|
||||
<div class="grid grid-cols-2 md:grid-cols-4 gap-4 mb-8">
|
||||
<div
|
||||
class="p-4 rounded-xl bg-n-solid-2 outline outline-1 outline-n-container shadow-sm"
|
||||
>
|
||||
<div class="text-3xl font-semibold text-n-slate-12">
|
||||
{{ accountsCount }}
|
||||
</div>
|
||||
<div class="text-sm text-n-slate-11">Accounts</div>
|
||||
</div>
|
||||
<div
|
||||
class="p-4 rounded-xl bg-n-solid-2 outline outline-1 outline-n-container shadow-sm"
|
||||
>
|
||||
<div class="text-3xl font-semibold text-n-slate-12">
|
||||
{{ usersCount }}
|
||||
</div>
|
||||
<div class="text-sm text-n-slate-11">Users</div>
|
||||
</div>
|
||||
<div
|
||||
class="p-4 rounded-xl bg-n-solid-2 outline outline-1 outline-n-container shadow-sm"
|
||||
>
|
||||
<div class="text-3xl font-semibold text-n-slate-12">
|
||||
{{ inboxesCount }}
|
||||
</div>
|
||||
<div class="text-sm text-n-slate-11">Inboxes</div>
|
||||
</div>
|
||||
<div
|
||||
class="p-4 rounded-xl bg-n-solid-2 outline outline-1 outline-n-container shadow-sm"
|
||||
>
|
||||
<div class="text-3xl font-semibold text-n-slate-12">
|
||||
{{ conversationsCount }}
|
||||
</div>
|
||||
<div class="text-sm text-n-slate-11">Conversations (30d)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="px-6 pt-4 pb-6 rounded-xl bg-n-solid-2 outline outline-1 outline-n-container shadow-sm"
|
||||
>
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div class="text-base font-semibold text-n-slate-12">
|
||||
Conversations
|
||||
</div>
|
||||
<select
|
||||
v-model="selectedChartFilter"
|
||||
class="w-auto px-3 py-1.5 text-sm rounded-lg border border-n-weak bg-n-background text-n-slate-12 cursor-pointer focus:outline-none focus:ring-2 focus:ring-n-brand"
|
||||
@change="onChartFilterChange"
|
||||
>
|
||||
<option
|
||||
v-for="option in chartFilterOptions"
|
||||
:key="option.value"
|
||||
:value="option.value"
|
||||
>
|
||||
{{ option.label }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="h-[300px]">
|
||||
<BarChart class="w-full h-full" :collection="chartData" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
@@ -99,37 +99,41 @@ export default {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="flex flex-col w-full h-full bg-slate-25">
|
||||
<section class="flex flex-col w-full h-full bg-n-background">
|
||||
<PlaygroundHeader
|
||||
:response-source-name="componentData.responseSourceName"
|
||||
:response-source-path="componentData.responseSourcePath"
|
||||
/>
|
||||
<div class="flex-1 px-8 py-4 overflow-auto">
|
||||
<div
|
||||
v-for="message in messages"
|
||||
:id="`message-${message.id}`"
|
||||
:key="message.id"
|
||||
>
|
||||
<UserMessage
|
||||
v-if="message.type === 'User'"
|
||||
:message="formatMessage(message.content)"
|
||||
/>
|
||||
<BotMessage v-else :message="formatMessage(message.content)" />
|
||||
<div class="flex-1 px-6 py-4 overflow-auto">
|
||||
<div class="w-full mx-auto max-w-[60rem]">
|
||||
<div
|
||||
v-for="message in messages"
|
||||
:id="`message-${message.id}`"
|
||||
:key="message.id"
|
||||
>
|
||||
<UserMessage
|
||||
v-if="message.type === 'User'"
|
||||
:message="formatMessage(message.content)"
|
||||
/>
|
||||
<BotMessage v-else :message="formatMessage(message.content)" />
|
||||
</div>
|
||||
<TypingIndicator v-if="isWaiting" />
|
||||
</div>
|
||||
<TypingIndicator v-if="isWaiting" />
|
||||
</div>
|
||||
<div class="w-full px-8 py-6">
|
||||
<textarea
|
||||
ref="messageInput"
|
||||
v-model="messageContent"
|
||||
:rows="4"
|
||||
class="resize-none block p-2.5 w-full text-sm text-gray-900 bg-gray-50 rounded-lg border !outline-2 border-slate-100 focus:ring-woot-500 focus:border-woot-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-woot-500 dark:focus:border-woot-500"
|
||||
placeholder="Type a message... [CMD/CTRL + Enter to send]"
|
||||
autofocus
|
||||
autocomplete="off"
|
||||
@keydown.meta.enter="onMessageSend"
|
||||
@keydown.ctrl.enter="onMessageSend"
|
||||
/>
|
||||
<div class="sticky bottom-0 z-10 px-6 py-6 bg-n-background">
|
||||
<div class="w-full mx-auto max-w-[60rem]">
|
||||
<textarea
|
||||
ref="messageInput"
|
||||
v-model="messageContent"
|
||||
:rows="4"
|
||||
class="resize-none block p-3 w-full text-sm text-n-slate-12 bg-n-solid-2 rounded-xl border border-n-weak focus:ring-2 focus:ring-woot-500 focus:border-woot-500 outline-none"
|
||||
placeholder="Type a message... [CMD/CTRL + Enter to send]"
|
||||
autofocus
|
||||
autocomplete="off"
|
||||
@keydown.meta.enter="onMessageSend"
|
||||
@keydown.ctrl.enter="onMessageSend"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
@@ -1 +1 @@
|
||||
<%= image_tag field.avatar_url if field.avatar_url.present? %>
|
||||
<%= image_tag field.avatar_url, class: "w-8 h-8 rounded-full" if field.avatar_url.present? %>
|
||||
|
||||
@@ -16,11 +16,10 @@ that displays all possible records to associate with.
|
||||
[1]: http://www.rubydoc.info/gems/administrate/Administrate/Field/BelongsTo
|
||||
%>
|
||||
|
||||
<div class="field-unit__label">
|
||||
<%= f.label field.permitted_attribute %>
|
||||
</div>
|
||||
<div class="field-unit__field">
|
||||
<div class="flex flex-col gap-1">
|
||||
<%= f.label field.permitted_attribute, class: "text-sm font-medium text-n-slate-11" %>
|
||||
<%= f.select(field.permitted_attribute,
|
||||
options_for_select(field.associated_resource_options, field.selected_option),
|
||||
include_blank: field.include_blank_option) %>
|
||||
{ include_blank: field.include_blank_option },
|
||||
{ class: "h-9 px-3 min-w-[200px] text-sm text-n-slate-12 bg-n-solid-2 border border-n-weak rounded-lg focus:ring-2 focus:ring-woot-500 focus:border-woot-500 outline-none" }) %>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<div class="flex flex-col gap-1 field-unit--belongs-to-search">
|
||||
<%= f.label field.permitted_attribute, class: "text-sm font-medium text-n-slate-11" %>
|
||||
<%= f.select(field.permitted_attribute,
|
||||
nil,
|
||||
{ include_blank: true },
|
||||
class: "h-9 px-3 min-w-[200px] text-sm text-n-slate-12 bg-n-solid-2 border border-n-weak rounded-lg focus:ring-2 focus:ring-woot-500 focus:border-woot-500 outline-none selectize-input",
|
||||
'data-url': polymorphic_url([namespace, field.associated_class], format: :json)) do %>
|
||||
<%= options_for_select(field.associated_resource_options, field.selected_option) %>
|
||||
<% end %>
|
||||
</div>
|
||||
@@ -0,0 +1,7 @@
|
||||
<div class="flex items-center gap-2">
|
||||
<%= f.check_box(
|
||||
field.attribute,
|
||||
class: "h-4 w-4 text-woot-500 bg-n-solid-2 border border-n-weak rounded focus:ring-2 focus:ring-woot-500 focus:ring-offset-0"
|
||||
) %>
|
||||
<%= f.label field.attribute, class: "text-sm font-medium text-n-slate-12" %>
|
||||
</div>
|
||||
@@ -0,0 +1,8 @@
|
||||
<div class="flex flex-col gap-1">
|
||||
<%= f.label field.attribute, class: "text-sm font-medium text-n-slate-11" %>
|
||||
<%= f.email_field(
|
||||
field.attribute,
|
||||
value: field.data,
|
||||
class: "h-9 px-3 text-sm text-n-slate-12 bg-n-solid-2 border border-n-weak rounded-lg focus:ring-2 focus:ring-woot-500 focus:border-woot-500 outline-none"
|
||||
) %>
|
||||
</div>
|
||||
@@ -0,0 +1,9 @@
|
||||
<div class="flex flex-col gap-1">
|
||||
<%= f.label field.attribute, class: "text-sm font-medium text-n-slate-11" %>
|
||||
<%= f.select(
|
||||
field.attribute,
|
||||
options_for_select(field.selectable_options, field.data),
|
||||
{ include_blank: false },
|
||||
{ class: "h-9 px-3 min-w-[120px] text-sm text-n-slate-12 bg-n-solid-2 border border-n-weak rounded-lg focus:ring-2 focus:ring-woot-500 focus:border-woot-500 outline-none" }
|
||||
) %>
|
||||
</div>
|
||||
@@ -0,0 +1,3 @@
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded-md text-xs font-medium bg-n-alpha-2 text-n-slate-11">
|
||||
<%= field.to_s %>
|
||||
</span>
|
||||
@@ -0,0 +1 @@
|
||||
<%= field.to_s %>
|
||||
@@ -0,0 +1,8 @@
|
||||
<div class="flex flex-col gap-1">
|
||||
<%= f.label field.attribute, class: "text-sm font-medium text-n-slate-11" %>
|
||||
<%= f.number_field(
|
||||
field.attribute,
|
||||
value: field.data,
|
||||
class: "h-9 px-3 text-sm text-n-slate-12 bg-n-solid-2 border border-n-weak rounded-lg focus:ring-2 focus:ring-woot-500 focus:border-woot-500 outline-none"
|
||||
) %>
|
||||
</div>
|
||||
@@ -0,0 +1,7 @@
|
||||
<div class="flex flex-col gap-1">
|
||||
<%= f.label field.attribute, class: "text-sm font-medium text-n-slate-11" %>
|
||||
<%= f.password_field(
|
||||
field.attribute,
|
||||
class: "h-9 px-3 text-sm text-n-slate-12 bg-n-solid-2 border border-n-weak rounded-lg focus:ring-2 focus:ring-woot-500 focus:border-woot-500 outline-none"
|
||||
) %>
|
||||
</div>
|
||||
@@ -0,0 +1,9 @@
|
||||
<div class="flex flex-col gap-1">
|
||||
<%= f.label field.attribute, class: "text-sm font-medium text-n-slate-11" %>
|
||||
<%= f.select(
|
||||
field.attribute,
|
||||
options_for_select(field.selectable_options, field.data),
|
||||
{ include_blank: field.include_blank_option },
|
||||
{ class: "h-9 px-3 min-w-[120px] text-sm text-n-slate-12 bg-n-solid-2 border border-n-weak rounded-lg focus:ring-2 focus:ring-woot-500 focus:border-woot-500 outline-none" }
|
||||
) %>
|
||||
</div>
|
||||
@@ -0,0 +1,9 @@
|
||||
<div class="flex flex-col gap-1">
|
||||
<%= f.label field.attribute, class: "text-sm font-medium text-n-slate-11" %>
|
||||
<%= f.select(
|
||||
field.attribute,
|
||||
options_for_select(field.selectable_options, field.data),
|
||||
{ include_blank: false },
|
||||
{ class: "h-9 px-3 min-w-[120px] text-sm text-n-slate-12 bg-n-solid-2 border border-n-weak rounded-lg focus:ring-2 focus:ring-woot-500 focus:border-woot-500 outline-none" }
|
||||
) %>
|
||||
</div>
|
||||
@@ -0,0 +1,3 @@
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded-md text-xs font-medium <%= field.active? ? 'bg-n-teal-3 text-n-teal-11' : 'bg-n-ruby-3 text-n-ruby-11' %>">
|
||||
<%= field.to_s %>
|
||||
</span>
|
||||
@@ -0,0 +1,3 @@
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded-md text-xs font-medium <%= field.active? ? 'bg-n-teal-3 text-n-teal-11' : 'bg-n-ruby-3 text-n-ruby-11' %>">
|
||||
<%= field.to_s %>
|
||||
</span>
|
||||
@@ -0,0 +1,8 @@
|
||||
<div class="flex flex-col gap-1">
|
||||
<%= f.label field.attribute, class: "text-sm font-medium text-n-slate-11" %>
|
||||
<%= f.text_field(
|
||||
field.attribute,
|
||||
value: field.data,
|
||||
class: "h-9 px-3 text-sm text-n-slate-12 bg-n-solid-2 border border-n-weak rounded-lg focus:ring-2 focus:ring-woot-500 focus:border-woot-500 outline-none"
|
||||
) %>
|
||||
</div>
|
||||
@@ -0,0 +1,9 @@
|
||||
<div class="flex flex-col gap-1">
|
||||
<%= f.label field.attribute, class: "text-sm font-medium text-n-slate-11" %>
|
||||
<%= f.text_area(
|
||||
field.attribute,
|
||||
value: field.data,
|
||||
rows: 4,
|
||||
class: "px-3 py-2 text-sm text-n-slate-12 bg-n-solid-2 border border-n-weak rounded-lg focus:ring-2 focus:ring-woot-500 focus:border-woot-500 outline-none resize-y"
|
||||
) %>
|
||||
</div>
|
||||
@@ -30,7 +30,7 @@ By default, it renders:
|
||||
<%= render "icons" %>
|
||||
<div class="flex w-full h-full">
|
||||
<%= render "navigation" -%>
|
||||
<main class="w-full overflow-auto" role="main">
|
||||
<main class="w-full overflow-auto bg-n-background" role="main">
|
||||
<%= render "flashes" -%>
|
||||
<%= yield %>
|
||||
</main>
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
<section class="main-content__body">
|
||||
<hr/>
|
||||
<%= form_for([:reset_cache, namespace, page.resource], method: :post, html: { class: "form" }) do |f| %>
|
||||
<div class="form-actions">
|
||||
<p class="pb-3">This will clear the IndexedDB cache keys from redis. <br>The next load will fetch the data from backend.</p>
|
||||
<%= f.submit 'Reset Frontend Cache' %>
|
||||
</div>
|
||||
<div class="px-6 py-4">
|
||||
<h3 class="text-sm font-medium text-n-slate-12 mb-2">Reset Frontend Cache</h3>
|
||||
<p class="text-xs text-n-slate-11 mb-3">This will clear the IndexedDB cache keys from redis. The next load will fetch the data from backend.</p>
|
||||
<%= form_for([:reset_cache, namespace, page.resource], method: :post) do |f| %>
|
||||
<%= f.submit 'Reset Frontend Cache', class: "inline-flex items-center justify-center h-8 px-3 text-sm font-medium text-n-slate-12 bg-n-alpha-2 rounded-lg hover:bg-n-alpha-3 transition-colors cursor-pointer" %>
|
||||
<% end %>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
<% if ENV.fetch('ENABLE_ACCOUNT_SEEDING', !Rails.env.production?) %>
|
||||
<section class="main-content__body">
|
||||
<hr/>
|
||||
<%= form_for([:seed, namespace, page.resource], method: :post, html: { class: "form" }) do |f| %>
|
||||
|
||||
<div class="form-actions">
|
||||
<div class="pb-3">
|
||||
<p>Click the button to generate seed data into this account for demos.</p>
|
||||
<p class="text-color-red">Note: This will clear all the existing data in this account.</p>
|
||||
</div>
|
||||
<%= f.submit 'Generate Seed Data' %>
|
||||
</div>
|
||||
<% if ENV.fetch('ENABLE_ACCOUNT_SEEDING', !Rails.env.production?) %>
|
||||
<div class="px-6 py-4">
|
||||
<h3 class="text-sm font-medium text-n-slate-12 mb-2">Generate Seed Data</h3>
|
||||
<p class="text-xs text-n-slate-11 mb-1">Click the button to generate seed data into this account for demos.</p>
|
||||
<p class="text-xs text-ruby-500 mb-3">Note: This will clear all the existing data in this account.</p>
|
||||
<%= form_for([:seed, namespace, page.resource], method: :post) do |f| %>
|
||||
<%= f.submit 'Generate Seed Data', class: "inline-flex items-center justify-center h-8 px-3 text-sm font-medium text-ruby-500 bg-ruby-100 rounded-lg hover:bg-ruby-200 transition-colors cursor-pointer" %>
|
||||
<% end %>
|
||||
</section>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
@@ -15,84 +15,169 @@ as well as a link to its edit page.
|
||||
|
||||
[1]: http://www.rubydoc.info/gems/administrate/Administrate/Page/Show %>
|
||||
|
||||
<% content_for(:title) do
|
||||
t("administrate.actions.show_resource", name: page.page_title)
|
||||
end %>
|
||||
<% content_for(:title) do
|
||||
t("administrate.actions.show_resource", name: page.page_title)
|
||||
end %>
|
||||
|
||||
<header class="main-content__header" role="banner">
|
||||
<h1 class="main-content__page-title">
|
||||
<%= content_for(:title) %>
|
||||
</h1>
|
||||
<section class="flex flex-col w-full h-full">
|
||||
<header class="sticky top-0 z-10 bg-n-background border-b border-n-weak" role="banner">
|
||||
<div class="flex items-center justify-between w-full h-16 mx-auto max-w-[60rem]">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="border border-n-weak p-2 rounded-full text-n-slate-11">
|
||||
<svg width="24" height="24"><use xlink:href="#icon-building-2" /></svg>
|
||||
</div>
|
||||
<div class="flex flex-col justify-center">
|
||||
<h1 class="text-base font-medium tracking-tight text-n-slate-12">
|
||||
<%= content_for(:title) %>
|
||||
</h1>
|
||||
<p class="text-xs text-n-slate-11 m-0">Billing, features, and user management</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<%= if accessible_action?(page.resource, :edit)
|
||||
link_to("Edit", [:edit, namespace, page.resource], class: "button")
|
||||
end %>
|
||||
<div class="flex items-center gap-2">
|
||||
<% if accessible_action?(page.resource, :edit) %>
|
||||
<%= link_to("Edit", [:edit, namespace, page.resource], class: "inline-flex items-center justify-center h-8 px-3 text-sm font-medium text-white bg-woot-500 rounded-lg hover:bg-woot-600 transition-colors") %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section class="main-content__body">
|
||||
<div class="pr-16">
|
||||
<% page.attributes.each do |title, attributes| %>
|
||||
<% if title.present? && title == 'all_features' %>
|
||||
<% regular_features, premium_features =
|
||||
attributes.partition do |attr|
|
||||
!SuperAdmin::AccountFeaturesHelper.account_premium_features.include?(
|
||||
attr.data.keys.first,
|
||||
)
|
||||
end %>
|
||||
|
||||
<div class="space-y-4">
|
||||
<% regular_features.each do |attribute| %>
|
||||
<div class="attribute-label" id="<%= attribute.name %>">
|
||||
<%= t(
|
||||
"helpers.label.#{resource_name}.#{attribute.name}",
|
||||
default: page.resource.class.human_attribute_name(attribute.name),
|
||||
) %>
|
||||
</div>
|
||||
|
||||
<div class="attribute-data attribute-data--<%=attribute.html_class%>"><%= render_field attribute, page: page %></div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<hr class="my-8 border-n-weak">
|
||||
|
||||
<div class="space-y-4">
|
||||
<% premium_features.each do |attribute| %>
|
||||
<div class="attribute-label" id="<%= attribute.name %>">
|
||||
<%= t(
|
||||
"helpers.label.#{resource_name}.#{attribute.name}",
|
||||
default: page.resource.class.human_attribute_name(attribute.name),
|
||||
) %>
|
||||
</div>
|
||||
|
||||
<div class="attribute-data attribute-data--<%=attribute.html_class%>"><%= render_field attribute, page: page %></div>
|
||||
<% end %>
|
||||
</div>
|
||||
<% else %>
|
||||
<fieldset class="<%= "field-unit--nested" if title.present? %>">
|
||||
<% if title.present? %>
|
||||
<legend><%= t "helpers.label.#{page.resource_name}.#{title}", default: title %></legend>
|
||||
<% end %>
|
||||
<main class="flex-1 px-6 overflow-y-auto">
|
||||
<div class="w-full mx-auto max-w-[60rem] py-6 space-y-6">
|
||||
|
||||
<%# Basic Information Card %>
|
||||
<div class="rounded-xl bg-n-solid-2 shadow outline-1 outline outline-n-container overflow-hidden">
|
||||
<div class="px-6 py-4 border-b border-n-weak">
|
||||
<h2 class="text-base font-medium text-n-slate-12">Account Information</h2>
|
||||
</div>
|
||||
<div class="divide-y divide-n-weak">
|
||||
<% page.attributes.each do |title, attributes| %>
|
||||
<% next if title.present? %>
|
||||
<% attributes.each do |attribute| %>
|
||||
<div class="attribute-label" id="<%= attribute.name %>">
|
||||
<%= t(
|
||||
"helpers.label.#{resource_name}.#{attribute.name}",
|
||||
default: page.resource.class.human_attribute_name(attribute.name),
|
||||
) %>
|
||||
<% next if ['account_users', 'custom_attributes', 'all_features'].include?(attribute.name.to_s) %>
|
||||
<div class="grid grid-cols-[180px,1fr] items-center min-h-12 px-6">
|
||||
<span class="text-sm text-n-slate-11">
|
||||
<%= t(
|
||||
"helpers.label.#{resource_name}.#{attribute.name}",
|
||||
default: page.resource.class.human_attribute_name(attribute.name),
|
||||
) %>
|
||||
</span>
|
||||
<span class="text-sm text-n-slate-12 py-3">
|
||||
<%= render_field attribute, page: page %>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="attribute-data attribute-data--<%=attribute.html_class%>"><%= render_field attribute, page: page %></div>
|
||||
<% end %>
|
||||
</fieldset>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%# Account Users Card %>
|
||||
<% page.attributes.each do |title, attributes| %>
|
||||
<% next if title.present? %>
|
||||
<% attributes.each do |attribute| %>
|
||||
<% if attribute.name.to_s == 'account_users' && page.resource.account_users.any? %>
|
||||
<div class="rounded-xl bg-n-solid-2 shadow outline-1 outline outline-n-container overflow-hidden">
|
||||
<div class="px-6 py-4 border-b border-n-weak">
|
||||
<h2 class="text-base font-medium text-n-slate-12">Account Users</h2>
|
||||
</div>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full">
|
||||
<thead class="border-b border-n-weak">
|
||||
<tr>
|
||||
<th class="text-left py-3 !pl-6 pr-4 text-sm text-n-slate-11">Account</th>
|
||||
<th class="text-left py-3 px-4 text-sm text-n-slate-11">User</th>
|
||||
<th class="text-left py-3 px-4 text-sm text-n-slate-11">Inviter</th>
|
||||
<th class="text-left py-3 px-4 text-sm text-n-slate-11">Role</th>
|
||||
<th class="text-left py-3 pl-4 !pr-6 text-sm text-n-slate-11"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-n-weak">
|
||||
<% page.resource.account_users.each do |account_user| %>
|
||||
<tr class="hover:bg-n-alpha-1">
|
||||
<td class="py-4 !pl-6 pr-4 text-sm text-n-slate-12">
|
||||
<%= link_to "##{account_user.account_id} #{account_user.account.name}", super_admin_account_path(account_user.account), class: "text-n-slate-12 hover:underline" %>
|
||||
</td>
|
||||
<td class="py-4 px-4 text-sm text-n-slate-12">
|
||||
<%= link_to "##{account_user.user_id} #{account_user.user.name}", super_admin_user_path(account_user.user), class: "text-n-slate-12 hover:underline" %>
|
||||
</td>
|
||||
<td class="py-4 px-4 text-sm text-n-slate-11">
|
||||
<% if account_user.inviter.present? %>
|
||||
<%= link_to account_user.inviter.name, super_admin_user_path(account_user.inviter), class: "text-n-slate-12 hover:underline" %>
|
||||
<% else %>
|
||||
<span class="text-n-slate-10">---</span>
|
||||
<% end %>
|
||||
</td>
|
||||
<td class="py-4 px-4">
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded-md text-xs font-medium bg-n-alpha-2 text-n-slate-12 capitalize">
|
||||
<%= account_user.role %>
|
||||
</span>
|
||||
</td>
|
||||
<td class="py-4 pl-4 !pr-6 text-right">
|
||||
<%= link_to "Destroy", super_admin_account_user_path(account_user), method: :delete, data: { confirm: "Are you sure?" }, class: "text-sm font-medium text-n-ruby-11 hover:underline" %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<%# Custom Attributes Card %>
|
||||
<% if page.resource.custom_attributes.present? %>
|
||||
<div class="rounded-xl bg-n-solid-2 shadow outline-1 outline outline-n-container overflow-hidden">
|
||||
<div class="px-6 py-4 border-b border-n-weak">
|
||||
<h2 class="text-base font-medium text-n-slate-12">Custom Attributes</h2>
|
||||
</div>
|
||||
<div class="divide-y divide-n-weak">
|
||||
<% page.resource.custom_attributes.each do |key, value| %>
|
||||
<div class="grid grid-cols-[180px,1fr] items-start min-h-12 px-6">
|
||||
<span class="text-sm text-n-slate-11 py-3">
|
||||
<%= key.to_s.titleize %>
|
||||
</span>
|
||||
<span class="text-sm text-n-slate-12 py-3 break-all font-mono">
|
||||
<%= value %>
|
||||
</span>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%# Features Section %>
|
||||
<% page.attributes.each do |title, attributes| %>
|
||||
<% next if title.present? %>
|
||||
<% attributes.each do |attribute| %>
|
||||
<% if attribute.name.to_s == 'all_features' %>
|
||||
<div class="rounded-xl bg-n-solid-2 shadow outline-1 outline outline-n-container overflow-hidden">
|
||||
<div class="px-6 py-4 border-b border-n-weak">
|
||||
<h2 class="text-base font-medium text-n-slate-12">Features</h2>
|
||||
</div>
|
||||
<div class="p-6">
|
||||
<%= render_field attribute, page: page %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<%# Actions Card %>
|
||||
<div class="rounded-xl bg-n-solid-2 shadow outline-1 outline outline-n-container overflow-hidden">
|
||||
<div class="px-6 py-4 border-b border-n-weak">
|
||||
<h2 class="text-base font-medium text-n-slate-12">Actions</h2>
|
||||
</div>
|
||||
<div class="divide-y divide-n-weak">
|
||||
<div class="px-6 py-4">
|
||||
<h3 class="text-sm font-medium text-n-slate-12 mb-3">Add User to Account</h3>
|
||||
<%= render 'super_admin/shared/account_user_form', page: page, namespace: namespace, resource_type: 'account' %>
|
||||
</div>
|
||||
<%= render partial: "seed_data", locals: { page: page } %>
|
||||
<%= render partial: "reset_cache", locals: { page: page } %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<%= render 'super_admin/shared/account_user_form', page: page, namespace: namespace, resource_type: 'account' %>
|
||||
|
||||
<%= render partial: "seed_data", locals: { page: page } %>
|
||||
|
||||
<%= render partial: "reset_cache", locals: { page: page } %>
|
||||
</main>
|
||||
</section>
|
||||
|
||||
@@ -2,78 +2,92 @@
|
||||
Configure Settings - <%= @config.titleize %>
|
||||
<% end %>
|
||||
|
||||
<header class="main-content__header" role="banner">
|
||||
<h1 class="main-content__page-title" id="page-title">
|
||||
<%= content_for(:title) %>
|
||||
</h1>
|
||||
</header>
|
||||
|
||||
<style>
|
||||
.eye-icon.eye-hide path {
|
||||
d: path('M3 3l18 18M10.5 10.677a2 2 0 002.823 2.823M7.362 7.561C5.68 8.74 4.279 10.42 3 12c1.889 2.991 5.282 6 9 6 1.55 0 3.043-.523 4.395-1.35M12 6c4.008 0 6.701 3.009 9 6a15.66 15.66 0 01-1.078 1.5');
|
||||
}
|
||||
</style>
|
||||
|
||||
<section class="main-content__body">
|
||||
<%= form_with url: super_admin_app_config_url(config: @config) , method: :post do |form| %>
|
||||
<% @allowed_configs.each do |key| %>
|
||||
<div class="flex mb-8">
|
||||
<div class="field-unit__label">
|
||||
<%= form.label "app_config[#{key}]", @installation_configs[key]&.dig('display_title') || key %>
|
||||
<section class="flex flex-col w-full h-full">
|
||||
<header class="sticky top-0 z-10 bg-n-background border-b border-n-weak" role="banner">
|
||||
<div class="flex items-center justify-between w-full h-16 mx-auto max-w-[60rem]">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="border border-n-weak p-2 rounded-full text-n-slate-11">
|
||||
<svg width="24" height="24"><use xlink:href="#icon-zap" /></svg>
|
||||
</div>
|
||||
<div class="-mt-2 field-unit__field ">
|
||||
<% if @installation_configs[key]&.dig('type') == 'boolean' %>
|
||||
<%= form.select "app_config[#{key}]",
|
||||
[["True", true], ["False", false]],
|
||||
{ selected: ActiveModel::Type::Boolean.new.cast(@app_config[key]) },
|
||||
class: "mt-2 border border-slate-100 p-1 rounded-md"
|
||||
%>
|
||||
<% elsif @installation_configs[key]&.dig('type') == 'code' %>
|
||||
<%= form.text_area "app_config[#{key}]",
|
||||
value: @app_config[key],
|
||||
rows: 12,
|
||||
wrap: 'off',
|
||||
class: "mt-2 border font-mono text-xs border-slate-100 p-1 rounded-md overflow-scroll"
|
||||
%>
|
||||
<% elsif @installation_configs[key]&.dig('type') == 'secret' %>
|
||||
<div class="relative">
|
||||
<%= form.password_field "app_config[#{key}]",
|
||||
id: "app_config_#{key}",
|
||||
value: @app_config[key],
|
||||
class: "mt-2 border border-slate-100 p-1.5 pr-8 rounded-md w-full"
|
||||
%>
|
||||
<button
|
||||
type="button"
|
||||
class="absolute reset-base !bg-white top-1/2 !outline-0 !text-n-slate-11 -translate-y-1/2 right-2 p-1 hover:!bg-n-slate-5 rounded-sm toggle-password"
|
||||
data-target="app_config_<%= key %>"
|
||||
>
|
||||
<svg class="eye-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M12 5C5.63636 5 2 12 2 12C2 12 5.63636 19 12 19C18.3636 19 22 12 22 12C22 12 18.3636 5 12 5Z"/>
|
||||
<path d="M12 15C13.6569 15 15 13.6569 15 12C15 10.3431 13.6569 9 12 9C10.3431 9 9 10.3431 9 12C9 13.6569 10.3431 15 12 15Z"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<% elsif @installation_configs[key]&.dig('type') == 'select' && @installation_configs[key]&.dig('options').present? %>
|
||||
<%= form.select "app_config[#{key}]",
|
||||
@installation_configs[key]['options'].map { |val, label| [label, val] },
|
||||
{ selected: @app_config[key] },
|
||||
class: "mt-2 border border-slate-100 p-1 rounded-md"
|
||||
%>
|
||||
<% else %>
|
||||
<%= form.text_field "app_config[#{key}]", value: @app_config[key] %>
|
||||
<% end %>
|
||||
<%if @installation_configs[key]&.dig('description').present? %>
|
||||
<p class="pt-2 text-xs italic text-slate-400">
|
||||
<%= @installation_configs[key]&.dig('description') %>
|
||||
</p>
|
||||
<% end %>
|
||||
<div class="flex flex-col justify-center">
|
||||
<h1 class="text-base font-medium tracking-tight text-n-slate-12" id="page-title">
|
||||
<%= content_for(:title) %>
|
||||
</h1>
|
||||
<p class="text-xs text-n-slate-11 m-0">Environment and instance configuration</p>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<div class="form-actions">
|
||||
<%= form.submit "Submit" %>
|
||||
</div>
|
||||
<% end %>
|
||||
</header>
|
||||
|
||||
<main class="flex-1 px-6 overflow-y-auto">
|
||||
<div class="w-full mx-auto max-w-[60rem] py-4">
|
||||
<%= form_with url: super_admin_app_config_url(config: @config), method: :post do |form| %>
|
||||
<% @allowed_configs.each do |key| %>
|
||||
<div class="flex mb-8">
|
||||
<div class="field-unit__label">
|
||||
<%= form.label "app_config[#{key}]", @installation_configs[key]&.dig('display_title') || key %>
|
||||
</div>
|
||||
<div class="-mt-2 field-unit__field">
|
||||
<% if @installation_configs[key]&.dig('type') == 'boolean' %>
|
||||
<%= form.select "app_config[#{key}]",
|
||||
[["True", true], ["False", false]],
|
||||
{ selected: ActiveModel::Type::Boolean.new.cast(@app_config[key]) },
|
||||
class: "mt-2 border border-n-weak p-1 rounded-md bg-n-solid-2"
|
||||
%>
|
||||
<% elsif @installation_configs[key]&.dig('type') == 'code' %>
|
||||
<%= form.text_area "app_config[#{key}]",
|
||||
value: @app_config[key],
|
||||
rows: 12,
|
||||
wrap: 'off',
|
||||
class: "mt-2 border font-mono text-xs border-n-weak p-1 rounded-md overflow-scroll bg-n-solid-2"
|
||||
%>
|
||||
<% elsif @installation_configs[key]&.dig('type') == 'secret' %>
|
||||
<div class="relative">
|
||||
<%= form.password_field "app_config[#{key}]",
|
||||
id: "app_config_#{key}",
|
||||
value: @app_config[key],
|
||||
class: "mt-2 border border-n-weak p-1.5 pr-8 rounded-md w-full bg-n-solid-2"
|
||||
%>
|
||||
<button
|
||||
type="button"
|
||||
class="absolute reset-base !bg-transparent top-1/2 !outline-0 !text-n-slate-11 -translate-y-1/2 right-2 p-1 hover:!bg-n-alpha-2 rounded-sm toggle-password"
|
||||
data-target="app_config_<%= key %>"
|
||||
>
|
||||
<svg class="eye-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M12 5C5.63636 5 2 12 2 12C2 12 5.63636 19 12 19C18.3636 19 22 12 22 12C22 12 18.3636 5 12 5Z"/>
|
||||
<path d="M12 15C13.6569 15 15 13.6569 15 12C15 10.3431 13.6569 9 12 9C10.3431 9 9 10.3431 9 12C9 13.6569 10.3431 15 12 15Z"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<% elsif @installation_configs[key]&.dig('type') == 'select' && @installation_configs[key]&.dig('options').present? %>
|
||||
<%= form.select "app_config[#{key}]",
|
||||
@installation_configs[key]['options'].map { |val, label| [label, val] },
|
||||
{ selected: @app_config[key] },
|
||||
class: "mt-2 border border-n-weak p-1 rounded-md bg-n-solid-2"
|
||||
%>
|
||||
<% else %>
|
||||
<%= form.text_field "app_config[#{key}]", value: @app_config[key], class: "border border-n-weak p-1.5 rounded-md bg-n-solid-2" %>
|
||||
<% end %>
|
||||
<% if @installation_configs[key]&.dig('description').present? %>
|
||||
<p class="pt-2 text-xs italic text-n-slate-11">
|
||||
<%= @installation_configs[key]&.dig('description') %>
|
||||
</p>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<div class="pt-4">
|
||||
<%= form.submit "Submit", class: "inline-flex items-center justify-center h-8 px-4 text-sm font-medium text-white bg-woot-500 rounded-lg hover:bg-woot-600 transition-colors cursor-pointer" %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</main>
|
||||
</section>
|
||||
|
||||
<% content_for :javascript do %>
|
||||
|
||||
@@ -18,78 +18,80 @@ to display a collection of resources in an HTML table.
|
||||
[1]: http://www.rubydoc.info/gems/administrate/Administrate/Page/Collection
|
||||
%>
|
||||
|
||||
<table aria-labelledby="<%= table_title %>">
|
||||
<thead>
|
||||
<tr>
|
||||
<% collection_presenter.attribute_types.each do |attr_name, attr_type| %>
|
||||
<th class="cell-label
|
||||
cell-label--<%= attr_type.html_class %>
|
||||
cell-label--<%= collection_presenter.ordered_html_class(attr_name) %>"
|
||||
scope="col"
|
||||
role="columnheader"
|
||||
aria-sort="<%= sort_order(collection_presenter.ordered_html_class(attr_name)) %>">
|
||||
<%= link_to(sanitized_order_params(page, collection_field_name).merge(
|
||||
collection_presenter.order_params_for(attr_name, key: collection_field_name)
|
||||
)) do %>
|
||||
<%= t(
|
||||
"helpers.label.#{collection_presenter.resource_name}.#{attr_name}",
|
||||
default: attr_name.to_s,
|
||||
).titleize %>
|
||||
<% if collection_presenter.ordered_by?(attr_name) %>
|
||||
<span class="cell-label__sort-indicator cell-label__sort-indicator--<%= collection_presenter.ordered_html_class(attr_name) %>">
|
||||
<svg aria-hidden="true">
|
||||
<use xlink:href="#icon-up-caret" />
|
||||
</svg>
|
||||
</span>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full" aria-labelledby="<%= table_title %>">
|
||||
<thead class="border-b border-n-weak">
|
||||
<tr>
|
||||
<% collection_presenter.attribute_types.each_with_index do |(attr_name, attr_type), index| %>
|
||||
<th class="text-left py-3 px-4 text-sm text-n-slate-11 first:!pl-3 last:!pr-3"
|
||||
scope="col"
|
||||
role="columnheader"
|
||||
aria-sort="<%= sort_order(collection_presenter.ordered_html_class(attr_name)) %>">
|
||||
<%= link_to(sanitized_order_params(page, collection_field_name).merge(
|
||||
collection_presenter.order_params_for(attr_name, key: collection_field_name)
|
||||
), class: "inline-flex items-center gap-1 hover:text-n-slate-12") do %>
|
||||
<%= t(
|
||||
"helpers.label.#{collection_presenter.resource_name}.#{attr_name}",
|
||||
default: attr_name.to_s,
|
||||
).titleize %>
|
||||
<% if collection_presenter.ordered_by?(attr_name) %>
|
||||
<span class="<%= collection_presenter.ordered_html_class(attr_name) == 'asc' ? '' : 'rotate-180' %>">
|
||||
<svg class="w-3 h-3" aria-hidden="true">
|
||||
<use xlink:href="#icon-up-caret" />
|
||||
</svg>
|
||||
</span>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</th>
|
||||
<% end %>
|
||||
<% [existing_action?(collection_presenter.resource_name, :edit),
|
||||
existing_action?(collection_presenter.resource_name, :destroy)].count(true).times do %>
|
||||
<th scope="col"></th>
|
||||
<% end %>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<% resources.each do |resource| %>
|
||||
<tr class="js-table-row"
|
||||
tabindex="0"
|
||||
<% if existing_action? collection_presenter.resource_name, :show %>
|
||||
<%= %(role=link data-url=#{polymorphic_path([namespace, resource])}) %>
|
||||
<% end %>
|
||||
>
|
||||
<% collection_presenter.attributes_for(resource).each do |attribute| %>
|
||||
<td class="cell-data cell-data--<%= attribute.html_class %>">
|
||||
<% if authorized_action? resource, :show -%>
|
||||
<a href="<%= polymorphic_path([namespace, resource]) -%>"
|
||||
class="action-show"
|
||||
>
|
||||
<%= render_field attribute %>
|
||||
</a>
|
||||
<% end -%>
|
||||
</td>
|
||||
</th>
|
||||
<% end %>
|
||||
|
||||
<% if existing_action? collection_presenter.resource_name, :edit %>
|
||||
<td><%= link_to(
|
||||
t("administrate.actions.edit"),
|
||||
[:edit, namespace, resource],
|
||||
class: "action-edit",
|
||||
) if authorized_action? resource, :edit%></td>
|
||||
<% if existing_action?(collection_presenter.resource_name, :edit) %>
|
||||
<th scope="col"></th>
|
||||
<% end %>
|
||||
|
||||
<% if existing_action? collection_presenter.resource_name, :destroy %>
|
||||
<td><%= link_to(
|
||||
t("administrate.actions.destroy"),
|
||||
[namespace, resource],
|
||||
class: "text-color-red",
|
||||
method: :delete,
|
||||
data: { confirm: t("administrate.actions.confirm") }
|
||||
) if authorized_action? resource, :destroy %></td>
|
||||
<% if existing_action?(collection_presenter.resource_name, :destroy) %>
|
||||
<th scope="col" class="pr-3"></th>
|
||||
<% end %>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
</thead>
|
||||
|
||||
<tbody class="divide-y divide-n-weak">
|
||||
<% resources.each do |resource| %>
|
||||
<tr class="js-table-row hover:bg-n-alpha-1 transition-colors"
|
||||
tabindex="0"
|
||||
<% if existing_action? collection_presenter.resource_name, :show %>
|
||||
<%= %(role=link data-url=#{polymorphic_path([namespace, resource])}) %>
|
||||
<% end %>
|
||||
>
|
||||
<% collection_presenter.attributes_for(resource).each_with_index do |attribute, index| %>
|
||||
<td class="py-4 px-4 text-sm text-n-slate-12 first:!pl-3 last:!pr-3">
|
||||
<% if authorized_action? resource, :show -%>
|
||||
<a href="<%= polymorphic_path([namespace, resource]) -%>"
|
||||
class="hover:underline"
|
||||
>
|
||||
<%= render_field attribute %>
|
||||
</a>
|
||||
<% end -%>
|
||||
</td>
|
||||
<% end %>
|
||||
|
||||
<% if existing_action?(collection_presenter.resource_name, :edit) %>
|
||||
<td class="py-4 px-4 text-right"><%= link_to(
|
||||
t("administrate.actions.edit"),
|
||||
[:edit, namespace, resource],
|
||||
class: "text-sm font-medium text-n-brand hover:underline",
|
||||
) if authorized_action? resource, :edit%></td>
|
||||
<% end %>
|
||||
|
||||
<% if existing_action?(collection_presenter.resource_name, :destroy) %>
|
||||
<td class="py-4 px-4 !pr-3 text-right"><%= link_to(
|
||||
t("administrate.actions.destroy"),
|
||||
[namespace, resource],
|
||||
class: "text-sm font-medium text-n-ruby-11 hover:underline",
|
||||
method: :delete,
|
||||
data: { confirm: t("administrate.actions.confirm") }
|
||||
) if authorized_action? resource, :destroy %></td>
|
||||
<% end %>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@@ -28,27 +28,23 @@ for a collection of resources.
|
||||
%>
|
||||
|
||||
<% if dashboard_class.const_defined?(:COLLECTION_FILTERS) && !dashboard_class::COLLECTION_FILTERS.empty? %>
|
||||
<div class="flex items-center bg-gray-100 border-0 rounded-md shadow-none relative w-[260px]">
|
||||
<div class="flex items-center h-10 px-2 w-full">
|
||||
<div class="flex items-center justify-center flex-shrink-0 mr-2 text-gray-500" title="Filter by">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3"></polygon>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="flex-1 h-full min-w-0 relative">
|
||||
<select id="filter-select" class="appearance-none bg-transparent border-0 text-gray-700 cursor-pointer text-sm h-full overflow-hidden truncate whitespace-nowrap w-full pr-7 pl-0 py-2 focus:outline-none bg-[url('data:image/svg+xml,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 width=%2712%27 height=%2712%27 viewBox=%270 0 12 12%27%3E%3Cpath fill=%27%23293f54%27 d=%27M6 9L1 4h10z%27/%3E%3C/svg%3E')] bg-[right_0.25rem_center] bg-no-repeat bg-[length:0.75rem]" onchange="applyFilter(this.value)">
|
||||
<option value="">All records</option>
|
||||
<% dashboard_class::COLLECTION_FILTERS.each do |filter_name, _| %>
|
||||
<option value="<%= filter_name %>" <%= 'selected' if filter_name.to_s == current_filter %>>
|
||||
<%= filter_name.to_s.titleize %>
|
||||
</option>
|
||||
<% end %>
|
||||
</select>
|
||||
<% if current_filter %>
|
||||
<a href="?" class="flex items-center justify-center rounded-full text-gray-500 text-xl font-bold h-[18px] w-[18px] leading-none absolute right-5 top-1/2 -translate-y-1/2 no-underline z-2 hover:text-gray-900" title="Clear filter">×</a>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="relative flex items-center">
|
||||
<div class="absolute left-3 text-n-slate-10">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3"></polygon>
|
||||
</svg>
|
||||
</div>
|
||||
<select id="filter-select" class="h-9 pl-9 pr-8 text-sm text-n-slate-12 bg-n-solid-2 border border-n-weak rounded-lg cursor-pointer appearance-none focus:ring-2 focus:ring-woot-500 focus:border-woot-500 outline-none bg-[url('data:image/svg+xml,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 width=%2712%27 height=%2712%27 viewBox=%270 0 12 12%27%3E%3Cpath fill=%27%236b7280%27 d=%27M6 9L1 4h10z%27/%3E%3C/svg%3E')] bg-[right_0.5rem_center] bg-no-repeat bg-[length:0.75rem]" onchange="applyFilter(this.value)">
|
||||
<option value="">All records</option>
|
||||
<% dashboard_class::COLLECTION_FILTERS.each do |filter_name, _| %>
|
||||
<option value="<%= filter_name %>" <%= 'selected' if filter_name.to_s == current_filter %>>
|
||||
<%= filter_name.to_s.titleize %>
|
||||
</option>
|
||||
<% end %>
|
||||
</select>
|
||||
<% if current_filter %>
|
||||
<a href="?" class="absolute right-6 text-n-slate-10 hover:text-n-slate-12 text-lg font-medium" title="Clear filter">×</a>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
</symbol>
|
||||
|
||||
<symbol id="icon-refresh-line" viewBox="0 0 16 16">
|
||||
<path d="M4.0778 3.4598C5.16654 2.51639 6.55939 1.99799 8 2C11.3138 2 14 4.6862 14 8C14 9.2816 13.598 10.4696 12.914 11.444L11 8H12.8C12.8001 7.05897 12.5235 6.13868 12.0048 5.35355C11.486 4.56842 10.748 3.95309 9.88231 3.58407C9.01666 3.21505 8.06163 3.10862 7.13597 3.27801C6.21032 3.4474 5.35487 3.88514 4.676 4.5368L4.0778 3.4598ZM11.9222 12.5402C10.8335 13.4836 9.44061 14.002 8 14C4.6862 14 2 11.3138 2 8C2 6.7184 2.402 5.5304 3.086 4.556L5 8H3.2C3.19992 8.94102 3.47645 9.86132 3.9952 10.6464C4.51395 11.4316 5.25204 12.0469 6.11769 12.4159C6.98334 12.7849 7.93837 12.8914 8.86403 12.722C9.78968 12.5526 10.6451 12.1149 11.324 11.4632L11.9222 12.5402Z" fill="#1F93FF"/>
|
||||
<path d="M4.0778 3.4598C5.16654 2.51639 6.55939 1.99799 8 2C11.3138 2 14 4.6862 14 8C14 9.2816 13.598 10.4696 12.914 11.444L11 8H12.8C12.8001 7.05897 12.5235 6.13868 12.0048 5.35355C11.486 4.56842 10.748 3.95309 9.88231 3.58407C9.01666 3.21505 8.06163 3.10862 7.13597 3.27801C6.21032 3.4474 5.35487 3.88514 4.676 4.5368L4.0778 3.4598ZM11.9222 12.5402C10.8335 13.4836 9.44061 14.002 8 14C4.6862 14 2 11.3138 2 8C2 6.7184 2.402 5.5304 3.086 4.556L5 8H3.2C3.19992 8.94102 3.47645 9.86132 3.9952 10.6464C4.51395 11.4316 5.25204 12.0469 6.11769 12.4159C6.98334 12.7849 7.93837 12.8914 8.86403 12.722C9.78968 12.5526 10.6451 12.1149 11.324 11.4632L11.9222 12.5402Z" fill="currentColor"/>
|
||||
</symbol>
|
||||
|
||||
<symbol id="icon-sailbot-fill" viewBox="0 0 24 24">
|
||||
@@ -93,27 +93,27 @@
|
||||
</symbol>
|
||||
|
||||
<symbol id="icon-message-line" viewBox="0 0 24 24">
|
||||
<path d="M7.0095 18.3L3 21.45V4.80002C3 4.56133 3.09482 4.33241 3.2636 4.16363C3.43239 3.99485 3.66131 3.90002 3.9 3.90002H20.1C20.3387 3.90002 20.5676 3.99485 20.7364 4.16363C20.9052 4.33241 21 4.56133 21 4.80002V17.4C21 17.6387 20.9052 17.8676 20.7364 18.0364C20.5676 18.2052 20.3387 18.3 20.1 18.3H7.0095ZM6.3867 16.5H19.2V5.70002H4.8V17.7465L6.3867 16.5ZM8.4 10.2H15.6V12H8.4V10.2Z" fill="#0A0D14"/>
|
||||
<path d="M7.0095 18.3L3 21.45V4.80002C3 4.56133 3.09482 4.33241 3.2636 4.16363C3.43239 3.99485 3.66131 3.90002 3.9 3.90002H20.1C20.3387 3.90002 20.5676 3.99485 20.7364 4.16363C20.9052 4.33241 21 4.56133 21 4.80002V17.4C21 17.6387 20.9052 17.8676 20.7364 18.0364C20.5676 18.2052 20.3387 18.3 20.1 18.3H7.0095ZM6.3867 16.5H19.2V5.70002H4.8V17.7465L6.3867 16.5ZM8.4 10.2H15.6V12H8.4V10.2Z" fill="currentColor"/>
|
||||
</symbol>
|
||||
|
||||
<symbol id="icon-messenger-line" viewBox="0 0 24 24">
|
||||
<path d="M8.1876 18.5025C8.7186 18.2685 9.3126 18.2244 9.8688 18.3774C10.5618 18.5664 11.2773 18.6618 12 18.66C16.1265 18.66 19.2 15.7017 19.2 11.73C19.2 7.7583 16.1265 4.8 12 4.8C7.8735 4.8 4.8 7.7583 4.8 11.73C4.8 13.773 5.6064 15.5748 7.0194 16.8384C7.27613 17.0658 7.48374 17.3432 7.62952 17.6537C7.7753 17.9641 7.85618 18.301 7.8672 18.6438L8.1876 18.5025ZM12 3C17.0706 3 21 6.7143 21 11.73C21 16.7457 17.0706 20.46 12 20.46C11.1199 20.4623 10.2436 20.346 9.3945 20.1144C9.23502 20.0706 9.06531 20.0829 8.9139 20.1495L7.1283 20.9379C7.02042 20.9856 6.90247 21.006 6.78484 20.9974C6.6672 20.9888 6.55347 20.9515 6.45366 20.8887C6.35384 20.8258 6.27099 20.7394 6.2124 20.637C6.1538 20.5347 6.12125 20.4195 6.1176 20.3016L6.0681 18.6996C6.06486 18.6022 6.0418 18.5065 6.00033 18.4183C5.95886 18.3301 5.89985 18.2512 5.8269 18.1866C4.0755 16.6215 3 14.3553 3 11.73C3 6.7143 6.9303 3 12 3ZM6.5955 14.2833L9.2388 10.0893C9.33825 9.9314 9.46936 9.79583 9.62385 9.69116C9.77834 9.58648 9.95286 9.51497 10.1364 9.48114C10.3199 9.44731 10.5084 9.4519 10.6901 9.49461C10.8718 9.53733 11.0426 9.61724 11.1918 9.7293L13.2942 11.3043C13.3879 11.375 13.5021 11.4133 13.6195 11.4133C13.737 11.4133 13.8512 11.375 13.9449 11.3043L16.7844 9.1479C17.1633 8.8608 17.6583 9.3144 17.4045 9.7176L14.7612 13.9116C14.6617 14.0695 14.5306 14.2051 14.3761 14.3097C14.2217 14.4144 14.0471 14.4859 13.8636 14.5198C13.6801 14.5536 13.4916 14.549 13.3099 14.5063C13.1282 14.4636 12.9574 14.3837 12.8082 14.2716L10.7058 12.6966C10.6121 12.6259 10.4979 12.5876 10.3804 12.5876C10.263 12.5876 10.1488 12.6259 10.0551 12.6966L7.2156 14.8521C6.8367 15.1392 6.3417 14.6856 6.5955 14.2824V14.2833Z" fill="#0A0D14"/>
|
||||
<path d="M8.1876 18.5025C8.7186 18.2685 9.3126 18.2244 9.8688 18.3774C10.5618 18.5664 11.2773 18.6618 12 18.66C16.1265 18.66 19.2 15.7017 19.2 11.73C19.2 7.7583 16.1265 4.8 12 4.8C7.8735 4.8 4.8 7.7583 4.8 11.73C4.8 13.773 5.6064 15.5748 7.0194 16.8384C7.27613 17.0658 7.48374 17.3432 7.62952 17.6537C7.7753 17.9641 7.85618 18.301 7.8672 18.6438L8.1876 18.5025ZM12 3C17.0706 3 21 6.7143 21 11.73C21 16.7457 17.0706 20.46 12 20.46C11.1199 20.4623 10.2436 20.346 9.3945 20.1144C9.23502 20.0706 9.06531 20.0829 8.9139 20.1495L7.1283 20.9379C7.02042 20.9856 6.90247 21.006 6.78484 20.9974C6.6672 20.9888 6.55347 20.9515 6.45366 20.8887C6.35384 20.8258 6.27099 20.7394 6.2124 20.637C6.1538 20.5347 6.12125 20.4195 6.1176 20.3016L6.0681 18.6996C6.06486 18.6022 6.0418 18.5065 6.00033 18.4183C5.95886 18.3301 5.89985 18.2512 5.8269 18.1866C4.0755 16.6215 3 14.3553 3 11.73C3 6.7143 6.9303 3 12 3ZM6.5955 14.2833L9.2388 10.0893C9.33825 9.9314 9.46936 9.79583 9.62385 9.69116C9.77834 9.58648 9.95286 9.51497 10.1364 9.48114C10.3199 9.44731 10.5084 9.4519 10.6901 9.49461C10.8718 9.53733 11.0426 9.61724 11.1918 9.7293L13.2942 11.3043C13.3879 11.375 13.5021 11.4133 13.6195 11.4133C13.737 11.4133 13.8512 11.375 13.9449 11.3043L16.7844 9.1479C17.1633 8.8608 17.6583 9.3144 17.4045 9.7176L14.7612 13.9116C14.6617 14.0695 14.5306 14.2051 14.3761 14.3097C14.2217 14.4144 14.0471 14.4859 13.8636 14.5198C13.6801 14.5536 13.4916 14.549 13.3099 14.5063C13.1282 14.4636 12.9574 14.3837 12.8082 14.2716L10.7058 12.6966C10.6121 12.6259 10.4979 12.5876 10.3804 12.5876C10.263 12.5876 10.1488 12.6259 10.0551 12.6966L7.2156 14.8521C6.8367 15.1392 6.3417 14.6856 6.5955 14.2824V14.2833Z" fill="currentColor"/>
|
||||
</symbol>
|
||||
|
||||
<symbol id="icon-mail-send-fill" viewBox="0 0 24 24">
|
||||
<path d="M2.99995 6.14999V4.79369C3.0016 4.55733 3.09616 4.33111 3.26321 4.16389C3.43026 3.99667 3.65639 3.90188 3.89275 3.89999H20.1072C20.6003 3.89999 21 4.30049 21 4.79369V19.2063C20.9983 19.4427 20.9037 19.6689 20.7367 19.8361C20.5696 20.0033 20.3435 20.0981 20.1072 20.1H3.89275C3.65588 20.0998 3.4288 20.0055 3.26139 19.8379C3.09398 19.6703 2.99995 19.4432 2.99995 19.2063V18.3H19.2V7.76999L12 14.25L2.99995 6.14999ZM1.19995 10.2H5.69995V12H1.19995V10.2ZM1.19995 14.7H8.39995V16.5H1.19995V14.7Z" fill="#0A0D14"/>
|
||||
<path d="M2.99995 6.14999V4.79369C3.0016 4.55733 3.09616 4.33111 3.26321 4.16389C3.43026 3.99667 3.65639 3.90188 3.89275 3.89999H20.1072C20.6003 3.89999 21 4.30049 21 4.79369V19.2063C20.9983 19.4427 20.9037 19.6689 20.7367 19.8361C20.5696 20.0033 20.3435 20.0981 20.1072 20.1H3.89275C3.65588 20.0998 3.4288 20.0055 3.26139 19.8379C3.09398 19.6703 2.99995 19.4432 2.99995 19.2063V18.3H19.2V7.76999L12 14.25L2.99995 6.14999ZM1.19995 10.2H5.69995V12H1.19995V10.2ZM1.19995 14.7H8.39995V16.5H1.19995V14.7Z" fill="currentColor"/>
|
||||
</symbol>
|
||||
|
||||
<symbol id="icon-chat-smile-3-line" viewBox="0 0 24 24">
|
||||
<path d="M3.00001 12C3.00001 7.0293 7.02931 3 12 3C16.9707 3 21 7.0293 21 12C21 16.9707 16.9707 21 12 21H3.00001L5.63611 18.3639C4.79914 17.5291 4.13539 16.5371 3.683 15.445C3.23061 14.3529 2.9985 13.1821 3.00001 12ZM7.34521 19.2H12C13.424 19.2 14.8161 18.7777 16.0001 17.9866C17.1841 17.1954 18.107 16.0709 18.6519 14.7553C19.1969 13.4397 19.3395 11.992 19.0617 10.5953C18.7838 9.19869 18.0981 7.91577 17.0912 6.90883C16.0842 5.90189 14.8013 5.21616 13.4047 4.93835C12.008 4.66053 10.5603 4.80312 9.24469 5.34807C7.92906 5.89302 6.80457 6.81586 6.01343 7.99989C5.22228 9.18393 4.80001 10.576 4.80001 12C4.80001 13.9368 5.56591 15.7485 6.90871 17.0913L8.18131 18.3639L7.34521 19.2ZM8.40001 12.9H15.6C15.6 13.8548 15.2207 14.7705 14.5456 15.4456C13.8705 16.1207 12.9548 16.5 12 16.5C11.0452 16.5 10.1296 16.1207 9.45442 15.4456C8.77929 14.7705 8.40001 13.8548 8.40001 12.9Z" fill="#0A0D14"/>
|
||||
<path d="M3.00001 12C3.00001 7.0293 7.02931 3 12 3C16.9707 3 21 7.0293 21 12C21 16.9707 16.9707 21 12 21H3.00001L5.63611 18.3639C4.79914 17.5291 4.13539 16.5371 3.683 15.445C3.23061 14.3529 2.9985 13.1821 3.00001 12ZM7.34521 19.2H12C13.424 19.2 14.8161 18.7777 16.0001 17.9866C17.1841 17.1954 18.107 16.0709 18.6519 14.7553C19.1969 13.4397 19.3395 11.992 19.0617 10.5953C18.7838 9.19869 18.0981 7.91577 17.0912 6.90883C16.0842 5.90189 14.8013 5.21616 13.4047 4.93835C12.008 4.66053 10.5603 4.80312 9.24469 5.34807C7.92906 5.89302 6.80457 6.81586 6.01343 7.99989C5.22228 9.18393 4.80001 10.576 4.80001 12C4.80001 13.9368 5.56591 15.7485 6.90871 17.0913L8.18131 18.3639L7.34521 19.2ZM8.40001 12.9H15.6C15.6 13.8548 15.2207 14.7705 14.5456 15.4456C13.8705 16.1207 12.9548 16.5 12 16.5C11.0452 16.5 10.1296 16.1207 9.45442 15.4456C8.77929 14.7705 8.40001 13.8548 8.40001 12.9Z" fill="currentColor"/>
|
||||
</symbol>
|
||||
|
||||
<symbol id="icon-telegram-line" viewBox="0 0 24 24">
|
||||
<path d="M12 19.2C13.9096 19.2 15.7409 18.4414 17.0912 17.0912C18.4414 15.7409 19.2 13.9096 19.2 12C19.2 10.0904 18.4414 8.25909 17.0912 6.90883C15.7409 5.55857 13.9096 4.8 12 4.8C10.0904 4.8 8.25909 5.55857 6.90883 6.90883C5.55857 8.25909 4.8 10.0904 4.8 12C4.8 13.9096 5.55857 15.7409 6.90883 17.0912C8.25909 18.4414 10.0904 19.2 12 19.2ZM12 21C7.0293 21 3 16.9707 3 12C3 7.0293 7.0293 3 12 3C16.9707 3 21 7.0293 21 12C21 16.9707 16.9707 21 12 21ZM9.201 13.053L6.9528 12.3519C6.4668 12.2034 6.4641 11.8686 7.0617 11.6283L15.8214 8.2443C16.3299 8.0373 16.6179 8.2992 16.4532 8.9553L14.9619 15.9933C14.8575 16.4946 14.556 16.6143 14.1375 16.383L11.8416 14.6838L10.7715 15.717C10.6617 15.8232 10.5726 15.9141 10.4034 15.9366C10.2351 15.96 10.0965 15.9096 9.9948 15.6306L9.2118 13.0467L9.201 13.0539V13.053Z" fill="#0A0D14"/>
|
||||
<path d="M12 19.2C13.9096 19.2 15.7409 18.4414 17.0912 17.0912C18.4414 15.7409 19.2 13.9096 19.2 12C19.2 10.0904 18.4414 8.25909 17.0912 6.90883C15.7409 5.55857 13.9096 4.8 12 4.8C10.0904 4.8 8.25909 5.55857 6.90883 6.90883C5.55857 8.25909 4.8 10.0904 4.8 12C4.8 13.9096 5.55857 15.7409 6.90883 17.0912C8.25909 18.4414 10.0904 19.2 12 19.2ZM12 21C7.0293 21 3 16.9707 3 12C3 7.0293 7.0293 3 12 3C16.9707 3 21 7.0293 21 12C21 16.9707 16.9707 21 12 21ZM9.201 13.053L6.9528 12.3519C6.4668 12.2034 6.4641 11.8686 7.0617 11.6283L15.8214 8.2443C16.3299 8.0373 16.6179 8.2992 16.4532 8.9553L14.9619 15.9933C14.8575 16.4946 14.556 16.6143 14.1375 16.383L11.8416 14.6838L10.7715 15.717C10.6617 15.8232 10.5726 15.9141 10.4034 15.9366C10.2351 15.96 10.0965 15.9096 9.9948 15.6306L9.2118 13.0467L9.201 13.0539V13.053Z" fill="currentColor"/>
|
||||
</symbol>
|
||||
|
||||
<symbol id="icon-line-line" viewBox="0 0 24 24">
|
||||
<path d="M21 10.821C21 12.4293 20.3817 13.881 19.0893 15.2976C17.1993 17.4702 12.9801 20.1243 12.0117 20.5284C11.0451 20.9343 11.1918 20.2701 11.2251 20.0451L11.3484 19.2801C11.379 19.0443 11.4096 18.6951 11.3196 18.4701C11.2188 18.2208 10.8192 18.0885 10.5267 18.0273C6.2022 17.4531 3 14.43 3 10.821C3 6.79347 7.0383 3.51477 12 3.51477C16.9608 3.51477 21 6.79347 21 10.821ZM17.76 14.0835C18.7617 12.9855 19.2 11.9586 19.2 10.821C19.2 7.87977 16.041 5.31477 12 5.31477C7.959 5.31477 4.8 7.87977 4.8 10.821C4.8 13.4355 7.2552 15.7773 10.7634 16.2426L10.8957 16.266C11.8659 16.4694 12.5913 16.8186 12.9918 17.8032L13.0242 17.8896C14.6496 16.8312 16.7808 15.2076 17.7591 14.0835H17.76ZM17.5242 10.4835C17.6445 10.4909 17.7574 10.5439 17.8399 10.6317C17.9225 10.7195 17.9684 10.8355 17.9684 10.956C17.9684 11.0765 17.9225 11.1924 17.8399 11.2802C17.7574 11.368 17.6445 11.421 17.5242 11.4285H16.2075V12.2727H17.5233C17.587 12.2699 17.6507 12.28 17.7104 12.3025C17.77 12.325 17.8246 12.3593 17.8707 12.4034C17.9167 12.4475 17.9534 12.5005 17.9785 12.5591C18.0035 12.6178 18.0164 12.6809 18.0164 12.7447C18.0164 12.8085 18.0035 12.8716 17.9785 12.9303C17.9534 12.989 17.9167 13.0419 17.8707 13.086C17.8246 13.1301 17.77 13.1645 17.7104 13.1869C17.6507 13.2094 17.587 13.2196 17.5233 13.2168H15.735C15.6104 13.2158 15.4912 13.1658 15.4032 13.0775C15.3153 12.9892 15.2657 12.8698 15.2652 12.7452V9.16677C15.2652 8.90847 15.4767 8.69427 15.7377 8.69427H17.5269C17.6522 8.69463 17.7723 8.74475 17.8606 8.83362C17.949 8.92248 17.9984 9.04281 17.998 9.16812C17.9977 9.29344 17.9476 9.41348 17.8587 9.50183C17.7698 9.59019 17.6495 9.63963 17.5242 9.63927H16.2084V10.4835H17.5242ZM14.6325 12.7452C14.6323 12.8071 14.6198 12.8684 14.5959 12.9255C14.572 12.9826 14.5371 13.0345 14.4931 13.0781C14.4491 13.1217 14.397 13.1563 14.3397 13.1798C14.2824 13.2032 14.221 13.2152 14.1591 13.215C14.085 13.2166 14.0116 13.2005 13.9451 13.1679C13.8785 13.1353 13.8208 13.0873 13.7766 13.0278L11.9442 10.5402V12.7452C11.9352 12.864 11.8817 12.975 11.7943 13.056C11.7069 13.137 11.5922 13.182 11.4731 13.182C11.3539 13.182 11.2392 13.137 11.1518 13.056C11.0644 12.975 11.0109 12.864 11.0019 12.7452V9.16677C11.0017 9.04233 11.0508 8.92287 11.1385 8.83462C11.2263 8.74638 11.3455 8.69655 11.4699 8.69607C11.6157 8.69607 11.7507 8.77347 11.8407 8.88597L13.6875 11.3835V9.16677C13.6875 8.90847 13.899 8.69427 14.16 8.69427C14.4183 8.69427 14.6325 8.90847 14.6325 9.16677V12.7452ZM10.3269 12.7452C10.3262 12.8703 10.276 12.9902 10.1873 13.0785C10.0987 13.1668 9.97867 13.2165 9.8535 13.2168C9.72873 13.2161 9.60928 13.1661 9.52113 13.0778C9.43299 12.9895 9.38327 12.8699 9.3828 12.7452V9.16677C9.3828 8.90847 9.5952 8.69427 9.8553 8.69427C10.1154 8.69427 10.3269 8.90847 10.3269 9.16677V12.7452ZM8.4774 13.2168H6.6873C6.56236 13.2161 6.44272 13.1662 6.35429 13.0779C6.26586 12.9897 6.21574 12.8701 6.2148 12.7452V9.16677C6.22513 9.04857 6.27938 8.93854 6.36685 8.85838C6.45432 8.77822 6.56865 8.73375 6.6873 8.73375C6.80595 8.73375 6.92028 8.77822 7.00775 8.85838C7.09522 8.93854 7.14947 9.04857 7.1598 9.16677V12.2718H8.4774C8.60272 12.2718 8.7229 12.3216 8.81151 12.4102C8.90012 12.4988 8.9499 12.619 8.9499 12.7443C8.9499 12.8696 8.90012 12.9898 8.81151 13.0784C8.7229 13.167 8.60272 13.2168 8.4774 13.2168Z" fill="#0A0D14"/>
|
||||
<path d="M21 10.821C21 12.4293 20.3817 13.881 19.0893 15.2976C17.1993 17.4702 12.9801 20.1243 12.0117 20.5284C11.0451 20.9343 11.1918 20.2701 11.2251 20.0451L11.3484 19.2801C11.379 19.0443 11.4096 18.6951 11.3196 18.4701C11.2188 18.2208 10.8192 18.0885 10.5267 18.0273C6.2022 17.4531 3 14.43 3 10.821C3 6.79347 7.0383 3.51477 12 3.51477C16.9608 3.51477 21 6.79347 21 10.821ZM17.76 14.0835C18.7617 12.9855 19.2 11.9586 19.2 10.821C19.2 7.87977 16.041 5.31477 12 5.31477C7.959 5.31477 4.8 7.87977 4.8 10.821C4.8 13.4355 7.2552 15.7773 10.7634 16.2426L10.8957 16.266C11.8659 16.4694 12.5913 16.8186 12.9918 17.8032L13.0242 17.8896C14.6496 16.8312 16.7808 15.2076 17.7591 14.0835H17.76ZM17.5242 10.4835C17.6445 10.4909 17.7574 10.5439 17.8399 10.6317C17.9225 10.7195 17.9684 10.8355 17.9684 10.956C17.9684 11.0765 17.9225 11.1924 17.8399 11.2802C17.7574 11.368 17.6445 11.421 17.5242 11.4285H16.2075V12.2727H17.5233C17.587 12.2699 17.6507 12.28 17.7104 12.3025C17.77 12.325 17.8246 12.3593 17.8707 12.4034C17.9167 12.4475 17.9534 12.5005 17.9785 12.5591C18.0035 12.6178 18.0164 12.6809 18.0164 12.7447C18.0164 12.8085 18.0035 12.8716 17.9785 12.9303C17.9534 12.989 17.9167 13.0419 17.8707 13.086C17.8246 13.1301 17.77 13.1645 17.7104 13.1869C17.6507 13.2094 17.587 13.2196 17.5233 13.2168H15.735C15.6104 13.2158 15.4912 13.1658 15.4032 13.0775C15.3153 12.9892 15.2657 12.8698 15.2652 12.7452V9.16677C15.2652 8.90847 15.4767 8.69427 15.7377 8.69427H17.5269C17.6522 8.69463 17.7723 8.74475 17.8606 8.83362C17.949 8.92248 17.9984 9.04281 17.998 9.16812C17.9977 9.29344 17.9476 9.41348 17.8587 9.50183C17.7698 9.59019 17.6495 9.63963 17.5242 9.63927H16.2084V10.4835H17.5242ZM14.6325 12.7452C14.6323 12.8071 14.6198 12.8684 14.5959 12.9255C14.572 12.9826 14.5371 13.0345 14.4931 13.0781C14.4491 13.1217 14.397 13.1563 14.3397 13.1798C14.2824 13.2032 14.221 13.2152 14.1591 13.215C14.085 13.2166 14.0116 13.2005 13.9451 13.1679C13.8785 13.1353 13.8208 13.0873 13.7766 13.0278L11.9442 10.5402V12.7452C11.9352 12.864 11.8817 12.975 11.7943 13.056C11.7069 13.137 11.5922 13.182 11.4731 13.182C11.3539 13.182 11.2392 13.137 11.1518 13.056C11.0644 12.975 11.0109 12.864 11.0019 12.7452V9.16677C11.0017 9.04233 11.0508 8.92287 11.1385 8.83462C11.2263 8.74638 11.3455 8.69655 11.4699 8.69607C11.6157 8.69607 11.7507 8.77347 11.8407 8.88597L13.6875 11.3835V9.16677C13.6875 8.90847 13.899 8.69427 14.16 8.69427C14.4183 8.69427 14.6325 8.90847 14.6325 9.16677V12.7452ZM10.3269 12.7452C10.3262 12.8703 10.276 12.9902 10.1873 13.0785C10.0987 13.1668 9.97867 13.2165 9.8535 13.2168C9.72873 13.2161 9.60928 13.1661 9.52113 13.0778C9.43299 12.9895 9.38327 12.8699 9.3828 12.7452V9.16677C9.3828 8.90847 9.5952 8.69427 9.8553 8.69427C10.1154 8.69427 10.3269 8.90847 10.3269 9.16677V12.7452ZM8.4774 13.2168H6.6873C6.56236 13.2161 6.44272 13.1662 6.35429 13.0779C6.26586 12.9897 6.21574 12.8701 6.2148 12.7452V9.16677C6.22513 9.04857 6.27938 8.93854 6.36685 8.85838C6.45432 8.77822 6.56865 8.73375 6.6873 8.73375C6.80595 8.73375 6.92028 8.77822 7.00775 8.85838C7.09522 8.93854 7.14947 9.04857 7.1598 9.16677V12.2718H8.4774C8.60272 12.2718 8.7229 12.3216 8.81151 12.4102C8.90012 12.4988 8.9499 12.619 8.9499 12.7443C8.9499 12.8696 8.90012 12.9898 8.81151 13.0784C8.7229 13.167 8.60272 13.2168 8.4774 13.2168Z" fill="currentColor"/>
|
||||
</symbol>
|
||||
|
||||
<symbol id="icon-eyeglass" viewBox="0 0 48 48">
|
||||
@@ -151,11 +151,11 @@
|
||||
</symbol>
|
||||
|
||||
<symbol id="icon-gear" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M3.50498 13.75C3.18794 13.2017 2.94148 12.6156 2.77148 12.0055C3.14146 11.8173 3.45218 11.5305 3.66926 11.1767C3.88633 10.8229 4.00131 10.4159 4.00146 10.0008C4.00162 9.58574 3.88695 9.1787 3.67014 8.82474C3.45332 8.47078 3.14282 8.18369 2.77298 7.99524C3.11201 6.76935 3.75753 5.64995 4.64873 4.74249C4.9968 4.96878 5.4007 5.09436 5.81572 5.10532C6.23074 5.11629 6.6407 5.01221 7.00023 4.80461C7.35976 4.59701 7.65485 4.29399 7.85283 3.92907C8.05081 3.56415 8.14396 3.15157 8.12198 2.73699C9.35357 2.41871 10.6459 2.41922 11.8772 2.73849C11.8554 3.15306 11.9488 3.56558 12.1469 3.9304C12.3451 4.29521 12.6403 4.59809 12.9999 4.80553C13.3595 5.01297 13.7694 5.11688 14.1844 5.10575C14.5994 5.09463 15.0033 4.9689 15.3512 4.74249C15.7855 5.18499 16.171 5.68824 16.495 6.24999C16.8197 6.81174 17.0627 7.39749 17.2285 7.99449C16.8585 8.18267 16.5478 8.46952 16.3307 8.82332C16.1136 9.17712 15.9987 9.58407 15.9985 9.99915C15.9984 10.4142 16.113 10.8213 16.3298 11.1752C16.5466 11.5292 16.8571 11.8163 17.227 12.0047C16.888 13.2306 16.2424 14.35 15.3512 15.2575C15.0032 15.0312 14.5993 14.9056 14.1843 14.8947C13.7692 14.8837 13.3593 14.9878 12.9997 15.1954C12.6402 15.403 12.3451 15.706 12.1471 16.0709C11.9492 16.4358 11.856 16.8484 11.878 17.263C10.6464 17.5813 9.35406 17.5808 8.12273 17.2615C8.14452 16.8469 8.05118 16.4344 7.85305 16.0696C7.65492 15.7048 7.35972 15.4019 7.00011 15.1944C6.64051 14.987 6.23053 14.8831 5.81553 14.8942C5.40053 14.9054 4.99671 15.0311 4.64873 15.2575C4.20548 14.8052 3.82118 14.2987 3.50498 13.75V13.75ZM7.74998 13.897C8.5492 14.358 9.15012 15.0978 9.43748 15.9745C9.81173 16.0097 10.1875 16.0105 10.5617 15.9752C10.8493 15.0984 11.4505 14.3586 12.25 13.8977C13.0489 13.4355 13.9904 13.2846 14.8937 13.474C15.1112 13.168 15.2987 12.8417 15.4547 12.5005C14.8393 11.8131 14.4993 10.9226 14.5 9.99999C14.5 9.05499 14.8525 8.17224 15.4547 7.49949C15.2976 7.15835 15.1093 6.83246 14.8922 6.52599C13.9894 6.71522 13.0486 6.5646 12.25 6.10299C11.4508 5.64202 10.8499 4.90223 10.5625 4.02549C10.1882 3.99024 9.81248 3.98949 9.43823 4.02474C9.15068 4.9016 8.54949 5.64141 7.74998 6.10224C6.95107 6.56448 6.00959 6.71538 5.10623 6.52599C4.88916 6.8322 4.70133 7.15814 4.54523 7.49949C5.16066 8.18691 5.50065 9.07733 5.49998 9.99999C5.49998 10.945 5.14748 11.8277 4.54523 12.5005C4.70234 12.8416 4.89064 13.1675 5.10773 13.474C6.01052 13.2848 6.95139 13.4354 7.74998 13.897ZM9.99998 12.25C9.40325 12.25 8.83095 12.0129 8.40899 11.591C7.98704 11.169 7.74998 10.5967 7.74998 9.99999C7.74998 9.40325 7.98704 8.83096 8.40899 8.409C8.83095 7.98704 9.40325 7.74999 9.99998 7.74999C10.5967 7.74999 11.169 7.98704 11.591 8.409C12.0129 8.83096 12.25 9.40325 12.25 9.99999C12.25 10.5967 12.0129 11.169 11.591 11.591C11.169 12.0129 10.5967 12.25 9.99998 12.25ZM9.99998 10.75C10.1989 10.75 10.3897 10.671 10.5303 10.5303C10.671 10.3897 10.75 10.1989 10.75 9.99999C10.75 9.80108 10.671 9.61031 10.5303 9.46966C10.3897 9.32901 10.1989 9.24999 9.99998 9.24999C9.80107 9.24999 9.61031 9.32901 9.46965 9.46966C9.329 9.61031 9.24998 9.80108 9.24998 9.99999C9.24998 10.1989 9.329 10.3897 9.46965 10.5303C9.61031 10.671 9.80107 10.75 9.99998 10.75V10.75Z" fill="#868C98"/>
|
||||
<path d="M3.50498 13.75C3.18794 13.2017 2.94148 12.6156 2.77148 12.0055C3.14146 11.8173 3.45218 11.5305 3.66926 11.1767C3.88633 10.8229 4.00131 10.4159 4.00146 10.0008C4.00162 9.58574 3.88695 9.1787 3.67014 8.82474C3.45332 8.47078 3.14282 8.18369 2.77298 7.99524C3.11201 6.76935 3.75753 5.64995 4.64873 4.74249C4.9968 4.96878 5.4007 5.09436 5.81572 5.10532C6.23074 5.11629 6.6407 5.01221 7.00023 4.80461C7.35976 4.59701 7.65485 4.29399 7.85283 3.92907C8.05081 3.56415 8.14396 3.15157 8.12198 2.73699C9.35357 2.41871 10.6459 2.41922 11.8772 2.73849C11.8554 3.15306 11.9488 3.56558 12.1469 3.9304C12.3451 4.29521 12.6403 4.59809 12.9999 4.80553C13.3595 5.01297 13.7694 5.11688 14.1844 5.10575C14.5994 5.09463 15.0033 4.9689 15.3512 4.74249C15.7855 5.18499 16.171 5.68824 16.495 6.24999C16.8197 6.81174 17.0627 7.39749 17.2285 7.99449C16.8585 8.18267 16.5478 8.46952 16.3307 8.82332C16.1136 9.17712 15.9987 9.58407 15.9985 9.99915C15.9984 10.4142 16.113 10.8213 16.3298 11.1752C16.5466 11.5292 16.8571 11.8163 17.227 12.0047C16.888 13.2306 16.2424 14.35 15.3512 15.2575C15.0032 15.0312 14.5993 14.9056 14.1843 14.8947C13.7692 14.8837 13.3593 14.9878 12.9997 15.1954C12.6402 15.403 12.3451 15.706 12.1471 16.0709C11.9492 16.4358 11.856 16.8484 11.878 17.263C10.6464 17.5813 9.35406 17.5808 8.12273 17.2615C8.14452 16.8469 8.05118 16.4344 7.85305 16.0696C7.65492 15.7048 7.35972 15.4019 7.00011 15.1944C6.64051 14.987 6.23053 14.8831 5.81553 14.8942C5.40053 14.9054 4.99671 15.0311 4.64873 15.2575C4.20548 14.8052 3.82118 14.2987 3.50498 13.75V13.75ZM7.74998 13.897C8.5492 14.358 9.15012 15.0978 9.43748 15.9745C9.81173 16.0097 10.1875 16.0105 10.5617 15.9752C10.8493 15.0984 11.4505 14.3586 12.25 13.8977C13.0489 13.4355 13.9904 13.2846 14.8937 13.474C15.1112 13.168 15.2987 12.8417 15.4547 12.5005C14.8393 11.8131 14.4993 10.9226 14.5 9.99999C14.5 9.05499 14.8525 8.17224 15.4547 7.49949C15.2976 7.15835 15.1093 6.83246 14.8922 6.52599C13.9894 6.71522 13.0486 6.5646 12.25 6.10299C11.4508 5.64202 10.8499 4.90223 10.5625 4.02549C10.1882 3.99024 9.81248 3.98949 9.43823 4.02474C9.15068 4.9016 8.54949 5.64141 7.74998 6.10224C6.95107 6.56448 6.00959 6.71538 5.10623 6.52599C4.88916 6.8322 4.70133 7.15814 4.54523 7.49949C5.16066 8.18691 5.50065 9.07733 5.49998 9.99999C5.49998 10.945 5.14748 11.8277 4.54523 12.5005C4.70234 12.8416 4.89064 13.1675 5.10773 13.474C6.01052 13.2848 6.95139 13.4354 7.74998 13.897ZM9.99998 12.25C9.40325 12.25 8.83095 12.0129 8.40899 11.591C7.98704 11.169 7.74998 10.5967 7.74998 9.99999C7.74998 9.40325 7.98704 8.83096 8.40899 8.409C8.83095 7.98704 9.40325 7.74999 9.99998 7.74999C10.5967 7.74999 11.169 7.98704 11.591 8.409C12.0129 8.83096 12.25 9.40325 12.25 9.99999C12.25 10.5967 12.0129 11.169 11.591 11.591C11.169 12.0129 10.5967 12.25 9.99998 12.25ZM9.99998 10.75C10.1989 10.75 10.3897 10.671 10.5303 10.5303C10.671 10.3897 10.75 10.1989 10.75 9.99999C10.75 9.80108 10.671 9.61031 10.5303 9.46966C10.3897 9.32901 10.1989 9.24999 9.99998 9.24999C9.80107 9.24999 9.61031 9.32901 9.46965 9.46966C9.329 9.61031 9.24998 9.80108 9.24998 9.99999C9.24998 10.1989 9.329 10.3897 9.46965 10.5303C9.61031 10.671 9.80107 10.75 9.99998 10.75V10.75Z" fill="currentColor"/>
|
||||
</symbol>
|
||||
|
||||
<symbol id="icon-linear" viewBox="0 0 24 24">
|
||||
<path d="M0.294 14.765c-0.053-0.228 0.218-0.371 0.383-0.206l8.762 8.762c0.165 0.165 0.022 0.436-0.206 0.383C4.812 22.668 1.332 19.188 0.294 14.765zM0 11.253c-0.004 0.068 0.021 0.134 0.07 0.183l12.494 12.494c0.048 0.048 0.115 0.074 0.183 0.07c0.568-0.035 1.127-0.11 1.671-0.222c0.183-0.038 0.247-0.263 0.115-0.396l-13.847-13.847c-0.132-0.132-0.358-0.068-0.396 0.115c-0.112 0.544-0.187 1.102-0.222 1.671zM1.011 7.129c-0.04 0.09-0.02 0.195 0.05 0.264l15.546 15.546c0.069 0.069 0.174 0.09 0.264 0.05c0.429-0.191 0.844-0.406 1.244-0.644c0.133-0.079 0.153-0.261 0.044-0.37l-16.134-16.134c-0.109-0.109-0.291-0.089-0.37 0.044c-0.238 0.4-0.453 0.816-0.644 1.244zM3.038 4.338c-0.089-0.089-0.094-0.231-0.011-0.325c2.2-2.46 5.4-4.013 8.973-4.013 6.627 0 12 5.373 12 12c0 3.562-1.55 6.76-4.013 8.961c-0.094 0.084-0.236 0.078-0.325-0.011l-16.624-16.612z"/>
|
||||
<path fill="currentColor" d="M0.294 14.765c-0.053-0.228 0.218-0.371 0.383-0.206l8.762 8.762c0.165 0.165 0.022 0.436-0.206 0.383C4.812 22.668 1.332 19.188 0.294 14.765zM0 11.253c-0.004 0.068 0.021 0.134 0.07 0.183l12.494 12.494c0.048 0.048 0.115 0.074 0.183 0.07c0.568-0.035 1.127-0.11 1.671-0.222c0.183-0.038 0.247-0.263 0.115-0.396l-13.847-13.847c-0.132-0.132-0.358-0.068-0.396 0.115c-0.112 0.544-0.187 1.102-0.222 1.671zM1.011 7.129c-0.04 0.09-0.02 0.195 0.05 0.264l15.546 15.546c0.069 0.069 0.174 0.09 0.264 0.05c0.429-0.191 0.844-0.406 1.244-0.644c0.133-0.079 0.153-0.261 0.044-0.37l-16.134-16.134c-0.109-0.109-0.291-0.089-0.37 0.044c-0.238 0.4-0.453 0.816-0.644 1.244zM3.038 4.338c-0.089-0.089-0.094-0.231-0.011-0.325c2.2-2.46 5.4-4.013 8.973-4.013 6.627 0 12 5.373 12 12c0 3.562-1.55 6.76-4.013 8.961c-0.094 0.084-0.236 0.078-0.325-0.011l-16.624-16.612z"/>
|
||||
</symbol>
|
||||
|
||||
<symbol id="icon-instagram" viewBox="0 0 24 24">
|
||||
@@ -177,4 +177,65 @@
|
||||
<symbol id="icon-slack" viewBox="0 0 24 24">
|
||||
<path fill="currentColor" d="M6.527 14.514A1.973 1.973 0 0 1 4.56 16.48a1.973 1.973 0 0 1-1.968-1.967c0-1.083.885-1.968 1.968-1.968h1.967zm.992 0c0-1.083.885-1.968 1.968-1.968s1.967.885 1.967 1.968v4.927a1.973 1.973 0 0 1-1.967 1.968a1.973 1.973 0 0 1-1.968-1.968zm1.968-7.987A1.973 1.973 0 0 1 7.519 4.56c0-1.083.885-1.967 1.968-1.967s1.967.884 1.967 1.967v1.968zm0 .992c1.083 0 1.967.884 1.967 1.967a1.973 1.973 0 0 1-1.967 1.968H4.56a1.973 1.973 0 0 1-1.968-1.968c0-1.083.885-1.967 1.968-1.967zm7.986 1.967c0-1.083.885-1.967 1.968-1.967s1.968.884 1.968 1.967a1.973 1.973 0 0 1-1.968 1.968h-1.968zm-.991 0a1.973 1.973 0 0 1-1.968 1.968a1.973 1.973 0 0 1-1.968-1.968V4.56c0-1.083.885-1.967 1.968-1.967s1.968.884 1.968 1.967zm-1.968 7.987c1.083 0 1.968.885 1.968 1.968a1.973 1.973 0 0 1-1.968 1.968a1.973 1.973 0 0 1-1.968-1.968v-1.968zm0-.992a1.973 1.973 0 0 1-1.968-1.967c0-1.083.885-1.968 1.968-1.968h4.927c1.083 0 1.968.885 1.968 1.968a1.973 1.973 0 0 1-1.968 1.967z"/>
|
||||
</symbol>
|
||||
|
||||
<!-- Lucide-style icons for sidebar -->
|
||||
<symbol id="icon-layout-dashboard" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect width="7" height="9" x="3" y="3" rx="1"/>
|
||||
<rect width="7" height="5" x="14" y="3" rx="1"/>
|
||||
<rect width="7" height="9" x="14" y="12" rx="1"/>
|
||||
<rect width="7" height="5" x="3" y="16" rx="1"/>
|
||||
</symbol>
|
||||
|
||||
<symbol id="icon-building-2" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M6 22V4a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v18Z"/>
|
||||
<path d="M6 12H4a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h2"/>
|
||||
<path d="M18 9h2a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-2"/>
|
||||
<path d="M10 6h4"/>
|
||||
<path d="M10 10h4"/>
|
||||
<path d="M10 14h4"/>
|
||||
<path d="M10 18h4"/>
|
||||
</symbol>
|
||||
|
||||
<symbol id="icon-users" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/>
|
||||
<circle cx="9" cy="7" r="4"/>
|
||||
<path d="M22 21v-2a4 4 0 0 0-3-3.87"/>
|
||||
<path d="M16 3.13a4 4 0 0 1 0 7.75"/>
|
||||
</symbol>
|
||||
|
||||
<symbol id="icon-toy-brick" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect width="18" height="12" x="3" y="8" rx="1"/>
|
||||
<path d="M10 8V5c0-.6-.4-1-1-1H6a1 1 0 0 0-1 1v3"/>
|
||||
<path d="M19 8V5c0-.6-.4-1-1-1h-3a1 1 0 0 0-1 1v3"/>
|
||||
</symbol>
|
||||
|
||||
<symbol id="icon-bot" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M12 8V4H8"/>
|
||||
<rect width="16" height="12" x="4" y="8" rx="2"/>
|
||||
<path d="M2 14h2"/>
|
||||
<path d="M20 14h2"/>
|
||||
<path d="M15 13v2"/>
|
||||
<path d="M9 13v2"/>
|
||||
</symbol>
|
||||
|
||||
<symbol id="icon-zap" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z"/>
|
||||
</symbol>
|
||||
|
||||
<symbol id="icon-layers" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="m12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83Z"/>
|
||||
<path d="m22 17.65-9.17 4.16a2 2 0 0 1-1.66 0L2 17.65"/>
|
||||
<path d="m22 12.65-9.17 4.16a2 2 0 0 1-1.66 0L2 12.65"/>
|
||||
</symbol>
|
||||
|
||||
<symbol id="icon-heart-pulse" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.3 1.5 4.05 3 5.5l7 7Z"/>
|
||||
<path d="M3.22 12H9.5l.5-1 2 4.5 2-7 1.5 3.5h5.27"/>
|
||||
</symbol>
|
||||
|
||||
<symbol id="icon-log-out" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/>
|
||||
<polyline points="16 17 21 12 16 7"/>
|
||||
<line x1="21" x2="9" y1="12" y2="12"/>
|
||||
</symbol>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 46 KiB |
@@ -1,7 +1,9 @@
|
||||
<li class="px-4 mb-1">
|
||||
<% text_class_name = current_page?(url) ? 'text-woot-500 bg-slate-25' : 'text-slate-800' %>
|
||||
<%= link_to(url, class: text_class_name + " -ml-1 focus:outline-none cursor-pointer flex items-center px-2 py-1.5 text-slate-800 cursor-pointer hover:text-woot-500 hover:bg-slate-25 rounded-lg") do %>
|
||||
<svg width="16" height="16"><use xlink:href="#<%= icon %>" /></svg>
|
||||
<span class="ml-2 text-sm"><%= label %></span>
|
||||
<li>
|
||||
<% is_active = current_page?(url) %>
|
||||
<% base_class = "flex items-center gap-2 px-2 py-1.5 h-8 text-sm font-medium rounded-lg" %>
|
||||
<% active_class = is_active ? "text-n-blue-text bg-n-alpha-2" : "text-n-slate-11 hover:bg-n-alpha-2" %>
|
||||
<%= link_to(url, class: "#{base_class} #{active_class}") do %>
|
||||
<svg width="16" height="16" class="flex-shrink-0"><use xlink:href="#<%= icon %>" /></svg>
|
||||
<span><%= label %></span>
|
||||
<% end %>
|
||||
</li>
|
||||
|
||||
@@ -12,25 +12,25 @@ as defined by the routes in the `admin/` namespace
|
||||
|
||||
<%
|
||||
sidebar_icons = {
|
||||
accounts: 'icon-building-4-line',
|
||||
users: 'icon-user-follow-line',
|
||||
platform_apps: 'icon-apps-2-line',
|
||||
agent_bots: 'icon-robot-line',
|
||||
accounts: 'icon-building-2',
|
||||
users: 'icon-users',
|
||||
platform_apps: 'icon-toy-brick',
|
||||
agent_bots: 'icon-bot',
|
||||
}
|
||||
%>
|
||||
|
||||
<div class="border-slate-100 border-r w-56 flex-shrink-0 justify-between h-full flex flex-col" role="navigation">
|
||||
<div class="border-n-weak border-r w-[200px] flex-shrink-0 justify-between h-full flex flex-col bg-n-background" role="navigation">
|
||||
<div>
|
||||
<div class="flex mx-4 mb-4 border-slate-100 border-b py-6">
|
||||
<%= link_to image_tag('/brand-assets/logo_thumbnail.svg', alt: 'Chatwoot Admin Dashboard', class: 'h-10'), super_admin_root_url %>
|
||||
<div class="flex flex-col ml-3">
|
||||
<div class="text-sm">Chatwoot <%= Chatwoot.config[:version] %></div>
|
||||
<div class="text-xs text-slate-700 mt-0.5">Super Admin Console</div>
|
||||
<div class="flex items-center px-4 border-n-weak border-b h-16 mt-px">
|
||||
<%= link_to image_tag('/brand-assets/logo_thumbnail.svg', alt: 'Chatwoot Admin Dashboard', class: 'h-8'), super_admin_root_url %>
|
||||
<div class="flex flex-col ml-2.5">
|
||||
<div class="text-sm font-medium text-n-slate-12">Chatwoot <%= Chatwoot.config[:version] %></div>
|
||||
<div class="text-xs text-n-slate-11">Super Admin Console</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ul class="my-4">
|
||||
<%= render partial: "nav_item", locals: { icon: 'icon-grid-line', url: super_admin_root_url, label: 'Dashboard' } %>
|
||||
<ul class="py-4 px-3 space-y-0.5">
|
||||
<%= render partial: "nav_item", locals: { icon: 'icon-layout-dashboard', url: super_admin_root_url, label: 'Dashboard' } %>
|
||||
<% Administrate::Namespace.new(namespace).resources.each do |resource| %>
|
||||
<% next if ["account_users", "access_tokens", "installation_configs", "dashboard", "devise/sessions", "app_configs", "instance_statuses", "settings"].include? resource.resource %>
|
||||
<%= render partial: "nav_item", locals: {
|
||||
@@ -44,12 +44,12 @@ as defined by the routes in the `admin/` namespace
|
||||
<%= render 'settings_menu', open: settings_open? %>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<ul class="my-4">
|
||||
<%= render partial: "nav_item", locals: { icon: 'icon-mist-fill', url: sidekiq_web_url, label: 'Sidekiq Dashboard' } %>
|
||||
<%= render partial: "nav_item", locals: { icon: 'icon-health-book-line', url: super_admin_instance_status_url, label: 'Instance Health' } %>
|
||||
<%= render partial: "nav_item", locals: { icon: 'icon-dashboard-line', url: '/', label: 'Agent Dashboard' } %>
|
||||
<%= render partial: "nav_item", locals: { icon: 'icon-logout-circle-r-line', url: super_admin_logout_url, label: 'Logout' } %>
|
||||
<div class="border-t border-n-weak">
|
||||
<ul class="py-4 px-3 space-y-0.5">
|
||||
<%= render partial: "nav_item", locals: { icon: 'icon-layers', url: sidekiq_web_url, label: 'Sidekiq Dashboard' } %>
|
||||
<%= render partial: "nav_item", locals: { icon: 'icon-heart-pulse', url: super_admin_instance_status_url, label: 'Instance Health' } %>
|
||||
<%= render partial: "nav_item", locals: { icon: 'icon-layout-dashboard', url: '/', label: 'Agent Dashboard' } %>
|
||||
<%= render partial: "nav_item", locals: { icon: 'icon-log-out', url: super_admin_logout_url, label: 'Logout' } %>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<form class="search" role="search">
|
||||
<label class="search__label" for="search">
|
||||
<svg class="search__eyeglass-icon" role="img">
|
||||
<form class="relative flex items-center" role="search">
|
||||
<label class="absolute left-3 text-n-slate-10" for="search">
|
||||
<svg class="w-4 h-4" role="img">
|
||||
<title>
|
||||
<%= t("administrate.search.label", resource: resource_name) %>
|
||||
</title>
|
||||
@@ -8,17 +8,19 @@
|
||||
</svg>
|
||||
</label>
|
||||
|
||||
<input class="search__input"
|
||||
<input class="h-9 w-[200px] pl-9 pr-8 text-sm text-n-slate-12 bg-n-solid-2 border border-n-weak rounded-lg focus:ring-2 focus:ring-woot-500 focus:border-woot-500 outline-none placeholder:text-n-slate-10"
|
||||
id="search"
|
||||
type="search"
|
||||
name="search"
|
||||
placeholder="<%= t("administrate.search.label", resource: resource_name) %>"
|
||||
value="<%= search_term %>">
|
||||
|
||||
<%= link_to clear_search_params, class: "search__clear-link" do %>
|
||||
<svg class="search__clear-icon" role="img">
|
||||
<title><%= t("administrate.search.clear") %></title>
|
||||
<use xlink:href="#icon-cancel" />
|
||||
</svg>
|
||||
<% if search_term.present? %>
|
||||
<%= link_to clear_search_params, class: "absolute right-2 text-n-slate-10 hover:text-n-slate-12" do %>
|
||||
<svg class="w-4 h-4" role="img">
|
||||
<title><%= t("administrate.search.clear") %></title>
|
||||
<use xlink:href="#icon-cancel" />
|
||||
</svg>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</form>
|
||||
@@ -1,24 +1,63 @@
|
||||
<li class="px-4 mb-1">
|
||||
<li>
|
||||
<details class="group" <%= 'open' if open %>>
|
||||
<summary class="-ml-1 flex items-center px-2 py-1.5 cursor-pointer rounded-lg <%= open ? 'text-woot-500 bg-slate-25' : 'text-slate-800 hover:text-woot-500 hover:bg-slate-25' %> list-none">
|
||||
<%= link_to super_admin_settings_url, class: 'flex items-center flex-1' do %>
|
||||
<svg width="16" height="16"><use xlink:href="#icon-settings-2-line" /></svg>
|
||||
<span class="ml-2 text-sm">Settings</span>
|
||||
<summary class="flex items-center gap-2 px-2 py-1.5 h-8 text-sm font-medium rounded-lg cursor-pointer list-none <%= open ? 'text-n-slate-12' : 'text-n-slate-11 hover:bg-n-alpha-2' %>">
|
||||
<%= link_to super_admin_settings_url, class: 'flex items-center gap-2 flex-1' do %>
|
||||
<svg width="16" height="16" class="flex-shrink-0"><use xlink:href="#icon-zap" /></svg>
|
||||
<span>Settings</span>
|
||||
<% end %>
|
||||
<svg class="ml-auto w-4 h-4 transition-transform duration-200 group-open:rotate-180" viewBox="0 0 20 20" fill="currentColor">
|
||||
<svg class="w-3 h-3 transition-transform duration-200 group-open:rotate-180" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
</summary>
|
||||
<ul class="ml-4 mt-1">
|
||||
<ul class="grid m-0 list-none settings-submenu">
|
||||
<% settings_pages.each do |_feature_key, attrs| %>
|
||||
<% url = super_admin_app_config_url(config: attrs['config_key']) %>
|
||||
<li class="px-4 mb-1">
|
||||
<% text_class = current_page?(url) ? 'text-woot-500 bg-slate-25' : 'text-slate-800' %>
|
||||
<%= link_to url, class: text_class + ' -ml-1 flex items-center px-2 py-1.5 hover:text-woot-500 hover:bg-slate-25 rounded-lg' do %>
|
||||
<span class="ml-2 text-sm"><%= attrs['name'] %></span>
|
||||
<li class="py-0.5 pl-3 ml-3 relative text-n-slate-11 settings-child-item">
|
||||
<% is_active = current_page?(url) %>
|
||||
<%= link_to url, class: "flex h-8 items-center gap-2 px-2 py-1 rounded-lg text-sm hover:bg-gradient-to-r from-transparent via-n-slate-3/70 to-n-slate-3/70 max-w-[140px] #{is_active ? 'text-n-blue-text bg-n-alpha-2' : ''}" do %>
|
||||
<% if attrs['icon'].present? %>
|
||||
<svg width="16" height="16" class="flex-shrink-0"><use xlink:href="#<%= attrs['icon'] %>" /></svg>
|
||||
<% end %>
|
||||
<span class="truncate"><%= attrs['name'] %></span>
|
||||
<% end %>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</details>
|
||||
</li>
|
||||
|
||||
<style>
|
||||
.settings-submenu .settings-child-item::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 2px;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
background-color: rgb(var(--slate-4));
|
||||
}
|
||||
|
||||
.settings-submenu .settings-child-item:first-child::before {
|
||||
border-radius: 4px 4px 0 0;
|
||||
}
|
||||
|
||||
.settings-submenu .settings-child-item:last-child::before {
|
||||
height: calc(50% - 4px);
|
||||
top: 0;
|
||||
border-radius: 4px 4px 0 0;
|
||||
}
|
||||
|
||||
.settings-submenu .settings-child-item:last-child::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
top: calc(50% - 6px);
|
||||
border-bottom: 2px solid rgb(var(--slate-4));
|
||||
border-left: 2px solid rgb(var(--slate-4));
|
||||
border-right: 0;
|
||||
border-top: 0;
|
||||
border-radius: 0 0 0 4px;
|
||||
left: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -27,49 +27,70 @@ It renders the `_table` partial to display details about the resources.
|
||||
<%= display_resource_name(page.resource_name) %>
|
||||
<% end %>
|
||||
|
||||
<header class="main-content__header" role="banner">
|
||||
<div class="flex items-center justify-between w-full">
|
||||
<h1 class="main-content__page-title m-0 mr-6" id="page-title">
|
||||
<%= content_for(:title) %>
|
||||
</h1>
|
||||
<%
|
||||
resource_icons = {
|
||||
'account' => 'icon-building-4-line',
|
||||
'user' => 'icon-user-follow-line',
|
||||
'account_user' => 'icon-user-follow-line',
|
||||
'agent_bot' => 'icon-robot-line',
|
||||
'response_source' => 'icon-book-2-line',
|
||||
'response_document' => 'icon-draft-line',
|
||||
'response' => 'icon-reply-line'
|
||||
}
|
||||
current_icon = resource_icons[page.resource_name] || 'icon-apps-2-line'
|
||||
%>
|
||||
|
||||
<div class="flex items-center">
|
||||
<% if show_search_bar %>
|
||||
<div class="flex items-center">
|
||||
<%= render("filters", page: page) %>
|
||||
<div class="ml-3">
|
||||
<%= render(
|
||||
"search",
|
||||
search_term: search_term,
|
||||
resource_name: display_resource_name(page.resource_name)
|
||||
) %>
|
||||
</div>
|
||||
<section class="flex flex-col w-full h-full">
|
||||
<header class="sticky top-0 z-10 bg-n-background border-b border-n-weak" role="banner">
|
||||
<div class="flex items-center justify-between w-full h-16 mx-auto max-w-[60rem]">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="border border-n-weak p-2 rounded-full text-n-slate-11">
|
||||
<svg width="24" height="24"><use xlink:href="#<%= current_icon %>" /></svg>
|
||||
</div>
|
||||
<% end %>
|
||||
<div class="flex flex-col justify-center">
|
||||
<h1 class="text-base font-medium tracking-tight text-n-slate-12" id="page-title">
|
||||
<%= content_for(:title) %>
|
||||
</h1>
|
||||
<p class="text-xs text-n-slate-11 m-0">Manage all registered <%= page.resource_name.pluralize.downcase %></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="whitespace-nowrap ml-4">
|
||||
<%= link_to(
|
||||
t(
|
||||
"administrate.actions.new_resource",
|
||||
name: page.resource_name.titleize.downcase
|
||||
),
|
||||
[:new, namespace, page.resource_path.to_sym],
|
||||
class: "button",
|
||||
) if accessible_action?(new_resource, :new) %>
|
||||
<div class="flex items-center gap-3">
|
||||
<% if show_search_bar %>
|
||||
<%= render("filters", page: page) %>
|
||||
<%= render(
|
||||
"search",
|
||||
search_term: search_term,
|
||||
resource_name: display_resource_name(page.resource_name)
|
||||
) %>
|
||||
<% end %>
|
||||
|
||||
<% if accessible_action?(new_resource, :new) %>
|
||||
<%= link_to(
|
||||
t(
|
||||
"administrate.actions.new_resource",
|
||||
name: page.resource_name.titleize.downcase
|
||||
),
|
||||
[:new, namespace, page.resource_path.to_sym],
|
||||
class: "inline-flex items-center justify-center h-8 px-3 text-sm font-medium text-white bg-woot-500 rounded-lg hover:bg-woot-600 transition-colors",
|
||||
) %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
</header>
|
||||
|
||||
<section class="main-content__body main-content__body--flush">
|
||||
<%= render(
|
||||
"collection",
|
||||
collection_presenter: page,
|
||||
collection_field_name: resource_name,
|
||||
page: page,
|
||||
resources: resources,
|
||||
table_title: "page-title"
|
||||
) %>
|
||||
<main class="flex-1 px-6 overflow-y-auto">
|
||||
<div class="w-full mx-auto max-w-[60rem] py-4">
|
||||
<%= render(
|
||||
"collection",
|
||||
collection_presenter: page,
|
||||
collection_field_name: resource_name,
|
||||
page: page,
|
||||
resources: resources,
|
||||
table_title: "page-title"
|
||||
) %>
|
||||
|
||||
<%= paginate resources, param_name: '_page'%>
|
||||
<%= paginate resources, param_name: '_page'%>
|
||||
</div>
|
||||
</main>
|
||||
</section>
|
||||
|
||||
@@ -18,48 +18,86 @@ as well as a link to its edit page.
|
||||
|
||||
<% content_for(:title) { t("administrate.actions.show_resource", name: page.page_title) } %>
|
||||
|
||||
<header class="main-content__header">
|
||||
<h1 class="main-content__page-title">
|
||||
<%= content_for(:title) %>
|
||||
</h1>
|
||||
<%
|
||||
resource_icons = {
|
||||
'account' => 'icon-building-4-line',
|
||||
'user' => 'icon-users',
|
||||
'account_user' => 'icon-user-follow-line',
|
||||
'agent_bot' => 'icon-toy-brick',
|
||||
'response_source' => 'icon-book-2-line',
|
||||
'response_document' => 'icon-draft-line',
|
||||
'response' => 'icon-reply-line'
|
||||
}
|
||||
current_icon = resource_icons[page.resource_name] || 'icon-folder-3-line'
|
||||
%>
|
||||
|
||||
<div>
|
||||
<%= link_to(
|
||||
"Edit",
|
||||
[:edit, namespace, page.resource],
|
||||
class: "button",
|
||||
) if accessible_action?(page.resource, :edit) %>
|
||||
<section class="flex flex-col w-full h-full">
|
||||
<header class="sticky top-0 z-10 bg-n-background border-b border-n-weak" role="banner">
|
||||
<div class="flex items-center justify-between w-full h-16 mx-auto max-w-[60rem]">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="border border-n-weak p-2 rounded-full text-n-slate-11">
|
||||
<svg width="24" height="24"><use xlink:href="#<%= current_icon %>" /></svg>
|
||||
</div>
|
||||
<div class="flex flex-col justify-center">
|
||||
<h1 class="text-base font-medium tracking-tight text-n-slate-12">
|
||||
<%= content_for(:title) %>
|
||||
</h1>
|
||||
<p class="text-xs text-n-slate-11 m-0">Resource details and configuration</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%= link_to(
|
||||
t("administrate.actions.destroy"),
|
||||
[namespace, page.resource],
|
||||
class: "button button--danger",
|
||||
method: :delete,
|
||||
data: { confirm: t("administrate.actions.confirm") }
|
||||
) if accessible_action?(page.resource, :destroy) %>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section class="main-content__body">
|
||||
<dl>
|
||||
<% page.attributes.each do |title, attributes| %>
|
||||
<fieldset class="<%= "field-unit--nested" if title.present? %>">
|
||||
<% if title.present? %>
|
||||
<legend><%= t "helpers.label.#{page.resource_name}.#{title}", default: title %></legend>
|
||||
<% end %>
|
||||
|
||||
<% attributes.each do |attribute| %>
|
||||
<dt class="attribute-label" id="<%= attribute.name %>">
|
||||
<%= t(
|
||||
"helpers.label.#{resource_name}.#{attribute.name}",
|
||||
default: page.resource.class.human_attribute_name(attribute.name),
|
||||
<div class="flex items-center gap-2">
|
||||
<% if accessible_action?(page.resource, :edit) %>
|
||||
<%= link_to(
|
||||
t("administrate.actions.edit"),
|
||||
[:edit, namespace, page.resource],
|
||||
class: "inline-flex items-center justify-center h-8 px-3 text-sm font-medium text-white bg-woot-500 rounded-lg hover:bg-woot-600 transition-colors"
|
||||
) %>
|
||||
</dt>
|
||||
|
||||
<dd class="attribute-data attribute-data--<%=attribute.html_class%>"
|
||||
><%= render_field attribute, page: page %></dd>
|
||||
<% end %>
|
||||
</fieldset>
|
||||
<% end %>
|
||||
</dl>
|
||||
|
||||
<% if accessible_action?(page.resource, :destroy) %>
|
||||
<%= link_to(
|
||||
t("administrate.actions.destroy"),
|
||||
[namespace, page.resource],
|
||||
class: "inline-flex items-center justify-center h-8 px-3 text-sm font-medium text-ruby-500 bg-ruby-100 rounded-lg hover:bg-ruby-200 transition-colors",
|
||||
method: :delete,
|
||||
data: { confirm: t("administrate.actions.confirm") }
|
||||
) %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="flex-1 px-6 overflow-y-auto">
|
||||
<div class="w-full mx-auto max-w-[60rem] py-6 space-y-6">
|
||||
<% page.attributes.each do |title, attributes| %>
|
||||
<div class="rounded-xl bg-n-solid-2 shadow outline-1 outline outline-n-container overflow-hidden">
|
||||
<div class="px-6 py-4 border-b border-n-weak">
|
||||
<% if title.present? %>
|
||||
<h2 class="text-base font-medium text-n-slate-12">
|
||||
<%= t "helpers.label.#{page.resource_name}.#{title}", default: title.to_s.titleize %>
|
||||
</h2>
|
||||
<% else %>
|
||||
<h2 class="text-base font-medium text-n-slate-12">Details</h2>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="divide-y divide-n-weak">
|
||||
<% attributes.each do |attribute| %>
|
||||
<div class="grid grid-cols-[180px,1fr] items-center min-h-12 px-6">
|
||||
<span class="text-sm text-n-slate-11">
|
||||
<%= t(
|
||||
"helpers.label.#{resource_name}.#{attribute.name}",
|
||||
default: page.resource.class.human_attribute_name(attribute.name),
|
||||
) %>
|
||||
</span>
|
||||
<span class="text-sm text-n-slate-12 py-3">
|
||||
<%= render_field attribute, page: page %>
|
||||
</span>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</main>
|
||||
</section>
|
||||
|
||||
@@ -7,5 +7,6 @@
|
||||
usersCount: @users_count,
|
||||
inboxesCount: @inboxes_count,
|
||||
conversationsCount: @conversations_count,
|
||||
chartData: @data
|
||||
chartData: @data,
|
||||
chartDays: @chart_days
|
||||
}) %>
|
||||
|
||||
@@ -1,23 +1,49 @@
|
||||
<% content_for(:title) do %>
|
||||
Instance Status
|
||||
<% end %>
|
||||
<header class="main-content__header" role="banner">
|
||||
<h1 class="main-content__page-title" id="page-title">
|
||||
<%= content_for(:title) %>
|
||||
</h1>
|
||||
</header>
|
||||
<section class="main-content__body">
|
||||
<table>
|
||||
<tr>
|
||||
<th>Metric</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
<% @metrics.each do |key,value| %>
|
||||
<tr>
|
||||
<td> <%= key %> </td>
|
||||
<td> <%= value %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</table>
|
||||
|
||||
<section class="flex flex-col w-full h-full">
|
||||
<header class="sticky top-0 z-10 bg-n-background border-b border-n-weak" role="banner">
|
||||
<div class="flex items-center justify-between w-full h-16 mx-auto max-w-[60rem]">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="border border-n-weak p-2 rounded-full text-n-slate-11">
|
||||
<svg width="24" height="24"><use xlink:href="#icon-heart-pulse" /></svg>
|
||||
</div>
|
||||
<div class="flex flex-col justify-center">
|
||||
<h1 class="text-base font-medium tracking-tight text-n-slate-12" id="page-title">
|
||||
<%= content_for(:title) %>
|
||||
</h1>
|
||||
<p class="text-xs text-n-slate-11 m-0">Chatwoot version and system information</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="flex-1 px-6 overflow-y-auto">
|
||||
<div class="w-full mx-auto max-w-[60rem] py-6">
|
||||
<div class="rounded-xl bg-n-solid-2 shadow outline-1 outline outline-n-container overflow-hidden">
|
||||
<div class="px-6 py-4 border-b border-n-weak">
|
||||
<h2 class="text-base font-medium text-n-slate-12">System Metrics</h2>
|
||||
</div>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full">
|
||||
<thead class="border-b border-n-weak">
|
||||
<tr>
|
||||
<th class="text-left py-3 pl-8 pr-4 text-sm text-n-slate-11">Metric</th>
|
||||
<th class="text-left py-3 pl-4 pr-8 text-sm text-n-slate-11">Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-n-weak">
|
||||
<% @metrics.each do |key, value| %>
|
||||
<tr class="hover:bg-n-alpha-1">
|
||||
<td class="py-4 pl-8 pr-4 text-sm text-n-slate-12 font-medium"><%= key %></td>
|
||||
<td class="py-4 pl-4 pr-8 text-sm text-n-slate-11 font-mono"><%= value %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</section>
|
||||
|
||||
@@ -1,129 +1,136 @@
|
||||
<% content_for(:title) do %>
|
||||
Settings
|
||||
<% end %>
|
||||
<header class="flex px-8 py-4 items-center border-b border-n-weak" role="banner">
|
||||
<div class="border border-n-weak mr-4 p-2 rounded-full">
|
||||
<svg width="24" height="24"><use xlink:href="#icon-settings-2-line" /></svg>
|
||||
</div>
|
||||
<div class="flex flex-col h-14 justify-center">
|
||||
<h1 class="text-base font-medium leading-6 text-n-slate-12" id="page-title">
|
||||
<%= content_for(:title) %>
|
||||
</h1>
|
||||
<p class="text-sm font-normal leading-5 text-slate-500 m-0">Update your instance settings, access billing portal</p>
|
||||
</div>
|
||||
</header>
|
||||
<section class="main-content__body px-8">
|
||||
<% if Redis::Alfred.get(Redis::Alfred::CHATWOOT_INSTALLATION_CONFIG_RESET_WARNING) %>
|
||||
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative mb-5" role="alert">
|
||||
<strong class="font-bold">Alert!</strong>
|
||||
<span class="block sm:inline">Unauthorized premium changes detected in Chatwoot. To keep using them, please upgrade your plan.
|
||||
Contact for help :</span><span class="inline rounded-full bg-red-200 px-2 text-white ml-2">sales@chatwoot.com</span>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="bg-white py-2 px-4 xl:px-0">
|
||||
<%= javascript_include_tag "secretField" %>
|
||||
<div class="flex items-center mb-6">
|
||||
<h4 class="text-sm font-medium leading-5 h-5 text-n-slate-12 mr-4">Installation Identifier</h4>
|
||||
<div data-secret-text="<%= ChatwootHub.installation_identifier %>" class="cell-data__secret-field text-sm leading-5 h-5 text-n-slate-11">
|
||||
<span data-secret-masked="true" class="select-none"></span>
|
||||
<button type="button" onclick="toggleSecretField(event)" data-secret-toggler class="inline-flex items-center justify-center h-5 w-5 p-0 rounded text-n-slate-11 hover:text-n-slate-12 transition-colors focus:outline-none">
|
||||
<svg width="20" height="20" class="w-5 h-5 fill-current">
|
||||
<use xlink:href="#eye-show" />
|
||||
</svg>
|
||||
</button>
|
||||
<button type="button" onclick="copySecretField(event)" data-secret-copier class="inline-flex items-center justify-center h-5 w-5 p-0 rounded text-n-slate-11 hover:text-n-slate-12 transition-colors focus:outline-none">
|
||||
<svg width="20" height="20" class="w-5 h-5 fill-current">
|
||||
<use xlink:href="#icon-copy" />
|
||||
</svg>
|
||||
</button>
|
||||
<section class="flex flex-col w-full h-full">
|
||||
<header class="sticky top-0 z-10 bg-n-background border-b border-n-weak" role="banner">
|
||||
<div class="flex items-center w-full h-16 mx-auto max-w-[60rem] gap-3">
|
||||
<div class="border border-n-weak p-2 rounded-full text-n-slate-11">
|
||||
<svg width="24" height="24"><use xlink:href="#icon-zap" /></svg>
|
||||
</div>
|
||||
<div class="flex flex-col justify-center">
|
||||
<h1 class="text-base font-medium tracking-tight text-n-slate-12" id="page-title">
|
||||
<%= content_for(:title) %>
|
||||
</h1>
|
||||
<p class="text-xs text-n-slate-11 m-0">Update your instance settings, access billing portal</p>
|
||||
</div>
|
||||
</div>
|
||||
<% if ChatwootApp.enterprise? %>
|
||||
<div class="flex p-4 outline outline-1 outline-n-container rounded-lg items-start md:items-center shadow-sm flex-col md:flex-row">
|
||||
<div class="flex flex-col flex-grow gap-1">
|
||||
<div class="flex items-center gap-2">
|
||||
<h2 class="h-5 leading-5 text-n-slate-12 text-sm font-medium">Current plan</h2>
|
||||
<a href="<%= refresh_super_admin_settings_url %>" class="inline-flex gap-1 text-xs font-medium items-center text-woot-500 hover:text-woot-700">
|
||||
<svg width="16" height="16"><use xlink:href="#icon-refresh-line" /></svg>
|
||||
<span>Refresh</span>
|
||||
</a>
|
||||
</div>
|
||||
<p class="text-n-slate-11 m-0 text-sm"><%= SuperAdmin::FeaturesHelper.plan_details.html_safe %></p>
|
||||
</header>
|
||||
|
||||
<main class="flex-1 px-6 overflow-y-auto">
|
||||
<div class="w-full mx-auto max-w-[60rem] py-4">
|
||||
<% if Redis::Alfred.get(Redis::Alfred::CHATWOOT_INSTALLATION_CONFIG_RESET_WARNING) %>
|
||||
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative mb-5" role="alert">
|
||||
<strong class="font-bold">Alert!</strong>
|
||||
<span class="block sm:inline">Unauthorized premium changes detected in Chatwoot. To keep using them, please upgrade your plan.
|
||||
Contact for help :</span><span class="inline rounded-full bg-red-200 px-2 text-white ml-2">sales@chatwoot.com</span>
|
||||
</div>
|
||||
<a href="<%= ChatwootHub.billing_url %>" target="_blank" rel="noopener noreferrer">
|
||||
<button class="mt-4 md:mt-0 flex gap-1 items-center bg-transparent shadow-sm h-9 hover:text-n-slate-12 hover:bg-slate-50 outline outline-1 outline-n-container rounded text-n-slate-11 font-medium p-2 focus:outline-none">
|
||||
<svg width="16" height="16"><use xlink:href="#icon-settings-2-line" /></svg>
|
||||
<span class="px-1">Manage</span>
|
||||
<% end %>
|
||||
|
||||
<%= javascript_include_tag "secretField" %>
|
||||
<div class="flex items-center mb-6">
|
||||
<h4 class="text-sm font-medium leading-5 h-5 text-n-slate-12 mr-4">Installation Identifier</h4>
|
||||
<div data-secret-text="<%= ChatwootHub.installation_identifier %>" class="cell-data__secret-field text-sm leading-5 h-5 text-n-slate-11">
|
||||
<span data-secret-masked="true" class="select-none"></span>
|
||||
<button type="button" onclick="toggleSecretField(event)" data-secret-toggler class="inline-flex items-center justify-center h-5 w-5 p-0 rounded text-n-slate-11 hover:text-n-slate-12 transition-colors focus:outline-none">
|
||||
<svg width="20" height="20" class="w-5 h-5 fill-current">
|
||||
<use xlink:href="#eye-show" />
|
||||
</svg>
|
||||
</button>
|
||||
<button type="button" onclick="copySecretField(event)" data-secret-copier class="inline-flex items-center justify-center h-5 w-5 p-0 rounded text-n-slate-11 hover:text-n-slate-12 transition-colors focus:outline-none">
|
||||
<svg width="20" height="20" class="w-5 h-5 fill-current">
|
||||
<use xlink:href="#icon-copy" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<% if ChatwootApp.enterprise? %>
|
||||
<div class="flex p-4 outline outline-1 outline-n-container rounded-xl items-start md:items-center shadow-sm flex-col md:flex-row bg-n-solid-2">
|
||||
<div class="flex flex-col flex-grow gap-1">
|
||||
<div class="flex items-center gap-2">
|
||||
<h2 class="h-5 leading-5 text-n-slate-12 text-sm font-medium">Current plan</h2>
|
||||
<a href="<%= refresh_super_admin_settings_url %>" class="inline-flex gap-1 text-xs font-medium items-center text-woot-500 hover:text-woot-700">
|
||||
<svg width="16" height="16"><use xlink:href="#icon-refresh-line" /></svg>
|
||||
<span>Refresh</span>
|
||||
</a>
|
||||
</div>
|
||||
<p class="text-n-slate-11 m-0 text-sm"><%= SuperAdmin::FeaturesHelper.plan_details.html_safe %></p>
|
||||
</div>
|
||||
<a href="<%= ChatwootHub.billing_url %>" target="_blank" rel="noopener noreferrer">
|
||||
<button class="mt-4 md:mt-0 flex gap-1 items-center bg-transparent shadow-sm h-9 hover:text-n-slate-12 hover:bg-n-alpha-2 outline outline-1 outline-n-container rounded text-n-slate-11 font-medium p-2 focus:outline-none">
|
||||
<svg width="16" height="16"><use xlink:href="#icon-settings-2-line" /></svg>
|
||||
<span class="px-1">Manage</span>
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if ChatwootHub.pricing_plan != 'community' && User.count > ChatwootHub.pricing_plan_quantity %>
|
||||
<div role="alert" class="mt-4">
|
||||
<div class="border border-t-0 border-red-400 rounded-b bg-red-100 px-4 py-3 text-red-700">
|
||||
<p>You have <%= User.count %> agents. Please add more licenses to add more users.</p>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="flex p-4 outline outline-1 outline-n-container rounded-xl mt-4 items-start md:items-center shadow-sm flex-col md:flex-row bg-n-solid-2">
|
||||
<div class="flex flex-col flex-grow gap-1">
|
||||
<h2 class="h-5 leading-5 text-n-slate-12 text-sm font-medium">Need help?</h2>
|
||||
<p class="text-n-slate-11 m-0 text-sm">Do you face any issues? We are here to help.</p>
|
||||
</div>
|
||||
<a href="https://discord.gg/cJXdrwS" target="_blank">
|
||||
<button class="flex mt-4 md:mt-0 gap-1 items-center bg-transparent shadow-sm h-9 bg-violet-500 hover:bg-violet-600 text-white border border-solid border-violet-600 rounded font-medium p-2 focus:outline-none">
|
||||
<svg class="h-4 w-4" width="24" height="24" fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M13.209 3.103c-.495-1.004-1.926-1.004-2.421 0L8.43 7.88l-5.273.766c-1.107.161-1.55 1.522-.748 2.303l3.815 3.72-.9 5.25c-.19 1.103.968 1.944 1.959 1.424l4.715-2.48 4.716 2.48c.99.52 2.148-.32 1.96-1.424l-.902-5.25 3.816-3.72c.8-.78.359-2.142-.748-2.303l-5.273-.766-2.358-4.777ZM9.74 8.615l2.258-4.576 2.259 4.576a1.35 1.35 0 0 0 1.016.738l5.05.734-3.654 3.562a1.35 1.35 0 0 0-.388 1.195l.862 5.03-4.516-2.375a1.35 1.35 0 0 0-1.257 0l-4.516 2.374.862-5.029a1.35 1.35 0 0 0-.388-1.195l-3.654-3.562 5.05-.734c.44-.063.82-.34 1.016-.738ZM1.164 3.782a.75.75 0 0 0 .118 1.054l2.5 2a.75.75 0 1 0 .937-1.172l-2.5-2a.75.75 0 0 0-1.055.118Z" fill="currentColor"/><path d="M22.836 18.218a.75.75 0 0 0-.117-1.054l-2.5-2a.75.75 0 0 0-.938 1.172l2.5 2a.75.75 0 0 0 1.055-.117ZM1.282 17.164a.75.75 0 1 0 .937 1.172l2.5-2a.75.75 0 0 0-.937-1.172l-2.5 2ZM22.836 3.782a.75.75 0 0 1-.117 1.054l-2.5 2a.75.75 0 0 1-.938-1.172l2.5-2a.75.75 0 0 1 1.055.118Z" fill="currentColor"/></svg>
|
||||
<span class="px-1">Community Support</span>
|
||||
</button>
|
||||
</a>
|
||||
<% if ChatwootHub.pricing_plan != 'community' %>
|
||||
<button class="ml-4 flex gap-1 items-center bg-transparent h-9 hover:text-n-slate-12 hover:bg-n-alpha-2 border border-solid border-n-weak rounded text-n-slate-11 font-medium p-2 focus:outline-none" onclick="window.$chatwoot.toggle('open')">
|
||||
<svg class="h-4 w-4" width="24" height="24" fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M13.209 3.103c-.495-1.004-1.926-1.004-2.421 0L8.43 7.88l-5.273.766c-1.107.161-1.55 1.522-.748 2.303l3.815 3.72-.9 5.25c-.19 1.103.968 1.944 1.959 1.424l4.715-2.48 4.716 2.48c.99.52 2.148-.32 1.96-1.424l-.902-5.25 3.816-3.72c.8-.78.359-2.142-.748-2.303l-5.273-.766-2.358-4.777ZM9.74 8.615l2.258-4.576 2.259 4.576a1.35 1.35 0 0 0 1.016.738l5.05.734-3.654 3.562a1.35 1.35 0 0 0-.388 1.195l.862 5.03-4.516-2.375a1.35 1.35 0 0 0-1.257 0l-4.516 2.374.862-5.029a1.35 1.35 0 0 0-.388-1.195l-3.654-3.562 5.05-.734c.44-.063.82-.34 1.016-.738ZM1.164 3.782a.75.75 0 0 0 .118 1.054l2.5 2a.75.75 0 1 0 .937-1.172l-2.5-2a.75.75 0 0 0-1.055.118Z" fill="currentColor"/><path d="M22.836 18.218a.75.75 0 0 0-.117-1.054l-2.5-2a.75.75 0 0 0-.938 1.172l2.5 2a.75.75 0 0 0 1.055-.117ZM1.282 17.164a.75.75 0 1 0 .937 1.172l2.5-2a.75.75 0 0 0-.937-1.172l-2.5 2ZM22.836 3.782a.75.75 0 0 1-.117 1.054l-2.5 2a.75.75 0 0 1-.938-1.172l2.5-2a.75.75 0 0 1 1.055.118Z" fill="currentColor"/></svg>
|
||||
<span class="px-1">Chat Support</span>
|
||||
</button>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if ChatwootHub.pricing_plan != 'community' && User.count > ChatwootHub.pricing_plan_quantity %>
|
||||
<div role="alert">
|
||||
<div class="border border-t-0 border-red-400 rounded-b bg-red-100 px-4 py-3 text-red-700">
|
||||
<p>You have <%= User.count %> agents. Please add more licenses to add more users.</p>
|
||||
<div class="mt-10 py-4">
|
||||
<h3 class="h-5 leading-5 text-n-slate-12 font-medium text-base">Features</h3>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
|
||||
<div class="flex p-4 outline outline-1 outline-n-container rounded-lg mt-4 items-start md:items-center shadow-sm flex-col md:flex-row">
|
||||
<div class="flex flex-col flex-grow gap-1">
|
||||
<h2 class="h-5 leading-5 text-n-slate-12 text-sm font-medium">Need help?</h2>
|
||||
<p class="text-n-slate-11 m-0 text-sm">Do you face any issues? We are here to help.</p>
|
||||
</div>
|
||||
<a href="https://discord.gg/cJXdrwS" target="_blank">
|
||||
<button class="flex mt-4 md:mt-0 gap-1 items-center bg-transparent shadow-sm h-9 bg-violet-500 hover:bg-violet-600 text-white border border-solid border-violet-600 rounded font-medium p-2 focus:outline-none">
|
||||
<svg class="h-4 w-4" width="24" height="24" fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M13.209 3.103c-.495-1.004-1.926-1.004-2.421 0L8.43 7.88l-5.273.766c-1.107.161-1.55 1.522-.748 2.303l3.815 3.72-.9 5.25c-.19 1.103.968 1.944 1.959 1.424l4.715-2.48 4.716 2.48c.99.52 2.148-.32 1.96-1.424l-.902-5.25 3.816-3.72c.8-.78.359-2.142-.748-2.303l-5.273-.766-2.358-4.777ZM9.74 8.615l2.258-4.576 2.259 4.576a1.35 1.35 0 0 0 1.016.738l5.05.734-3.654 3.562a1.35 1.35 0 0 0-.388 1.195l.862 5.03-4.516-2.375a1.35 1.35 0 0 0-1.257 0l-4.516 2.374.862-5.029a1.35 1.35 0 0 0-.388-1.195l-3.654-3.562 5.05-.734c.44-.063.82-.34 1.016-.738ZM1.164 3.782a.75.75 0 0 0 .118 1.054l2.5 2a.75.75 0 1 0 .937-1.172l-2.5-2a.75.75 0 0 0-1.055.118Z" fill="currentColor"/><path d="M22.836 18.218a.75.75 0 0 0-.117-1.054l-2.5-2a.75.75 0 0 0-.938 1.172l2.5 2a.75.75 0 0 0 1.055-.117ZM1.282 17.164a.75.75 0 1 0 .937 1.172l2.5-2a.75.75 0 0 0-.937-1.172l-2.5 2ZM22.836 3.782a.75.75 0 0 1-.117 1.054l-2.5 2a.75.75 0 0 1-.938-1.172l2.5-2a.75.75 0 0 1 1.055.118Z" fill="currentColor"/></svg>
|
||||
<span class="px-1">Community Support</span>
|
||||
</button>
|
||||
</a>
|
||||
<% if ChatwootHub.pricing_plan !='community' %>
|
||||
<button class="ml-4 flex gap-1 items-center bg-transparent h-9 hover:text-n-slate-12 hover:bg-slate-50 border border-solid border-slate-100 rounded text-n-slate-11 font-medium p-2 focus:outline-none" onclick="window.$chatwoot.toggle('open')">
|
||||
<svg class="h-4 w-4" width="24" height="24" fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M13.209 3.103c-.495-1.004-1.926-1.004-2.421 0L8.43 7.88l-5.273.766c-1.107.161-1.55 1.522-.748 2.303l3.815 3.72-.9 5.25c-.19 1.103.968 1.944 1.959 1.424l4.715-2.48 4.716 2.48c.99.52 2.148-.32 1.96-1.424l-.902-5.25 3.816-3.72c.8-.78.359-2.142-.748-2.303l-5.273-.766-2.358-4.777ZM9.74 8.615l2.258-4.576 2.259 4.576a1.35 1.35 0 0 0 1.016.738l5.05.734-3.654 3.562a1.35 1.35 0 0 0-.388 1.195l.862 5.03-4.516-2.375a1.35 1.35 0 0 0-1.257 0l-4.516 2.374.862-5.029a1.35 1.35 0 0 0-.388-1.195l-3.654-3.562 5.05-.734c.44-.063.82-.34 1.016-.738ZM1.164 3.782a.75.75 0 0 0 .118 1.054l2.5 2a.75.75 0 1 0 .937-1.172l-2.5-2a.75.75 0 0 0-1.055.118Z" fill="currentColor"/><path d="M22.836 18.218a.75.75 0 0 0-.117-1.054l-2.5-2a.75.75 0 0 0-.938 1.172l2.5 2a.75.75 0 0 0 1.055-.117ZM1.282 17.164a.75.75 0 1 0 .937 1.172l2.5-2a.75.75 0 0 0-.937-1.172l-2.5 2ZM22.836 3.782a.75.75 0 0 1-.117 1.054l-2.5 2a.75.75 0 0 1-.938-1.172l2.5-2a.75.75 0 0 1 1.055.118Z" fill="currentColor"/></svg>
|
||||
<span class="px-1">Chat Support</span>
|
||||
</button>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="mt-10 py-4">
|
||||
<h3 class="h-5 leading-5 text-n-slate-12 font-medium text-base">Features</h3>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-x-2 gap-y-3">
|
||||
<% SuperAdmin::FeaturesHelper.available_features.each do |feature, attrs| %>
|
||||
<div class="group outline outline-1 outline-n-container p-4 rounded-lg relative shadow-sm">
|
||||
<span class="<%= attrs[:enabled] ? 'bg-green-400 text-white': 'bg-slate-300 text-slate-800' %> absolute rounded-full p-1 inline-flex right-4 top-5">
|
||||
<svg width="14" height="14"><use xlink:href="<%= attrs[:enabled] ? '#icon-tick-line': '#icon-lock-line' %>" /></svg>
|
||||
</span>
|
||||
<div class="visible <% if !attrs[:enabled] %> group-hover:invisible <% end %> flex items-center justify-center w-10 h-10 mb-2 border border-slate-100 border-solid text-slate-800 rounded-full">
|
||||
<svg width="20" height="20"><use xlink:href="#<%= attrs[:icon] %>" /></svg>
|
||||
</div>
|
||||
<% if !attrs[:enabled] %>
|
||||
<div class="flex h-9 absolute top-5 items-center invisible group-hover:visible">
|
||||
<% if ChatwootApp.enterprise? %>
|
||||
<%= render 'upgrade_button_enterprise' %>
|
||||
<% else %>
|
||||
<%= render 'upgrade_button_community' %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
<div class="flex items-center justify-between mb-1.5 mt-4">
|
||||
<div class="flex items-center gap-2">
|
||||
<h3 class="text-n-slate-12 font-medium"><%= attrs[:name] %></h3>
|
||||
<% if attrs[:enterprise] %>
|
||||
<span class="px-2 h-4 leading-4 rounded-xl text-green-800 font-medium bg-green-100/70 text-xxs">EE</span>
|
||||
<% end %>
|
||||
<% if attrs[:config_key].present? && attrs[:enabled] %>
|
||||
<a class="inline-flex items-center justify-center h-5 w-5 hover:bg-slate-50 rounded-sm" href="/super_admin/app_config?config=<%= attrs[:config_key] %>">
|
||||
<svg width="18" height="18"><use xlink:href="#icon-gear" /></svg>
|
||||
</a>
|
||||
<% end %>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3">
|
||||
<% SuperAdmin::FeaturesHelper.available_features.each do |feature, attrs| %>
|
||||
<div class="group outline outline-1 outline-n-container p-4 rounded-xl relative shadow-sm bg-n-solid-2">
|
||||
<span class="<%= attrs[:enabled] ? 'bg-green-400 text-white': 'bg-slate-300 text-slate-800' %> absolute rounded-full p-1 inline-flex right-4 top-5">
|
||||
<svg width="14" height="14"><use xlink:href="<%= attrs[:enabled] ? '#icon-tick-line': '#icon-lock-line' %>" /></svg>
|
||||
</span>
|
||||
<div class="visible <% if !attrs[:enabled] %> group-hover:invisible <% end %> flex items-center justify-center w-10 h-10 mb-2 border border-n-weak border-solid text-n-slate-11 rounded-full">
|
||||
<svg width="20" height="20"><use xlink:href="#<%= attrs[:icon] %>" /></svg>
|
||||
</div>
|
||||
<% if !attrs[:enabled] %>
|
||||
<div class="flex h-9 absolute top-5 items-center invisible group-hover:visible">
|
||||
<% if ChatwootApp.enterprise? %>
|
||||
<%= render 'upgrade_button_enterprise' %>
|
||||
<% else %>
|
||||
<%= render 'upgrade_button_community' %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
<div class="flex items-center justify-between mb-1.5 mt-4">
|
||||
<div class="flex items-center gap-2">
|
||||
<h3 class="text-n-slate-12 font-medium"><%= attrs[:name] %></h3>
|
||||
<% if attrs[:enterprise] %>
|
||||
<span class="px-2 h-4 leading-4 rounded-xl text-green-800 font-medium bg-green-100/70 text-xxs">EE</span>
|
||||
<% end %>
|
||||
<% if attrs[:config_key].present? && attrs[:enabled] %>
|
||||
<a class="inline-flex items-center justify-center h-5 w-5 hover:bg-n-alpha-2 rounded-sm" href="/super_admin/app_config?config=<%= attrs[:config_key] %>">
|
||||
<svg width="18" height="18"><use xlink:href="#icon-gear" /></svg>
|
||||
</a>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-n-slate-11 mb-0 text-sm"><%= attrs[:description] %></p>
|
||||
</div>
|
||||
<p class="text-n-slate-11 mb-0"><%= attrs[:description] %></p>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</section>
|
||||
|
||||
@@ -11,44 +11,18 @@ Used by both account and user show pages.
|
||||
- `resource_type`: Either 'account' or 'user' to determine hidden field
|
||||
%>
|
||||
|
||||
<section class="main-content__body">
|
||||
<% account_user_page = Administrate::Page::Form.new(AccountUserDashboard.new, AccountUser.new) %>
|
||||
<%= form_for([namespace, account_user_page.resource], html: { class: "form" }) do |f| %>
|
||||
<% if account_user_page.resource.errors.any? %>
|
||||
<div id="error_explanation">
|
||||
<h2>
|
||||
<%= t(
|
||||
"administrate.form.errors",
|
||||
pluralized_errors: pluralize(
|
||||
account_user_page.resource.errors.count,
|
||||
t("administrate.form.error")
|
||||
),
|
||||
resource_name: display_resource_name(account_user_page.resource_name)
|
||||
) %>
|
||||
</h2>
|
||||
|
||||
<ul>
|
||||
<% account_user_page.resource.errors.full_messages.each do |message| %>
|
||||
<li class="flash-error"><%= message %></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% account_user_page = Administrate::Page::Form.new(AccountUserDashboard.new, AccountUser.new) %>
|
||||
<%= form_for([namespace, account_user_page.resource]) do |f| %>
|
||||
<div class="flex items-end gap-4 flex-wrap">
|
||||
<% account_user_page.attributes.each do |title, attributes| -%>
|
||||
<% attributes.each do |attribute| %>
|
||||
<% if attribute.name == resource_type %>
|
||||
<% if attribute.name.to_s == resource_type %>
|
||||
<%= f.hidden_field("#{resource_type}_id", value: page.resource.id) %>
|
||||
<% else %>
|
||||
<div class="field-unit field-unit--<%= attribute.html_class %> field-unit--<%= requireness(attribute) %>">
|
||||
<%= render_field attribute, f: f %>
|
||||
</div>
|
||||
<%= render_field attribute, f: f %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end -%>
|
||||
|
||||
<div class="form-actions">
|
||||
<%= f.submit %>
|
||||
</div>
|
||||
<% end %>
|
||||
</section>
|
||||
<%= f.submit "Add User", class: "inline-flex items-center justify-center h-9 px-4 text-sm font-medium text-white bg-woot-500 rounded-lg hover:bg-woot-600 transition-colors cursor-pointer" %>
|
||||
</div>
|
||||
<% end %>
|
||||
@@ -18,78 +18,79 @@ to display a collection of resources in an HTML table.
|
||||
[1]: http://www.rubydoc.info/gems/administrate/Administrate/Page/Collection
|
||||
%>
|
||||
|
||||
<table aria-labelledby="<%= table_title %>">
|
||||
<thead>
|
||||
<tr>
|
||||
<% collection_presenter.attribute_types.each do |attr_name, attr_type| %>
|
||||
<th class="cell-label
|
||||
cell-label--<%= attr_type.html_class %>
|
||||
cell-label--<%= collection_presenter.ordered_html_class(attr_name) %>"
|
||||
scope="col"
|
||||
role="columnheader"
|
||||
aria-sort="<%= sort_order(collection_presenter.ordered_html_class(attr_name)) %>">
|
||||
<%= link_to(sanitized_order_params(page, collection_field_name).merge(
|
||||
collection_presenter.order_params_for(attr_name, key: collection_field_name)
|
||||
)) do %>
|
||||
<%= t(
|
||||
"helpers.label.#{collection_presenter.resource_name}.#{attr_name}",
|
||||
default: attr_name.to_s,
|
||||
).titleize %>
|
||||
<% if collection_presenter.ordered_by?(attr_name) %>
|
||||
<span class="cell-label__sort-indicator cell-label__sort-indicator--<%= collection_presenter.ordered_html_class(attr_name) %>">
|
||||
<svg aria-hidden="true">
|
||||
<use xlink:href="#icon-up-caret" />
|
||||
</svg>
|
||||
</span>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full" aria-labelledby="<%= table_title %>">
|
||||
<thead class="border-b border-n-weak">
|
||||
<tr>
|
||||
<% collection_presenter.attribute_types.each_with_index do |(attr_name, attr_type), index| %>
|
||||
<th class="text-left py-3 px-4 text-sm text-n-slate-11 first:!pl-3 last:!pr-3"
|
||||
scope="col"
|
||||
role="columnheader"
|
||||
aria-sort="<%= sort_order(collection_presenter.ordered_html_class(attr_name)) %>">
|
||||
<%= link_to(sanitized_order_params(page, collection_field_name).merge(
|
||||
collection_presenter.order_params_for(attr_name, key: collection_field_name)
|
||||
), class: "inline-flex items-center gap-1 hover:text-n-slate-12") do %>
|
||||
<%= t(
|
||||
"helpers.label.#{collection_presenter.resource_name}.#{attr_name}",
|
||||
default: attr_name.to_s,
|
||||
).titleize %>
|
||||
<% if collection_presenter.ordered_by?(attr_name) %>
|
||||
<span class="<%= collection_presenter.ordered_html_class(attr_name) == 'asc' ? '' : 'rotate-180' %>">
|
||||
<svg class="w-3 h-3" aria-hidden="true">
|
||||
<use xlink:href="#icon-up-caret" />
|
||||
</svg>
|
||||
</span>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</th>
|
||||
<% end %>
|
||||
<% [existing_action?(collection_presenter.resource_name, :edit),
|
||||
existing_action?(collection_presenter.resource_name, :destroy)].count(true).times do %>
|
||||
<th scope="col"></th>
|
||||
<% end %>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<% resources.each do |resource| %>
|
||||
<tr class="js-table-row"
|
||||
tabindex="0"
|
||||
<% if existing_action? collection_presenter.resource_name, :show %>
|
||||
<%= %(role=link data-url=#{polymorphic_path([namespace, resource.becomes(User)])}) %>
|
||||
<% end %>
|
||||
>
|
||||
<% collection_presenter.attributes_for(resource).each do |attribute| %>
|
||||
<td class="cell-data cell-data--<%= attribute.html_class %>">
|
||||
<% if authorized_action? resource, :show -%>
|
||||
<a href="<%= polymorphic_path([namespace, resource.becomes(User)]) -%>"
|
||||
class="action-show"
|
||||
>
|
||||
<%= render_field attribute %>
|
||||
</a>
|
||||
<% end -%>
|
||||
</td>
|
||||
</th>
|
||||
<% end %>
|
||||
|
||||
<% if existing_action? collection_presenter.resource_name, :edit %>
|
||||
<td><%= link_to(
|
||||
t("administrate.actions.edit"),
|
||||
[:edit, namespace, resource.becomes(User)],
|
||||
class: "action-edit",
|
||||
) if authorized_action? resource, :edit%></td>
|
||||
<% if existing_action?(collection_presenter.resource_name, :edit) %>
|
||||
<th scope="col"></th>
|
||||
<% end %>
|
||||
|
||||
<% if existing_action? collection_presenter.resource_name, :destroy %>
|
||||
<td><%= link_to(
|
||||
t("administrate.actions.destroy"),
|
||||
[namespace, collection_presenter.resource_name == 'account_user' ? resource : resource.becomes(User)],
|
||||
class: "text-color-red",
|
||||
method: :delete,
|
||||
data: { confirm: t("administrate.actions.confirm") }
|
||||
) if authorized_action? resource, :destroy %></td>
|
||||
<% if existing_action?(collection_presenter.resource_name, :destroy) %>
|
||||
<th scope="col" class="pr-3"></th>
|
||||
<% end %>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
</thead>
|
||||
|
||||
<tbody class="divide-y divide-n-weak">
|
||||
<% resources.each do |resource| %>
|
||||
<tr class="js-table-row hover:bg-n-alpha-1 transition-colors"
|
||||
tabindex="0"
|
||||
<% if existing_action? collection_presenter.resource_name, :show %>
|
||||
<%= %(role=link data-url=#{polymorphic_path([namespace, resource.becomes(User)])}) %>
|
||||
<% end %>
|
||||
>
|
||||
<% collection_presenter.attributes_for(resource).each_with_index do |attribute, index| %>
|
||||
<td class="py-4 px-4 text-sm text-n-slate-12 first:!pl-3 last:!pr-3">
|
||||
<% if authorized_action? resource, :show -%>
|
||||
<a href="<%= polymorphic_path([namespace, resource.becomes(User)]) -%>"
|
||||
class="hover:underline"
|
||||
>
|
||||
<%= render_field attribute %>
|
||||
</a>
|
||||
<% end -%>
|
||||
</td>
|
||||
<% end %>
|
||||
<% if existing_action?(collection_presenter.resource_name, :edit) %>
|
||||
<td class="py-4 px-4 text-right"><%= link_to(
|
||||
t("administrate.actions.edit"),
|
||||
[:edit, namespace, resource.becomes(User)],
|
||||
class: "text-sm font-medium text-n-brand hover:underline",
|
||||
) if authorized_action? resource, :edit%></td>
|
||||
<% end %>
|
||||
|
||||
<% if existing_action?(collection_presenter.resource_name, :destroy) %>
|
||||
<td class="py-4 pl-4 !pr-3 text-right"><%= link_to(
|
||||
t("administrate.actions.destroy"),
|
||||
[namespace, collection_presenter.resource_name == 'account_user' ? resource : resource.becomes(User)],
|
||||
class: "text-sm font-medium text-n-ruby-11 hover:underline",
|
||||
method: :delete,
|
||||
data: { confirm: t("administrate.actions.confirm") }
|
||||
) if authorized_action? resource, :destroy %></td>
|
||||
<% end %>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<section class="main-content__body">
|
||||
<hr/>
|
||||
<div class="form-actions">
|
||||
<p class="text-color-red">Caution: Any actions executed after impersonate will appear as if performed by the impersonated user - [<%= page.resource.name %> ]</p>
|
||||
<a class='button' target='_blank' href='<%= page.resource.generate_sso_link_with_impersonation %>'>Impersonate user </a>
|
||||
</div>
|
||||
</section>
|
||||
<div class="px-6 py-4">
|
||||
<h3 class="text-sm font-medium text-n-slate-12 mb-2">Impersonate User</h3>
|
||||
<p class="text-xs text-ruby-500 mb-3">Caution: Any actions executed after impersonate will appear as if performed by the impersonated user - [<%= page.resource.name %>]</p>
|
||||
<a target="_blank" href="<%= page.resource.generate_sso_link_with_impersonation %>" class="inline-flex items-center justify-center h-8 px-3 text-sm font-medium text-n-slate-12 bg-n-alpha-2 rounded-lg hover:bg-n-alpha-3 transition-colors">
|
||||
Impersonate user
|
||||
</a>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -18,44 +18,151 @@ as well as a link to its edit page.
|
||||
|
||||
<% content_for(:title) { t("administrate.actions.show_resource", name: page.page_title) } %>
|
||||
|
||||
<header class="main-content__header" role="banner">
|
||||
<h1 class="main-content__page-title">
|
||||
<%= content_for(:title) %>
|
||||
</h1>
|
||||
<section class="flex flex-col w-full h-full">
|
||||
<header class="sticky top-0 z-10 bg-n-background border-b border-n-weak" role="banner">
|
||||
<div class="flex items-center justify-between w-full h-16 mx-auto max-w-[60rem]">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="border border-n-weak p-2 rounded-full text-n-slate-11">
|
||||
<svg width="24" height="24"><use xlink:href="#icon-users" /></svg>
|
||||
</div>
|
||||
<div class="flex flex-col justify-center">
|
||||
<h1 class="text-base font-medium tracking-tight text-n-slate-12">
|
||||
<%= content_for(:title) %>
|
||||
</h1>
|
||||
<p class="text-xs text-n-slate-11 m-0">Profile, accounts, and access control</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<%= link_to(
|
||||
<div class="flex items-center gap-2">
|
||||
<% if authorized_action?(page.resource, :edit) %>
|
||||
<%= link_to(
|
||||
t("administrate.actions.edit"),
|
||||
[:edit, namespace, page.resource.becomes(User)],
|
||||
class: "button",
|
||||
) if authorized_action? page.resource, :edit %>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section class="main-content__body">
|
||||
<dl>
|
||||
<% page.attributes.each do |title, attributes| %>
|
||||
<fieldset class="<%= "field-unit--nested" if title.present? %>">
|
||||
<% if title.present? %>
|
||||
<legend><%= t "helpers.label.#{page.resource_name}.#{title}", default: title %></legend>
|
||||
<% end %>
|
||||
|
||||
<% attributes.each do |attribute| %>
|
||||
<dt class="attribute-label" id="<%= attribute.name %>">
|
||||
<%= t(
|
||||
"helpers.label.#{resource_name}.#{attribute.name}",
|
||||
default: page.resource.class.human_attribute_name(attribute.name),
|
||||
[:edit, namespace, page.resource.becomes(User)],
|
||||
class: "inline-flex items-center justify-center h-8 px-3 text-sm font-medium text-white bg-woot-500 rounded-lg hover:bg-woot-600 transition-colors"
|
||||
) %>
|
||||
</dt>
|
||||
|
||||
<dd class="attribute-data attribute-data--<%=attribute.html_class%>"
|
||||
><%= render_field attribute, page: page %></dd>
|
||||
<% end %>
|
||||
</fieldset>
|
||||
<% end %>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="flex-1 px-6 overflow-y-auto">
|
||||
<div class="w-full mx-auto max-w-[60rem] py-6 space-y-6">
|
||||
|
||||
<%# User Information Card %>
|
||||
<div class="rounded-xl bg-n-solid-2 shadow outline-1 outline outline-n-container overflow-hidden">
|
||||
<div class="px-6 py-4 border-b border-n-weak">
|
||||
<h2 class="text-base font-medium text-n-slate-12">User Information</h2>
|
||||
</div>
|
||||
<div class="divide-y divide-n-weak">
|
||||
<% page.attributes.each do |title, attributes| %>
|
||||
<% next if title.present? %>
|
||||
<% attributes.each do |attribute| %>
|
||||
<% next if ['account_users', 'custom_attributes'].include?(attribute.name.to_s) %>
|
||||
<div class="grid grid-cols-[180px,1fr] items-center min-h-12 px-6">
|
||||
<span class="text-sm text-n-slate-11">
|
||||
<%= t(
|
||||
"helpers.label.#{resource_name}.#{attribute.name}",
|
||||
default: page.resource.class.human_attribute_name(attribute.name),
|
||||
) %>
|
||||
</span>
|
||||
<span class="text-sm text-n-slate-12 py-3">
|
||||
<%= render_field attribute, page: page %>
|
||||
</span>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%# Account Users Card %>
|
||||
<% page.attributes.each do |title, attributes| %>
|
||||
<% next if title.present? %>
|
||||
<% attributes.each do |attribute| %>
|
||||
<% if attribute.name.to_s == 'account_users' && page.resource.account_users.any? %>
|
||||
<div class="rounded-xl bg-n-solid-2 shadow outline-1 outline outline-n-container overflow-hidden">
|
||||
<div class="px-6 py-4 border-b border-n-weak">
|
||||
<h2 class="text-base font-medium text-n-slate-12">Account Users</h2>
|
||||
</div>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full">
|
||||
<thead class="border-b border-n-weak">
|
||||
<tr>
|
||||
<th class="text-left py-3 !pl-6 pr-4 text-sm text-n-slate-11">Account</th>
|
||||
<th class="text-left py-3 px-4 text-sm text-n-slate-11">User</th>
|
||||
<th class="text-left py-3 px-4 text-sm text-n-slate-11">Inviter</th>
|
||||
<th class="text-left py-3 px-4 text-sm text-n-slate-11">Role</th>
|
||||
<th class="text-left py-3 pl-4 !pr-6 text-sm text-n-slate-11"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-n-weak">
|
||||
<% page.resource.account_users.each do |account_user| %>
|
||||
<tr class="hover:bg-n-alpha-1">
|
||||
<td class="py-4 !pl-6 pr-4 text-sm text-n-slate-12">
|
||||
<%= link_to "##{account_user.account_id} #{account_user.account.name}", super_admin_account_path(account_user.account), class: "text-n-slate-12 hover:underline" %>
|
||||
</td>
|
||||
<td class="py-4 px-4 text-sm text-n-slate-12">
|
||||
<%= link_to "##{account_user.user_id} #{account_user.user.name}", super_admin_user_path(account_user.user), class: "text-n-slate-12 hover:underline" %>
|
||||
</td>
|
||||
<td class="py-4 px-4 text-sm text-n-slate-11">
|
||||
<% if account_user.inviter.present? %>
|
||||
<%= link_to account_user.inviter.name, super_admin_user_path(account_user.inviter), class: "text-n-slate-12 hover:underline" %>
|
||||
<% else %>
|
||||
<span class="text-n-slate-10">---</span>
|
||||
<% end %>
|
||||
</td>
|
||||
<td class="py-4 px-4">
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded-md text-xs font-medium bg-n-alpha-2 text-n-slate-12 capitalize">
|
||||
<%= account_user.role %>
|
||||
</span>
|
||||
</td>
|
||||
<td class="py-4 pl-4 !pr-6 text-right">
|
||||
<%= link_to "Destroy", super_admin_account_user_path(account_user), method: :delete, data: { confirm: "Are you sure?" }, class: "text-sm font-medium text-n-ruby-11 hover:underline" %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<%# Custom Attributes Card %>
|
||||
<% if page.resource.try(:custom_attributes).present? %>
|
||||
<div class="rounded-xl bg-n-solid-2 shadow outline-1 outline outline-n-container overflow-hidden">
|
||||
<div class="px-6 py-4 border-b border-n-weak">
|
||||
<h2 class="text-base font-medium text-n-slate-12">Custom Attributes</h2>
|
||||
</div>
|
||||
<div class="divide-y divide-n-weak">
|
||||
<% page.resource.custom_attributes.each do |key, value| %>
|
||||
<div class="grid grid-cols-[180px,1fr] items-start min-h-12 px-6">
|
||||
<span class="text-sm text-n-slate-11 py-3">
|
||||
<%= key.to_s.titleize %>
|
||||
</span>
|
||||
<span class="text-sm text-n-slate-12 py-3 break-all font-mono">
|
||||
<%= value %>
|
||||
</span>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%# Actions Card %>
|
||||
<div class="rounded-xl bg-n-solid-2 shadow outline-1 outline outline-n-container overflow-hidden">
|
||||
<div class="px-6 py-4 border-b border-n-weak">
|
||||
<h2 class="text-base font-medium text-n-slate-12">Actions</h2>
|
||||
</div>
|
||||
<div class="divide-y divide-n-weak">
|
||||
<div class="px-6 py-4">
|
||||
<h3 class="text-sm font-medium text-n-slate-12 mb-3">Add User to Account</h3>
|
||||
<%= render 'super_admin/shared/account_user_form', page: page, namespace: namespace, resource_type: 'user' %>
|
||||
</div>
|
||||
<%= render partial: "impersonate", locals: {page: page} %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</main>
|
||||
</section>
|
||||
|
||||
<%= render 'super_admin/shared/account_user_form', page: page, namespace: namespace, resource_type: 'user' %>
|
||||
|
||||
<%= render partial: "impersonate", locals: {page: page} %>
|
||||
|
||||
Reference in New Issue
Block a user