hiddifypanel 10.12.1__py3-none-any.whl → 10.15.0.dev0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. hiddifypanel/VERSION +1 -1
  2. hiddifypanel/VERSION.py +2 -2
  3. hiddifypanel/auth.py +15 -4
  4. hiddifypanel/base.py +58 -50
  5. hiddifypanel/cache.py +43 -25
  6. hiddifypanel/database.py +9 -0
  7. hiddifypanel/drivers/abstract_driver.py +2 -0
  8. hiddifypanel/drivers/singbox_api.py +17 -15
  9. hiddifypanel/drivers/ssh_liberty_bridge_api.py +2 -0
  10. hiddifypanel/drivers/user_driver.py +12 -6
  11. hiddifypanel/drivers/wireguard_api.py +2 -0
  12. hiddifypanel/drivers/xray_api.py +14 -9
  13. hiddifypanel/hutils/__init__.py +1 -0
  14. hiddifypanel/hutils/convert.py +13 -2
  15. hiddifypanel/hutils/crypto.py +21 -2
  16. hiddifypanel/hutils/flask.py +19 -5
  17. hiddifypanel/hutils/importer/xui.py +5 -2
  18. hiddifypanel/hutils/node/__init__.py +3 -0
  19. hiddifypanel/hutils/node/api_client.py +76 -0
  20. hiddifypanel/hutils/node/child.py +147 -0
  21. hiddifypanel/hutils/node/parent.py +100 -0
  22. hiddifypanel/hutils/node/shared.py +65 -0
  23. hiddifypanel/hutils/proxy/shared.py +15 -3
  24. hiddifypanel/models/__init__.py +2 -2
  25. hiddifypanel/models/admin.py +14 -2
  26. hiddifypanel/models/base_account.py +3 -3
  27. hiddifypanel/models/child.py +30 -16
  28. hiddifypanel/models/config.py +39 -15
  29. hiddifypanel/models/config_enum.py +55 -8
  30. hiddifypanel/models/domain.py +28 -20
  31. hiddifypanel/models/parent_domain.py +2 -2
  32. hiddifypanel/models/proxy.py +13 -4
  33. hiddifypanel/models/report.py +2 -3
  34. hiddifypanel/models/usage.py +2 -2
  35. hiddifypanel/models/user.py +18 -9
  36. hiddifypanel/panel/admin/Actions.py +4 -6
  37. hiddifypanel/panel/admin/AdminstratorAdmin.py +13 -2
  38. hiddifypanel/panel/admin/Dashboard.py +5 -10
  39. hiddifypanel/panel/admin/DomainAdmin.py +12 -11
  40. hiddifypanel/panel/admin/NodeAdmin.py +6 -2
  41. hiddifypanel/panel/admin/ProxyAdmin.py +4 -3
  42. hiddifypanel/panel/admin/SettingAdmin.py +60 -21
  43. hiddifypanel/panel/admin/UserAdmin.py +10 -2
  44. hiddifypanel/panel/admin/templates/index.html +1 -1
  45. hiddifypanel/panel/admin/templates/parent_dash.html +2 -4
  46. hiddifypanel/panel/cli.py +16 -16
  47. hiddifypanel/panel/commercial/ProxyDetailsAdmin.py +10 -5
  48. hiddifypanel/panel/commercial/__init__.py +7 -5
  49. hiddifypanel/panel/commercial/restapi/v2/admin/__init__.py +0 -5
  50. hiddifypanel/panel/commercial/restapi/v2/admin/admin_info_api.py +2 -2
  51. hiddifypanel/panel/commercial/restapi/v2/admin/admin_log_api.py +4 -5
  52. hiddifypanel/panel/commercial/restapi/v2/admin/admin_user_api.py +8 -35
  53. hiddifypanel/panel/commercial/restapi/v2/admin/admin_users_api.py +4 -4
  54. hiddifypanel/panel/commercial/restapi/v2/admin/schema.py +157 -0
  55. hiddifypanel/panel/commercial/restapi/v2/admin/server_status_api.py +3 -3
  56. hiddifypanel/panel/commercial/restapi/v2/admin/user_api.py +9 -73
  57. hiddifypanel/panel/commercial/restapi/v2/admin/users_api.py +1 -1
  58. hiddifypanel/panel/commercial/restapi/v2/child/__init__.py +18 -0
  59. hiddifypanel/panel/commercial/restapi/v2/child/actions.py +63 -0
  60. hiddifypanel/panel/commercial/restapi/v2/child/register_parent_api.py +34 -0
  61. hiddifypanel/panel/commercial/restapi/v2/child/schema.py +7 -0
  62. hiddifypanel/panel/commercial/restapi/v2/child/sync_parent_api.py +21 -0
  63. hiddifypanel/panel/commercial/restapi/v2/panel/__init__.py +13 -0
  64. hiddifypanel/panel/commercial/restapi/v2/panel/info.py +18 -0
  65. hiddifypanel/panel/commercial/restapi/v2/panel/ping_pong.py +23 -0
  66. hiddifypanel/panel/commercial/restapi/v2/panel/schema.py +7 -0
  67. hiddifypanel/panel/commercial/restapi/v2/parent/__init__.py +16 -0
  68. hiddifypanel/panel/commercial/restapi/v2/parent/register_api.py +65 -0
  69. hiddifypanel/panel/commercial/restapi/v2/parent/schema.py +115 -0
  70. hiddifypanel/panel/commercial/restapi/v2/parent/status_api.py +26 -0
  71. hiddifypanel/panel/commercial/restapi/v2/parent/sync_api.py +53 -0
  72. hiddifypanel/panel/commercial/restapi/v2/parent/usage_api.py +57 -0
  73. hiddifypanel/panel/commercial/telegrambot/admin.py +1 -2
  74. hiddifypanel/panel/common.py +21 -6
  75. hiddifypanel/panel/hiddify.py +9 -80
  76. hiddifypanel/panel/init_db.py +84 -38
  77. hiddifypanel/panel/usage.py +33 -18
  78. hiddifypanel/panel/user/templates/home/usage.html +1 -1
  79. hiddifypanel/panel/user/templates/new.html +2 -2
  80. hiddifypanel/static/css/custom.css +13 -0
  81. hiddifypanel/static/images/hiddify.png +0 -0
  82. hiddifypanel/static/images/hiddify2.png +0 -0
  83. hiddifypanel/static/new/assets/hiddify-logo-7617d937.png +0 -0
  84. hiddifypanel/static/new/assets/{index-4510b616.js → index-ccb9873c.js} +2 -2
  85. hiddifypanel/static/new/assets/index-fa00de9a.css +1 -0
  86. hiddifypanel/static/new/i18n/en.json +6 -6
  87. hiddifypanel/static/new/i18n/fa.json +1 -1
  88. hiddifypanel/templates/admin-layout.html +24 -40
  89. hiddifypanel/templates/fake.html +22 -0
  90. hiddifypanel/templates/master.html +24 -42
  91. hiddifypanel/translations/en/LC_MESSAGES/messages.mo +0 -0
  92. hiddifypanel/translations/en/LC_MESSAGES/messages.po +95 -5
  93. hiddifypanel/translations/fa/LC_MESSAGES/messages.mo +0 -0
  94. hiddifypanel/translations/fa/LC_MESSAGES/messages.po +96 -4
  95. hiddifypanel/translations/pt/LC_MESSAGES/messages.mo +0 -0
  96. hiddifypanel/translations/pt/LC_MESSAGES/messages.po +98 -6
  97. hiddifypanel/translations/ru/LC_MESSAGES/messages.mo +0 -0
  98. hiddifypanel/translations/ru/LC_MESSAGES/messages.po +91 -1
  99. hiddifypanel/translations/zh/LC_MESSAGES/messages.mo +0 -0
  100. hiddifypanel/translations/zh/LC_MESSAGES/messages.po +92 -2
  101. hiddifypanel/translations.i18n/en.json +61 -5
  102. hiddifypanel/translations.i18n/fa.json +60 -4
  103. hiddifypanel/translations.i18n/pt.json +63 -7
  104. hiddifypanel/translations.i18n/ru.json +57 -1
  105. hiddifypanel/translations.i18n/zh.json +58 -2
  106. {hiddifypanel-10.12.1.dist-info → hiddifypanel-10.15.0.dev0.dist-info}/METADATA +47 -47
  107. {hiddifypanel-10.12.1.dist-info → hiddifypanel-10.15.0.dev0.dist-info}/RECORD +112 -94
  108. hiddifypanel/panel/commercial/restapi/v2/DTO.py +0 -9
  109. hiddifypanel/panel/commercial/restapi/v2/hello/__init__.py +0 -16
  110. hiddifypanel/panel/commercial/restapi/v2/hello/hello.py +0 -32
  111. hiddifypanel/static/new/assets/hiddify-logo-7617d937_old.png +0 -0
  112. hiddifypanel/static/new/assets/index-669b32c8.css +0 -1
  113. /hiddifypanel/static/images/{hiddify1.png → hiddify-old.png} +0 -0
  114. {hiddifypanel-10.12.1.dist-info → hiddifypanel-10.15.0.dev0.dist-info}/LICENSE.md +0 -0
  115. {hiddifypanel-10.12.1.dist-info → hiddifypanel-10.15.0.dev0.dist-info}/WHEEL +0 -0
  116. {hiddifypanel-10.12.1.dist-info → hiddifypanel-10.15.0.dev0.dist-info}/entry_points.txt +0 -0
  117. {hiddifypanel-10.12.1.dist-info → hiddifypanel-10.15.0.dev0.dist-info}/top_level.txt +0 -0
