base.html 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084
  1. <!--
  2. Copyright (C) 2023 Nicola Murino
  3. This WebUI uses the KeenThemes Mega Bundle, a proprietary theme:
  4. https://keenthemes.com/products/templates-mega-bundle
  5. KeenThemes HTML/CSS/JS components are allowed for use only within the
  6. SFTPGo product and restricted to be used in a resealable HTML template
  7. that can compete with KeenThemes products anyhow.
  8. This WebUI is allowed for use only within the SFTPGo product and
  9. therefore cannot be used in derivative works/products without an
  10. explicit grant from the SFTPGo Team ([email protected]).
  11. -->
  12. {{- define "errmsg"}}
  13. <div id="errorMsg" class="{{if not . }}d-none {{end}}rounded border-warning border border-dashed bg-light-warning d-flex align-items-center p-5 mb-10">
  14. <i class="ki-duotone ki-information-5 fs-3x text-warning me-5">
  15. <span class="path1"></span>
  16. <span class="path2"></span>
  17. <span class="path3"></span>
  18. </i>
  19. <div class="text-gray-800 fw-bold fs-5 d-flex flex-column pe-0 pe-sm-10">
  20. <span {{if .}}data-i18n="{{.Message}}" {{if .HasArgs}}data-i18n-options="{{.Args}}"{{end}}{{end}} id="errorTxt"></span>
  21. </div>
  22. <button id="id_dismiss_error_msg" type="button" class="position-absolute position-sm-relative m-2 m-sm-0 top-0 end-0 btn btn-icon btn-sm btn-active-light-primary ms-sm-auto">
  23. <i class="ki-solid ki-cross fs-2x text-gray-700"></i>
  24. </button>
  25. </div>
  26. {{- end}}
  27. {{- define "theme-setup"}}
  28. <script type="text/javascript" {{- if .}} nonce="{{.}}"{{- end}}>
  29. var defaultThemeMode = "system";
  30. var themeMode;
  31. if ( document.documentElement ) {
  32. if ( document.documentElement.hasAttribute("data-bs-theme-mode")) {
  33. themeMode = document.documentElement.getAttribute("data-bs-theme-mode");
  34. } else {
  35. if ( localStorage.getItem("data-bs-theme") !== null ) {
  36. themeMode = localStorage.getItem("data-bs-theme");
  37. } else {
  38. themeMode = defaultThemeMode;
  39. }
  40. }
  41. if (themeMode === "system") {
  42. themeMode = window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
  43. }
  44. document.documentElement.setAttribute("data-bs-theme", themeMode);
  45. }
  46. </script>
  47. {{- end }}
  48. {{- define "commonjs"}}
  49. <script type="text/javascript" {{- if .}} nonce="{{.}}"{{- end}}>
  50. window.addEventListener("pageshow", function (event) {
  51. if (event.persisted) {
  52. let loadings = document.querySelectorAll('[data-kt-indicator=on]');
  53. if (loadings){
  54. [].forEach.call(loadings, function (loading) {
  55. loading.removeAttribute('data-kt-indicator');
  56. loading.disabled = false;
  57. });
  58. }
  59. }
  60. });
  61. </script>
  62. {{- end}}
  63. {{- define "basejs"}}
  64. <script type="text/javascript" {{- if .CSPNonce}} nonce="{{.CSPNonce}}"{{- end}}>
  65. // https://developer.mozilla.org/en-US/docs/Web/API/Document/createTextNode
  66. function escapeHTML(str) {
  67. var div = document.createElement('div');
  68. div.appendChild(document.createTextNode(str));
  69. return div.innerHTML;
  70. }
  71. function fileSizeIEC(a,b,c,d,e){
  72. return (b=Math,c=b.log,d=1024,e=c(a)/c(d)|0,a/b.pow(d,e)).toFixed(1)
  73. +' '+(e?'KMGTPEZY'[--e]+'iB':'Bytes')
  74. }
  75. function humanizeSpeed(a,b,c,d,e){
  76. return (b=Math,c=b.log,d=1024,e=c(a)/c(d)|0,a/b.pow(d,e)).toFixed(1)
  77. +' '+(e?'KMGTPEZY'[--e]+'B/s':'Bytes/s')
  78. }
  79. function initRepeaterItems() {
  80. let repeaterDeleteButtons = document.querySelectorAll('[data-repeater-delete]');
  81. let repeaterCreateButtons = document.querySelectorAll('[data-repeater-create]');
  82. repeaterDeleteButtons.forEach(d => {
  83. d.addEventListener("click", function(e){
  84. e.preventDefault();
  85. });
  86. });
  87. repeaterCreateButtons.forEach(d => {
  88. d.addEventListener("click", function(e){
  89. e.preventDefault();
  90. });
  91. });
  92. }
  93. function initRepeater(selector) {
  94. $(selector).repeater({
  95. initEmpty: false,
  96. show: function () {
  97. $(this).find('.select-repetear').each(function(){
  98. initializeSelect2El(this);
  99. let el = $(this);
  100. if (el.hasClass('select-first')){
  101. let firstVal = el.find("option:first-child").val();
  102. el.val(firstVal).trigger('change');
  103. }
  104. });
  105. $(this).localize();
  106. $(this).slideDown();
  107. $(this).find('[data-repeater-delete]').on("click", function(e){
  108. e.preventDefault();
  109. });
  110. },
  111. hide: function (deleteElement) {
  112. $(this).slideUp(deleteElement);
  113. }
  114. });
  115. $(selector).find('.select-repetear').each(function(){
  116. initializeSelect2El(this);
  117. });
  118. }
  119. function clearChilds(el) {
  120. while (el.firstChild) {
  121. el.removeChild(el.firstChild);
  122. }
  123. }
  124. function initializeSelect2El(element) {
  125. if (element.getAttribute("data-kt-initialized") === "1") {
  126. return;
  127. }
  128. let options = {
  129. dir: document.body.getAttribute('direction'),
  130. language: {
  131. noResults: function () {
  132. return $.t('select2.no_results');
  133. },
  134. searching: function () {
  135. return $.t('select2.searching');
  136. },
  137. removeAllItems: function () {
  138. return $.t('select2.removeall');
  139. },
  140. removeItem: function () {
  141. return $.t('select2.remove');
  142. },
  143. search: function() {
  144. return $.t('general.search');
  145. }
  146. }
  147. };
  148. if (element.getAttribute('data-hide-search') == 'true') {
  149. options.minimumResultsForSearch = Infinity;
  150. }
  151. $(element).select2(options);
  152. element.setAttribute("data-kt-initialized", "1");
  153. }
  154. const lngs = {
  155. en: { nativeName: 'English' },
  156. it: { nativeName: 'Italiano' }
  157. };
  158. const renderI18n = () => {
  159. $('title').text('{{.Branding.Name}} - '+$.t('{{.Title}}'));
  160. $('body').localize();
  161. let select2elements = [].slice.call(document.querySelectorAll('[data-control="i18n-select2"]'));
  162. select2elements.map(function (element){
  163. initializeSelect2El(element);
  164. });
  165. }
  166. function initLocalizer() {
  167. i18next
  168. .use(i18nextChainedBackend)
  169. .use(i18nextBrowserLanguageDetector)
  170. .init({
  171. debug: false,
  172. supportedLngs: ["en", "it"],
  173. fallbackLng: 'en',
  174. load: 'languageOnly',
  175. backend: {
  176. backends: [
  177. i18nextLocalStorageBackend,
  178. i18nextHttpBackend
  179. ],
  180. backendOptions: [{
  181. expirationTime: 7 * 24 * 60 * 60 * 1000, // 7 days
  182. defaultVersion: '{{.Version}}'
  183. }, {
  184. loadPath: '{{.StaticURL}}/locales/{{"{{lng}}"}}/{{"{{ns}}"}}.json?_='+new Date().getTime().toString()
  185. }
  186. ]
  187. }
  188. }, (err, t) => {
  189. if (err) {
  190. console.error(err);
  191. } else {
  192. jqueryI18next.init(i18next, $, { useOptionsAttr: true });
  193. var languageSwitcher = $('#languageSwitcher');
  194. if (languageSwitcher){
  195. Object.keys(lngs).map((lng) => {
  196. const opt = new Option(lngs[lng].nativeName, lng);
  197. if (lng === i18next.resolvedLanguage) {
  198. opt.setAttribute("selected", "selected");
  199. }
  200. languageSwitcher.append(opt);
  201. });
  202. languageSwitcher.on('change', function(){
  203. const chosenLng = $(this).find("option:selected").attr('value');
  204. i18next.changeLanguage(chosenLng, () => {
  205. renderI18n();
  206. });
  207. });
  208. }
  209. renderI18n();
  210. $.event.trigger({
  211. type: "i18nload"
  212. });
  213. }
  214. $('#app_loader').addClass("d-none");
  215. $('#app_root').removeClass("d-none");
  216. $.event.trigger({
  217. type: "i18nshow"
  218. });
  219. });
  220. }
  221. function setI18NData(el, value, options) {
  222. el.removeAttr("data-i18n-options");
  223. el.attr("data-i18n", value);
  224. el.localize(options);
  225. }
  226. function handlePasswordInputVisibility(el) {
  227. let pwdVisibility = $(el.querySelector('[data-password-control="visibility"]'));
  228. let passwordInput = el.querySelector('[data-password-control="input"]');
  229. pwdVisibility.off("click");
  230. pwdVisibility.on('click', function(){
  231. let visibleIcon = this.querySelector(':scope > i:not(.d-none)');
  232. let hiddenIcon = this.querySelector(':scope > i.d-none');
  233. visibleIcon.classList.add('d-none');
  234. hiddenIcon.classList.remove('d-none');
  235. if (passwordInput){
  236. if (passwordInput.getAttribute('type').toLowerCase() === 'password' ) {
  237. passwordInput.setAttribute('type', 'text');
  238. } else {
  239. passwordInput.setAttribute('type', 'password');
  240. }
  241. passwordInput.focus();
  242. }
  243. });
  244. }
  245. function getCurrentURI(){
  246. let port = window.location.port;
  247. if (port){
  248. return window.location.protocol+"//"+window.location.hostname+":"+port;
  249. }
  250. return window.location.protocol+"//"+window.location.hostname;
  251. }
  252. function onFilesystemChanged(val){
  253. const supportedFs = ["local", "s3", "gcs", "azblob", "crypt", "sftp", "http"];
  254. let fsName = "local";
  255. switch (val){
  256. case '1':
  257. fsName = "s3";
  258. break;
  259. case '2':
  260. fsName = "gcs";
  261. break;
  262. case '3':
  263. fsName = "azblob";
  264. break;
  265. case '4':
  266. fsName = "crypt";
  267. break;
  268. case '5':
  269. fsName = "sftp";
  270. break;
  271. case '6':
  272. fsName = "http";
  273. break;
  274. }
  275. for (let i = 0; i < supportedFs.length; i++){
  276. if (supportedFs[i] == fsName){
  277. $('.form-group.fsconfig-'+fsName).show();
  278. } else {
  279. $('.form-group.fsconfig-'+supportedFs[i]).hide();
  280. }
  281. }
  282. }
  283. KTUtil.onDOMContentLoaded(function () {
  284. var dismissErrorBtn = $('#id_dismiss_error_msg');
  285. if (dismissErrorBtn){
  286. dismissErrorBtn.on("click", function(){
  287. $('#errorMsg').addClass("d-none");
  288. });
  289. }
  290. var logoutBtn = $('#id_logout_link');
  291. if (logoutBtn){
  292. logoutBtn.on("click", function(){
  293. doLogout();
  294. });
  295. }
  296. document.querySelectorAll('[data-password-control="container"]').forEach(el => {
  297. handlePasswordInputVisibility(el);
  298. });
  299. initLocalizer();
  300. });
  301. </script>
  302. {{- end}}
  303. {{- define "globalstyle"}}
  304. <style {{- if .}} nonce="{{.}}"{{- end}}>
  305. .text-sidebar {
  306. color: var(--bs-white);
  307. }
  308. [data-bs-theme="dark"] .text-sidebar {
  309. color: var(--bs-white);
  310. }
  311. .wrap-word {
  312. overflow-wrap: break-word;
  313. }
  314. .line-through {
  315. text-decoration: line-through;
  316. }
  317. .section-title {
  318. color: var(--bs-text-gray-800);
  319. font-weight: 600 !important;
  320. font-size: 1.45rem !important;
  321. }
  322. .section-title-inner {
  323. color: var(--bs-text-gray-800);
  324. font-weight: 600 !important;
  325. font-size: 1.3rem !important;
  326. }
  327. .readonly-input {
  328. color: var(--bs-text-gray-800);
  329. font-weight: 500 !important;
  330. font-size: 1.1rem !important;
  331. }
  332. .shortcut {
  333. font-family: monospace; color: #666;
  334. }
  335. .overflow-auto {
  336. overflow: auto;
  337. }
  338. .visibility-auto {
  339. content-visibility: auto;
  340. }
  341. </style>
  342. {{- end}}
  343. {{- define "fonts"}}
  344. <style {{- if .}} nonce="{{.CSPNonce}}"{{- end}}>
  345. /* cyrillic-ext */
  346. @font-face {
  347. font-family: 'Inter';
  348. font-style: normal;
  349. font-weight: 300;
  350. src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2JL7SUc.woff2) format('woff2');
  351. unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
  352. }
  353. /* cyrillic */
  354. @font-face {
  355. font-family: 'Inter';
  356. font-style: normal;
  357. font-weight: 300;
  358. src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa0ZL7SUc.woff2) format('woff2');
  359. unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
  360. }
  361. /* greek-ext */
  362. @font-face {
  363. font-family: 'Inter';
  364. font-style: normal;
  365. font-weight: 300;
  366. src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2ZL7SUc.woff2) format('woff2');
  367. unicode-range: U+1F00-1FFF;
  368. }
  369. /* greek */
  370. @font-face {
  371. font-family: 'Inter';
  372. font-style: normal;
  373. font-weight: 300;
  374. src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1pL7SUc.woff2) format('woff2');
  375. unicode-range: U+0370-03FF;
  376. }
  377. /* vietnamese */
  378. @font-face {
  379. font-family: 'Inter';
  380. font-style: normal;
  381. font-weight: 300;
  382. src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2pL7SUc.woff2) format('woff2');
  383. unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
  384. }
  385. /* latin-ext */
  386. @font-face {
  387. font-family: 'Inter';
  388. font-style: normal;
  389. font-weight: 300;
  390. src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa25L7SUc.woff2) format('woff2');
  391. unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
  392. }
  393. /* latin */
  394. @font-face {
  395. font-family: 'Inter';
  396. font-style: normal;
  397. font-weight: 300;
  398. src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1ZL7.woff2) format('woff2');
  399. unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
  400. }
  401. /* cyrillic-ext */
  402. @font-face {
  403. font-family: 'Inter';
  404. font-style: normal;
  405. font-weight: 400;
  406. src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2JL7SUc.woff2) format('woff2');
  407. unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
  408. }
  409. /* cyrillic */
  410. @font-face {
  411. font-family: 'Inter';
  412. font-style: normal;
  413. font-weight: 400;
  414. src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa0ZL7SUc.woff2) format('woff2');
  415. unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
  416. }
  417. /* greek-ext */
  418. @font-face {
  419. font-family: 'Inter';
  420. font-style: normal;
  421. font-weight: 400;
  422. src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2ZL7SUc.woff2) format('woff2');
  423. unicode-range: U+1F00-1FFF;
  424. }
  425. /* greek */
  426. @font-face {
  427. font-family: 'Inter';
  428. font-style: normal;
  429. font-weight: 400;
  430. src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1pL7SUc.woff2) format('woff2');
  431. unicode-range: U+0370-03FF;
  432. }
  433. /* vietnamese */
  434. @font-face {
  435. font-family: 'Inter';
  436. font-style: normal;
  437. font-weight: 400;
  438. src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2pL7SUc.woff2) format('woff2');
  439. unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
  440. }
  441. /* latin-ext */
  442. @font-face {
  443. font-family: 'Inter';
  444. font-style: normal;
  445. font-weight: 400;
  446. src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa25L7SUc.woff2) format('woff2');
  447. unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
  448. }
  449. /* latin */
  450. @font-face {
  451. font-family: 'Inter';
  452. font-style: normal;
  453. font-weight: 400;
  454. src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1ZL7.woff2) format('woff2');
  455. unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
  456. }
  457. /* cyrillic-ext */
  458. @font-face {
  459. font-family: 'Inter';
  460. font-style: normal;
  461. font-weight: 500;
  462. src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2JL7SUc.woff2) format('woff2');
  463. unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
  464. }
  465. /* cyrillic */
  466. @font-face {
  467. font-family: 'Inter';
  468. font-style: normal;
  469. font-weight: 500;
  470. src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa0ZL7SUc.woff2) format('woff2');
  471. unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
  472. }
  473. /* greek-ext */
  474. @font-face {
  475. font-family: 'Inter';
  476. font-style: normal;
  477. font-weight: 500;
  478. src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2ZL7SUc.woff2) format('woff2');
  479. unicode-range: U+1F00-1FFF;
  480. }
  481. /* greek */
  482. @font-face {
  483. font-family: 'Inter';
  484. font-style: normal;
  485. font-weight: 500;
  486. src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1pL7SUc.woff2) format('woff2');
  487. unicode-range: U+0370-03FF;
  488. }
  489. /* vietnamese */
  490. @font-face {
  491. font-family: 'Inter';
  492. font-style: normal;
  493. font-weight: 500;
  494. src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2pL7SUc.woff2) format('woff2');
  495. unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
  496. }
  497. /* latin-ext */
  498. @font-face {
  499. font-family: 'Inter';
  500. font-style: normal;
  501. font-weight: 500;
  502. src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa25L7SUc.woff2) format('woff2');
  503. unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
  504. }
  505. /* latin */
  506. @font-face {
  507. font-family: 'Inter';
  508. font-style: normal;
  509. font-weight: 500;
  510. src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1ZL7.woff2) format('woff2');
  511. unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
  512. }
  513. /* cyrillic-ext */
  514. @font-face {
  515. font-family: 'Inter';
  516. font-style: normal;
  517. font-weight: 600;
  518. src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2JL7SUc.woff2) format('woff2');
  519. unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
  520. }
  521. /* cyrillic */
  522. @font-face {
  523. font-family: 'Inter';
  524. font-style: normal;
  525. font-weight: 600;
  526. src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa0ZL7SUc.woff2) format('woff2');
  527. unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
  528. }
  529. /* greek-ext */
  530. @font-face {
  531. font-family: 'Inter';
  532. font-style: normal;
  533. font-weight: 600;
  534. src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2ZL7SUc.woff2) format('woff2');
  535. unicode-range: U+1F00-1FFF;
  536. }
  537. /* greek */
  538. @font-face {
  539. font-family: 'Inter';
  540. font-style: normal;
  541. font-weight: 600;
  542. src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1pL7SUc.woff2) format('woff2');
  543. unicode-range: U+0370-03FF;
  544. }
  545. /* vietnamese */
  546. @font-face {
  547. font-family: 'Inter';
  548. font-style: normal;
  549. font-weight: 600;
  550. src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2pL7SUc.woff2) format('woff2');
  551. unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
  552. }
  553. /* latin-ext */
  554. @font-face {
  555. font-family: 'Inter';
  556. font-style: normal;
  557. font-weight: 600;
  558. src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa25L7SUc.woff2) format('woff2');
  559. unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
  560. }
  561. /* latin */
  562. @font-face {
  563. font-family: 'Inter';
  564. font-style: normal;
  565. font-weight: 600;
  566. src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1ZL7.woff2) format('woff2');
  567. unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
  568. }
  569. /* cyrillic-ext */
  570. @font-face {
  571. font-family: 'Inter';
  572. font-style: normal;
  573. font-weight: 700;
  574. src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2JL7SUc.woff2) format('woff2');
  575. unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
  576. }
  577. /* cyrillic */
  578. @font-face {
  579. font-family: 'Inter';
  580. font-style: normal;
  581. font-weight: 700;
  582. src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa0ZL7SUc.woff2) format('woff2');
  583. unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
  584. }
  585. /* greek-ext */
  586. @font-face {
  587. font-family: 'Inter';
  588. font-style: normal;
  589. font-weight: 700;
  590. src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2ZL7SUc.woff2) format('woff2');
  591. unicode-range: U+1F00-1FFF;
  592. }
  593. /* greek */
  594. @font-face {
  595. font-family: 'Inter';
  596. font-style: normal;
  597. font-weight: 700;
  598. src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1pL7SUc.woff2) format('woff2');
  599. unicode-range: U+0370-03FF;
  600. }
  601. /* vietnamese */
  602. @font-face {
  603. font-family: 'Inter';
  604. font-style: normal;
  605. font-weight: 700;
  606. src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2pL7SUc.woff2) format('woff2');
  607. unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
  608. }
  609. /* latin-ext */
  610. @font-face {
  611. font-family: 'Inter';
  612. font-style: normal;
  613. font-weight: 700;
  614. src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa25L7SUc.woff2) format('woff2');
  615. unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
  616. }
  617. /* latin */
  618. @font-face {
  619. font-family: 'Inter';
  620. font-style: normal;
  621. font-weight: 700;
  622. src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1ZL7.woff2) format('woff2');
  623. unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
  624. }
  625. </style>
  626. {{- end}}
  627. {{- define "theme-switcher"}}
  628. <div class="d-flex align-items-center ms-2 ms-lg-3">
  629. <a href="#" class="btn btn-icon btn-active-light-primary w-35px h-35px w-md-40px h-md-40px" data-kt-menu-trigger="{default:'click', lg: 'hover'}" data-kt-menu-attach="parent" data-kt-menu-placement="bottom-end">
  630. <i class="ki-duotone ki-night-day theme-light-show fs-2">
  631. <span class="path1"></span>
  632. <span class="path2"></span>
  633. <span class="path3"></span>
  634. <span class="path4"></span>
  635. <span class="path5"></span>
  636. <span class="path6"></span>
  637. <span class="path7"></span>
  638. <span class="path8"></span>
  639. <span class="path9"></span>
  640. <span class="path10"></span>
  641. </i>
  642. <i class="ki-duotone ki-moon theme-dark-show fs-2">
  643. <span class="path1"></span>
  644. <span class="path2"></span>
  645. </i>
  646. </a>
  647. <div class="menu menu-sub menu-sub-dropdown menu-column menu-rounded menu-title-gray-700 menu-icon-gray-500 menu-active-bg menu-state-color fw-semibold py-4 fs-base w-150px" data-kt-menu="true" data-kt-element="theme-mode-menu">
  648. <div class="menu-item px-3 my-0">
  649. <a href="#" class="menu-link px-3 py-2" data-kt-element="mode" data-kt-value="light">
  650. <span class="menu-icon" data-kt-element="icon">
  651. <i class="ki-duotone ki-night-day fs-2">
  652. <span class="path1"></span>
  653. <span class="path2"></span>
  654. <span class="path3"></span>
  655. <span class="path4"></span>
  656. <span class="path5"></span>
  657. <span class="path6"></span>
  658. <span class="path7"></span>
  659. <span class="path8"></span>
  660. <span class="path9"></span>
  661. <span class="path10"></span>
  662. </i>
  663. </span>
  664. <span data-i18n="theme.light" class="menu-title">Light</span>
  665. </a>
  666. </div>
  667. <div class="menu-item px-3 my-0">
  668. <a href="#" class="menu-link px-3 py-2" data-kt-element="mode" data-kt-value="dark">
  669. <span class="menu-icon" data-kt-element="icon">
  670. <i class="ki-duotone ki-moon fs-2">
  671. <span class="path1"></span>
  672. <span class="path2"></span>
  673. </i>
  674. </span>
  675. <span data-i18n="theme.dark" class="menu-title">Dark</span>
  676. </a>
  677. </div>
  678. <div class="menu-item px-3 my-0">
  679. <a href="#" class="menu-link px-3 py-2" data-kt-element="mode" data-kt-value="system">
  680. <span class="menu-icon" data-kt-element="icon">
  681. <i class="ki-duotone ki-screen fs-2">
  682. <span class="path1"></span>
  683. <span class="path2"></span>
  684. <span class="path3"></span>
  685. <span class="path4"></span>
  686. </i>
  687. </span>
  688. <span data-i18n="theme.system" class="menu-title">System</span>
  689. </a>
  690. </div>
  691. </div>
  692. </div>
  693. {{- end}}
  694. {{- define "infomsg"}}
  695. <div class="notice d-flex bg-light-primary rounded border-primary border border-dashed p-4 mb-10">
  696. <div class="d-flex flex-stack flex-grow-1">
  697. <div class="fs-5 fw-semibold text-break text-wrap text-gray-800">
  698. <span data-i18n="{{.}}"></span>
  699. </div>
  700. </div>
  701. </div>
  702. {{- end}}
  703. {{- define "infomsg-no-mb"}}
  704. <div class="notice d-flex bg-light-primary rounded border-primary border border-dashed p-4">
  705. <div class="d-flex flex-stack flex-grow-1">
  706. <div class="fs-5 fw-semibold text-break text-wrap text-gray-800">
  707. <span data-i18n="{{.}}"></span>
  708. </div>
  709. </div>
  710. </div>
  711. {{- end}}
  712. {{- define "base"}}
  713. <!DOCTYPE html>
  714. <html lang="en">
  715. <head>
  716. <title></title>
  717. <meta charset="utf-8" />
  718. <meta name="description" content="" />
  719. <meta name="viewport" content="width=device-width, initial-scale=1" />
  720. <link rel="shortcut icon" href="{{.StaticURL}}{{.Branding.FaviconPath}}" />
  721. {{- template "fonts" . }}
  722. {{- range .Branding.DefaultCSS}}
  723. <link href="{{$.StaticURL}}{{.}}" rel="stylesheet" type="text/css">
  724. {{- end}}
  725. {{- template "globalstyle" .CSPNonce }}
  726. {{- block "extra_css" .}}{{- end}}
  727. {{- range .Branding.ExtraCSS}}
  728. <link href="{{$.StaticURL}}{{.}}" rel="stylesheet" type="text/css">
  729. {{- end}}
  730. {{- template "commonjs" .CSPNonce }}
  731. </head>
  732. <body data-kt-app-header-fixed="true" data-kt-app-header-fixed-mobile="true" data-kt-app-toolbar-enabled="true" data-kt-app-sidebar-enabled="true" data-kt-app-sidebar-fixed="true" data-kt-app-sidebar-push-header="true" data-kt-app-sidebar-push-toolbar="true" data-kt-app-sidebar-push-footer="true" class="app-default">
  733. {{- template "theme-setup" .CSPNonce }}
  734. <div id="app_loader" class="align-items-center text-center my-10">
  735. <span class="spinner-border w-15px h-15px text-muted align-middle me-2"></span>
  736. </div>
  737. <div class="d-flex flex-column flex-root app-root d-none" id="app_root">
  738. <div class="app-page flex-column flex-column-fluid " id="kt_app_page">
  739. {{- if .LoggedUser.Username}}
  740. <div id="kt_app_header" class="app-header" data-kt-sticky="true" data-kt-sticky-activate="{default: true, lg: true}" data-kt-sticky-name="app-header-minimize" data-kt-sticky-offset="{default: '200px', lg: '300px'}" data-kt-sticky-animation="false">
  741. <div class="app-container container-fluid d-flex align-items-stretch flex-stack " id="kt_app_header_container">
  742. <div class="d-flex align-items-center d-block d-lg-none ms-n3" title="Show sidebar menu">
  743. <div class="btn btn-icon btn-color-gray-800 btn-active-color-primary w-35px h-35px me-1" id="kt_app_sidebar_mobile_toggle">
  744. <i class="ki-duotone ki-abstract-14 fs-2">
  745. <span class="path1"></span>
  746. <span class="path2"></span>
  747. </i>
  748. </div>
  749. <span>
  750. <img alt="Logo" src="{{.StaticURL}}{{.Branding.LogoPath}}" class="h-30px" />
  751. </span>
  752. </div>
  753. <div class="app-navbar flex-lg-grow-1" id="kt_app_header_navbar">
  754. <div class="app-navbar-item d-flex align-items-center flex-lg-grow-1 me-2 me-lg-0">
  755. </div>
  756. <!-- <div class="d-flex align-self-center flex-center flex-shrink-0">
  757. </div> -->
  758. <div class="d-flex align-self-center flex-center flex-shrink-0">
  759. {{- template "navitems" .}}
  760. </div>
  761. </div>
  762. </div>
  763. </div>
  764. {{- end}}
  765. <div class="{{- if .LoggedUser.Username}}app-wrapper{{- end}} flex-column flex-row-fluid " id="kt_app_wrapper">
  766. {{- if .LoggedUser.Username}}
  767. <!-- <div id="kt_app_toolbar" class="app-toolbar">
  768. <div id="kt_app_toolbar_container" class="app-container container-fluid d-flex flex-lg-column py-3 py-lg-6 ">
  769. </div>
  770. </div> -->
  771. <div id="kt_app_sidebar" class="app-sidebar flex-column" data-kt-drawer="true" data-kt-drawer-name="app-sidebar" data-kt-drawer-activate="{default: true, lg: false}" data-kt-drawer-overlay="true" data-kt-drawer-width="300px" data-kt-drawer-direction="start" data-kt-drawer-toggle="#kt_app_sidebar_mobile_toggle">
  772. <div class="app-sidebar-header flex-column mx-10 pt-8" id="kt_app_sidebar_header">
  773. <div class="d-flex flex-stack d-none d-lg-flex mb-13">
  774. <div class="app-sidebar-logo">
  775. <img alt="Logo" src="{{.StaticURL}}{{.Branding.LogoPath}}" class="h-40px app-sidebar-logo-default" />
  776. <span class="text-sidebar fs-4 fw-semibold ps-5">{{.Branding.ShortName}}</span>
  777. </div>
  778. </div>
  779. </div>
  780. <div class="app-sidebar-navs flex-column-fluid pb-6" id="kt_app_sidebar_navs">
  781. <div id="kt_app_sidebar_navs_wrappers" class="hover-scroll-y my-2 mx-4" data-kt-scroll="true" data-kt-scroll-activate="true" data-kt-scroll-height="auto" data-kt-scroll-dependencies="#kt_app_sidebar_header" data-kt-scroll-wrappers="#kt_app_sidebar_navs" data-kt-scroll-offset="5px">
  782. <div id="#kt_app_sidebar_menu" data-kt-menu="true" data-kt-menu-expand="false" class="menu menu-column menu-rounded menu-sub-indention menu-active-bg mb-7">
  783. {{- template "sidebaritems" .}}
  784. </div>
  785. </div>
  786. </div>
  787. </div>
  788. {{- end}}
  789. <div class="app-main flex-column flex-row-fluid " id="kt_app_main">
  790. <div class="d-flex flex-column flex-column-fluid">
  791. <div id="kt_app_content" class="app-content flex-column-fluid">
  792. <div id="kt_app_content_container" class="app-container container-fluid">
  793. {{- template "page_body" .}}
  794. </div>
  795. </div>
  796. </div>
  797. {{- if .LoggedUser.Username}}
  798. <div id="kt_app_footer" class="app-footer">
  799. <div class="app-container container-fluid d-flex flex-column flex-md-row flex-center flex-md-stack py-3 align-items-center justify-content-center">
  800. <div class="text-gray-900 order-2 order-md-1">
  801. <span class="text-gray-700 fw-semibold me-1">SFTPGo {{.Version}}</span>
  802. </div>
  803. </div>
  804. </div>
  805. {{- end}}
  806. </div>
  807. </div>
  808. </div>
  809. </div>
  810. <div id="kt_scrolltop" class="scrolltop" data-kt-scrolltop="true">
  811. <i class="ki-duotone ki-arrow-up">
  812. <span class="path1"></span>
  813. <span class="path2"></span>
  814. </i>
  815. </div>
  816. <div class="page-loader flex-column">
  817. <span class="spinner-border text-primary" role="status"></span>
  818. <span id="loading_message" class="text-muted fs-4 fw-semibold mt-5"></span>
  819. </div>
  820. <div class="modal fade" tabindex="-1" id="modal_alert">
  821. <div class="modal-dialog modal-dialog-centered">
  822. <div class="modal-content">
  823. <div class="modal-body">
  824. <div class="d-flex flex-center flex-column">
  825. <span id="modal_alert_icon">
  826. </span>
  827. <div class="mt-10 text-center">
  828. <span id="modal_alert_text" class="fs-6 text-gray-900 fw-semibold"></span>
  829. </div>
  830. </div>
  831. <div id="modal_alert_items" class="d-flex flex-column mt-5 d-none">
  832. </div>
  833. </div>
  834. <div class="modal-footer border-0 justify-content-center">
  835. <button id="modal_alert_cancel" type="button" class="btn btn-secondary m-2"></button>
  836. <button id="modal_alert_ok" type="button" class="btn btn-primary m-2"></button>
  837. </div>
  838. </div>
  839. </div>
  840. </div>
  841. <div class="toast-container position-fixed top-0 end-0 p-3">
  842. <div id="toast_container" class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-bs-autohide="false">
  843. <div class="toast-body border-0 d-flex align-items-center">
  844. <span id="toast_icon"></span>
  845. <span id="toast_msg" class="fs-5 fw-semibold text-gray-800 me-auto"></span>
  846. <button data-i18n="[aria-label]general.close" type="button" class="btn btn-icon btn-sm btn-active-light-primary position-absolute position-sm-relative m-2 m-sm-0 top-0 end-0 ms-sm-auto" data-bs-dismiss="toast" aria-label="Close">
  847. <i class="ki-solid ki-cross fs-2x text-gray-700"></i>
  848. </button>
  849. </div>
  850. </div>
  851. </div>
  852. {{- block "modals" .}}{{- end}}
  853. <script {{- if .CSPNonce}} nonce="{{.CSPNonce}}"{{- end}} src="{{.StaticURL}}/assets/plugins/global/plugins.bundle.js"></script>
  854. <script {{- if .CSPNonce}} nonce="{{.CSPNonce}}"{{- end}} src="{{.StaticURL}}/assets/js/scripts.bundle.js"></script>
  855. <script {{- if .CSPNonce}} nonce="{{.CSPNonce}}"{{- end}} src="{{.StaticURL}}/vendor/i18next/i18next.js"></script>
  856. <script {{- if .CSPNonce}} nonce="{{.CSPNonce}}"{{- end}} src="{{.StaticURL}}/vendor/i18next/jquery-i18next.js"></script>
  857. <script {{- if .CSPNonce}} nonce="{{.CSPNonce}}"{{- end}} src="{{.StaticURL}}/vendor/i18next/i18nextBrowserLanguageDetector.js"></script>
  858. <script {{- if .CSPNonce}} nonce="{{.CSPNonce}}"{{- end}} src="{{.StaticURL}}/vendor/i18next/i18nextChainedBackend.js"></script>
  859. <script {{- if .CSPNonce}} nonce="{{.CSPNonce}}"{{- end}} src="{{.StaticURL}}/vendor/i18next/i18nextLocalStorageBackend.js"></script>
  860. <script {{- if .CSPNonce}} nonce="{{.CSPNonce}}"{{- end}} src="{{.StaticURL}}/vendor/i18next/i18nextHttpBackend.js"></script>
  861. {{- template "basejs" . }}
  862. <script type="text/javascript" {{- if .CSPNonce}} nonce="{{.CSPNonce}}"{{- end}}>
  863. var ModalAlert = function () {
  864. var modal;
  865. var promiseResolve;
  866. var isResolved;
  867. function resolvePromise(result) {
  868. if (!isResolved) {
  869. isResolved = true;
  870. promiseResolve({
  871. isConfirmed: result
  872. });
  873. }
  874. }
  875. var cancelFn = function() {
  876. resolvePromise(false);
  877. modal.hide();
  878. }
  879. var okFn = function() {
  880. resolvePromise(true);
  881. modal.hide();
  882. }
  883. var hideFn = function() {
  884. resolvePromise(false);
  885. }
  886. return {
  887. fire: function (params) {
  888. modal = new bootstrap.Modal('#modal_alert');
  889. let modalEl = $('#modal_alert');
  890. let okBtn = $("#modal_alert_ok");
  891. let cancelBtn = $("#modal_alert_cancel");
  892. let itemsList = $('#modal_alert_items');
  893. modalEl.off('hide.bs.modal');
  894. modalEl.on('hide.bs.modal', hideFn);
  895. cancelBtn.off("click");
  896. okBtn.off("click");
  897. cancelBtn.on("click", cancelFn);
  898. okBtn.on("click", okFn);
  899. okBtn.removeClass();
  900. okBtn.addClass(params.customClass.confirmButton);
  901. okBtn.addClass("m-2");
  902. okBtn.text(params.confirmButtonText);
  903. if (params.cancelButtonText){
  904. cancelBtn.text(params.cancelButtonText);
  905. cancelBtn.removeClass();
  906. cancelBtn.addClass(params.customClass.cancelButton);
  907. cancelBtn.addClass("m-2");
  908. } else {
  909. cancelBtn.addClass("d-none");
  910. }
  911. $("#modal_alert_text").text(params.text);
  912. itemsList.empty();
  913. itemsList.addClass("d-none");
  914. if (params.items && params.items.length > 0){
  915. itemsList.removeClass("d-none");
  916. $.each(params.items, function(key, item) {
  917. itemText = escapeHTML(item);
  918. itemsList.append(`<li class="d-flex align-items-center py-2 fw-bold fs-6 text-gray-800"><span class="bullet bullet-dot bg-primary me-2"></span>${itemText}</li>`);
  919. });
  920. }
  921. switch (params.icon){
  922. case "warning":
  923. $("#modal_alert_icon").html(`<i class="ki-duotone ki-information-5 fs-5x text-danger">
  924. <span class="path1"></span>
  925. <span class="path2"></span>
  926. <span class="path3"></span>
  927. </i>`);
  928. break;
  929. case "success":
  930. $("#modal_alert_icon").html(`<i class="ki-duotone ki-check-square fs-5x text-success">
  931. <span class="path1"></span>
  932. <span class="path2"></span>
  933. </i>`);
  934. break;
  935. default:
  936. $("#modal_alert_icon").html(`<i class="ki-duotone ki-question-2 fs-5x text-primary">
  937. <span class="path1"></span>
  938. <span class="path2"></span>
  939. <span class="path3"></span>
  940. </i>`);
  941. }
  942. return new Promise(function(resolve, reject) {
  943. promiseResolve = resolve;
  944. isResolved = false;
  945. modal.show();
  946. });
  947. }
  948. }
  949. }();
  950. function showToast(status, msg, options) {
  951. const toast = bootstrap.Toast.getOrCreateInstance(document.getElementById('toast_container'));
  952. if (status === 1){
  953. $("#toast_icon").html(`<i class="ki-duotone ki-check-square fs-3x text-success me-5">
  954. <span class="path1"></span>
  955. <span class="path2"></span>
  956. </i>`);
  957. } else {
  958. $("#toast_icon").html(`<i class="ki-duotone ki-information-5 fs-3x text-warning me-5">
  959. <span class="path1"></span>
  960. <span class="path2"></span>
  961. <span class="path3"></span>
  962. </i>`);
  963. }
  964. setI18NData($('#toast_msg'), msg, options)
  965. toast.show();
  966. }
  967. function doLogout() {
  968. ModalAlert.fire({
  969. text: $.t("general.confirm_logout"),
  970. icon: "question",
  971. confirmButtonText: $.t("login.signout"),
  972. cancelButtonText: $.t("general.cancel"),
  973. customClass: {
  974. confirmButton: "btn btn-primary",
  975. cancelButton: 'btn btn-secondary'
  976. }
  977. }).then((result) =>{
  978. if (result.isConfirmed){
  979. window.location.replace('{{.LogoutURL}}');
  980. }
  981. });
  982. }
  983. </script>
  984. {{- block "extra_js" .}}{{- end}}
  985. </body>
  986. </html>
  987. {{- end}}