diff --git a/themes-default/slim/static/js/store.js b/themes-default/slim/static/js/store.js index 34dde2bf19..f0469eab98 100644 --- a/themes-default/slim/static/js/store.js +++ b/themes-default/slim/static/js/store.js @@ -71,8 +71,21 @@ const store = new Puex({ notifications: { enabled: true }, - qualities: {}, - statuses: {}, + qualities: { + values: {}, + anySets: {}, + presets: {}, + strings: { + values: {}, + anySets: {}, + presets: {}, + cssClass: {} + } + }, + statuses: { + values: {}, + strings: {} + }, // Main config config: { wikiUrl: null, diff --git a/themes-default/slim/views/layouts/main.mako b/themes-default/slim/views/layouts/main.mako index 4095025eb6..ad05236561 100644 --- a/themes-default/slim/views/layouts/main.mako +++ b/themes-default/slim/views/layouts/main.mako @@ -66,7 +66,25 @@ <%block name="content" /> - <%include file="/partials/footer.mako" /> + + +
+ + + +
+ +
+ + + +
+ +
+ + + +
@@ -125,9 +143,11 @@ + + <%include file="/vue-components/app-footer.mako"/> <%include file="/vue-components/asset.mako"/> <%include file="/vue-components/file-browser.mako"/> <%include file="/vue-components/plot-info.mako"/> diff --git a/themes-default/slim/views/partials/footer.mako b/themes-default/slim/views/partials/footer.mako deleted file mode 100644 index 8e1e7c3a91..0000000000 --- a/themes-default/slim/views/partials/footer.mako +++ /dev/null @@ -1,80 +0,0 @@ -<%! - from datetime import datetime - from time import time - from contextlib2 import suppress - import os - import re - from medusa.app import ( - daily_search_scheduler as daily_search_scheduler, - backlog_search_scheduler as backlog_search_scheduler, - BRANCH, DATE_PRESET, TIME_PRESET - ) - from medusa.helper.common import pretty_file_size - from medusa.show.show import Show - - mem_usage = None - with suppress(ImportError): - from psutil import Process - from os import getpid - mem_usage = 'psutil' - - with suppress(ImportError): - if not mem_usage: - import resource # resource module is unix only - mem_usage = 'resource' -%> - -% if loggedIn: - <% - stats = Show.overall_stats() - ep_downloaded = stats['episodes']['downloaded'] - ep_snatched = stats['episodes']['snatched'] - ep_total = stats['episodes']['total'] - ep_percentage = '' if ep_total == 0 else '(%s%%)' % re.sub(r'(\d+)(\.\d)\d+', r'\1\2', str((float(ep_downloaded)/float(ep_total))*100)) - %> - -% endif - - -
- - - -
- -
- - - -
- -
- - - -
diff --git a/themes-default/slim/views/vue-components/app-footer.mako b/themes-default/slim/views/vue-components/app-footer.mako new file mode 100644 index 0000000000..f4d2edbcc6 --- /dev/null +++ b/themes-default/slim/views/vue-components/app-footer.mako @@ -0,0 +1,128 @@ + +<%! + import json + from time import time + + from medusa.app import backlog_search_scheduler, daily_search_scheduler + from medusa.helper.common import pretty_file_size + from medusa.show.show import Show + + mem_usage = None + try: + from psutil import Process + from os import getpid + mem_usage = 'psutil' + except ImportError: + try: + import resource # resource module is unix only + mem_usage = 'resource' + except ImportError: + pass +%> + diff --git a/themes/dark/assets/js/store.js b/themes/dark/assets/js/store.js index 34dde2bf19..f0469eab98 100644 --- a/themes/dark/assets/js/store.js +++ b/themes/dark/assets/js/store.js @@ -71,8 +71,21 @@ const store = new Puex({ notifications: { enabled: true }, - qualities: {}, - statuses: {}, + qualities: { + values: {}, + anySets: {}, + presets: {}, + strings: { + values: {}, + anySets: {}, + presets: {}, + cssClass: {} + } + }, + statuses: { + values: {}, + strings: {} + }, // Main config config: { wikiUrl: null, diff --git a/themes/dark/assets/js/store.js.map b/themes/dark/assets/js/store.js.map index ff7c1f0591..a39646cb28 100644 --- a/themes/dark/assets/js/store.js.map +++ b/themes/dark/assets/js/store.js.map @@ -1 +1 @@ -{"version":3,"names":[],"mappings":"","sources":["js/store.js"],"sourcesContent":["(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c=\"function\"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error(\"Cannot find module '\"+i+\"'\");throw a.code=\"MODULE_NOT_FOUND\",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u=\"function\"==typeof require&&require,i=0;i message.hash === data.hash);\n if (existingMessage.length === 1) {\n state.socket.messages[state.socket.messages.indexOf(existingMessage)] = message;\n } else {\n state.socket.messages.push(message);\n }\n }\n },\n // Mutations for websocket reconnect methods\n [SOCKET_RECONNECT](state, count) {\n console.info(state, count);\n },\n [SOCKET_RECONNECT_ERROR](state) {\n state.socket.reconnectError = true;\n\n const title = 'Error connecting to websocket';\n let error = '';\n error += 'Please check your network connection. ';\n error += 'If you are using a reverse proxy, please take a look at our wiki for config examples.';\n\n displayNotification('notice', title, error);\n },\n [NOTIFICATIONS_ENABLED](state) {\n state.notifications.enabled = true;\n },\n [NOTIFICATIONS_DISABLED](state) {\n state.notifications.enabled = false;\n },\n [ADD_CONFIG](state, { section, config }) {\n if (section === 'main') {\n state.config = config;\n }\n if (['qualities', 'statuses'].includes(section)) {\n state[section] = config;\n }\n },\n [ADD_SHOW](state, show) {\n const { shows } = state;\n const showExists = shows.filter(({ id, indexer }) => id[indexer] === show.id[indexer]).length === 1;\n if (showExists) {\n state.shows[shows.indexOf(showExists)] = show;\n } else {\n state.shows.push(show);\n }\n }\n },\n // Add all blocking code here\n // No actions should write to the store\n // Please use context.commit to fire off a mutation that'll update the store\n // Do not use store.commit in any actions!\n actions: {\n login(context, credentials) {\n const { commit } = context;\n commit(LOGIN_PENDING);\n\n // @TODO: Add real JWT login\n const apiLogin = () => Promise.resolve({ username: 'admin' });\n\n apiLogin(credentials).then(user => {\n return commit(LOGIN_SUCCESS, user);\n }).catch(error => {\n commit(LOGIN_FAILED, { error, credentials });\n });\n },\n logout(context) {\n const { commit } = context;\n commit(LOGOUT);\n },\n getConfig(context, section) {\n const { commit } = context;\n return api.get('/config/' + (section || '')).then(res => {\n if (section) {\n const config = res.data;\n return commit(ADD_CONFIG, { section, config });\n }\n Object.keys(res.data).forEach(section => {\n const config = res.data[section];\n commit(ADD_CONFIG, { section, config });\n });\n });\n },\n setConfig(context, { section, config }) {\n if (section !== 'main') {\n return;\n }\n return api.patch('config/' + section, config);\n },\n updateConfig(context, { section, config }) {\n return store.commit(ADD_CONFIG, { section, config });\n },\n getShow(context, { indexer, id }) {\n const { commit } = context;\n return api.get('/series/' + indexer + id).then(res => {\n commit(ADD_SHOW, res.data);\n });\n },\n getShows(context, shows) {\n const { commit, dispatch } = context;\n\n // If no shows are provided get all of them\n if (!shows) {\n return api.get('/series?limit=1000').then(res => {\n const shows = res.data;\n return shows.forEach(show => {\n commit(ADD_SHOW, show);\n });\n });\n }\n\n return shows.forEach(show => dispatch('getShow', show));\n },\n testNotifications() {\n return displayNotification('error', 'test', 'test
hello world', 'notification-test');\n },\n setLayout(context, { page, layout }) {\n return api.patch('config/main', {\n layout: {\n [page]: layout\n // For now we reload the page since the layouts use python still\n } }).then(setTimeout(() => location.reload(), 500));\n }\n },\n // @TODO Add logging here\n plugins: []\n});\n\nconst websocketUrl = (() => {\n const proto = window.location.protocol === 'https:' ? 'wss:' : 'ws:';\n const webRoot = apiRoot.replace('/api/v2/', '');\n const WSMessageUrl = '/ui';\n return proto + '//' + window.location.hostname + ':' + window.location.port + webRoot + '/ws' + WSMessageUrl;\n})();\n\nVue.use(VueNativeSock, websocketUrl, {\n store,\n format: 'json',\n reconnection: true, // (Boolean) whether to reconnect automatically (false)\n reconnectionAttempts: 2, // (Number) number of reconnection attempts before giving up (Infinity),\n reconnectionDelay: 1000 // (Number) how long to initially wait before attempting a new (1000)\n});\n\nwindow.store = store;\n\n},{}]},{},[1]);\n"],"file":"store.js"} \ No newline at end of file +{"version":3,"names":[],"mappings":"","sources":["js/store.js"],"sourcesContent":["(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c=\"function\"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error(\"Cannot find module '\"+i+\"'\");throw a.code=\"MODULE_NOT_FOUND\",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u=\"function\"==typeof require&&require,i=0;i message.hash === data.hash);\n if (existingMessage.length === 1) {\n state.socket.messages[state.socket.messages.indexOf(existingMessage)] = message;\n } else {\n state.socket.messages.push(message);\n }\n }\n },\n // Mutations for websocket reconnect methods\n [SOCKET_RECONNECT](state, count) {\n console.info(state, count);\n },\n [SOCKET_RECONNECT_ERROR](state) {\n state.socket.reconnectError = true;\n\n const title = 'Error connecting to websocket';\n let error = '';\n error += 'Please check your network connection. ';\n error += 'If you are using a reverse proxy, please take a look at our wiki for config examples.';\n\n displayNotification('notice', title, error);\n },\n [NOTIFICATIONS_ENABLED](state) {\n state.notifications.enabled = true;\n },\n [NOTIFICATIONS_DISABLED](state) {\n state.notifications.enabled = false;\n },\n [ADD_CONFIG](state, { section, config }) {\n if (section === 'main') {\n state.config = config;\n }\n if (['qualities', 'statuses'].includes(section)) {\n state[section] = config;\n }\n },\n [ADD_SHOW](state, show) {\n const { shows } = state;\n const showExists = shows.filter(({ id, indexer }) => id[indexer] === show.id[indexer]).length === 1;\n if (showExists) {\n state.shows[shows.indexOf(showExists)] = show;\n } else {\n state.shows.push(show);\n }\n }\n },\n // Add all blocking code here\n // No actions should write to the store\n // Please use context.commit to fire off a mutation that'll update the store\n // Do not use store.commit in any actions!\n actions: {\n login(context, credentials) {\n const { commit } = context;\n commit(LOGIN_PENDING);\n\n // @TODO: Add real JWT login\n const apiLogin = () => Promise.resolve({ username: 'admin' });\n\n apiLogin(credentials).then(user => {\n return commit(LOGIN_SUCCESS, user);\n }).catch(error => {\n commit(LOGIN_FAILED, { error, credentials });\n });\n },\n logout(context) {\n const { commit } = context;\n commit(LOGOUT);\n },\n getConfig(context, section) {\n const { commit } = context;\n return api.get('/config/' + (section || '')).then(res => {\n if (section) {\n const config = res.data;\n return commit(ADD_CONFIG, { section, config });\n }\n Object.keys(res.data).forEach(section => {\n const config = res.data[section];\n commit(ADD_CONFIG, { section, config });\n });\n });\n },\n setConfig(context, { section, config }) {\n if (section !== 'main') {\n return;\n }\n return api.patch('config/' + section, config);\n },\n updateConfig(context, { section, config }) {\n return store.commit(ADD_CONFIG, { section, config });\n },\n getShow(context, { indexer, id }) {\n const { commit } = context;\n return api.get('/series/' + indexer + id).then(res => {\n commit(ADD_SHOW, res.data);\n });\n },\n getShows(context, shows) {\n const { commit, dispatch } = context;\n\n // If no shows are provided get all of them\n if (!shows) {\n return api.get('/series?limit=1000').then(res => {\n const shows = res.data;\n return shows.forEach(show => {\n commit(ADD_SHOW, show);\n });\n });\n }\n\n return shows.forEach(show => dispatch('getShow', show));\n },\n testNotifications() {\n return displayNotification('error', 'test', 'test
hello world', 'notification-test');\n },\n setLayout(context, { page, layout }) {\n return api.patch('config/main', {\n layout: {\n [page]: layout\n // For now we reload the page since the layouts use python still\n } }).then(setTimeout(() => location.reload(), 500));\n }\n },\n // @TODO Add logging here\n plugins: []\n});\n\nconst websocketUrl = (() => {\n const proto = window.location.protocol === 'https:' ? 'wss:' : 'ws:';\n const webRoot = apiRoot.replace('/api/v2/', '');\n const WSMessageUrl = '/ui';\n return proto + '//' + window.location.hostname + ':' + window.location.port + webRoot + '/ws' + WSMessageUrl;\n})();\n\nVue.use(VueNativeSock, websocketUrl, {\n store,\n format: 'json',\n reconnection: true, // (Boolean) whether to reconnect automatically (false)\n reconnectionAttempts: 2, // (Number) number of reconnection attempts before giving up (Infinity),\n reconnectionDelay: 1000 // (Number) how long to initially wait before attempting a new (1000)\n});\n\nwindow.store = store;\n\n},{}]},{},[1]);\n"],"file":"store.js"} \ No newline at end of file diff --git a/themes/dark/templates/layouts/main.mako b/themes/dark/templates/layouts/main.mako index 4095025eb6..ad05236561 100644 --- a/themes/dark/templates/layouts/main.mako +++ b/themes/dark/templates/layouts/main.mako @@ -66,7 +66,25 @@ <%block name="content" /> - <%include file="/partials/footer.mako" /> + + +
+ + + +
+ +
+ + + +
+ +
+ + + +
@@ -125,9 +143,11 @@ + + <%include file="/vue-components/app-footer.mako"/> <%include file="/vue-components/asset.mako"/> <%include file="/vue-components/file-browser.mako"/> <%include file="/vue-components/plot-info.mako"/> diff --git a/themes/dark/templates/partials/footer.mako b/themes/dark/templates/partials/footer.mako deleted file mode 100644 index 8e1e7c3a91..0000000000 --- a/themes/dark/templates/partials/footer.mako +++ /dev/null @@ -1,80 +0,0 @@ -<%! - from datetime import datetime - from time import time - from contextlib2 import suppress - import os - import re - from medusa.app import ( - daily_search_scheduler as daily_search_scheduler, - backlog_search_scheduler as backlog_search_scheduler, - BRANCH, DATE_PRESET, TIME_PRESET - ) - from medusa.helper.common import pretty_file_size - from medusa.show.show import Show - - mem_usage = None - with suppress(ImportError): - from psutil import Process - from os import getpid - mem_usage = 'psutil' - - with suppress(ImportError): - if not mem_usage: - import resource # resource module is unix only - mem_usage = 'resource' -%> - -% if loggedIn: - <% - stats = Show.overall_stats() - ep_downloaded = stats['episodes']['downloaded'] - ep_snatched = stats['episodes']['snatched'] - ep_total = stats['episodes']['total'] - ep_percentage = '' if ep_total == 0 else '(%s%%)' % re.sub(r'(\d+)(\.\d)\d+', r'\1\2', str((float(ep_downloaded)/float(ep_total))*100)) - %> -
- -
-% endif - - -
- - - -
- -
- - - -
- -
- - - -
diff --git a/themes/dark/templates/vue-components/app-footer.mako b/themes/dark/templates/vue-components/app-footer.mako new file mode 100644 index 0000000000..f4d2edbcc6 --- /dev/null +++ b/themes/dark/templates/vue-components/app-footer.mako @@ -0,0 +1,128 @@ + +<%! + import json + from time import time + + from medusa.app import backlog_search_scheduler, daily_search_scheduler + from medusa.helper.common import pretty_file_size + from medusa.show.show import Show + + mem_usage = None + try: + from psutil import Process + from os import getpid + mem_usage = 'psutil' + except ImportError: + try: + import resource # resource module is unix only + mem_usage = 'resource' + except ImportError: + pass +%> + diff --git a/themes/light/assets/js/store.js b/themes/light/assets/js/store.js index 34dde2bf19..f0469eab98 100644 --- a/themes/light/assets/js/store.js +++ b/themes/light/assets/js/store.js @@ -71,8 +71,21 @@ const store = new Puex({ notifications: { enabled: true }, - qualities: {}, - statuses: {}, + qualities: { + values: {}, + anySets: {}, + presets: {}, + strings: { + values: {}, + anySets: {}, + presets: {}, + cssClass: {} + } + }, + statuses: { + values: {}, + strings: {} + }, // Main config config: { wikiUrl: null, diff --git a/themes/light/assets/js/store.js.map b/themes/light/assets/js/store.js.map index ff7c1f0591..a39646cb28 100644 --- a/themes/light/assets/js/store.js.map +++ b/themes/light/assets/js/store.js.map @@ -1 +1 @@ -{"version":3,"names":[],"mappings":"","sources":["js/store.js"],"sourcesContent":["(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c=\"function\"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error(\"Cannot find module '\"+i+\"'\");throw a.code=\"MODULE_NOT_FOUND\",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u=\"function\"==typeof require&&require,i=0;i message.hash === data.hash);\n if (existingMessage.length === 1) {\n state.socket.messages[state.socket.messages.indexOf(existingMessage)] = message;\n } else {\n state.socket.messages.push(message);\n }\n }\n },\n // Mutations for websocket reconnect methods\n [SOCKET_RECONNECT](state, count) {\n console.info(state, count);\n },\n [SOCKET_RECONNECT_ERROR](state) {\n state.socket.reconnectError = true;\n\n const title = 'Error connecting to websocket';\n let error = '';\n error += 'Please check your network connection. ';\n error += 'If you are using a reverse proxy, please take a look at our wiki for config examples.';\n\n displayNotification('notice', title, error);\n },\n [NOTIFICATIONS_ENABLED](state) {\n state.notifications.enabled = true;\n },\n [NOTIFICATIONS_DISABLED](state) {\n state.notifications.enabled = false;\n },\n [ADD_CONFIG](state, { section, config }) {\n if (section === 'main') {\n state.config = config;\n }\n if (['qualities', 'statuses'].includes(section)) {\n state[section] = config;\n }\n },\n [ADD_SHOW](state, show) {\n const { shows } = state;\n const showExists = shows.filter(({ id, indexer }) => id[indexer] === show.id[indexer]).length === 1;\n if (showExists) {\n state.shows[shows.indexOf(showExists)] = show;\n } else {\n state.shows.push(show);\n }\n }\n },\n // Add all blocking code here\n // No actions should write to the store\n // Please use context.commit to fire off a mutation that'll update the store\n // Do not use store.commit in any actions!\n actions: {\n login(context, credentials) {\n const { commit } = context;\n commit(LOGIN_PENDING);\n\n // @TODO: Add real JWT login\n const apiLogin = () => Promise.resolve({ username: 'admin' });\n\n apiLogin(credentials).then(user => {\n return commit(LOGIN_SUCCESS, user);\n }).catch(error => {\n commit(LOGIN_FAILED, { error, credentials });\n });\n },\n logout(context) {\n const { commit } = context;\n commit(LOGOUT);\n },\n getConfig(context, section) {\n const { commit } = context;\n return api.get('/config/' + (section || '')).then(res => {\n if (section) {\n const config = res.data;\n return commit(ADD_CONFIG, { section, config });\n }\n Object.keys(res.data).forEach(section => {\n const config = res.data[section];\n commit(ADD_CONFIG, { section, config });\n });\n });\n },\n setConfig(context, { section, config }) {\n if (section !== 'main') {\n return;\n }\n return api.patch('config/' + section, config);\n },\n updateConfig(context, { section, config }) {\n return store.commit(ADD_CONFIG, { section, config });\n },\n getShow(context, { indexer, id }) {\n const { commit } = context;\n return api.get('/series/' + indexer + id).then(res => {\n commit(ADD_SHOW, res.data);\n });\n },\n getShows(context, shows) {\n const { commit, dispatch } = context;\n\n // If no shows are provided get all of them\n if (!shows) {\n return api.get('/series?limit=1000').then(res => {\n const shows = res.data;\n return shows.forEach(show => {\n commit(ADD_SHOW, show);\n });\n });\n }\n\n return shows.forEach(show => dispatch('getShow', show));\n },\n testNotifications() {\n return displayNotification('error', 'test', 'test
hello world
  • item 1
  • item 2
', 'notification-test');\n },\n setLayout(context, { page, layout }) {\n return api.patch('config/main', {\n layout: {\n [page]: layout\n // For now we reload the page since the layouts use python still\n } }).then(setTimeout(() => location.reload(), 500));\n }\n },\n // @TODO Add logging here\n plugins: []\n});\n\nconst websocketUrl = (() => {\n const proto = window.location.protocol === 'https:' ? 'wss:' : 'ws:';\n const webRoot = apiRoot.replace('/api/v2/', '');\n const WSMessageUrl = '/ui';\n return proto + '//' + window.location.hostname + ':' + window.location.port + webRoot + '/ws' + WSMessageUrl;\n})();\n\nVue.use(VueNativeSock, websocketUrl, {\n store,\n format: 'json',\n reconnection: true, // (Boolean) whether to reconnect automatically (false)\n reconnectionAttempts: 2, // (Number) number of reconnection attempts before giving up (Infinity),\n reconnectionDelay: 1000 // (Number) how long to initially wait before attempting a new (1000)\n});\n\nwindow.store = store;\n\n},{}]},{},[1]);\n"],"file":"store.js"} \ No newline at end of file +{"version":3,"names":[],"mappings":"","sources":["js/store.js"],"sourcesContent":["(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c=\"function\"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error(\"Cannot find module '\"+i+\"'\");throw a.code=\"MODULE_NOT_FOUND\",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u=\"function\"==typeof require&&require,i=0;i message.hash === data.hash);\n if (existingMessage.length === 1) {\n state.socket.messages[state.socket.messages.indexOf(existingMessage)] = message;\n } else {\n state.socket.messages.push(message);\n }\n }\n },\n // Mutations for websocket reconnect methods\n [SOCKET_RECONNECT](state, count) {\n console.info(state, count);\n },\n [SOCKET_RECONNECT_ERROR](state) {\n state.socket.reconnectError = true;\n\n const title = 'Error connecting to websocket';\n let error = '';\n error += 'Please check your network connection. ';\n error += 'If you are using a reverse proxy, please take a look at our wiki for config examples.';\n\n displayNotification('notice', title, error);\n },\n [NOTIFICATIONS_ENABLED](state) {\n state.notifications.enabled = true;\n },\n [NOTIFICATIONS_DISABLED](state) {\n state.notifications.enabled = false;\n },\n [ADD_CONFIG](state, { section, config }) {\n if (section === 'main') {\n state.config = config;\n }\n if (['qualities', 'statuses'].includes(section)) {\n state[section] = config;\n }\n },\n [ADD_SHOW](state, show) {\n const { shows } = state;\n const showExists = shows.filter(({ id, indexer }) => id[indexer] === show.id[indexer]).length === 1;\n if (showExists) {\n state.shows[shows.indexOf(showExists)] = show;\n } else {\n state.shows.push(show);\n }\n }\n },\n // Add all blocking code here\n // No actions should write to the store\n // Please use context.commit to fire off a mutation that'll update the store\n // Do not use store.commit in any actions!\n actions: {\n login(context, credentials) {\n const { commit } = context;\n commit(LOGIN_PENDING);\n\n // @TODO: Add real JWT login\n const apiLogin = () => Promise.resolve({ username: 'admin' });\n\n apiLogin(credentials).then(user => {\n return commit(LOGIN_SUCCESS, user);\n }).catch(error => {\n commit(LOGIN_FAILED, { error, credentials });\n });\n },\n logout(context) {\n const { commit } = context;\n commit(LOGOUT);\n },\n getConfig(context, section) {\n const { commit } = context;\n return api.get('/config/' + (section || '')).then(res => {\n if (section) {\n const config = res.data;\n return commit(ADD_CONFIG, { section, config });\n }\n Object.keys(res.data).forEach(section => {\n const config = res.data[section];\n commit(ADD_CONFIG, { section, config });\n });\n });\n },\n setConfig(context, { section, config }) {\n if (section !== 'main') {\n return;\n }\n return api.patch('config/' + section, config);\n },\n updateConfig(context, { section, config }) {\n return store.commit(ADD_CONFIG, { section, config });\n },\n getShow(context, { indexer, id }) {\n const { commit } = context;\n return api.get('/series/' + indexer + id).then(res => {\n commit(ADD_SHOW, res.data);\n });\n },\n getShows(context, shows) {\n const { commit, dispatch } = context;\n\n // If no shows are provided get all of them\n if (!shows) {\n return api.get('/series?limit=1000').then(res => {\n const shows = res.data;\n return shows.forEach(show => {\n commit(ADD_SHOW, show);\n });\n });\n }\n\n return shows.forEach(show => dispatch('getShow', show));\n },\n testNotifications() {\n return displayNotification('error', 'test', 'test
hello world
  • item 1
  • item 2
', 'notification-test');\n },\n setLayout(context, { page, layout }) {\n return api.patch('config/main', {\n layout: {\n [page]: layout\n // For now we reload the page since the layouts use python still\n } }).then(setTimeout(() => location.reload(), 500));\n }\n },\n // @TODO Add logging here\n plugins: []\n});\n\nconst websocketUrl = (() => {\n const proto = window.location.protocol === 'https:' ? 'wss:' : 'ws:';\n const webRoot = apiRoot.replace('/api/v2/', '');\n const WSMessageUrl = '/ui';\n return proto + '//' + window.location.hostname + ':' + window.location.port + webRoot + '/ws' + WSMessageUrl;\n})();\n\nVue.use(VueNativeSock, websocketUrl, {\n store,\n format: 'json',\n reconnection: true, // (Boolean) whether to reconnect automatically (false)\n reconnectionAttempts: 2, // (Number) number of reconnection attempts before giving up (Infinity),\n reconnectionDelay: 1000 // (Number) how long to initially wait before attempting a new (1000)\n});\n\nwindow.store = store;\n\n},{}]},{},[1]);\n"],"file":"store.js"} \ No newline at end of file diff --git a/themes/light/templates/layouts/main.mako b/themes/light/templates/layouts/main.mako index 4095025eb6..ad05236561 100644 --- a/themes/light/templates/layouts/main.mako +++ b/themes/light/templates/layouts/main.mako @@ -66,7 +66,25 @@ <%block name="content" /> - <%include file="/partials/footer.mako" /> + + +
+ + + +
+ +
+ + + +
+ +
+ + + +
@@ -125,9 +143,11 @@ + + <%include file="/vue-components/app-footer.mako"/> <%include file="/vue-components/asset.mako"/> <%include file="/vue-components/file-browser.mako"/> <%include file="/vue-components/plot-info.mako"/> diff --git a/themes/light/templates/partials/footer.mako b/themes/light/templates/partials/footer.mako deleted file mode 100644 index 8e1e7c3a91..0000000000 --- a/themes/light/templates/partials/footer.mako +++ /dev/null @@ -1,80 +0,0 @@ -<%! - from datetime import datetime - from time import time - from contextlib2 import suppress - import os - import re - from medusa.app import ( - daily_search_scheduler as daily_search_scheduler, - backlog_search_scheduler as backlog_search_scheduler, - BRANCH, DATE_PRESET, TIME_PRESET - ) - from medusa.helper.common import pretty_file_size - from medusa.show.show import Show - - mem_usage = None - with suppress(ImportError): - from psutil import Process - from os import getpid - mem_usage = 'psutil' - - with suppress(ImportError): - if not mem_usage: - import resource # resource module is unix only - mem_usage = 'resource' -%> - -% if loggedIn: - <% - stats = Show.overall_stats() - ep_downloaded = stats['episodes']['downloaded'] - ep_snatched = stats['episodes']['snatched'] - ep_total = stats['episodes']['total'] - ep_percentage = '' if ep_total == 0 else '(%s%%)' % re.sub(r'(\d+)(\.\d)\d+', r'\1\2', str((float(ep_downloaded)/float(ep_total))*100)) - %> -
- -
-% endif - - -
- - - -
- -
- - - -
- -
- - - -
diff --git a/themes/light/templates/vue-components/app-footer.mako b/themes/light/templates/vue-components/app-footer.mako new file mode 100644 index 0000000000..f4d2edbcc6 --- /dev/null +++ b/themes/light/templates/vue-components/app-footer.mako @@ -0,0 +1,128 @@ + +<%! + import json + from time import time + + from medusa.app import backlog_search_scheduler, daily_search_scheduler + from medusa.helper.common import pretty_file_size + from medusa.show.show import Show + + mem_usage = None + try: + from psutil import Process + from os import getpid + mem_usage = 'psutil' + except ImportError: + try: + import resource # resource module is unix only + mem_usage = 'resource' + except ImportError: + pass +%> +