@@ -2,22 +2,52 @@ import datetime
2
2
  import json
3
3
  import os
4
4
  import random
5
- import string
6
5
  import sys
7
6
  import uuid
8
7
 
9
- from dateutil import relativedelta
10
8
 
11
9
  from hiddifypanel import Events, hutils
12
10
  from hiddifypanel.models import *
13
- from hiddifypanel.models import ConfigEnum, User, set_hconfig, ChildMode
14
11
  from hiddifypanel.panel import hiddify
15
- from hiddifypanel.database import db
12
+ from hiddifypanel.database import db, db_execute
16
13
  from hiddifypanel import hutils
17
-
14
+ from sqlalchemy import text
18
15
  from flask import g
19
16
 
20
- MAX_DB_VERSION = 80
17
+ MAX_DB_VERSION = 90
18
+
19
+
20
+ def _v83(child_id):
21
+ set_hconfig(ConfigEnum.log_level, LogLevel.CRITICAL)
22
+
23
+
24
+ def _v82(child_id):
25
+ set_hconfig(ConfigEnum.vless_enable, True)
26
+ set_hconfig(ConfigEnum.trojan_enable, True)
27
+ set_hconfig(ConfigEnum.reality_enable, True)
28
+ set_hconfig(ConfigEnum.tcp_enable, True)
29
+ set_hconfig(ConfigEnum.quic_enable, True)
30
+ set_hconfig(ConfigEnum.xtls_enable, True)
31
+ set_hconfig(ConfigEnum.h2_enable, True)
32
+
33
+
34
+ def _v80(child_id):
35
+ set_hconfig(ConfigEnum.parent_domain, '')
36
+ set_hconfig(ConfigEnum.parent_admin_proxy_path, '')
37
+
38
+
39
+ def _v79(child_id):
40
+ set_hconfig(ConfigEnum.panel_mode, PanelMode.standalone)
41
+
42
+
43
+ def _v78(child_id):
44
+ # equalize panel unique id and root child unique id
45
+ root_child_unique_id = Child.query.filter(Child.name == "Root").first().unique_id
46
+ set_hconfig(ConfigEnum.unique_id, root_child_unique_id)
47
+
48
+
49
+ def _v77(child_id):
50
+ pass
21
51
 
22
52
 
23
53
  def _v75(child_id):
@@ -225,7 +255,7 @@ def _v33():
225
255
 
226
256
  def _v31():
227
257
  add_config_if_not_exist(ConfigEnum.reality_short_ids, uuid.uuid4().hex[0:random.randint(1, 8) * 2])
228
- key_pair = hiddify.generate_x25519_keys()
258
+ key_pair = hutils.crypto.generate_x25519_keys()
229
259
  add_config_if_not_exist(ConfigEnum.reality_private_key, key_pair['private_key'])
230
260
  add_config_if_not_exist(ConfigEnum.reality_public_key, key_pair['public_key'])
231
261
  db.session.bulk_save_objects(get_proxy_rows_v1())
@@ -507,7 +537,7 @@ def make_proxy_rows(cfgs):
507
537
 
508
538
  def add_config_if_not_exist(key: ConfigEnum, val: str | int, child_id: int | None = None):
509
539
  if child_id is None:
510
- child_id = Child.current.id
540
+ child_id = Child.current().id
511
541
 
512
542
  old_val = hconfig(key, child_id)
513
543
  print(key, val, child_id, old_val)
@@ -518,15 +548,18 @@ def add_config_if_not_exist(key: ConfigEnum, val: str | int, child_id: int | Non
518
548
  def add_column(column):
519
549
  try:
520
550
  column_type = column.type.compile(db.engine.dialect)
521
- db.engine.execute(f'ALTER TABLE {column.table.name} ADD COLUMN {column.name} {column_type}')
551
+
552
+ db_execute(f'ALTER TABLE {column.table.name} ADD COLUMN {column.name} {column_type}')
522
553
  except BaseException:
523
554
  pass
524
555
 
525
556
 
526
- def execute(query):
557
+ def execute(query: str):
527
558
  try:
528
- db.engine.execute(query)
529
- except BaseException:
559
+
560
+ db_execute(query)
561
+ except BaseException as e:
562
+ print(e)
530
563
  pass
531
564
 
532
565
 
@@ -546,7 +579,8 @@ def add_new_enum_values():
546
579
  # Get the values in the enum column in the database
547
580
  # result = db.engine.execute(f"SELECT DISTINCT `{column_name}` FROM {table_name}")
548
581
  # db_values = {row[0] for row in result}
549
- result = db.engine.execute(f"SHOW COLUMNS FROM {table_name} LIKE '{column_name}';")
582
+
583
+ result = db_execute(f"SHOW COLUMNS FROM {table_name} LIKE '{column_name}';")
550
584
  db_values = []
551
585
 
552
586
  for row in result:
@@ -565,7 +599,7 @@ def add_new_enum_values():
565
599
  # Add the new value to the enum column in the database
566
600
  enumstr = ','.join([f"'{a}'" for a in [*existing_values, *old_values]])
567
601
 
568
- db.engine.execute(f"ALTER TABLE {table_name} MODIFY COLUMN `{column_name}` ENUM({enumstr});")
602
+ db_execute(text(f"ALTER TABLE {table_name} MODIFY COLUMN `{column_name}` ENUM({enumstr});"))
569
603
 
570
604
  db.session.commit()
571
605
 
@@ -665,32 +699,44 @@ def init_db():
665
699
 
666
700
 
667
701
  def migrate(db_version):
668
- execute('CREATE INDEX date ON daily_usage (date);')
669
- execute('CREATE INDEX username ON user (username);')
670
- execute('CREATE INDEX username ON admin_user (username);')
671
- execute('CREATE INDEX telegram_id ON user (telegram_id);')
672
- execute('CREATE INDEX telegram_id ON admin_user (telegram_id);')
673
-
674
- execute('ALTER TABLE proxy DROP INDEX `name`;')
675
-
676
- execute("alter table user alter column telegram_id bigint;")
677
- execute("alter table admin_user alter column telegram_id bigint;")
702
+ for table_name, table_obj in db.metadata.tables.items():
703
+ for column in table_obj.columns:
704
+ add_column(column)
705
+ Events.db_prehook.notify()
706
+ if db_version < 82:
707
+ execute('ALTER TABLE child DROP INDEX `name`;')
708
+ if db_version < 77:
709
+ execute('ALTER TABLE user_detail DROP COLUMN connected_ips;')
710
+ execute('update user_detail set connected_devices="" where connected_devices IS NULL')
711
+
712
+ if db_version < 70:
713
+ execute('CREATE INDEX date ON daily_usage (date);')
714
+ execute('CREATE INDEX username ON user (username);')
715
+ execute('CREATE INDEX username ON admin_user (username);')
716
+ execute('CREATE INDEX telegram_id ON user (telegram_id);')
717
+ execute('CREATE INDEX telegram_id ON admin_user (telegram_id);')
718
+
719
+ execute('ALTER TABLE proxy DROP INDEX `name`;')
720
+
721
+ execute("ALTER TABLE user MODIFY COLUMN telegram_id BIGINT;")
722
+ execute("ALTER TABLE admin_user MODIFY COLUMN telegram_id BIGINT;")
723
+
724
+ # aaa
725
+ # # add_column(UserDetail.connected_devices)
726
+ # add_column(Child.mode)
727
+ # add_column(Child.name)
728
+ # add_column(User.lang)
729
+ # add_column(AdminUser.lang)
730
+ # add_column(User.username)
731
+ # add_column(User.password)
732
+ # add_column(AdminUser.username)
733
+ # add_column(AdminUser.password)
734
+ # add_column(User.wg_pk)
735
+ # add_column(User.wg_pub)
736
+ # add_column(User.wg_psk)
678
737
 
679
- add_column(Child.mode)
680
- add_column(Child.name)
681
- add_column(User.lang)
682
- add_column(AdminUser.lang)
683
- add_column(User.username)
684
- add_column(User.password)
685
- add_column(AdminUser.username)
686
- add_column(AdminUser.password)
687
- add_column(User.wg_pk)
688
- add_column(User.wg_pub)
689
- add_column(User.wg_psk)
690
-
691
- add_column(Domain.extra_params)
738
+ # add_column(Domain.extra_params)
692
739
 
693
- Events.db_prehook.notify()
694
740
  if db_version < 52:
695
741
  execute(f'update domain set mode="sub_link_only", sub_link_only=false where sub_link_only = true or mode=1 or mode="1"')
696
742
  execute(f'update domain set mode="direct", sub_link_only=false where mode=0 or mode="0"')
@@ -1,34 +1,36 @@
1
1
  from flask_babel import lazy_gettext as _
2
2
  from sqlalchemy import func
3
+ from typing import Dict
3
4
  import datetime
4
5
 
5
6
  from hiddifypanel.drivers import user_driver
6
7
  from hiddifypanel.models import *
7
8
  from hiddifypanel.panel import hiddify
8
9
  from hiddifypanel.database import db
10
+ from hiddifypanel import hutils
9
11
 
10
12
  to_gig_d = 1024**3
11
13
 
12
14
 
13
15
  def update_local_usage():
14
16
  res = user_driver.get_users_usage(reset=True)
15
- return add_users_usage(res, child_id=0)
17
+ return _add_users_usage(res, child_id=0)
16
18
 
17
19
  # return {"status": 'success', "comments":res}
18
20
 
19
21
 
20
- def add_users_usage_uuid(uuids_bytes, child_id):
21
- users = User.query.filter(User.uuid.in_(keys(uuids_bytes)))
22
+ def add_users_usage_uuid(uuids_bytes: Dict[str, Dict], child_id, sync=False):
23
+ uuids_bytes = {u: v for u, v in uuids_bytes.items() if v}
24
+ uuids = uuids_bytes.keys()
25
+ users = User.query.filter(User.uuid.in_(uuids))
22
26
  dbusers_bytes = {u: uuids_bytes.get(u.uuid, 0) for u in users}
23
- add_users_usage(dbusers_bytes, child_id)
27
+ _add_users_usage(dbusers_bytes, child_id, sync) # type: ignore
24
28
 
25
29
 
26
- def add_users_usage(dbusers_bytes, child_id):
27
- print(dbusers_bytes)
28
- if not hconfig(ConfigEnum.is_parent) and hconfig(ConfigEnum.parent_panel):
29
- from hiddifypanel.panel import hiddify_api
30
- hiddify_api.add_user_usage_to_parent(dbusers_bytes)
31
-
30
+ def _add_users_usage(users_usage_data: Dict[User, Dict], child_id, sync=False):
31
+ '''
32
+ sync: when enabled, it means we have received usages from the parent panel
33
+ '''
32
34
  res = {}
33
35
  have_change = False
34
36
  before_enabled_users = user_driver.get_enabled_users()
@@ -42,16 +44,16 @@ def add_users_usage(dbusers_bytes, child_id):
42
44
  daily_usage[adm.id].online = User.query.filter(User.added_by == adm.id).filter(func.DATE(User.last_online) == today).count()
43
45
  # db.session.commit()
44
46
  userDetails = {p.user_id: p for p in UserDetail.query.filter(UserDetail.child_id == child_id).all()}
45
- for user, uinfo in dbusers_bytes.items():
47
+ for user, uinfo in users_usage_data.items():
46
48
  usage_bytes = uinfo['usage']
47
- ips = uinfo['ips']
49
+ devices = uinfo['devices']
48
50
  # user_active_before=user.is_active
49
51
  detail = userDetails.get(user.id)
50
52
  if not detail:
51
53
  detail = UserDetail(user_id=user.id, child_id=child_id)
52
54
  detail.current_usage_GB = detail.current_usage_GB or 0
53
55
  db.session.add(detail)
54
- detail.connected_ips = ips
56
+ detail.connected_devices = devices
55
57
  detail.current_usage_GB = detail.current_usage_GB or 0
56
58
  if not user.last_reset_time or user.user_should_reset():
57
59
  user.last_reset_time = datetime.date.today()
@@ -66,11 +68,20 @@ def add_users_usage(dbusers_bytes, child_id):
66
68
  if not isinstance(usage_bytes, int) or usage_bytes == 0:
67
69
  res[user.uuid] = "No usage"
68
70
  else:
69
- daily_usage.get(user.added_by, daily_usage[1]).usage += usage_bytes
71
+ if sync:
72
+ if daily_usage.get(user.added_by, daily_usage[1]).usage != usage_bytes:
73
+ daily_usage.get(user.added_by, daily_usage[1]).usage = usage_bytes
74
+ else:
75
+ daily_usage.get(user.added_by, daily_usage[1]).usage += usage_bytes
70
76
  in_gig = (usage_bytes) / to_gig_d
71
77
  res[user.uuid] = in_gig
72
- user.current_usage_GB += in_gig
73
- detail.current_usage_GB += in_gig
78
+ if sync:
79
+ if user.current_usage_GB != in_gig:
80
+ user.current_usage_GB = in_gig
81
+ # detail.current_usage_GB = in_gig
82
+ else:
83
+ user.current_usage_GB += in_gig
84
+ detail.current_usage_GB += in_gig
74
85
  user.last_online = datetime.datetime.now()
75
86
  detail.last_online = datetime.datetime.now()
76
87
 
@@ -83,15 +94,19 @@ def add_users_usage(dbusers_bytes, child_id):
83
94
  have_change = True
84
95
  res[user.uuid] = f"{res[user.uuid]} !OUT of USAGE! Client Removed"
85
96
 
86
- db.session.commit()
97
+ db.session.commit() # type: ignore
87
98
  if have_change:
88
99
  hiddify.quick_apply_users()
89
100
 
101
+ # sync with the parent
102
+ if not sync:
103
+ if hutils.node.is_child():
104
+ hutils.node.child.sync_users_usage_with_parent()
90
105
  return {"status": 'success', "comments": res}
91
106
 
92
107
 
93
108
  def send_bot_message(user):
94
- if not (hconfig(ConfigEnum.telegram_bot_token) and not hconfig(ConfigEnum.parent_panel)):
109
+ if not (hconfig(ConfigEnum.telegram_bot_token) or not hutils.node.is_parent()):
95
110
  return
96
111
  if not user.telegram_id:
97
112
  return
@@ -23,7 +23,7 @@
23
23
  {% endif %}
24
24
  {% if not user.is_active %}
25
25
  {{_("User is inactive")}}
26
- {% if (user.ips|length)>user.max_ips: %}
26
+ {% if (user.devices|length)>user.max_ips: %}
27
27
  <br>
28
28
  <i class="fa-solid fa-users-slash text-danger"></i> {{_("Too many Connected IPs")}}
29
29
  {% endif %}
@@ -13,8 +13,8 @@
13
13
  <link rel="manifest" href="{{ url_for('common_bp.LoginView:create_pwa_manifest',secret_uuid=g.account.uuid or '')}}">
14
14
 
15
15
  <title>Hiddify | Panel</title>
16
- <script type="module" crossorigin src="../static/new/assets/index-4510b616.js"></script>
17
- <link rel="stylesheet" href="../static/new/assets/index-669b32c8.css">
16
+ <script type="module" crossorigin src="../static/new/assets/index-ccb9873c.js"></script>
17
+ <link rel="stylesheet" href="../static/new/assets/index-fa00de9a.css">
18
18
  </head>
19
19
  <body>
20
20
  <div id="root"></div>
@@ -555,4 +555,17 @@ td.col-uuid a {
555
555
 
556
556
  .select2-container {
557
557
  display: none;
558
+ }
559
+
560
+
561
+ #main-sidebar .nav-sidebar>.nav-item>.nav-link {
562
+ color: white;
563
+ }
564
+
565
+ #main-sidebar .nav-sidebar>.nav-item>.nav-link:hover {
566
+ background: #007bff;
567
+ }
568
+
569
+ .dark-mode #main-sidebar .nav-sidebar>.nav-item>.nav-link:hover {
570
+ background: #3f6791;
558
571
  }
Binary file
Binary file