mirror of
https://github.com/inventree/InvenTree.git
synced 2026-06-13 12:00:51 +00:00
Part page loading improvements (#3185)
* Lazy load the pricing bom table when the "pricing" tab is selected * Update django-debug-toolbar configuration * Major refactoring for the 'can_build' function - Use a single annotated query to the db, rather than a for loop (which is what a caveman would use) - Query performance is greatly improved - Also refactors existing variant-part-stock subquery code, to make it re-usable * Use minified JS and CSS where possible * Render a 'preview' version of each part image - Saves load time when the image is quite large - Adds a data migration to render out the new variation * Adds 'preview' version of company images * Defer loading of javascript files Note: some cannot be deferred - jquery in particular * Crucial bugfix for user roles context - Previously was *not* being calculated correctly - A non-superuser role would most likely display pages incorrectly * Prevent loading of "about" on every page - Load dynamically when requested - Takes ~400ms! - Cuts out a lot of fat * Match displayed image size to preview image size * Utilize caching framework for accessing user "role" information - Reduces number of DB queries required by rendering framework * Remove redundant query elements * Remove 'stock' field from PartBrief serializer - A calculated field on a serializer is a *bad idea* when that calculation requires a DB hit * Query improvements for StockItem serializer - Remove calculated fields - Fix annotations * Bug fixes * Remove JS load test - Loading of JS files is now deferred, so the unit test does not work as it used to * Fix broken template for "maintenance" page * Remove thumbnail generation migrations - Already performed manually as part of ''invoke migrate" - Running as a migration causes unit test problems - Not sensible to run this as a data-migration anyway * tweak for build table
This commit is contained in:
@@ -6,7 +6,7 @@ import InvenTree.status
|
|||||||
from InvenTree.status_codes import (BuildStatus, PurchaseOrderStatus,
|
from InvenTree.status_codes import (BuildStatus, PurchaseOrderStatus,
|
||||||
SalesOrderStatus, StockHistoryCode,
|
SalesOrderStatus, StockHistoryCode,
|
||||||
StockStatus)
|
StockStatus)
|
||||||
from users.models import RuleSet
|
from users.models import RuleSet, check_user_role
|
||||||
|
|
||||||
|
|
||||||
def health_status(request):
|
def health_status(request):
|
||||||
@@ -83,31 +83,13 @@ def user_roles(request):
|
|||||||
roles = {
|
roles = {
|
||||||
}
|
}
|
||||||
|
|
||||||
if user.is_superuser:
|
for role in RuleSet.RULESET_MODELS.keys():
|
||||||
for ruleset in RuleSet.RULESET_MODELS.keys(): # pragma: no cover
|
|
||||||
roles[ruleset] = {
|
|
||||||
'view': True,
|
|
||||||
'add': True,
|
|
||||||
'change': True,
|
|
||||||
'delete': True,
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
for group in user.groups.all():
|
|
||||||
for rule in group.rule_sets.all():
|
|
||||||
|
|
||||||
# Ensure the role name is in the dict
|
permissions = {}
|
||||||
if rule.name not in roles:
|
|
||||||
roles[rule.name] = {
|
|
||||||
'view': user.is_superuser,
|
|
||||||
'add': user.is_superuser,
|
|
||||||
'change': user.is_superuser,
|
|
||||||
'delete': user.is_superuser
|
|
||||||
}
|
|
||||||
|
|
||||||
# Roles are additive across groups
|
for perm in ['view', 'add', 'change', 'delete']:
|
||||||
roles[rule.name]['view'] |= rule.can_view
|
permissions[perm] = user.is_superuser or check_user_role(user, role, perm)
|
||||||
roles[rule.name]['add'] |= rule.can_add
|
|
||||||
roles[rule.name]['change'] |= rule.can_change
|
roles[role] = permissions
|
||||||
roles[rule.name]['delete'] |= rule.can_delete
|
|
||||||
|
|
||||||
return {'roles': roles}
|
return {'roles': roles}
|
||||||
|
|||||||
@@ -309,6 +309,11 @@ if DEBUG_TOOLBAR_ENABLED: # pragma: no cover
|
|||||||
INSTALLED_APPS.append('debug_toolbar')
|
INSTALLED_APPS.append('debug_toolbar')
|
||||||
MIDDLEWARE.append('debug_toolbar.middleware.DebugToolbarMiddleware')
|
MIDDLEWARE.append('debug_toolbar.middleware.DebugToolbarMiddleware')
|
||||||
|
|
||||||
|
DEBUG_TOOLBAR_CONFIG = {
|
||||||
|
'RESULTS_CACHE_SIZE': 100,
|
||||||
|
'OBSERVE_REQUEST_CALLBACK': lambda x: False,
|
||||||
|
}
|
||||||
|
|
||||||
# Internal IP addresses allowed to see the debug toolbar
|
# Internal IP addresses allowed to see the debug toolbar
|
||||||
INTERNAL_IPS = [
|
INTERNAL_IPS = [
|
||||||
'127.0.0.1',
|
'127.0.0.1',
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -470,8 +470,8 @@ main {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.part-thumb {
|
.part-thumb {
|
||||||
width: 200px;
|
width: 256px;
|
||||||
height: 200px;
|
height: 256px;
|
||||||
margin: 2px;
|
margin: 2px;
|
||||||
padding: 3px;
|
padding: 3px;
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
|
|||||||
@@ -222,6 +222,29 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
var l10 = {
|
var l10 = {
|
||||||
|
code: 'bn',
|
||||||
|
week: {
|
||||||
|
dow: 0, // Sunday is the first day of the week.
|
||||||
|
doy: 6, // The week that contains Jan 1st is the first week of the year.
|
||||||
|
},
|
||||||
|
buttonText: {
|
||||||
|
prev: 'পেছনে',
|
||||||
|
next: 'সামনে',
|
||||||
|
today: 'আজ',
|
||||||
|
month: 'মাস',
|
||||||
|
week: 'সপ্তাহ',
|
||||||
|
day: 'দিন',
|
||||||
|
list: 'তালিকা',
|
||||||
|
},
|
||||||
|
weekText: 'সপ্তাহ',
|
||||||
|
allDayText: 'সারাদিন',
|
||||||
|
moreLinkText: function(n) {
|
||||||
|
return '+অন্যান্য ' + n
|
||||||
|
},
|
||||||
|
noEventsText: 'কোনো ইভেন্ট নেই',
|
||||||
|
};
|
||||||
|
|
||||||
|
var l11 = {
|
||||||
code: 'bs',
|
code: 'bs',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
@@ -244,7 +267,7 @@
|
|||||||
noEventsText: 'Nema događaja za prikazivanje',
|
noEventsText: 'Nema događaja za prikazivanje',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l11 = {
|
var l12 = {
|
||||||
code: 'ca',
|
code: 'ca',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
@@ -265,7 +288,7 @@
|
|||||||
noEventsText: 'No hi ha esdeveniments per mostrar',
|
noEventsText: 'No hi ha esdeveniments per mostrar',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l12 = {
|
var l13 = {
|
||||||
code: 'cs',
|
code: 'cs',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
@@ -288,7 +311,7 @@
|
|||||||
noEventsText: 'Žádné akce k zobrazení',
|
noEventsText: 'Žádné akce k zobrazení',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l13 = {
|
var l14 = {
|
||||||
code: 'cy',
|
code: 'cy',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
@@ -310,7 +333,7 @@
|
|||||||
noEventsText: 'Dim digwyddiadau',
|
noEventsText: 'Dim digwyddiadau',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l14 = {
|
var l15 = {
|
||||||
code: 'da',
|
code: 'da',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
@@ -331,7 +354,12 @@
|
|||||||
noEventsText: 'Ingen arrangementer at vise',
|
noEventsText: 'Ingen arrangementer at vise',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l15 = {
|
function affix$1(buttonText) {
|
||||||
|
return (buttonText === 'Tag' || buttonText === 'Monat') ? 'r' :
|
||||||
|
buttonText === 'Jahr' ? 's' : ''
|
||||||
|
}
|
||||||
|
|
||||||
|
var l16 = {
|
||||||
code: 'de-at',
|
code: 'de-at',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
@@ -348,14 +376,49 @@
|
|||||||
list: 'Terminübersicht',
|
list: 'Terminübersicht',
|
||||||
},
|
},
|
||||||
weekText: 'KW',
|
weekText: 'KW',
|
||||||
|
weekTextLong: 'Woche',
|
||||||
allDayText: 'Ganztägig',
|
allDayText: 'Ganztägig',
|
||||||
moreLinkText: function(n) {
|
moreLinkText: function(n) {
|
||||||
return '+ weitere ' + n
|
return '+ weitere ' + n
|
||||||
},
|
},
|
||||||
noEventsText: 'Keine Ereignisse anzuzeigen',
|
noEventsText: 'Keine Ereignisse anzuzeigen',
|
||||||
|
buttonHints: {
|
||||||
|
prev(buttonText) {
|
||||||
|
return `Vorherige${affix$1(buttonText)} ${buttonText}`
|
||||||
|
},
|
||||||
|
next(buttonText) {
|
||||||
|
return `Nächste${affix$1(buttonText)} ${buttonText}`
|
||||||
|
},
|
||||||
|
today(buttonText) {
|
||||||
|
// → Heute, Diese Woche, Dieser Monat, Dieses Jahr
|
||||||
|
if (buttonText === 'Tag') {
|
||||||
|
return 'Heute'
|
||||||
|
}
|
||||||
|
return `Diese${affix$1(buttonText)} ${buttonText}`
|
||||||
|
},
|
||||||
|
},
|
||||||
|
viewHint(buttonText) {
|
||||||
|
// → Tagesansicht, Wochenansicht, Monatsansicht, Jahresansicht
|
||||||
|
const glue = buttonText === 'Woche' ? 'n' : buttonText === 'Monat' ? 's' : 'es';
|
||||||
|
return buttonText + glue + 'ansicht'
|
||||||
|
},
|
||||||
|
navLinkHint: 'Gehe zu $0',
|
||||||
|
moreLinkHint(eventCnt) {
|
||||||
|
return 'Zeige ' + (eventCnt === 1 ?
|
||||||
|
'ein weiteres Ereignis' :
|
||||||
|
eventCnt + ' weitere Ereignisse')
|
||||||
|
},
|
||||||
|
closeHint: 'Schließen',
|
||||||
|
timeHint: 'Uhrzeit',
|
||||||
|
eventHint: 'Ereignis',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l16 = {
|
function affix(buttonText) {
|
||||||
|
return (buttonText === 'Tag' || buttonText === 'Monat') ? 'r' :
|
||||||
|
buttonText === 'Jahr' ? 's' : ''
|
||||||
|
}
|
||||||
|
|
||||||
|
var l17 = {
|
||||||
code: 'de',
|
code: 'de',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
@@ -372,14 +435,44 @@
|
|||||||
list: 'Terminübersicht',
|
list: 'Terminübersicht',
|
||||||
},
|
},
|
||||||
weekText: 'KW',
|
weekText: 'KW',
|
||||||
|
weekTextLong: 'Woche',
|
||||||
allDayText: 'Ganztägig',
|
allDayText: 'Ganztägig',
|
||||||
moreLinkText: function(n) {
|
moreLinkText: function(n) {
|
||||||
return '+ weitere ' + n
|
return '+ weitere ' + n
|
||||||
},
|
},
|
||||||
noEventsText: 'Keine Ereignisse anzuzeigen',
|
noEventsText: 'Keine Ereignisse anzuzeigen',
|
||||||
|
buttonHints: {
|
||||||
|
prev(buttonText) {
|
||||||
|
return `Vorherige${affix(buttonText)} ${buttonText}`
|
||||||
|
},
|
||||||
|
next(buttonText) {
|
||||||
|
return `Nächste${affix(buttonText)} ${buttonText}`
|
||||||
|
},
|
||||||
|
today(buttonText) {
|
||||||
|
// → Heute, Diese Woche, Dieser Monat, Dieses Jahr
|
||||||
|
if (buttonText === 'Tag') {
|
||||||
|
return 'Heute'
|
||||||
|
}
|
||||||
|
return `Diese${affix(buttonText)} ${buttonText}`
|
||||||
|
},
|
||||||
|
},
|
||||||
|
viewHint(buttonText) {
|
||||||
|
// → Tagesansicht, Wochenansicht, Monatsansicht, Jahresansicht
|
||||||
|
const glue = buttonText === 'Woche' ? 'n' : buttonText === 'Monat' ? 's' : 'es';
|
||||||
|
return buttonText + glue + 'ansicht'
|
||||||
|
},
|
||||||
|
navLinkHint: 'Gehe zu $0',
|
||||||
|
moreLinkHint(eventCnt) {
|
||||||
|
return 'Zeige ' + (eventCnt === 1 ?
|
||||||
|
'ein weiteres Ereignis' :
|
||||||
|
eventCnt + ' weitere Ereignisse')
|
||||||
|
},
|
||||||
|
closeHint: 'Schließen',
|
||||||
|
timeHint: 'Uhrzeit',
|
||||||
|
eventHint: 'Ereignis',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l17 = {
|
var l18 = {
|
||||||
code: 'el',
|
code: 'el',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
@@ -400,31 +493,61 @@
|
|||||||
noEventsText: 'Δεν υπάρχουν γεγονότα προς εμφάνιση',
|
noEventsText: 'Δεν υπάρχουν γεγονότα προς εμφάνιση',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l18 = {
|
var l19 = {
|
||||||
code: 'en-au',
|
code: 'en-au',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
doy: 4, // The week that contains Jan 4th is the first week of the year.
|
doy: 4, // The week that contains Jan 4th is the first week of the year.
|
||||||
},
|
},
|
||||||
|
buttonHints: {
|
||||||
|
prev: 'Previous $0',
|
||||||
|
next: 'Next $0',
|
||||||
|
today: 'This $0',
|
||||||
|
},
|
||||||
|
viewHint: '$0 view',
|
||||||
|
navLinkHint: 'Go to $0',
|
||||||
|
moreLinkHint(eventCnt) {
|
||||||
|
return `Show ${eventCnt} more event${eventCnt === 1 ? '' : 's'}`
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
var l19 = {
|
var l20 = {
|
||||||
code: 'en-gb',
|
code: 'en-gb',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
doy: 4, // The week that contains Jan 4th is the first week of the year.
|
doy: 4, // The week that contains Jan 4th is the first week of the year.
|
||||||
},
|
},
|
||||||
|
buttonHints: {
|
||||||
|
prev: 'Previous $0',
|
||||||
|
next: 'Next $0',
|
||||||
|
today: 'This $0',
|
||||||
|
},
|
||||||
|
viewHint: '$0 view',
|
||||||
|
navLinkHint: 'Go to $0',
|
||||||
|
moreLinkHint(eventCnt) {
|
||||||
|
return `Show ${eventCnt} more event${eventCnt === 1 ? '' : 's'}`
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
var l20 = {
|
var l21 = {
|
||||||
code: 'en-nz',
|
code: 'en-nz',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
doy: 4, // The week that contains Jan 4th is the first week of the year.
|
doy: 4, // The week that contains Jan 4th is the first week of the year.
|
||||||
},
|
},
|
||||||
|
buttonHints: {
|
||||||
|
prev: 'Previous $0',
|
||||||
|
next: 'Next $0',
|
||||||
|
today: 'This $0',
|
||||||
|
},
|
||||||
|
viewHint: '$0 view',
|
||||||
|
navLinkHint: 'Go to $0',
|
||||||
|
moreLinkHint(eventCnt) {
|
||||||
|
return `Show ${eventCnt} more event${eventCnt === 1 ? '' : 's'}`
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
var l21 = {
|
var l22 = {
|
||||||
code: 'eo',
|
code: 'eo',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
@@ -445,7 +568,7 @@
|
|||||||
noEventsText: 'Neniuj eventoj por montri',
|
noEventsText: 'Neniuj eventoj por montri',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l22 = {
|
var l23 = {
|
||||||
code: 'es',
|
code: 'es',
|
||||||
week: {
|
week: {
|
||||||
dow: 0, // Sunday is the first day of the week.
|
dow: 0, // Sunday is the first day of the week.
|
||||||
@@ -466,7 +589,7 @@
|
|||||||
noEventsText: 'No hay eventos para mostrar',
|
noEventsText: 'No hay eventos para mostrar',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l23 = {
|
var l24 = {
|
||||||
code: 'es',
|
code: 'es',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
@@ -481,13 +604,32 @@
|
|||||||
day: 'Día',
|
day: 'Día',
|
||||||
list: 'Agenda',
|
list: 'Agenda',
|
||||||
},
|
},
|
||||||
|
buttonHints: {
|
||||||
|
prev: '$0 antes',
|
||||||
|
next: '$0 siguiente',
|
||||||
|
today(buttonText) {
|
||||||
|
return (buttonText === 'Día') ? 'Hoy' :
|
||||||
|
((buttonText === 'Semana') ? 'Esta' : 'Este') + ' ' + buttonText.toLocaleLowerCase()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
viewHint(buttonText) {
|
||||||
|
return 'Vista ' + (buttonText === 'Semana' ? 'de la' : 'del') + ' ' + buttonText.toLocaleLowerCase()
|
||||||
|
},
|
||||||
weekText: 'Sm',
|
weekText: 'Sm',
|
||||||
|
weekTextLong: 'Semana',
|
||||||
allDayText: 'Todo el día',
|
allDayText: 'Todo el día',
|
||||||
moreLinkText: 'más',
|
moreLinkText: 'más',
|
||||||
|
moreLinkHint(eventCnt) {
|
||||||
|
return `Mostrar ${eventCnt} eventos más`
|
||||||
|
},
|
||||||
noEventsText: 'No hay eventos para mostrar',
|
noEventsText: 'No hay eventos para mostrar',
|
||||||
|
navLinkHint: 'Ir al $0',
|
||||||
|
closeHint: 'Cerrar',
|
||||||
|
timeHint: 'La hora',
|
||||||
|
eventHint: 'Evento',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l24 = {
|
var l25 = {
|
||||||
code: 'et',
|
code: 'et',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
@@ -510,7 +652,7 @@
|
|||||||
noEventsText: 'Kuvamiseks puuduvad sündmused',
|
noEventsText: 'Kuvamiseks puuduvad sündmused',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l25 = {
|
var l26 = {
|
||||||
code: 'eu',
|
code: 'eu',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
@@ -531,7 +673,7 @@
|
|||||||
noEventsText: 'Ez dago ekitaldirik erakusteko',
|
noEventsText: 'Ez dago ekitaldirik erakusteko',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l26 = {
|
var l27 = {
|
||||||
code: 'fa',
|
code: 'fa',
|
||||||
week: {
|
week: {
|
||||||
dow: 6, // Saturday is the first day of the week.
|
dow: 6, // Saturday is the first day of the week.
|
||||||
@@ -555,7 +697,7 @@
|
|||||||
noEventsText: 'هیچ رویدادی به نمایش',
|
noEventsText: 'هیچ رویدادی به نمایش',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l27 = {
|
var l28 = {
|
||||||
code: 'fi',
|
code: 'fi',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
@@ -576,7 +718,7 @@
|
|||||||
noEventsText: 'Ei näytettäviä tapahtumia',
|
noEventsText: 'Ei näytettäviä tapahtumia',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l28 = {
|
var l29 = {
|
||||||
code: 'fr',
|
code: 'fr',
|
||||||
buttonText: {
|
buttonText: {
|
||||||
prev: 'Précédent',
|
prev: 'Précédent',
|
||||||
@@ -594,7 +736,7 @@
|
|||||||
noEventsText: 'Aucun événement à afficher',
|
noEventsText: 'Aucun événement à afficher',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l29 = {
|
var l30 = {
|
||||||
code: 'fr-ch',
|
code: 'fr-ch',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
@@ -616,7 +758,7 @@
|
|||||||
noEventsText: 'Aucun événement à afficher',
|
noEventsText: 'Aucun événement à afficher',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l30 = {
|
var l31 = {
|
||||||
code: 'fr',
|
code: 'fr',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
@@ -638,7 +780,7 @@
|
|||||||
noEventsText: 'Aucun événement à afficher',
|
noEventsText: 'Aucun événement à afficher',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l31 = {
|
var l32 = {
|
||||||
code: 'gl',
|
code: 'gl',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
@@ -659,7 +801,7 @@
|
|||||||
noEventsText: 'Non hai eventos para amosar',
|
noEventsText: 'Non hai eventos para amosar',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l32 = {
|
var l33 = {
|
||||||
code: 'he',
|
code: 'he',
|
||||||
direction: 'rtl',
|
direction: 'rtl',
|
||||||
buttonText: {
|
buttonText: {
|
||||||
@@ -677,7 +819,7 @@
|
|||||||
weekText: 'שבוע',
|
weekText: 'שבוע',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l33 = {
|
var l34 = {
|
||||||
code: 'hi',
|
code: 'hi',
|
||||||
week: {
|
week: {
|
||||||
dow: 0, // Sunday is the first day of the week.
|
dow: 0, // Sunday is the first day of the week.
|
||||||
@@ -700,7 +842,7 @@
|
|||||||
noEventsText: 'कोई घटनाओं को प्रदर्शित करने के लिए',
|
noEventsText: 'कोई घटनाओं को प्रदर्शित करने के लिए',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l34 = {
|
var l35 = {
|
||||||
code: 'hr',
|
code: 'hr',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
@@ -723,7 +865,7 @@
|
|||||||
noEventsText: 'Nema događaja za prikaz',
|
noEventsText: 'Nema događaja za prikaz',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l35 = {
|
var l36 = {
|
||||||
code: 'hu',
|
code: 'hu',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
@@ -736,7 +878,7 @@
|
|||||||
month: 'Hónap',
|
month: 'Hónap',
|
||||||
week: 'Hét',
|
week: 'Hét',
|
||||||
day: 'Nap',
|
day: 'Nap',
|
||||||
list: 'Napló',
|
list: 'Lista',
|
||||||
},
|
},
|
||||||
weekText: 'Hét',
|
weekText: 'Hét',
|
||||||
allDayText: 'Egész nap',
|
allDayText: 'Egész nap',
|
||||||
@@ -744,7 +886,7 @@
|
|||||||
noEventsText: 'Nincs megjeleníthető esemény',
|
noEventsText: 'Nincs megjeleníthető esemény',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l36 = {
|
var l37 = {
|
||||||
code: 'hy-am',
|
code: 'hy-am',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
@@ -767,7 +909,7 @@
|
|||||||
noEventsText: 'Բացակայում է իրադարձությունը ցուցադրելու',
|
noEventsText: 'Բացակայում է իրադարձությունը ցուցադրելու',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l37 = {
|
var l38 = {
|
||||||
code: 'id',
|
code: 'id',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
@@ -788,7 +930,7 @@
|
|||||||
noEventsText: 'Tidak ada acara untuk ditampilkan',
|
noEventsText: 'Tidak ada acara untuk ditampilkan',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l38 = {
|
var l39 = {
|
||||||
code: 'is',
|
code: 'is',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
@@ -809,7 +951,7 @@
|
|||||||
noEventsText: 'Engir viðburðir til að sýna',
|
noEventsText: 'Engir viðburðir til að sýna',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l39 = {
|
var l40 = {
|
||||||
code: 'it',
|
code: 'it',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
@@ -832,7 +974,7 @@
|
|||||||
noEventsText: 'Non ci sono eventi da visualizzare',
|
noEventsText: 'Non ci sono eventi da visualizzare',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l40 = {
|
var l41 = {
|
||||||
code: 'ja',
|
code: 'ja',
|
||||||
buttonText: {
|
buttonText: {
|
||||||
prev: '前',
|
prev: '前',
|
||||||
@@ -851,7 +993,7 @@
|
|||||||
noEventsText: '表示する予定はありません',
|
noEventsText: '表示する予定はありません',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l41 = {
|
var l42 = {
|
||||||
code: 'ka',
|
code: 'ka',
|
||||||
week: {
|
week: {
|
||||||
dow: 1,
|
dow: 1,
|
||||||
@@ -874,7 +1016,7 @@
|
|||||||
noEventsText: 'ღონისძიებები არ არის',
|
noEventsText: 'ღონისძიებები არ არის',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l42 = {
|
var l43 = {
|
||||||
code: 'kk',
|
code: 'kk',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
@@ -897,7 +1039,29 @@
|
|||||||
noEventsText: 'Көрсету үшін оқиғалар жоқ',
|
noEventsText: 'Көрсету үшін оқиғалар жоқ',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l43 = {
|
var l44 = {
|
||||||
|
code: 'km',
|
||||||
|
week: {
|
||||||
|
dow: 1, // Monday is the first day of the week.
|
||||||
|
doy: 4, // The week that contains Jan 4th is the first week of the year.
|
||||||
|
},
|
||||||
|
buttonText: {
|
||||||
|
prev: 'មុន',
|
||||||
|
next: 'បន្ទាប់',
|
||||||
|
today: 'ថ្ងៃនេះ',
|
||||||
|
year: 'ឆ្នាំ',
|
||||||
|
month: 'ខែ',
|
||||||
|
week: 'សប្តាហ៍',
|
||||||
|
day: 'ថ្ងៃ',
|
||||||
|
list: 'បញ្ជី',
|
||||||
|
},
|
||||||
|
weekText: 'សប្តាហ៍',
|
||||||
|
allDayText: 'ពេញមួយថ្ងៃ',
|
||||||
|
moreLinkText: 'ច្រើនទៀត',
|
||||||
|
noEventsText: 'គ្មានព្រឹត្តិការណ៍ត្រូវបង្ហាញ',
|
||||||
|
};
|
||||||
|
|
||||||
|
var l45 = {
|
||||||
code: 'ko',
|
code: 'ko',
|
||||||
buttonText: {
|
buttonText: {
|
||||||
prev: '이전달',
|
prev: '이전달',
|
||||||
@@ -914,7 +1078,29 @@
|
|||||||
noEventsText: '일정이 없습니다',
|
noEventsText: '일정이 없습니다',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l44 = {
|
var l46 = {
|
||||||
|
code: 'ku',
|
||||||
|
week: {
|
||||||
|
dow: 6, // Saturday is the first day of the week.
|
||||||
|
doy: 12, // The week that contains Jan 1st is the first week of the year.
|
||||||
|
},
|
||||||
|
direction: 'rtl',
|
||||||
|
buttonText: {
|
||||||
|
prev: 'پێشتر',
|
||||||
|
next: 'دواتر',
|
||||||
|
today: 'ئەمڕو',
|
||||||
|
month: 'مانگ',
|
||||||
|
week: 'هەفتە',
|
||||||
|
day: 'ڕۆژ',
|
||||||
|
list: 'بەرنامە',
|
||||||
|
},
|
||||||
|
weekText: 'هەفتە',
|
||||||
|
allDayText: 'هەموو ڕۆژەکە',
|
||||||
|
moreLinkText: 'زیاتر',
|
||||||
|
noEventsText: 'هیچ ڕووداوێك نیە',
|
||||||
|
};
|
||||||
|
|
||||||
|
var l47 = {
|
||||||
code: 'lb',
|
code: 'lb',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
@@ -935,7 +1121,7 @@
|
|||||||
noEventsText: 'Nee Evenementer ze affichéieren',
|
noEventsText: 'Nee Evenementer ze affichéieren',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l45 = {
|
var l48 = {
|
||||||
code: 'lt',
|
code: 'lt',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
@@ -956,7 +1142,7 @@
|
|||||||
noEventsText: 'Nėra įvykių rodyti',
|
noEventsText: 'Nėra įvykių rodyti',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l46 = {
|
var l49 = {
|
||||||
code: 'lv',
|
code: 'lv',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
@@ -979,7 +1165,7 @@
|
|||||||
noEventsText: 'Nav notikumu',
|
noEventsText: 'Nav notikumu',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l47 = {
|
var l50 = {
|
||||||
code: 'mk',
|
code: 'mk',
|
||||||
buttonText: {
|
buttonText: {
|
||||||
prev: 'претходно',
|
prev: 'претходно',
|
||||||
@@ -998,7 +1184,7 @@
|
|||||||
noEventsText: 'Нема настани за прикажување',
|
noEventsText: 'Нема настани за прикажување',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l48 = {
|
var l51 = {
|
||||||
code: 'ms',
|
code: 'ms',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
@@ -1021,7 +1207,7 @@
|
|||||||
noEventsText: 'Tiada peristiwa untuk dipaparkan',
|
noEventsText: 'Tiada peristiwa untuk dipaparkan',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l49 = {
|
var l52 = {
|
||||||
code: 'nb',
|
code: 'nb',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
@@ -1037,12 +1223,23 @@
|
|||||||
list: 'Agenda',
|
list: 'Agenda',
|
||||||
},
|
},
|
||||||
weekText: 'Uke',
|
weekText: 'Uke',
|
||||||
|
weekTextLong: 'Uke',
|
||||||
allDayText: 'Hele dagen',
|
allDayText: 'Hele dagen',
|
||||||
moreLinkText: 'til',
|
moreLinkText: 'til',
|
||||||
noEventsText: 'Ingen hendelser å vise',
|
noEventsText: 'Ingen hendelser å vise',
|
||||||
|
buttonHints: {
|
||||||
|
prev: 'Forrige $0',
|
||||||
|
next: 'Neste $0',
|
||||||
|
today: 'Nåværende $0',
|
||||||
|
},
|
||||||
|
viewHint: '$0 visning',
|
||||||
|
navLinkHint: 'Gå til $0',
|
||||||
|
moreLinkHint(eventCnt) {
|
||||||
|
return `Vis ${eventCnt} flere hendelse${eventCnt === 1 ? '' : 'r'}`
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
var l50 = {
|
var l53 = {
|
||||||
code: 'ne', // code for nepal
|
code: 'ne', // code for nepal
|
||||||
week: {
|
week: {
|
||||||
dow: 7, // Sunday is the first day of the week.
|
dow: 7, // Sunday is the first day of the week.
|
||||||
@@ -1063,7 +1260,7 @@
|
|||||||
noEventsText: 'देखाउनको लागि कुनै घटनाहरू छैनन्',
|
noEventsText: 'देखाउनको लागि कुनै घटनाहरू छैनन्',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l51 = {
|
var l54 = {
|
||||||
code: 'nl',
|
code: 'nl',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
@@ -1084,7 +1281,7 @@
|
|||||||
noEventsText: 'Geen evenementen om te laten zien',
|
noEventsText: 'Geen evenementen om te laten zien',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l52 = {
|
var l55 = {
|
||||||
code: 'nn',
|
code: 'nn',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
@@ -1105,7 +1302,7 @@
|
|||||||
noEventsText: 'Ingen hendelser å vise',
|
noEventsText: 'Ingen hendelser å vise',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l53 = {
|
var l56 = {
|
||||||
code: 'pl',
|
code: 'pl',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
@@ -1126,7 +1323,7 @@
|
|||||||
noEventsText: 'Brak wydarzeń do wyświetlenia',
|
noEventsText: 'Brak wydarzeń do wyświetlenia',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l54 = {
|
var l57 = {
|
||||||
code: 'pt-br',
|
code: 'pt-br',
|
||||||
buttonText: {
|
buttonText: {
|
||||||
prev: 'Anterior',
|
prev: 'Anterior',
|
||||||
@@ -1145,7 +1342,7 @@
|
|||||||
noEventsText: 'Não há eventos para mostrar',
|
noEventsText: 'Não há eventos para mostrar',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l55 = {
|
var l58 = {
|
||||||
code: 'pt',
|
code: 'pt',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
@@ -1166,7 +1363,7 @@
|
|||||||
noEventsText: 'Não há eventos para mostrar',
|
noEventsText: 'Não há eventos para mostrar',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l56 = {
|
var l59 = {
|
||||||
code: 'ro',
|
code: 'ro',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
@@ -1189,7 +1386,7 @@
|
|||||||
noEventsText: 'Nu există evenimente de afișat',
|
noEventsText: 'Nu există evenimente de afișat',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l57 = {
|
var l60 = {
|
||||||
code: 'ru',
|
code: 'ru',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
@@ -1212,7 +1409,28 @@
|
|||||||
noEventsText: 'Нет событий для отображения',
|
noEventsText: 'Нет событий для отображения',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l58 = {
|
var l61 = {
|
||||||
|
code: 'si-lk',
|
||||||
|
week: {
|
||||||
|
dow: 1, // Monday is the first day of the week.
|
||||||
|
doy: 4, // The week that contains Jan 4th is the first week of the year.
|
||||||
|
},
|
||||||
|
buttonText: {
|
||||||
|
prev: 'පෙර',
|
||||||
|
next: 'පසු',
|
||||||
|
today: 'අද',
|
||||||
|
month: 'මාසය',
|
||||||
|
week: 'සතිය',
|
||||||
|
day: 'දවස',
|
||||||
|
list: 'ලැයිස්තුව',
|
||||||
|
},
|
||||||
|
weekText: 'සති',
|
||||||
|
allDayText: 'සියලු',
|
||||||
|
moreLinkText: 'තවත්',
|
||||||
|
noEventsText: 'මුකුත් නැත',
|
||||||
|
};
|
||||||
|
|
||||||
|
var l62 = {
|
||||||
code: 'sk',
|
code: 'sk',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
@@ -1235,7 +1453,7 @@
|
|||||||
noEventsText: 'Žiadne akcie na zobrazenie',
|
noEventsText: 'Žiadne akcie na zobrazenie',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l59 = {
|
var l63 = {
|
||||||
code: 'sl',
|
code: 'sl',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
@@ -1256,7 +1474,24 @@
|
|||||||
noEventsText: 'Ni dogodkov za prikaz',
|
noEventsText: 'Ni dogodkov za prikaz',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l60 = {
|
var l64 = {
|
||||||
|
code: 'sm',
|
||||||
|
buttonText: {
|
||||||
|
prev: 'Talu ai',
|
||||||
|
next: 'Mulimuli atu',
|
||||||
|
today: 'Aso nei',
|
||||||
|
month: 'Masina',
|
||||||
|
week: 'Vaiaso',
|
||||||
|
day: 'Aso',
|
||||||
|
list: 'Faasologa',
|
||||||
|
},
|
||||||
|
weekText: 'Vaiaso',
|
||||||
|
allDayText: 'Aso atoa',
|
||||||
|
moreLinkText: 'sili atu',
|
||||||
|
noEventsText: 'Leai ni mea na tutupu',
|
||||||
|
};
|
||||||
|
|
||||||
|
var l65 = {
|
||||||
code: 'sq',
|
code: 'sq',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
@@ -1279,7 +1514,7 @@
|
|||||||
noEventsText: 'Nuk ka evente për të shfaqur',
|
noEventsText: 'Nuk ka evente për të shfaqur',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l61 = {
|
var l66 = {
|
||||||
code: 'sr-cyrl',
|
code: 'sr-cyrl',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
@@ -1302,7 +1537,7 @@
|
|||||||
noEventsText: 'Нема догађаја за приказ',
|
noEventsText: 'Нема догађаја за приказ',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l62 = {
|
var l67 = {
|
||||||
code: 'sr',
|
code: 'sr',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
@@ -1325,7 +1560,7 @@
|
|||||||
noEventsText: 'Nеma događaja za prikaz',
|
noEventsText: 'Nеma događaja za prikaz',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l63 = {
|
var l68 = {
|
||||||
code: 'sv',
|
code: 'sv',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
@@ -1340,13 +1575,56 @@
|
|||||||
day: 'Dag',
|
day: 'Dag',
|
||||||
list: 'Program',
|
list: 'Program',
|
||||||
},
|
},
|
||||||
|
buttonHints: {
|
||||||
|
prev(buttonText) {
|
||||||
|
return `Föregående ${buttonText.toLocaleLowerCase()}`
|
||||||
|
},
|
||||||
|
next(buttonText) {
|
||||||
|
return `Nästa ${buttonText.toLocaleLowerCase()}`
|
||||||
|
},
|
||||||
|
today(buttonText) {
|
||||||
|
return (buttonText === 'Program' ? 'Detta' : 'Denna') + ' ' + buttonText.toLocaleLowerCase()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
viewHint: '$0 vy',
|
||||||
|
navLinkHint: 'Gå till $0',
|
||||||
|
moreLinkHint(eventCnt) {
|
||||||
|
return `Visa ytterligare ${eventCnt} händelse${eventCnt === 1 ? '' : 'r'}`
|
||||||
|
},
|
||||||
weekText: 'v.',
|
weekText: 'v.',
|
||||||
|
weekTextLong: 'Vecka',
|
||||||
allDayText: 'Heldag',
|
allDayText: 'Heldag',
|
||||||
moreLinkText: 'till',
|
moreLinkText: 'till',
|
||||||
noEventsText: 'Inga händelser att visa',
|
noEventsText: 'Inga händelser att visa',
|
||||||
|
closeHint: 'Stäng',
|
||||||
|
timeHint: 'Klockan',
|
||||||
|
eventHint: 'Händelse',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l64 = {
|
var l69 = {
|
||||||
|
code: 'ta-in',
|
||||||
|
week: {
|
||||||
|
dow: 1, // Monday is the first day of the week.
|
||||||
|
doy: 4, // The week that contains Jan 4th is the first week of the year.
|
||||||
|
},
|
||||||
|
buttonText: {
|
||||||
|
prev: 'முந்தைய',
|
||||||
|
next: 'அடுத்தது',
|
||||||
|
today: 'இன்று',
|
||||||
|
month: 'மாதம்',
|
||||||
|
week: 'வாரம்',
|
||||||
|
day: 'நாள்',
|
||||||
|
list: 'தினசரி அட்டவணை',
|
||||||
|
},
|
||||||
|
weekText: 'வாரம்',
|
||||||
|
allDayText: 'நாள் முழுவதும்',
|
||||||
|
moreLinkText: function(n) {
|
||||||
|
return '+ மேலும் ' + n
|
||||||
|
},
|
||||||
|
noEventsText: 'காண்பிக்க நிகழ்வுகள் இல்லை',
|
||||||
|
};
|
||||||
|
|
||||||
|
var l70 = {
|
||||||
code: 'th',
|
code: 'th',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
@@ -1370,7 +1648,7 @@
|
|||||||
noEventsText: 'ไม่มีกิจกรรมที่จะแสดง',
|
noEventsText: 'ไม่มีกิจกรรมที่จะแสดง',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l65 = {
|
var l71 = {
|
||||||
code: 'tr',
|
code: 'tr',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
@@ -1391,7 +1669,7 @@
|
|||||||
noEventsText: 'Gösterilecek etkinlik yok',
|
noEventsText: 'Gösterilecek etkinlik yok',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l66 = {
|
var l72 = {
|
||||||
code: 'ug',
|
code: 'ug',
|
||||||
buttonText: {
|
buttonText: {
|
||||||
month: 'ئاي',
|
month: 'ئاي',
|
||||||
@@ -1402,7 +1680,7 @@
|
|||||||
allDayText: 'پۈتۈن كۈن',
|
allDayText: 'پۈتۈن كۈن',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l67 = {
|
var l73 = {
|
||||||
code: 'uk',
|
code: 'uk',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
@@ -1425,7 +1703,7 @@
|
|||||||
noEventsText: 'Немає подій для відображення',
|
noEventsText: 'Немає подій для відображення',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l68 = {
|
var l74 = {
|
||||||
code: 'uz',
|
code: 'uz',
|
||||||
buttonText: {
|
buttonText: {
|
||||||
month: 'Oy',
|
month: 'Oy',
|
||||||
@@ -1440,7 +1718,7 @@
|
|||||||
noEventsText: "Ko'rsatish uchun voqealar yo'q",
|
noEventsText: "Ko'rsatish uchun voqealar yo'q",
|
||||||
};
|
};
|
||||||
|
|
||||||
var l69 = {
|
var l75 = {
|
||||||
code: 'vi',
|
code: 'vi',
|
||||||
week: {
|
week: {
|
||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
@@ -1463,7 +1741,7 @@
|
|||||||
noEventsText: 'Không có sự kiện để hiển thị',
|
noEventsText: 'Không có sự kiện để hiển thị',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l70 = {
|
var l76 = {
|
||||||
code: 'zh-cn',
|
code: 'zh-cn',
|
||||||
week: {
|
week: {
|
||||||
// GB/T 7408-1994《数据元和交换格式·信息交换·日期和时间表示法》与ISO 8601:1988等效
|
// GB/T 7408-1994《数据元和交换格式·信息交换·日期和时间表示法》与ISO 8601:1988等效
|
||||||
@@ -1487,7 +1765,7 @@
|
|||||||
noEventsText: '没有事件显示',
|
noEventsText: '没有事件显示',
|
||||||
};
|
};
|
||||||
|
|
||||||
var l71 = {
|
var l77 = {
|
||||||
code: 'zh-tw',
|
code: 'zh-tw',
|
||||||
buttonText: {
|
buttonText: {
|
||||||
prev: '上月',
|
prev: '上月',
|
||||||
@@ -1507,7 +1785,7 @@
|
|||||||
/* eslint max-len: off */
|
/* eslint max-len: off */
|
||||||
|
|
||||||
var localesAll = [
|
var localesAll = [
|
||||||
l0, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, l16, l17, l18, l19, l20, l21, l22, l23, l24, l25, l26, l27, l28, l29, l30, l31, l32, l33, l34, l35, l36, l37, l38, l39, l40, l41, l42, l43, l44, l45, l46, l47, l48, l49, l50, l51, l52, l53, l54, l55, l56, l57, l58, l59, l60, l61, l62, l63, l64, l65, l66, l67, l68, l69, l70, l71,
|
l0, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, l16, l17, l18, l19, l20, l21, l22, l23, l24, l25, l26, l27, l28, l29, l30, l31, l32, l33, l34, l35, l36, l37, l38, l39, l40, l41, l42, l43, l44, l45, l46, l47, l48, l49, l50, l51, l52, l53, l54, l55, l56, l57, l58, l59, l60, l61, l62, l63, l64, l65, l66, l67, l68, l69, l70, l71, l72, l73, l74, l75, l76, l77,
|
||||||
];
|
];
|
||||||
|
|
||||||
return localesAll;
|
return localesAll;
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,29 @@
|
|||||||
|
FullCalendar.globalLocales.push(function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var bn = {
|
||||||
|
code: 'bn',
|
||||||
|
week: {
|
||||||
|
dow: 0, // Sunday is the first day of the week.
|
||||||
|
doy: 6, // The week that contains Jan 1st is the first week of the year.
|
||||||
|
},
|
||||||
|
buttonText: {
|
||||||
|
prev: 'পেছনে',
|
||||||
|
next: 'সামনে',
|
||||||
|
today: 'আজ',
|
||||||
|
month: 'মাস',
|
||||||
|
week: 'সপ্তাহ',
|
||||||
|
day: 'দিন',
|
||||||
|
list: 'তালিকা',
|
||||||
|
},
|
||||||
|
weekText: 'সপ্তাহ',
|
||||||
|
allDayText: 'সারাদিন',
|
||||||
|
moreLinkText: function(n) {
|
||||||
|
return '+অন্যান্য ' + n
|
||||||
|
},
|
||||||
|
noEventsText: 'কোনো ইভেন্ট নেই',
|
||||||
|
};
|
||||||
|
|
||||||
|
return bn;
|
||||||
|
|
||||||
|
}());
|
||||||
@@ -1,6 +1,11 @@
|
|||||||
FullCalendar.globalLocales.push(function () {
|
FullCalendar.globalLocales.push(function () {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
function affix(buttonText) {
|
||||||
|
return (buttonText === 'Tag' || buttonText === 'Monat') ? 'r' :
|
||||||
|
buttonText === 'Jahr' ? 's' : ''
|
||||||
|
}
|
||||||
|
|
||||||
var deAt = {
|
var deAt = {
|
||||||
code: 'de-at',
|
code: 'de-at',
|
||||||
week: {
|
week: {
|
||||||
@@ -18,11 +23,41 @@ FullCalendar.globalLocales.push(function () {
|
|||||||
list: 'Terminübersicht',
|
list: 'Terminübersicht',
|
||||||
},
|
},
|
||||||
weekText: 'KW',
|
weekText: 'KW',
|
||||||
|
weekTextLong: 'Woche',
|
||||||
allDayText: 'Ganztägig',
|
allDayText: 'Ganztägig',
|
||||||
moreLinkText: function(n) {
|
moreLinkText: function(n) {
|
||||||
return '+ weitere ' + n
|
return '+ weitere ' + n
|
||||||
},
|
},
|
||||||
noEventsText: 'Keine Ereignisse anzuzeigen',
|
noEventsText: 'Keine Ereignisse anzuzeigen',
|
||||||
|
buttonHints: {
|
||||||
|
prev(buttonText) {
|
||||||
|
return `Vorherige${affix(buttonText)} ${buttonText}`
|
||||||
|
},
|
||||||
|
next(buttonText) {
|
||||||
|
return `Nächste${affix(buttonText)} ${buttonText}`
|
||||||
|
},
|
||||||
|
today(buttonText) {
|
||||||
|
// → Heute, Diese Woche, Dieser Monat, Dieses Jahr
|
||||||
|
if (buttonText === 'Tag') {
|
||||||
|
return 'Heute'
|
||||||
|
}
|
||||||
|
return `Diese${affix(buttonText)} ${buttonText}`
|
||||||
|
},
|
||||||
|
},
|
||||||
|
viewHint(buttonText) {
|
||||||
|
// → Tagesansicht, Wochenansicht, Monatsansicht, Jahresansicht
|
||||||
|
const glue = buttonText === 'Woche' ? 'n' : buttonText === 'Monat' ? 's' : 'es';
|
||||||
|
return buttonText + glue + 'ansicht'
|
||||||
|
},
|
||||||
|
navLinkHint: 'Gehe zu $0',
|
||||||
|
moreLinkHint(eventCnt) {
|
||||||
|
return 'Zeige ' + (eventCnt === 1 ?
|
||||||
|
'ein weiteres Ereignis' :
|
||||||
|
eventCnt + ' weitere Ereignisse')
|
||||||
|
},
|
||||||
|
closeHint: 'Schließen',
|
||||||
|
timeHint: 'Uhrzeit',
|
||||||
|
eventHint: 'Ereignis',
|
||||||
};
|
};
|
||||||
|
|
||||||
return deAt;
|
return deAt;
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
FullCalendar.globalLocales.push(function () {
|
FullCalendar.globalLocales.push(function () {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
function affix(buttonText) {
|
||||||
|
return (buttonText === 'Tag' || buttonText === 'Monat') ? 'r' :
|
||||||
|
buttonText === 'Jahr' ? 's' : ''
|
||||||
|
}
|
||||||
|
|
||||||
var de = {
|
var de = {
|
||||||
code: 'de',
|
code: 'de',
|
||||||
week: {
|
week: {
|
||||||
@@ -18,11 +23,41 @@ FullCalendar.globalLocales.push(function () {
|
|||||||
list: 'Terminübersicht',
|
list: 'Terminübersicht',
|
||||||
},
|
},
|
||||||
weekText: 'KW',
|
weekText: 'KW',
|
||||||
|
weekTextLong: 'Woche',
|
||||||
allDayText: 'Ganztägig',
|
allDayText: 'Ganztägig',
|
||||||
moreLinkText: function(n) {
|
moreLinkText: function(n) {
|
||||||
return '+ weitere ' + n
|
return '+ weitere ' + n
|
||||||
},
|
},
|
||||||
noEventsText: 'Keine Ereignisse anzuzeigen',
|
noEventsText: 'Keine Ereignisse anzuzeigen',
|
||||||
|
buttonHints: {
|
||||||
|
prev(buttonText) {
|
||||||
|
return `Vorherige${affix(buttonText)} ${buttonText}`
|
||||||
|
},
|
||||||
|
next(buttonText) {
|
||||||
|
return `Nächste${affix(buttonText)} ${buttonText}`
|
||||||
|
},
|
||||||
|
today(buttonText) {
|
||||||
|
// → Heute, Diese Woche, Dieser Monat, Dieses Jahr
|
||||||
|
if (buttonText === 'Tag') {
|
||||||
|
return 'Heute'
|
||||||
|
}
|
||||||
|
return `Diese${affix(buttonText)} ${buttonText}`
|
||||||
|
},
|
||||||
|
},
|
||||||
|
viewHint(buttonText) {
|
||||||
|
// → Tagesansicht, Wochenansicht, Monatsansicht, Jahresansicht
|
||||||
|
const glue = buttonText === 'Woche' ? 'n' : buttonText === 'Monat' ? 's' : 'es';
|
||||||
|
return buttonText + glue + 'ansicht'
|
||||||
|
},
|
||||||
|
navLinkHint: 'Gehe zu $0',
|
||||||
|
moreLinkHint(eventCnt) {
|
||||||
|
return 'Zeige ' + (eventCnt === 1 ?
|
||||||
|
'ein weiteres Ereignis' :
|
||||||
|
eventCnt + ' weitere Ereignisse')
|
||||||
|
},
|
||||||
|
closeHint: 'Schließen',
|
||||||
|
timeHint: 'Uhrzeit',
|
||||||
|
eventHint: 'Ereignis',
|
||||||
};
|
};
|
||||||
|
|
||||||
return de;
|
return de;
|
||||||
|
|||||||
@@ -7,6 +7,16 @@ FullCalendar.globalLocales.push(function () {
|
|||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
doy: 4, // The week that contains Jan 4th is the first week of the year.
|
doy: 4, // The week that contains Jan 4th is the first week of the year.
|
||||||
},
|
},
|
||||||
|
buttonHints: {
|
||||||
|
prev: 'Previous $0',
|
||||||
|
next: 'Next $0',
|
||||||
|
today: 'This $0',
|
||||||
|
},
|
||||||
|
viewHint: '$0 view',
|
||||||
|
navLinkHint: 'Go to $0',
|
||||||
|
moreLinkHint(eventCnt) {
|
||||||
|
return `Show ${eventCnt} more event${eventCnt === 1 ? '' : 's'}`
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
return enAu;
|
return enAu;
|
||||||
|
|||||||
@@ -7,6 +7,16 @@ FullCalendar.globalLocales.push(function () {
|
|||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
doy: 4, // The week that contains Jan 4th is the first week of the year.
|
doy: 4, // The week that contains Jan 4th is the first week of the year.
|
||||||
},
|
},
|
||||||
|
buttonHints: {
|
||||||
|
prev: 'Previous $0',
|
||||||
|
next: 'Next $0',
|
||||||
|
today: 'This $0',
|
||||||
|
},
|
||||||
|
viewHint: '$0 view',
|
||||||
|
navLinkHint: 'Go to $0',
|
||||||
|
moreLinkHint(eventCnt) {
|
||||||
|
return `Show ${eventCnt} more event${eventCnt === 1 ? '' : 's'}`
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
return enGb;
|
return enGb;
|
||||||
|
|||||||
@@ -7,6 +7,16 @@ FullCalendar.globalLocales.push(function () {
|
|||||||
dow: 1, // Monday is the first day of the week.
|
dow: 1, // Monday is the first day of the week.
|
||||||
doy: 4, // The week that contains Jan 4th is the first week of the year.
|
doy: 4, // The week that contains Jan 4th is the first week of the year.
|
||||||
},
|
},
|
||||||
|
buttonHints: {
|
||||||
|
prev: 'Previous $0',
|
||||||
|
next: 'Next $0',
|
||||||
|
today: 'This $0',
|
||||||
|
},
|
||||||
|
viewHint: '$0 view',
|
||||||
|
navLinkHint: 'Go to $0',
|
||||||
|
moreLinkHint(eventCnt) {
|
||||||
|
return `Show ${eventCnt} more event${eventCnt === 1 ? '' : 's'}`
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
return enNz;
|
return enNz;
|
||||||
|
|||||||
@@ -16,10 +16,29 @@ FullCalendar.globalLocales.push(function () {
|
|||||||
day: 'Día',
|
day: 'Día',
|
||||||
list: 'Agenda',
|
list: 'Agenda',
|
||||||
},
|
},
|
||||||
|
buttonHints: {
|
||||||
|
prev: '$0 antes',
|
||||||
|
next: '$0 siguiente',
|
||||||
|
today(buttonText) {
|
||||||
|
return (buttonText === 'Día') ? 'Hoy' :
|
||||||
|
((buttonText === 'Semana') ? 'Esta' : 'Este') + ' ' + buttonText.toLocaleLowerCase()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
viewHint(buttonText) {
|
||||||
|
return 'Vista ' + (buttonText === 'Semana' ? 'de la' : 'del') + ' ' + buttonText.toLocaleLowerCase()
|
||||||
|
},
|
||||||
weekText: 'Sm',
|
weekText: 'Sm',
|
||||||
|
weekTextLong: 'Semana',
|
||||||
allDayText: 'Todo el día',
|
allDayText: 'Todo el día',
|
||||||
moreLinkText: 'más',
|
moreLinkText: 'más',
|
||||||
|
moreLinkHint(eventCnt) {
|
||||||
|
return `Mostrar ${eventCnt} eventos más`
|
||||||
|
},
|
||||||
noEventsText: 'No hay eventos para mostrar',
|
noEventsText: 'No hay eventos para mostrar',
|
||||||
|
navLinkHint: 'Ir al $0',
|
||||||
|
closeHint: 'Cerrar',
|
||||||
|
timeHint: 'La hora',
|
||||||
|
eventHint: 'Evento',
|
||||||
};
|
};
|
||||||
|
|
||||||
return es;
|
return es;
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ FullCalendar.globalLocales.push(function () {
|
|||||||
month: 'Hónap',
|
month: 'Hónap',
|
||||||
week: 'Hét',
|
week: 'Hét',
|
||||||
day: 'Nap',
|
day: 'Nap',
|
||||||
list: 'Napló',
|
list: 'Lista',
|
||||||
},
|
},
|
||||||
weekText: 'Hét',
|
weekText: 'Hét',
|
||||||
allDayText: 'Egész nap',
|
allDayText: 'Egész nap',
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
FullCalendar.globalLocales.push(function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var km = {
|
||||||
|
code: 'km',
|
||||||
|
week: {
|
||||||
|
dow: 1, // Monday is the first day of the week.
|
||||||
|
doy: 4, // The week that contains Jan 4th is the first week of the year.
|
||||||
|
},
|
||||||
|
buttonText: {
|
||||||
|
prev: 'មុន',
|
||||||
|
next: 'បន្ទាប់',
|
||||||
|
today: 'ថ្ងៃនេះ',
|
||||||
|
year: 'ឆ្នាំ',
|
||||||
|
month: 'ខែ',
|
||||||
|
week: 'សប្តាហ៍',
|
||||||
|
day: 'ថ្ងៃ',
|
||||||
|
list: 'បញ្ជី',
|
||||||
|
},
|
||||||
|
weekText: 'សប្តាហ៍',
|
||||||
|
allDayText: 'ពេញមួយថ្ងៃ',
|
||||||
|
moreLinkText: 'ច្រើនទៀត',
|
||||||
|
noEventsText: 'គ្មានព្រឹត្តិការណ៍ត្រូវបង្ហាញ',
|
||||||
|
};
|
||||||
|
|
||||||
|
return km;
|
||||||
|
|
||||||
|
}());
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
FullCalendar.globalLocales.push(function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var ku = {
|
||||||
|
code: 'ku',
|
||||||
|
week: {
|
||||||
|
dow: 6, // Saturday is the first day of the week.
|
||||||
|
doy: 12, // The week that contains Jan 1st is the first week of the year.
|
||||||
|
},
|
||||||
|
direction: 'rtl',
|
||||||
|
buttonText: {
|
||||||
|
prev: 'پێشتر',
|
||||||
|
next: 'دواتر',
|
||||||
|
today: 'ئەمڕو',
|
||||||
|
month: 'مانگ',
|
||||||
|
week: 'هەفتە',
|
||||||
|
day: 'ڕۆژ',
|
||||||
|
list: 'بەرنامە',
|
||||||
|
},
|
||||||
|
weekText: 'هەفتە',
|
||||||
|
allDayText: 'هەموو ڕۆژەکە',
|
||||||
|
moreLinkText: 'زیاتر',
|
||||||
|
noEventsText: 'هیچ ڕووداوێك نیە',
|
||||||
|
};
|
||||||
|
|
||||||
|
return ku;
|
||||||
|
|
||||||
|
}());
|
||||||
@@ -17,9 +17,20 @@ FullCalendar.globalLocales.push(function () {
|
|||||||
list: 'Agenda',
|
list: 'Agenda',
|
||||||
},
|
},
|
||||||
weekText: 'Uke',
|
weekText: 'Uke',
|
||||||
|
weekTextLong: 'Uke',
|
||||||
allDayText: 'Hele dagen',
|
allDayText: 'Hele dagen',
|
||||||
moreLinkText: 'til',
|
moreLinkText: 'til',
|
||||||
noEventsText: 'Ingen hendelser å vise',
|
noEventsText: 'Ingen hendelser å vise',
|
||||||
|
buttonHints: {
|
||||||
|
prev: 'Forrige $0',
|
||||||
|
next: 'Neste $0',
|
||||||
|
today: 'Nåværende $0',
|
||||||
|
},
|
||||||
|
viewHint: '$0 visning',
|
||||||
|
navLinkHint: 'Gå til $0',
|
||||||
|
moreLinkHint(eventCnt) {
|
||||||
|
return `Vis ${eventCnt} flere hendelse${eventCnt === 1 ? '' : 'r'}`
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
return nb;
|
return nb;
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
FullCalendar.globalLocales.push(function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var siLk = {
|
||||||
|
code: 'si-lk',
|
||||||
|
week: {
|
||||||
|
dow: 1, // Monday is the first day of the week.
|
||||||
|
doy: 4, // The week that contains Jan 4th is the first week of the year.
|
||||||
|
},
|
||||||
|
buttonText: {
|
||||||
|
prev: 'පෙර',
|
||||||
|
next: 'පසු',
|
||||||
|
today: 'අද',
|
||||||
|
month: 'මාසය',
|
||||||
|
week: 'සතිය',
|
||||||
|
day: 'දවස',
|
||||||
|
list: 'ලැයිස්තුව',
|
||||||
|
},
|
||||||
|
weekText: 'සති',
|
||||||
|
allDayText: 'සියලු',
|
||||||
|
moreLinkText: 'තවත්',
|
||||||
|
noEventsText: 'මුකුත් නැත',
|
||||||
|
};
|
||||||
|
|
||||||
|
return siLk;
|
||||||
|
|
||||||
|
}());
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
FullCalendar.globalLocales.push(function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var sm = {
|
||||||
|
code: 'sm',
|
||||||
|
buttonText: {
|
||||||
|
prev: 'Talu ai',
|
||||||
|
next: 'Mulimuli atu',
|
||||||
|
today: 'Aso nei',
|
||||||
|
month: 'Masina',
|
||||||
|
week: 'Vaiaso',
|
||||||
|
day: 'Aso',
|
||||||
|
list: 'Faasologa',
|
||||||
|
},
|
||||||
|
weekText: 'Vaiaso',
|
||||||
|
allDayText: 'Aso atoa',
|
||||||
|
moreLinkText: 'sili atu',
|
||||||
|
noEventsText: 'Leai ni mea na tutupu',
|
||||||
|
};
|
||||||
|
|
||||||
|
return sm;
|
||||||
|
|
||||||
|
}());
|
||||||
@@ -16,10 +16,30 @@ FullCalendar.globalLocales.push(function () {
|
|||||||
day: 'Dag',
|
day: 'Dag',
|
||||||
list: 'Program',
|
list: 'Program',
|
||||||
},
|
},
|
||||||
|
buttonHints: {
|
||||||
|
prev(buttonText) {
|
||||||
|
return `Föregående ${buttonText.toLocaleLowerCase()}`
|
||||||
|
},
|
||||||
|
next(buttonText) {
|
||||||
|
return `Nästa ${buttonText.toLocaleLowerCase()}`
|
||||||
|
},
|
||||||
|
today(buttonText) {
|
||||||
|
return (buttonText === 'Program' ? 'Detta' : 'Denna') + ' ' + buttonText.toLocaleLowerCase()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
viewHint: '$0 vy',
|
||||||
|
navLinkHint: 'Gå till $0',
|
||||||
|
moreLinkHint(eventCnt) {
|
||||||
|
return `Visa ytterligare ${eventCnt} händelse${eventCnt === 1 ? '' : 'r'}`
|
||||||
|
},
|
||||||
weekText: 'v.',
|
weekText: 'v.',
|
||||||
|
weekTextLong: 'Vecka',
|
||||||
allDayText: 'Heldag',
|
allDayText: 'Heldag',
|
||||||
moreLinkText: 'till',
|
moreLinkText: 'till',
|
||||||
noEventsText: 'Inga händelser att visa',
|
noEventsText: 'Inga händelser att visa',
|
||||||
|
closeHint: 'Stäng',
|
||||||
|
timeHint: 'Klockan',
|
||||||
|
eventHint: 'Händelse',
|
||||||
};
|
};
|
||||||
|
|
||||||
return sv;
|
return sv;
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
FullCalendar.globalLocales.push(function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var taIn = {
|
||||||
|
code: 'ta-in',
|
||||||
|
week: {
|
||||||
|
dow: 1, // Monday is the first day of the week.
|
||||||
|
doy: 4, // The week that contains Jan 4th is the first week of the year.
|
||||||
|
},
|
||||||
|
buttonText: {
|
||||||
|
prev: 'முந்தைய',
|
||||||
|
next: 'அடுத்தது',
|
||||||
|
today: 'இன்று',
|
||||||
|
month: 'மாதம்',
|
||||||
|
week: 'வாரம்',
|
||||||
|
day: 'நாள்',
|
||||||
|
list: 'தினசரி அட்டவணை',
|
||||||
|
},
|
||||||
|
weekText: 'வாரம்',
|
||||||
|
allDayText: 'நாள் முழுவதும்',
|
||||||
|
moreLinkText: function(n) {
|
||||||
|
return '+ மேலும் ' + n
|
||||||
|
},
|
||||||
|
noEventsText: 'காண்பிக்க நிகழ்வுகள் இல்லை',
|
||||||
|
};
|
||||||
|
|
||||||
|
return taIn;
|
||||||
|
|
||||||
|
}());
|
||||||
@@ -1,11 +1,12 @@
|
|||||||
|
|
||||||
/* classes attached to <body> */
|
/* classes attached to <body> */
|
||||||
|
/* TODO: make fc-event selector work when calender in shadow DOM */
|
||||||
.fc-not-allowed,
|
.fc-not-allowed,
|
||||||
.fc-not-allowed .fc-event { /* override events' custom cursors */
|
.fc-not-allowed .fc-event { /* override events' custom cursors */
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* TODO: not attached to body. attached to specific els. move */
|
||||||
.fc-unselectable {
|
.fc-unselectable {
|
||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
-moz-user-select: none;
|
-moz-user-select: none;
|
||||||
@@ -367,10 +368,6 @@ When it's NOT activated, the fc-button classes won't even be in the DOM.
|
|||||||
/* for most browsers, if a height isn't set on the table, can't do liquid-height within cells */
|
/* for most browsers, if a height isn't set on the table, can't do liquid-height within cells */
|
||||||
/* serves as a min-height. harmless */
|
/* serves as a min-height. harmless */
|
||||||
}
|
}
|
||||||
.fc .fc-scrollgrid-section-liquid {
|
|
||||||
height: auto
|
|
||||||
|
|
||||||
}
|
|
||||||
.fc .fc-scrollgrid-section-liquid > td {
|
.fc .fc-scrollgrid-section-liquid > td {
|
||||||
height: 100%; /* better than `auto`, for firefox */
|
height: 100%; /* better than `auto`, for firefox */
|
||||||
}
|
}
|
||||||
@@ -394,9 +391,8 @@ When it's NOT activated, the fc-button classes won't even be in the DOM.
|
|||||||
.fc .fc-scrollgrid-section-sticky > * {
|
.fc .fc-scrollgrid-section-sticky > * {
|
||||||
background: #fff;
|
background: #fff;
|
||||||
background: var(--fc-page-bg-color, #fff);
|
background: var(--fc-page-bg-color, #fff);
|
||||||
position: -webkit-sticky;
|
|
||||||
position: sticky;
|
position: sticky;
|
||||||
z-index: 2; /* TODO: var */
|
z-index: 3; /* TODO: var */
|
||||||
/* TODO: box-shadow when sticking */
|
/* TODO: box-shadow when sticking */
|
||||||
}
|
}
|
||||||
.fc .fc-scrollgrid-section-header.fc-scrollgrid-section-sticky > * {
|
.fc .fc-scrollgrid-section-header.fc-scrollgrid-section-sticky > * {
|
||||||
@@ -411,7 +407,6 @@ When it's NOT activated, the fc-button classes won't even be in the DOM.
|
|||||||
margin-bottom: -1px;
|
margin-bottom: -1px;
|
||||||
}
|
}
|
||||||
.fc-sticky { /* no .fc wrap because used as child of body */
|
.fc-sticky { /* no .fc wrap because used as child of body */
|
||||||
position: -webkit-sticky;
|
|
||||||
position: sticky;
|
position: sticky;
|
||||||
}
|
}
|
||||||
.fc .fc-view-harness {
|
.fc .fc-view-harness {
|
||||||
@@ -535,14 +530,17 @@ a.fc-event:hover {
|
|||||||
bottom: -20px;
|
bottom: -20px;
|
||||||
}
|
}
|
||||||
/* selecting (always TOUCH) */
|
/* selecting (always TOUCH) */
|
||||||
|
/* OR, focused by tab-index */
|
||||||
|
/* (TODO: maybe not the best focus-styling for .fc-daygrid-dot-event) */
|
||||||
/* ---------------------------------------------------------------------------------------------------- */
|
/* ---------------------------------------------------------------------------------------------------- */
|
||||||
.fc-event-selected {
|
.fc-event-selected,
|
||||||
|
.fc-event:focus {
|
||||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2)
|
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2)
|
||||||
|
|
||||||
/* expand hit area (subclasses should expand) */
|
/* expand hit area (subclasses should expand) */
|
||||||
|
|
||||||
}
|
}
|
||||||
.fc-event-selected:before {
|
.fc-event-selected:before, .fc-event:focus:before {
|
||||||
content: "";
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 3;
|
z-index: 3;
|
||||||
@@ -551,12 +549,13 @@ a.fc-event:hover {
|
|||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
}
|
}
|
||||||
.fc-event-selected {
|
.fc-event-selected,
|
||||||
|
.fc-event:focus {
|
||||||
|
|
||||||
/* dimmer effect */
|
/* dimmer effect */
|
||||||
|
|
||||||
}
|
}
|
||||||
.fc-event-selected:after {
|
.fc-event-selected:after, .fc-event:focus:after {
|
||||||
content: "";
|
content: "";
|
||||||
background: rgba(0, 0, 0, 0.25);
|
background: rgba(0, 0, 0, 0.25);
|
||||||
background: var(--fc-event-selected-overlay-color, rgba(0, 0, 0, 0.25));
|
background: var(--fc-event-selected-overlay-color, rgba(0, 0, 0, 0.25));
|
||||||
@@ -635,38 +634,33 @@ A HORIZONTAL event
|
|||||||
.fc-direction-rtl .fc-h-event:not(.fc-event-selected) .fc-event-resizer-end {
|
.fc-direction-rtl .fc-h-event:not(.fc-event-selected) .fc-event-resizer-end {
|
||||||
cursor: w-resize;
|
cursor: w-resize;
|
||||||
left: -4px;
|
left: -4px;
|
||||||
left: calc(var(--fc-event-resizer-thickness, 8px) / -2);
|
left: calc(-0.5 * var(--fc-event-resizer-thickness, 8px));
|
||||||
}
|
}
|
||||||
.fc-direction-ltr .fc-h-event:not(.fc-event-selected) .fc-event-resizer-end,
|
.fc-direction-ltr .fc-h-event:not(.fc-event-selected) .fc-event-resizer-end,
|
||||||
.fc-direction-rtl .fc-h-event:not(.fc-event-selected) .fc-event-resizer-start {
|
.fc-direction-rtl .fc-h-event:not(.fc-event-selected) .fc-event-resizer-start {
|
||||||
cursor: e-resize;
|
cursor: e-resize;
|
||||||
right: -4px;
|
right: -4px;
|
||||||
right: calc(var(--fc-event-resizer-thickness, 8px) / -2);
|
right: calc(-0.5 * var(--fc-event-resizer-thickness, 8px));
|
||||||
}
|
}
|
||||||
/* resizers for TOUCH */
|
/* resizers for TOUCH */
|
||||||
.fc-h-event.fc-event-selected .fc-event-resizer {
|
.fc-h-event.fc-event-selected .fc-event-resizer {
|
||||||
top: 50%;
|
top: 50%;
|
||||||
margin-top: -4px;
|
margin-top: -4px;
|
||||||
margin-top: calc(var(--fc-event-resizer-dot-total-width, 8px) / -2);
|
margin-top: calc(-0.5 * var(--fc-event-resizer-dot-total-width, 8px));
|
||||||
}
|
}
|
||||||
.fc-direction-ltr .fc-h-event.fc-event-selected .fc-event-resizer-start,
|
.fc-direction-ltr .fc-h-event.fc-event-selected .fc-event-resizer-start,
|
||||||
.fc-direction-rtl .fc-h-event.fc-event-selected .fc-event-resizer-end {
|
.fc-direction-rtl .fc-h-event.fc-event-selected .fc-event-resizer-end {
|
||||||
left: -4px;
|
left: -4px;
|
||||||
left: calc(var(--fc-event-resizer-dot-total-width, 8px) / -2);
|
left: calc(-0.5 * var(--fc-event-resizer-dot-total-width, 8px));
|
||||||
}
|
}
|
||||||
.fc-direction-ltr .fc-h-event.fc-event-selected .fc-event-resizer-end,
|
.fc-direction-ltr .fc-h-event.fc-event-selected .fc-event-resizer-end,
|
||||||
.fc-direction-rtl .fc-h-event.fc-event-selected .fc-event-resizer-start {
|
.fc-direction-rtl .fc-h-event.fc-event-selected .fc-event-resizer-start {
|
||||||
right: -4px;
|
right: -4px;
|
||||||
right: calc(var(--fc-event-resizer-dot-total-width, 8px) / -2);
|
right: calc(-0.5 * var(--fc-event-resizer-dot-total-width, 8px));
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
:root {
|
|
||||||
--fc-daygrid-event-dot-width: 8px;
|
|
||||||
}
|
}
|
||||||
.fc .fc-popover {
|
.fc .fc-popover {
|
||||||
position: fixed;
|
position: absolute;
|
||||||
top: 0; /* for when not positioned yet */
|
z-index: 9999;
|
||||||
box-shadow: 0 2px 6px rgba(0,0,0,.15);
|
box-shadow: 0 2px 6px rgba(0,0,0,.15);
|
||||||
}
|
}
|
||||||
.fc .fc-popover-header {
|
.fc .fc-popover-header {
|
||||||
@@ -694,6 +688,11 @@ A HORIZONTAL event
|
|||||||
background: rgba(208, 208, 208, 0.3);
|
background: rgba(208, 208, 208, 0.3);
|
||||||
background: var(--fc-neutral-bg-color, rgba(208, 208, 208, 0.3));
|
background: var(--fc-neutral-bg-color, rgba(208, 208, 208, 0.3));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--fc-daygrid-event-dot-width: 8px;
|
||||||
|
}
|
||||||
/* help things clear margins of inner content */
|
/* help things clear margins of inner content */
|
||||||
.fc-daygrid-day-frame,
|
.fc-daygrid-day-frame,
|
||||||
.fc-daygrid-day-events,
|
.fc-daygrid-day-events,
|
||||||
@@ -814,8 +813,12 @@ A HORIZONTAL event
|
|||||||
}
|
}
|
||||||
.fc .fc-daygrid-day-bottom {
|
.fc .fc-daygrid-day-bottom {
|
||||||
font-size: .85em;
|
font-size: .85em;
|
||||||
margin: 2px 3px 0;
|
padding: 2px 3px 0
|
||||||
}
|
}
|
||||||
|
.fc .fc-daygrid-day-bottom:before {
|
||||||
|
content: "";
|
||||||
|
clear: both;
|
||||||
|
display: table; }
|
||||||
.fc .fc-daygrid-more-link {
|
.fc .fc-daygrid-more-link {
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 4;
|
z-index: 4;
|
||||||
@@ -843,9 +846,6 @@ A HORIZONTAL event
|
|||||||
/* popover */
|
/* popover */
|
||||||
|
|
||||||
}
|
}
|
||||||
.fc .fc-more-popover {
|
|
||||||
z-index: 8;
|
|
||||||
}
|
|
||||||
.fc .fc-more-popover .fc-popover-body {
|
.fc .fc-more-popover .fc-popover-body {
|
||||||
min-width: 220px;
|
min-width: 220px;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
@@ -1139,7 +1139,7 @@ A VERTICAL event
|
|||||||
min-height: 100%; /* liquid-hack is below */
|
min-height: 100%; /* liquid-hack is below */
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
.fc-liquid-hack .fc-timegrid-col-frame {
|
.fc-media-screen.fc-liquid-hack .fc-timegrid-col-frame {
|
||||||
height: auto;
|
height: auto;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
@@ -1165,9 +1165,6 @@ A VERTICAL event
|
|||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
}
|
}
|
||||||
.fc-media-screen .fc-timegrid-event-harness {
|
|
||||||
position: absolute; /* top/left/right/bottom will all be set by JS */
|
|
||||||
}
|
|
||||||
.fc {
|
.fc {
|
||||||
|
|
||||||
/* bg */
|
/* bg */
|
||||||
@@ -1211,18 +1208,30 @@ A VERTICAL event
|
|||||||
.fc-direction-rtl .fc-timegrid-col-events {
|
.fc-direction-rtl .fc-timegrid-col-events {
|
||||||
margin: 0 2px 0 2.5%;
|
margin: 0 2px 0 2.5%;
|
||||||
}
|
}
|
||||||
|
.fc-timegrid-event-harness {
|
||||||
|
position: absolute /* top/left/right/bottom will all be set by JS */
|
||||||
|
}
|
||||||
|
.fc-timegrid-event-harness > .fc-timegrid-event {
|
||||||
|
position: absolute; /* absolute WITHIN the harness */
|
||||||
|
top: 0; /* for when not yet positioned */
|
||||||
|
bottom: 0; /* " */
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
.fc-timegrid-event-harness-inset .fc-timegrid-event,
|
.fc-timegrid-event-harness-inset .fc-timegrid-event,
|
||||||
.fc-timegrid-event.fc-event-mirror {
|
.fc-timegrid-event.fc-event-mirror,
|
||||||
|
.fc-timegrid-more-link {
|
||||||
box-shadow: 0px 0px 0px 1px #fff;
|
box-shadow: 0px 0px 0px 1px #fff;
|
||||||
box-shadow: 0px 0px 0px 1px var(--fc-page-bg-color, #fff);
|
box-shadow: 0px 0px 0px 1px var(--fc-page-bg-color, #fff);
|
||||||
}
|
}
|
||||||
.fc-timegrid-event { /* events need to be root */
|
.fc-timegrid-event,
|
||||||
|
.fc-timegrid-more-link { /* events need to be root */
|
||||||
font-size: .85em;
|
font-size: .85em;
|
||||||
|
|
||||||
font-size: var(--fc-small-font-size, .85em);
|
font-size: var(--fc-small-font-size, .85em);
|
||||||
border-radius: 3px
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
.fc-timegrid-event { /* events need to be root */
|
||||||
|
margin-bottom: 1px /* give some space from bottom */
|
||||||
}
|
}
|
||||||
.fc-timegrid-event .fc-event-main {
|
.fc-timegrid-event .fc-event-main {
|
||||||
padding: 1px 1px 0;
|
padding: 1px 1px 0;
|
||||||
@@ -1233,24 +1242,37 @@ A VERTICAL event
|
|||||||
font-size: var(--fc-small-font-size, .85em);
|
font-size: var(--fc-small-font-size, .85em);
|
||||||
margin-bottom: 1px;
|
margin-bottom: 1px;
|
||||||
}
|
}
|
||||||
.fc-timegrid-event-condensed .fc-event-main-frame {
|
.fc-timegrid-event-short .fc-event-main-frame {
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
.fc-timegrid-event-condensed .fc-event-time:after {
|
.fc-timegrid-event-short .fc-event-time:after {
|
||||||
content: '\00a0-\00a0'; /* dash surrounded by non-breaking spaces */
|
content: '\00a0-\00a0'; /* dash surrounded by non-breaking spaces */
|
||||||
}
|
}
|
||||||
.fc-timegrid-event-condensed .fc-event-title {
|
.fc-timegrid-event-short .fc-event-title {
|
||||||
font-size: .85em;
|
font-size: .85em;
|
||||||
font-size: var(--fc-small-font-size, .85em)
|
font-size: var(--fc-small-font-size, .85em)
|
||||||
}
|
}
|
||||||
.fc-media-screen .fc-timegrid-event {
|
.fc-timegrid-more-link { /* does NOT inherit from fc-timegrid-event */
|
||||||
position: absolute; /* absolute WITHIN the harness */
|
position: absolute;
|
||||||
|
z-index: 9999; /* hack */
|
||||||
|
color: inherit;
|
||||||
|
color: var(--fc-more-link-text-color, inherit);
|
||||||
|
background: #d0d0d0;
|
||||||
|
background: var(--fc-more-link-bg-color, #d0d0d0);
|
||||||
|
cursor: pointer;
|
||||||
|
margin-bottom: 1px; /* match space below fc-timegrid-event */
|
||||||
|
}
|
||||||
|
.fc-timegrid-more-link-inner { /* has fc-sticky */
|
||||||
|
padding: 3px 2px;
|
||||||
top: 0;
|
top: 0;
|
||||||
bottom: 1px; /* stay away from bottom slot line */
|
}
|
||||||
left: 0;
|
.fc-direction-ltr .fc-timegrid-more-link {
|
||||||
right: 0;
|
right: 0;
|
||||||
}
|
}
|
||||||
|
.fc-direction-rtl .fc-timegrid-more-link {
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
.fc {
|
.fc {
|
||||||
|
|
||||||
/* line */
|
/* line */
|
||||||
@@ -1336,12 +1358,28 @@ A VERTICAL event
|
|||||||
border-right: 0;
|
border-right: 0;
|
||||||
}
|
}
|
||||||
.fc .fc-list-sticky .fc-list-day > * { /* the cells */
|
.fc .fc-list-sticky .fc-list-day > * { /* the cells */
|
||||||
position: -webkit-sticky;
|
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0;
|
top: 0;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
background: var(--fc-page-bg-color, #fff); /* for when headers are styled to be transparent and sticky */
|
background: var(--fc-page-bg-color, #fff); /* for when headers are styled to be transparent and sticky */
|
||||||
}
|
}
|
||||||
|
.fc {
|
||||||
|
|
||||||
|
/* only exists for aria reasons, hide for non-screen-readers */
|
||||||
|
|
||||||
|
}
|
||||||
|
.fc .fc-list-table thead {
|
||||||
|
position: absolute;
|
||||||
|
left: -10000px;
|
||||||
|
}
|
||||||
|
.fc {
|
||||||
|
|
||||||
|
/* the table's border-style:hidden gets confused by hidden thead. force-hide top border of first cell */
|
||||||
|
|
||||||
|
}
|
||||||
|
.fc .fc-list-table tbody > tr:first-child th {
|
||||||
|
border-top: 0;
|
||||||
|
}
|
||||||
.fc .fc-list-table th {
|
.fc .fc-list-table th {
|
||||||
padding: 0; /* uses an inner-wrapper instead... */
|
padding: 0; /* uses an inner-wrapper instead... */
|
||||||
}
|
}
|
||||||
@@ -1427,3 +1465,31 @@ A VERTICAL event
|
|||||||
color: inherit; /* natural color for navlinks */
|
color: inherit; /* natural color for navlinks */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.fc-theme-bootstrap5 a:not([href]) {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-theme-bootstrap5 .fc-list,
|
||||||
|
.fc-theme-bootstrap5 .fc-scrollgrid,
|
||||||
|
.fc-theme-bootstrap5 td,
|
||||||
|
.fc-theme-bootstrap5 th {
|
||||||
|
border: 1px solid var(--bs-gray-400);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-theme-bootstrap5 {
|
||||||
|
|
||||||
|
/* HACK: reapply core styles after highe-precedence border statement above */
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-theme-bootstrap5 .fc-scrollgrid {
|
||||||
|
border-right-width: 0;
|
||||||
|
border-bottom-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-theme-bootstrap5-shaded {
|
||||||
|
background-color: var(--bs-gray-200);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -107,14 +107,9 @@ function inventreeDocReady() {
|
|||||||
|
|
||||||
// Callback to launch the 'About' window
|
// Callback to launch the 'About' window
|
||||||
$('#launch-about').click(function() {
|
$('#launch-about').click(function() {
|
||||||
var modal = $('#modal-about');
|
launchModalForm(`/about/`, {
|
||||||
|
no_post: true,
|
||||||
modal.modal({
|
|
||||||
backdrop: 'static',
|
|
||||||
keyboard: true,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
modal.modal('show');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Callback to launch the 'Database Stats' window
|
// Callback to launch the 'Database Stats' window
|
||||||
@@ -126,8 +121,6 @@ function inventreeDocReady() {
|
|||||||
|
|
||||||
// Initialize clipboard-buttons
|
// Initialize clipboard-buttons
|
||||||
attachClipboard('.clip-btn');
|
attachClipboard('.clip-btn');
|
||||||
attachClipboard('.clip-btn', 'modal-about');
|
|
||||||
attachClipboard('.clip-btn-version', 'modal-about', 'about-copy-text');
|
|
||||||
|
|
||||||
// Generate brand-icons
|
// Generate brand-icons
|
||||||
$('.brand-icon').each(function(i, obj) {
|
$('.brand-icon').each(function(i, obj) {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
"""Unit tests for the main web views."""
|
"""Unit tests for the main web views."""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import re
|
|
||||||
|
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
|
||||||
@@ -42,17 +41,3 @@ class ViewTests(InvenTreeTestCase):
|
|||||||
self.assertIn("<div id='detail-panels'>", content)
|
self.assertIn("<div id='detail-panels'>", content)
|
||||||
|
|
||||||
# TODO: In future, run the javascript and ensure that the panels get created!
|
# TODO: In future, run the javascript and ensure that the panels get created!
|
||||||
|
|
||||||
def test_js_load(self):
|
|
||||||
"""Test that the required javascript files are loaded correctly."""
|
|
||||||
# Change this number as more javascript files are added to the index page
|
|
||||||
N_SCRIPT_FILES = 40
|
|
||||||
|
|
||||||
content = self.get_index_page()
|
|
||||||
|
|
||||||
# Extract all required javascript files from the index page content
|
|
||||||
script_files = re.findall("<script type='text\\/javascript' src=\"([^\"]*)\"><\\/script>", content)
|
|
||||||
|
|
||||||
self.assertEqual(len(script_files), N_SCRIPT_FILES)
|
|
||||||
|
|
||||||
# TODO: Request the javascript files from the server, and ensure they are correcty loaded
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ from stock.urls import stock_urls
|
|||||||
from users.api import user_urls
|
from users.api import user_urls
|
||||||
|
|
||||||
from .api import InfoView, NotFoundView
|
from .api import InfoView, NotFoundView
|
||||||
from .views import (AppearanceSelectView, CurrencyRefreshView,
|
from .views import (AboutView, AppearanceSelectView, CurrencyRefreshView,
|
||||||
CustomConnectionsView, CustomEmailView,
|
CustomConnectionsView, CustomEmailView,
|
||||||
CustomPasswordResetFromKeyView,
|
CustomPasswordResetFromKeyView,
|
||||||
CustomSessionDeleteOtherView, CustomSessionDeleteView,
|
CustomSessionDeleteOtherView, CustomSessionDeleteView,
|
||||||
@@ -150,6 +150,7 @@ frontendpatterns = [
|
|||||||
re_path(r'^notifications/', include(notifications_urls)),
|
re_path(r'^notifications/', include(notifications_urls)),
|
||||||
re_path(r'^search/', SearchView.as_view(), name='search'),
|
re_path(r'^search/', SearchView.as_view(), name='search'),
|
||||||
re_path(r'^settings/', include(settings_urls)),
|
re_path(r'^settings/', include(settings_urls)),
|
||||||
|
re_path(r'^about/', AboutView.as_view(), name='about'),
|
||||||
re_path(r'^stats/', DatabaseStatsView.as_view(), name='stats'),
|
re_path(r'^stats/', DatabaseStatsView.as_view(), name='stats'),
|
||||||
|
|
||||||
# admin sites
|
# admin sites
|
||||||
|
|||||||
@@ -750,6 +750,13 @@ class DatabaseStatsView(AjaxView):
|
|||||||
ajax_form_title = _("System Information")
|
ajax_form_title = _("System Information")
|
||||||
|
|
||||||
|
|
||||||
|
class AboutView(AjaxView):
|
||||||
|
"""A view for displaying InvenTree version information"""
|
||||||
|
|
||||||
|
ajax_template_name = "about.html"
|
||||||
|
ajax_form_title = _("About InvenTree")
|
||||||
|
|
||||||
|
|
||||||
class NotificationsView(TemplateView):
|
class NotificationsView(TemplateView):
|
||||||
"""View for showing notifications."""
|
"""View for showing notifications."""
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
{% block thumbnail %}
|
{% block thumbnail %}
|
||||||
<img class="part-thumb"
|
<img class="part-thumb"
|
||||||
{% if build.part.image %}
|
{% if build.part.image %}
|
||||||
src="{{ build.part.image.url }}"
|
src="{{ build.part.image.preview.url }}"
|
||||||
{% else %}
|
{% else %}
|
||||||
src="{% static 'img/blank_image.png' %}"
|
src="{% static 'img/blank_image.png' %}"
|
||||||
{% endif %}/>
|
{% endif %}/>
|
||||||
|
|||||||
@@ -127,7 +127,10 @@ class Company(models.Model):
|
|||||||
upload_to=rename_company_image,
|
upload_to=rename_company_image,
|
||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
variations={'thumbnail': (128, 128)},
|
variations={
|
||||||
|
'thumbnail': (128, 128),
|
||||||
|
'preview': (256, 256),
|
||||||
|
},
|
||||||
delete_orphans=True,
|
delete_orphans=True,
|
||||||
verbose_name=_('Image'),
|
verbose_name=_('Image'),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -47,7 +47,7 @@
|
|||||||
<div class='dropzone part-thumb-container' id='company-thumb'>
|
<div class='dropzone part-thumb-container' id='company-thumb'>
|
||||||
<img class="part-thumb" id='company-image'
|
<img class="part-thumb" id='company-image'
|
||||||
{% if company.image %}
|
{% if company.image %}
|
||||||
src="{{ company.image.url }}"
|
src="{{ company.image.preview.url }}"
|
||||||
{% else %}
|
{% else %}
|
||||||
src="{% static 'img/blank_image.png' %}"
|
src="{% static 'img/blank_image.png' %}"
|
||||||
{% endif %}/>
|
{% endif %}/>
|
||||||
|
|||||||
@@ -50,7 +50,7 @@
|
|||||||
{% block thumbnail %}
|
{% block thumbnail %}
|
||||||
<img class='part-thumb'
|
<img class='part-thumb'
|
||||||
{% if part.part.image %}
|
{% if part.part.image %}
|
||||||
src='{{ part.part.image.url }}'
|
src='{{ part.part.image.preview.url }}'
|
||||||
{% else %}
|
{% else %}
|
||||||
src="{% static 'img/blank_image.png' %}"
|
src="{% static 'img/blank_image.png' %}"
|
||||||
{% endif %}/>
|
{% endif %}/>
|
||||||
|
|||||||
@@ -62,7 +62,7 @@
|
|||||||
{% block thumbnail %}
|
{% block thumbnail %}
|
||||||
<img class='part-thumb'
|
<img class='part-thumb'
|
||||||
{% if part.part.image %}
|
{% if part.part.image %}
|
||||||
src='{{ part.part.image.url }}'
|
src='{{ part.part.image.preview.url }}'
|
||||||
{% else %}
|
{% else %}
|
||||||
src="{% static 'img/blank_image.png' %}"
|
src="{% static 'img/blank_image.png' %}"
|
||||||
{% endif %}/>
|
{% endif %}/>
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ Relevant PRs:
|
|||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import OuterRef, Q
|
from django.db.models import F, FloatField, Func, OuterRef, Q, Subquery
|
||||||
from django.db.models.functions import Coalesce
|
from django.db.models.functions import Coalesce
|
||||||
|
|
||||||
from sql_util.utils import SubquerySum
|
from sql_util.utils import SubquerySum
|
||||||
@@ -139,3 +139,22 @@ def variant_stock_query(reference: str = '', filter: Q = stock.models.StockItem.
|
|||||||
part__lft__gt=OuterRef(f'{reference}lft'),
|
part__lft__gt=OuterRef(f'{reference}lft'),
|
||||||
part__rght__lt=OuterRef(f'{reference}rght'),
|
part__rght__lt=OuterRef(f'{reference}rght'),
|
||||||
).filter(filter)
|
).filter(filter)
|
||||||
|
|
||||||
|
|
||||||
|
def annotate_variant_quantity(subquery: Q, reference: str = 'quantity'):
|
||||||
|
"""Create a subquery annotation for all variant part stock items on the given parent query
|
||||||
|
|
||||||
|
Args:
|
||||||
|
subquery: A 'variant_stock_query' Q object
|
||||||
|
reference: The relationship reference of the variant stock items from the current queryset
|
||||||
|
"""
|
||||||
|
|
||||||
|
return Coalesce(
|
||||||
|
Subquery(
|
||||||
|
subquery.annotate(
|
||||||
|
total=Func(F(reference), function='SUM', output_field=FloatField())
|
||||||
|
).values('total')
|
||||||
|
),
|
||||||
|
0,
|
||||||
|
output_field=FloatField(),
|
||||||
|
)
|
||||||
|
|||||||
+86
-34
@@ -13,7 +13,7 @@ from django.contrib.auth.models import User
|
|||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.core.validators import MinValueValidator
|
from django.core.validators import MinValueValidator
|
||||||
from django.db import models, transaction
|
from django.db import models, transaction
|
||||||
from django.db.models import Q, Sum, UniqueConstraint
|
from django.db.models import ExpressionWrapper, F, Q, Sum, UniqueConstraint
|
||||||
from django.db.models.functions import Coalesce
|
from django.db.models.functions import Coalesce
|
||||||
from django.db.models.signals import post_save
|
from django.db.models.signals import post_save
|
||||||
from django.db.utils import IntegrityError
|
from django.db.utils import IntegrityError
|
||||||
@@ -34,6 +34,7 @@ from stdimage.models import StdImageField
|
|||||||
import common.models
|
import common.models
|
||||||
import InvenTree.ready
|
import InvenTree.ready
|
||||||
import InvenTree.tasks
|
import InvenTree.tasks
|
||||||
|
import part.filters as part_filters
|
||||||
import part.settings as part_settings
|
import part.settings as part_settings
|
||||||
from build import models as BuildModels
|
from build import models as BuildModels
|
||||||
from common.models import InvenTreeSetting
|
from common.models import InvenTreeSetting
|
||||||
@@ -74,9 +75,9 @@ class PartCategory(MetadataMixin, InvenTreeTree):
|
|||||||
tree_id = self.tree_id
|
tree_id = self.tree_id
|
||||||
|
|
||||||
# Update each part in this category to point to the parent category
|
# Update each part in this category to point to the parent category
|
||||||
for part in self.parts.all():
|
for p in self.parts.all():
|
||||||
part.category = self.parent
|
p.category = self.parent
|
||||||
part.save()
|
p.save()
|
||||||
|
|
||||||
# Update each child category
|
# Update each child category
|
||||||
for child in self.children.all():
|
for child in self.children.all():
|
||||||
@@ -221,7 +222,7 @@ class PartCategory(MetadataMixin, InvenTreeTree):
|
|||||||
|
|
||||||
if include_parents:
|
if include_parents:
|
||||||
queryset = PartCategoryStar.objects.filter(
|
queryset = PartCategoryStar.objects.filter(
|
||||||
category__pk__in=[cat.pk for cat in cats]
|
category__in=cats,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
queryset = PartCategoryStar.objects.filter(
|
queryset = PartCategoryStar.objects.filter(
|
||||||
@@ -800,7 +801,10 @@ class Part(MetadataMixin, MPTTModel):
|
|||||||
upload_to=rename_part_image,
|
upload_to=rename_part_image,
|
||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
variations={'thumbnail': (128, 128)},
|
variations={
|
||||||
|
'thumbnail': (128, 128),
|
||||||
|
'preview': (256, 256),
|
||||||
|
},
|
||||||
delete_orphans=False,
|
delete_orphans=False,
|
||||||
verbose_name=_('Image'),
|
verbose_name=_('Image'),
|
||||||
)
|
)
|
||||||
@@ -968,13 +972,10 @@ class Part(MetadataMixin, MPTTModel):
|
|||||||
def requiring_build_orders(self):
|
def requiring_build_orders(self):
|
||||||
"""Return list of outstanding build orders which require this part."""
|
"""Return list of outstanding build orders which require this part."""
|
||||||
# List parts that this part is required for
|
# List parts that this part is required for
|
||||||
parts = self.get_used_in().all()
|
|
||||||
|
|
||||||
part_ids = [part.pk for part in parts]
|
|
||||||
|
|
||||||
# Now, get a list of outstanding build orders which require this part
|
# Now, get a list of outstanding build orders which require this part
|
||||||
builds = BuildModels.Build.objects.filter(
|
builds = BuildModels.Build.objects.filter(
|
||||||
part__in=part_ids,
|
part__in=self.get_used_in().all(),
|
||||||
status__in=BuildStatus.ACTIVE_CODES
|
status__in=BuildStatus.ACTIVE_CODES
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1098,7 +1099,7 @@ class Part(MetadataMixin, MPTTModel):
|
|||||||
|
|
||||||
if include_variants:
|
if include_variants:
|
||||||
queryset = queryset.filter(
|
queryset = queryset.filter(
|
||||||
part__pk__in=[part.pk for part in self.get_ancestors(include_self=True)]
|
part__in=self.get_ancestors(include_self=True),
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
queryset = queryset.filter(part=self)
|
queryset = queryset.filter(part=self)
|
||||||
@@ -1142,18 +1143,70 @@ class Part(MetadataMixin, MPTTModel):
|
|||||||
|
|
||||||
total = None
|
total = None
|
||||||
|
|
||||||
bom_items = self.get_bom_items().prefetch_related('sub_part__stock_items')
|
# Prefetch related tables, to reduce query expense
|
||||||
|
queryset = self.get_bom_items().prefetch_related(
|
||||||
|
'sub_part__stock_items',
|
||||||
|
'sub_part__stock_items__allocations',
|
||||||
|
'sub_part__stock_items__sales_order_allocations',
|
||||||
|
'substitutes',
|
||||||
|
'substitutes__part__stock_items',
|
||||||
|
)
|
||||||
|
|
||||||
# Calculate the minimum number of parts that can be built using each sub-part
|
# Annotate the 'available stock' for each part in the BOM
|
||||||
for item in bom_items.all():
|
ref = 'sub_part__'
|
||||||
stock = item.sub_part.available_stock
|
queryset = queryset.alias(
|
||||||
|
total_stock=part_filters.annotate_total_stock(reference=ref),
|
||||||
|
so_allocations=part_filters.annotate_sales_order_allocations(reference=ref),
|
||||||
|
bo_allocations=part_filters.annotate_build_order_allocations(reference=ref),
|
||||||
|
)
|
||||||
|
|
||||||
# If (by some chance) we get here but the BOM item quantity is invalid,
|
# Calculate the 'available stock' based on previous annotations
|
||||||
# ignore!
|
queryset = queryset.annotate(
|
||||||
if item.quantity <= 0:
|
available_stock=ExpressionWrapper(
|
||||||
continue
|
F('total_stock') - F('so_allocations') - F('bo_allocations'),
|
||||||
|
output_field=models.DecimalField(),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
n = int(stock / item.quantity)
|
# Extract similar information for any 'substitute' parts
|
||||||
|
ref = 'substitutes__part__'
|
||||||
|
queryset = queryset.alias(
|
||||||
|
sub_total_stock=part_filters.annotate_total_stock(reference=ref),
|
||||||
|
sub_so_allocations=part_filters.annotate_sales_order_allocations(reference=ref),
|
||||||
|
sub_bo_allocations=part_filters.annotate_build_order_allocations(reference=ref),
|
||||||
|
)
|
||||||
|
|
||||||
|
queryset = queryset.annotate(
|
||||||
|
substitute_stock=ExpressionWrapper(
|
||||||
|
F('sub_total_stock') - F('sub_so_allocations') - F('sub_bo_allocations'),
|
||||||
|
output_field=models.DecimalField(),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Extract similar information for any 'variant' parts
|
||||||
|
variant_stock_query = part_filters.variant_stock_query(reference='sub_part__')
|
||||||
|
|
||||||
|
queryset = queryset.alias(
|
||||||
|
var_total_stock=part_filters.annotate_variant_quantity(variant_stock_query, reference='quantity'),
|
||||||
|
var_bo_allocations=part_filters.annotate_variant_quantity(variant_stock_query, reference='allocations__quantity'),
|
||||||
|
var_so_allocations=part_filters.annotate_variant_quantity(variant_stock_query, reference='sales_order_allocations__quantity'),
|
||||||
|
)
|
||||||
|
|
||||||
|
queryset = queryset.annotate(
|
||||||
|
variant_stock=ExpressionWrapper(
|
||||||
|
F('var_total_stock') - F('var_bo_allocations') - F('var_so_allocations'),
|
||||||
|
output_field=models.DecimalField(),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
for item in queryset.all():
|
||||||
|
# Iterate through each item in the queryset, work out the limiting quantity
|
||||||
|
quantity = item.available_stock + item.substitute_stock
|
||||||
|
|
||||||
|
if item.allow_variants:
|
||||||
|
quantity += item.variant_stock
|
||||||
|
|
||||||
|
n = int(quantity / item.quantity)
|
||||||
|
|
||||||
if total is None or n < total:
|
if total is None or n < total:
|
||||||
total = n
|
total = n
|
||||||
@@ -1336,11 +1389,10 @@ class Part(MetadataMixin, MPTTModel):
|
|||||||
parents = self.get_ancestors(include_self=False)
|
parents = self.get_ancestors(include_self=False)
|
||||||
|
|
||||||
# There are parents available
|
# There are parents available
|
||||||
if parents.count() > 0:
|
if parents.exists():
|
||||||
parent_ids = [p.pk for p in parents]
|
|
||||||
|
|
||||||
parent_filter = Q(
|
parent_filter = Q(
|
||||||
part__id__in=parent_ids,
|
part__in=parents,
|
||||||
inherited=True
|
inherited=True
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1425,7 +1477,7 @@ class Part(MetadataMixin, MPTTModel):
|
|||||||
@property
|
@property
|
||||||
def has_bom(self):
|
def has_bom(self):
|
||||||
"""Return True if this Part instance has any BOM items"""
|
"""Return True if this Part instance has any BOM items"""
|
||||||
return self.get_bom_items().count() > 0
|
return self.get_bom_items().exists()
|
||||||
|
|
||||||
def get_trackable_parts(self):
|
def get_trackable_parts(self):
|
||||||
"""Return a queryset of all trackable parts in the BOM for this part."""
|
"""Return a queryset of all trackable parts in the BOM for this part."""
|
||||||
@@ -1440,7 +1492,7 @@ class Part(MetadataMixin, MPTTModel):
|
|||||||
|
|
||||||
This is important when building the part.
|
This is important when building the part.
|
||||||
"""
|
"""
|
||||||
return self.get_trackable_parts().count() > 0
|
return self.get_trackable_parts().exists()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def bom_count(self):
|
def bom_count(self):
|
||||||
@@ -1482,7 +1534,7 @@ class Part(MetadataMixin, MPTTModel):
|
|||||||
# Validate each line item, ignoring inherited ones
|
# Validate each line item, ignoring inherited ones
|
||||||
bom_items = self.get_bom_items(include_inherited=False)
|
bom_items = self.get_bom_items(include_inherited=False)
|
||||||
|
|
||||||
for item in bom_items.all():
|
for item in bom_items:
|
||||||
item.validate_hash()
|
item.validate_hash()
|
||||||
|
|
||||||
self.bom_checksum = self.get_bom_hash()
|
self.bom_checksum = self.get_bom_hash()
|
||||||
@@ -1509,7 +1561,7 @@ class Part(MetadataMixin, MPTTModel):
|
|||||||
if parts is None:
|
if parts is None:
|
||||||
parts = set()
|
parts = set()
|
||||||
|
|
||||||
bom_items = self.get_bom_items().all()
|
bom_items = self.get_bom_items()
|
||||||
|
|
||||||
for bom_item in bom_items:
|
for bom_item in bom_items:
|
||||||
|
|
||||||
@@ -1533,7 +1585,7 @@ class Part(MetadataMixin, MPTTModel):
|
|||||||
def has_complete_bom_pricing(self):
|
def has_complete_bom_pricing(self):
|
||||||
"""Return true if there is pricing information for each item in the BOM."""
|
"""Return true if there is pricing information for each item in the BOM."""
|
||||||
use_internal = common.models.InvenTreeSetting.get_setting('PART_BOM_USE_INTERNAL_PRICE', False)
|
use_internal = common.models.InvenTreeSetting.get_setting('PART_BOM_USE_INTERNAL_PRICE', False)
|
||||||
for item in self.get_bom_items().all().select_related('sub_part'):
|
for item in self.get_bom_items().select_related('sub_part'):
|
||||||
if item.sub_part.get_price_range(internal=use_internal) is None:
|
if item.sub_part.get_price_range(internal=use_internal) is None:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -1609,7 +1661,7 @@ class Part(MetadataMixin, MPTTModel):
|
|||||||
min_price = None
|
min_price = None
|
||||||
max_price = None
|
max_price = None
|
||||||
|
|
||||||
for item in self.get_bom_items().all().select_related('sub_part'):
|
for item in self.get_bom_items().select_related('sub_part'):
|
||||||
|
|
||||||
if item.sub_part.pk == self.pk:
|
if item.sub_part.pk == self.pk:
|
||||||
logger.warning(f"WARNING: BomItem ID {item.pk} contains itself in BOM")
|
logger.warning(f"WARNING: BomItem ID {item.pk} contains itself in BOM")
|
||||||
@@ -1689,7 +1741,7 @@ class Part(MetadataMixin, MPTTModel):
|
|||||||
@property
|
@property
|
||||||
def has_price_breaks(self):
|
def has_price_breaks(self):
|
||||||
"""Return True if this part has sale price breaks"""
|
"""Return True if this part has sale price breaks"""
|
||||||
return self.price_breaks.count() > 0
|
return self.price_breaks.exists()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def price_breaks(self):
|
def price_breaks(self):
|
||||||
@@ -1725,7 +1777,7 @@ class Part(MetadataMixin, MPTTModel):
|
|||||||
@property
|
@property
|
||||||
def has_internal_price_breaks(self):
|
def has_internal_price_breaks(self):
|
||||||
"""Return True if this Part has internal pricing information"""
|
"""Return True if this Part has internal pricing information"""
|
||||||
return self.internal_price_breaks.count() > 0
|
return self.internal_price_breaks.exists()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def internal_price_breaks(self):
|
def internal_price_breaks(self):
|
||||||
@@ -1978,7 +2030,7 @@ class Part(MetadataMixin, MPTTModel):
|
|||||||
@property
|
@property
|
||||||
def has_variants(self):
|
def has_variants(self):
|
||||||
"""Check if this Part object has variants underneath it."""
|
"""Check if this Part object has variants underneath it."""
|
||||||
return self.get_all_variants().count() > 0
|
return self.get_all_variants().exists()
|
||||||
|
|
||||||
def get_all_variants(self):
|
def get_all_variants(self):
|
||||||
"""Return all Part object which exist as a variant under this part."""
|
"""Return all Part object which exist as a variant under this part."""
|
||||||
@@ -1993,7 +2045,7 @@ class Part(MetadataMixin, MPTTModel):
|
|||||||
b) It has non-virtual template parts above it
|
b) It has non-virtual template parts above it
|
||||||
c) It has non-virtual sibling variants
|
c) It has non-virtual sibling variants
|
||||||
"""
|
"""
|
||||||
return self.get_conversion_options().count() > 0
|
return self.get_conversion_options().exists()
|
||||||
|
|
||||||
def get_conversion_options(self):
|
def get_conversion_options(self):
|
||||||
"""Return options for converting this part to a "variant" within the same tree.
|
"""Return options for converting this part to a "variant" within the same tree.
|
||||||
@@ -2520,7 +2572,7 @@ class BomItem(DataImportMixin, models.Model):
|
|||||||
- Allow stock from all directly specified substitute parts
|
- Allow stock from all directly specified substitute parts
|
||||||
- If allow_variants is True, allow all part variants
|
- If allow_variants is True, allow all part variants
|
||||||
"""
|
"""
|
||||||
return Q(part__in=[part.pk for part in self.get_valid_parts_for_allocation()])
|
return Q(part__in=self.get_valid_parts_for_allocation())
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
"""Enforce 'clean' operation when saving a BomItem instance"""
|
"""Enforce 'clean' operation when saving a BomItem instance"""
|
||||||
|
|||||||
@@ -4,8 +4,7 @@ import imghdr
|
|||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
|
||||||
from django.db import models, transaction
|
from django.db import models, transaction
|
||||||
from django.db.models import (ExpressionWrapper, F, FloatField, Func, Q,
|
from django.db.models import ExpressionWrapper, F, FloatField, Q
|
||||||
Subquery)
|
|
||||||
from django.db.models.functions import Coalesce
|
from django.db.models.functions import Coalesce
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
@@ -251,8 +250,6 @@ class PartBriefSerializer(InvenTreeModelSerializer):
|
|||||||
|
|
||||||
thumbnail = serializers.CharField(source='get_thumbnail_url', read_only=True)
|
thumbnail = serializers.CharField(source='get_thumbnail_url', read_only=True)
|
||||||
|
|
||||||
stock = serializers.FloatField(source='total_stock')
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
"""Metaclass defining serializer fields"""
|
"""Metaclass defining serializer fields"""
|
||||||
model = Part
|
model = Part
|
||||||
@@ -270,7 +267,6 @@ class PartBriefSerializer(InvenTreeModelSerializer):
|
|||||||
'is_template',
|
'is_template',
|
||||||
'purchaseable',
|
'purchaseable',
|
||||||
'salable',
|
'salable',
|
||||||
'stock',
|
|
||||||
'trackable',
|
'trackable',
|
||||||
'virtual',
|
'virtual',
|
||||||
'units',
|
'units',
|
||||||
@@ -322,14 +318,7 @@ class PartSerializer(InvenTreeModelSerializer):
|
|||||||
variant_query = part.filters.variant_stock_query()
|
variant_query = part.filters.variant_stock_query()
|
||||||
|
|
||||||
queryset = queryset.annotate(
|
queryset = queryset.annotate(
|
||||||
variant_stock=Coalesce(
|
variant_stock=part.filters.annotate_variant_quantity(variant_query, reference='quantity'),
|
||||||
Subquery(
|
|
||||||
variant_query.annotate(
|
|
||||||
total=Func(F('quantity'), function='SUM', output_field=FloatField())
|
|
||||||
).values('total')),
|
|
||||||
0,
|
|
||||||
output_field=FloatField(),
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Filter to limit builds to "active"
|
# Filter to limit builds to "active"
|
||||||
@@ -642,35 +631,14 @@ class BomItemSerializer(InvenTreeModelSerializer):
|
|||||||
variant_stock_query = part.filters.variant_stock_query(reference='sub_part__')
|
variant_stock_query = part.filters.variant_stock_query(reference='sub_part__')
|
||||||
|
|
||||||
queryset = queryset.alias(
|
queryset = queryset.alias(
|
||||||
variant_stock_total=Coalesce(
|
variant_stock_total=part.filters.annotate_variant_quantity(variant_stock_query, reference='quantity'),
|
||||||
Subquery(
|
variant_bo_allocations=part.filters.annotate_variant_quantity(variant_stock_query, reference='sales_order_allocations__quantity'),
|
||||||
variant_stock_query.annotate(
|
variant_so_allocations=part.filters.annotate_variant_quantity(variant_stock_query, reference='allocations__quantity'),
|
||||||
total=Func(F('quantity'), function='SUM', output_field=FloatField())
|
|
||||||
).values('total')),
|
|
||||||
0,
|
|
||||||
output_field=FloatField()
|
|
||||||
),
|
|
||||||
variant_stock_build_order_allocations=Coalesce(
|
|
||||||
Subquery(
|
|
||||||
variant_stock_query.annotate(
|
|
||||||
total=Func(F('sales_order_allocations__quantity'), function='SUM', output_field=FloatField()),
|
|
||||||
).values('total')),
|
|
||||||
0,
|
|
||||||
output_field=FloatField(),
|
|
||||||
),
|
|
||||||
variant_stock_sales_order_allocations=Coalesce(
|
|
||||||
Subquery(
|
|
||||||
variant_stock_query.annotate(
|
|
||||||
total=Func(F('allocations__quantity'), function='SUM', output_field=FloatField()),
|
|
||||||
).values('total')),
|
|
||||||
0,
|
|
||||||
output_field=FloatField(),
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
queryset = queryset.annotate(
|
queryset = queryset.annotate(
|
||||||
available_variant_stock=ExpressionWrapper(
|
available_variant_stock=ExpressionWrapper(
|
||||||
F('variant_stock_total') - F('variant_stock_build_order_allocations') - F('variant_stock_sales_order_allocations'),
|
F('variant_stock_total') - F('variant_bo_allocations') - F('variant_so_allocations'),
|
||||||
output_field=FloatField(),
|
output_field=FloatField(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -690,17 +690,6 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Load the BOM table data in the pricing view
|
|
||||||
{% if part.has_bom and roles.sales_order.view %}
|
|
||||||
loadBomTable($("#bom-pricing-table"), {
|
|
||||||
editable: false,
|
|
||||||
bom_url: "{% url 'api-bom-list' %}",
|
|
||||||
part_url: "{% url 'api-part-list' %}",
|
|
||||||
parent_id: {{ part.id }} ,
|
|
||||||
sub_part_detail: true,
|
|
||||||
});
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
onPanelLoad("purchase-orders", function() {
|
onPanelLoad("purchase-orders", function() {
|
||||||
loadPartPurchaseOrderTable(
|
loadPartPurchaseOrderTable(
|
||||||
"#purchase-order-table",
|
"#purchase-order-table",
|
||||||
@@ -885,9 +874,20 @@
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
onPanelLoad('pricing', function() {
|
||||||
{% default_currency as currency %}
|
{% default_currency as currency %}
|
||||||
|
|
||||||
|
// Load the BOM table data in the pricing view
|
||||||
|
{% if part.has_bom and roles.sales_order.view %}
|
||||||
|
loadBomTable($("#bom-pricing-table"), {
|
||||||
|
editable: false,
|
||||||
|
bom_url: "{% url 'api-bom-list' %}",
|
||||||
|
part_url: "{% url 'api-part-list' %}",
|
||||||
|
parent_id: {{ part.id }} ,
|
||||||
|
sub_part_detail: true,
|
||||||
|
});
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
// history graphs
|
// history graphs
|
||||||
{% if price_history %}
|
{% if price_history %}
|
||||||
var purchasepricedata = {
|
var purchasepricedata = {
|
||||||
@@ -1031,6 +1031,7 @@
|
|||||||
}
|
}
|
||||||
var SalePriceChart = loadSellPricingChart($('#SalePriceChart'), salepricedata)
|
var SalePriceChart = loadSellPricingChart($('#SalePriceChart'), salepricedata)
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
});
|
||||||
|
|
||||||
enableSidebar('part');
|
enableSidebar('part');
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
<img class="part-thumb" id='part-image'
|
<img class="part-thumb" id='part-image'
|
||||||
{% if part.image %}
|
{% if part.image %}
|
||||||
src="{{ part.image.url }}"
|
src="{{ part.image.preview.url }}"
|
||||||
{% else %}
|
{% else %}
|
||||||
src="{% static 'img/blank_image.png' %}"
|
src="{% static 'img/blank_image.png' %}"
|
||||||
{% endif %}/>
|
{% endif %}/>
|
||||||
|
|||||||
@@ -74,7 +74,6 @@ class StockDetail(RetrieveUpdateDestroyAPI):
|
|||||||
kwargs['part_detail'] = True
|
kwargs['part_detail'] = True
|
||||||
kwargs['location_detail'] = True
|
kwargs['location_detail'] = True
|
||||||
kwargs['supplier_part_detail'] = True
|
kwargs['supplier_part_detail'] = True
|
||||||
kwargs['test_detail'] = True
|
|
||||||
kwargs['context'] = self.get_serializer_context()
|
kwargs['context'] = self.get_serializer_context()
|
||||||
|
|
||||||
return self.serializer_class(*args, **kwargs)
|
return self.serializer_class(*args, **kwargs)
|
||||||
|
|||||||
@@ -88,6 +88,12 @@ class StockItemSerializer(InvenTree.serializers.InvenTreeModelSerializer):
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def annotate_queryset(queryset):
|
def annotate_queryset(queryset):
|
||||||
"""Add some extra annotations to the queryset, performing database queries as efficiently as possible."""
|
"""Add some extra annotations to the queryset, performing database queries as efficiently as possible."""
|
||||||
|
|
||||||
|
queryset = queryset.prefetch_related(
|
||||||
|
'sales_order',
|
||||||
|
'purchase_order',
|
||||||
|
)
|
||||||
|
|
||||||
# Annotate the queryset with the total allocated to sales orders
|
# Annotate the queryset with the total allocated to sales orders
|
||||||
queryset = queryset.annotate(
|
queryset = queryset.annotate(
|
||||||
allocated=Coalesce(
|
allocated=Coalesce(
|
||||||
@@ -136,20 +142,14 @@ class StockItemSerializer(InvenTree.serializers.InvenTreeModelSerializer):
|
|||||||
|
|
||||||
location_detail = LocationBriefSerializer(source='location', many=False, read_only=True)
|
location_detail = LocationBriefSerializer(source='location', many=False, read_only=True)
|
||||||
|
|
||||||
tracking_items = serializers.IntegerField(source='tracking_info_count', read_only=True, required=False)
|
|
||||||
|
|
||||||
quantity = InvenTreeDecimalField()
|
quantity = InvenTreeDecimalField()
|
||||||
|
|
||||||
allocated = serializers.FloatField(source='allocation_count', required=False)
|
# Annotated fields
|
||||||
|
tracking_items = serializers.IntegerField(read_only=True, required=False)
|
||||||
|
allocated = serializers.FloatField(required=False)
|
||||||
expired = serializers.BooleanField(required=False, read_only=True)
|
expired = serializers.BooleanField(required=False, read_only=True)
|
||||||
|
|
||||||
stale = serializers.BooleanField(required=False, read_only=True)
|
stale = serializers.BooleanField(required=False, read_only=True)
|
||||||
|
|
||||||
# serial = serializers.CharField(required=False)
|
|
||||||
|
|
||||||
required_tests = serializers.IntegerField(source='required_test_count', read_only=True, required=False)
|
|
||||||
|
|
||||||
purchase_price = InvenTree.serializers.InvenTreeMoneySerializer(
|
purchase_price = InvenTree.serializers.InvenTreeMoneySerializer(
|
||||||
label=_('Purchase Price'),
|
label=_('Purchase Price'),
|
||||||
max_digits=19, decimal_places=4,
|
max_digits=19, decimal_places=4,
|
||||||
@@ -171,7 +171,6 @@ class StockItemSerializer(InvenTree.serializers.InvenTreeModelSerializer):
|
|||||||
return str(obj.purchase_price) if obj.purchase_price else '-'
|
return str(obj.purchase_price) if obj.purchase_price else '-'
|
||||||
|
|
||||||
purchase_order_reference = serializers.CharField(source='purchase_order.reference', read_only=True)
|
purchase_order_reference = serializers.CharField(source='purchase_order.reference', read_only=True)
|
||||||
|
|
||||||
sales_order_reference = serializers.CharField(source='sales_order.reference', read_only=True)
|
sales_order_reference = serializers.CharField(source='sales_order.reference', read_only=True)
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
@@ -179,7 +178,6 @@ class StockItemSerializer(InvenTree.serializers.InvenTreeModelSerializer):
|
|||||||
part_detail = kwargs.pop('part_detail', False)
|
part_detail = kwargs.pop('part_detail', False)
|
||||||
location_detail = kwargs.pop('location_detail', False)
|
location_detail = kwargs.pop('location_detail', False)
|
||||||
supplier_part_detail = kwargs.pop('supplier_part_detail', False)
|
supplier_part_detail = kwargs.pop('supplier_part_detail', False)
|
||||||
test_detail = kwargs.pop('test_detail', False)
|
|
||||||
|
|
||||||
super(StockItemSerializer, self).__init__(*args, **kwargs)
|
super(StockItemSerializer, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
@@ -192,9 +190,6 @@ class StockItemSerializer(InvenTree.serializers.InvenTreeModelSerializer):
|
|||||||
if supplier_part_detail is not True:
|
if supplier_part_detail is not True:
|
||||||
self.fields.pop('supplier_part_detail')
|
self.fields.pop('supplier_part_detail')
|
||||||
|
|
||||||
if test_detail is not True:
|
|
||||||
self.fields.pop('required_tests')
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
"""Metaclass options."""
|
"""Metaclass options."""
|
||||||
|
|
||||||
@@ -208,7 +203,6 @@ class StockItemSerializer(InvenTree.serializers.InvenTreeModelSerializer):
|
|||||||
'delete_on_deplete',
|
'delete_on_deplete',
|
||||||
'expired',
|
'expired',
|
||||||
'expiry_date',
|
'expiry_date',
|
||||||
'in_stock',
|
|
||||||
'is_building',
|
'is_building',
|
||||||
'link',
|
'link',
|
||||||
'location',
|
'location',
|
||||||
@@ -222,7 +216,6 @@ class StockItemSerializer(InvenTree.serializers.InvenTreeModelSerializer):
|
|||||||
'purchase_order_reference',
|
'purchase_order_reference',
|
||||||
'pk',
|
'pk',
|
||||||
'quantity',
|
'quantity',
|
||||||
'required_tests',
|
|
||||||
'sales_order',
|
'sales_order',
|
||||||
'sales_order_reference',
|
'sales_order_reference',
|
||||||
'serial',
|
'serial',
|
||||||
@@ -249,7 +242,6 @@ class StockItemSerializer(InvenTree.serializers.InvenTreeModelSerializer):
|
|||||||
'stocktake_date',
|
'stocktake_date',
|
||||||
'stocktake_user',
|
'stocktake_user',
|
||||||
'updated',
|
'updated',
|
||||||
'in_stock'
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -136,7 +136,7 @@
|
|||||||
{% endblock actions %}
|
{% endblock actions %}
|
||||||
|
|
||||||
{% block thumbnail %}
|
{% block thumbnail %}
|
||||||
<img class='part-thumb' {% if item.part.image %}src="{{ item.part.image.url }}"{% else %}src="{% static 'img/blank_image.png' %}"{% endif %}/>
|
<img class='part-thumb' {% if item.part.image %}src="{{ item.part.image.preview.url }}"{% else %}src="{% static 'img/blank_image.png' %}"{% endif %}/>
|
||||||
{% endblock thumbnail %}
|
{% endblock thumbnail %}
|
||||||
|
|
||||||
{% block details %}
|
{% block details %}
|
||||||
|
|||||||
@@ -2,17 +2,6 @@
|
|||||||
{% load inventree_extras %}
|
{% load inventree_extras %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
<div class='modal fade modal-fixed-footer' tabindex='-1' role='dialog' id='modal-about'>
|
|
||||||
<div class='modal-dialog'>
|
|
||||||
<div class='modal-content'>
|
|
||||||
<div class="modal-header">
|
|
||||||
<img src="{% static 'img/inventree.png' %}" height='40px' style='float: left; padding-right: 25px;' alt='Inventree Logo'>
|
|
||||||
<h4>{% trans "InvenTree Version Information" %}</h4>
|
|
||||||
<button type='button' class='btn-close' data-bs-dismiss='modal' aria-label='{% trans "Close" %}'></button>
|
|
||||||
</div>
|
|
||||||
<div class='modal-form-content-wrapper'>
|
|
||||||
<div class='modal-form-content'>
|
|
||||||
<div>
|
|
||||||
<table class='table table-striped table-condensed'>
|
<table class='table table-striped table-condensed'>
|
||||||
<col width='25'>
|
<col width='25'>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -97,13 +86,3 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class='modal-footer'>
|
|
||||||
<button type='button' class='btn btn-outline-secondary' data-bs-dismiss='modal'>{% trans "Close" %}</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|||||||
@@ -84,29 +84,14 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Scripts -->
|
|
||||||
<script type="text/javascript" src="{% static 'script/jquery_3.3.1_jquery.min.js' %}"></script>
|
|
||||||
<script type='text/javascript' src="{% static 'script/jquery-ui/jquery-ui.min.js' %}"></script>
|
|
||||||
<script type="text/javascript" src="{% static 'bootstrap/js/bootstrap.bundle.min.js' %}"></script>
|
|
||||||
|
|
||||||
<!-- general JS -->
|
<!-- general JS -->
|
||||||
|
{% include "third_party_js.html" %}
|
||||||
|
|
||||||
<script type='text/javascript' src="{% static 'script/inventree/inventree.js' %}"></script>
|
<script type='text/javascript' src="{% static 'script/inventree/inventree.js' %}"></script>
|
||||||
<script type='text/javascript' src="{% i18n_static 'notification.js' %}"></script>
|
<script type='text/javascript' src="{% i18n_static 'notification.js' %}"></script>
|
||||||
|
|
||||||
<!-- fontawesome -->
|
|
||||||
<script type='text/javascript' src="{% static 'fontawesome/js/solid.js' %}"></script>
|
|
||||||
<script type='text/javascript' src="{% static 'fontawesome/js/brands.js' %}"></script>
|
|
||||||
<script type='text/javascript' src="{% static 'fontawesome/js/fontawesome.js' %}"></script>
|
|
||||||
|
|
||||||
<!-- 3rd party general js -->
|
|
||||||
<script type="text/javascript" src="{% static 'fullcalendar/main.js' %}"></script>
|
|
||||||
<script type="text/javascript" src="{% static 'fullcalendar/locales-all.js' %}"></script>
|
|
||||||
<script type="text/javascript" src="{% static 'select2/js/select2.full.js' %}"></script>
|
|
||||||
<script type='text/javascript' src="{% static 'script/moment.js' %}"></script>
|
|
||||||
<script type='text/javascript' src="{% static 'script/chart.min.js' %}"></script>
|
|
||||||
<script type='text/javascript' src="{% static 'script/clipboard.min.js' %}"></script>
|
|
||||||
<script type='text/javascript' src="{% static 'script/randomColor.min.js' %}"></script>
|
|
||||||
|
|
||||||
|
|
||||||
<script type='text/javascript'>
|
<script type='text/javascript'>
|
||||||
|
|
||||||
|
|||||||
@@ -39,15 +39,15 @@
|
|||||||
|
|
||||||
<!-- CSS -->
|
<!-- CSS -->
|
||||||
<link rel="stylesheet" href="{% static 'bootstrap/css/bootstrap.min.css' %}">
|
<link rel="stylesheet" href="{% static 'bootstrap/css/bootstrap.min.css' %}">
|
||||||
<link rel="stylesheet" href="{% static 'bootstrap-table/bootstrap-table.css' %}">
|
<link rel="stylesheet" href="{% static 'bootstrap-table/bootstrap-table.min.css' %}">
|
||||||
<link rel="stylesheet" href="{% static 'bootstrap-table/extensions/group-by-v2/bootstrap-table-group-by.css' %}">
|
<link rel="stylesheet" href="{% static 'bootstrap-table/extensions/group-by-v2/bootstrap-table-group-by.min.css' %}">
|
||||||
<link rel="stylesheet" href="{% static 'bootstrap-table/extensions/filter-control/bootstrap-table-filter-control.css' %}">
|
<link rel="stylesheet" href="{% static 'bootstrap-table/extensions/filter-control/bootstrap-table-filter-control.css' %}">
|
||||||
<link rel='stylesheet' href='{% static "treegrid/css/jquery.treegrid.css" %}'>
|
<link rel='stylesheet' href='{% static "treegrid/css/jquery.treegrid.css" %}'>
|
||||||
<link rel="stylesheet" href="{% static 'fontawesome/css/brands.min.css' %}">
|
<link rel="stylesheet" href="{% static 'fontawesome/css/brands.min.css' %}">
|
||||||
<link rel="stylesheet" href="{% static 'fontawesome/css/solid.min.css' %}">
|
<link rel="stylesheet" href="{% static 'fontawesome/css/solid.min.css' %}">
|
||||||
<link rel="stylesheet" href="{% static 'select2/css/select2.css' %}">
|
<link rel="stylesheet" href="{% static 'select2/css/select2.min.css' %}">
|
||||||
<link rel="stylesheet" href="{% static 'select2/css/select2-bootstrap-5-theme.css' %}">
|
<link rel="stylesheet" href="{% static 'select2/css/select2-bootstrap-5-theme.css' %}">
|
||||||
<link rel="stylesheet" href="{% static 'fullcalendar/main.css' %}">
|
<link rel="stylesheet" href="{% static 'fullcalendar/main.min.css' %}">
|
||||||
<link rel="stylesheet" href="{% static 'script/jquery-ui/jquery-ui.min.css' %}">
|
<link rel="stylesheet" href="{% static 'script/jquery-ui/jquery-ui.min.css' %}">
|
||||||
<link rel="stylesheet" href="{% static 'easymde/easymde.min.css' %}">
|
<link rel="stylesheet" href="{% static 'easymde/easymde.min.css' %}">
|
||||||
|
|
||||||
@@ -132,83 +132,48 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% include 'modals.html' %}
|
{% include 'modals.html' %}
|
||||||
{% if show_about %}{% include 'about.html' %}{% endif %}
|
|
||||||
{% include "notifications.html" %}
|
{% include "notifications.html" %}
|
||||||
{% include "search.html" %}
|
{% include "search.html" %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Scripts -->
|
{% include "third_party_js.html" %}
|
||||||
<script type="text/javascript" src="{% static 'script/jquery_3.3.1_jquery.min.js' %}"></script>
|
|
||||||
<script type='text/javascript' src="{% static 'script/jquery.form.min.js' %}"></script>
|
|
||||||
<script type='text/javascript' src="{% static 'script/jquery-ui/jquery-ui.min.js' %}"></script>
|
|
||||||
|
|
||||||
<script type="text/javascript" src="{% static 'bootstrap/js/bootstrap.bundle.min.js' %}"></script>
|
|
||||||
<script type='text/javascript' src="{% static 'script/bootstrap/bootstrap-treeview.js' %}"></script>
|
|
||||||
<script type='text/javascript' src="{% static 'bootstrap-table/bootstrap-table.js' %}"></script>
|
|
||||||
|
|
||||||
<!-- jquery-treegrid -->
|
|
||||||
<script type='text/javascript' src='{% static "treegrid/js/jquery.treegrid.js" %}'></script>
|
|
||||||
<script type='text/javascript' src='{% static "treegrid/js/jquery.treegrid.bootstrap3.js" %}'></script>
|
|
||||||
|
|
||||||
<!-- boostrap-table extensions -->
|
|
||||||
<script type='text/javascript' src='{% static "bootstrap-table/extensions/group-by-v2/bootstrap-table-group-by.js" %}'></script>
|
|
||||||
<script type='text/javascript' src='{% static "bootstrap-table/extensions/filter-control/bootstrap-table-filter-control.js" %}'></script>
|
|
||||||
<script type='text/javascript' src='{% static "bootstrap-table/extensions/treegrid/bootstrap-table-treegrid.js" %}'></script>
|
|
||||||
<script type='text/javascript' src='{% static "bootstrap-table/extensions/custom-view/bootstrap-table-custom-view.js" %}'></script>
|
|
||||||
|
|
||||||
<!-- 3rd party general js -->
|
|
||||||
<script type="text/javascript" src="{% static 'fullcalendar/main.js' %}"></script>
|
|
||||||
<script type="text/javascript" src="{% static 'fullcalendar/locales-all.js' %}"></script>
|
|
||||||
<script type="text/javascript" src="{% static 'select2/js/select2.full.js' %}"></script>
|
|
||||||
<script type='text/javascript' src="{% static 'script/chart.js' %}"></script>
|
|
||||||
<script type='text/javascript' src="{% static 'script/moment.js' %}"></script>
|
|
||||||
<script type='text/javascript' src="{% static 'script/chartjs-adapter-moment.js' %}"></script>
|
|
||||||
<script type='text/javascript' src="{% static 'easymde/easymde.min.js' %}"></script>
|
|
||||||
|
|
||||||
<script type='text/javascript' src="{% static 'script/clipboard.min.js' %}"></script>
|
|
||||||
<script type='text/javascript' src="{% static 'script/randomColor.min.js' %}"></script>
|
|
||||||
<script type='text/javascript' src="{% static 'script/qr-scanner.umd.min.js' %}"></script>
|
|
||||||
|
|
||||||
<!-- general JS -->
|
<!-- general JS -->
|
||||||
<script type='text/javascript' src="{% static 'script/inventree/inventree.js' %}"></script>
|
<script defer type='text/javascript' src="{% static 'script/inventree/inventree.js' %}"></script>
|
||||||
|
|
||||||
<!-- dynamic javascript templates -->
|
<!-- dynamic javascript templates -->
|
||||||
<script type='text/javascript' src="{% url 'calendar.js' %}"></script>
|
<script defer type='text/javascript' src="{% url 'calendar.js' %}"></script>
|
||||||
<script type='text/javascript' src="{% url 'nav.js' %}"></script>
|
<script defer type='text/javascript' src="{% url 'nav.js' %}"></script>
|
||||||
<script type='text/javascript' src="{% url 'settings.js' %}"></script>
|
<script defer type='text/javascript' src="{% url 'settings.js' %}"></script>
|
||||||
|
|
||||||
<!-- translated javascript templates-->
|
<!-- translated javascript templates-->
|
||||||
<script type='text/javascript' src="{% i18n_static 'api.js' %}"></script>
|
<script defer type='text/javascript' src="{% i18n_static 'api.js' %}"></script>
|
||||||
<script type='text/javascript' src="{% i18n_static 'attachment.js' %}"></script>
|
<script defer type='text/javascript' src="{% i18n_static 'attachment.js' %}"></script>
|
||||||
<script type='text/javascript' src="{% i18n_static 'barcode.js' %}"></script>
|
<script defer type='text/javascript' src="{% i18n_static 'barcode.js' %}"></script>
|
||||||
<script type='text/javascript' src="{% i18n_static 'bom.js' %}"></script>
|
<script defer type='text/javascript' src="{% i18n_static 'bom.js' %}"></script>
|
||||||
<script type='text/javascript' src="{% i18n_static 'build.js' %}"></script>
|
<script defer type='text/javascript' src="{% i18n_static 'build.js' %}"></script>
|
||||||
<script type='text/javascript' src="{% i18n_static 'company.js' %}"></script>
|
<script defer type='text/javascript' src="{% i18n_static 'company.js' %}"></script>
|
||||||
<script type='text/javascript' src="{% i18n_static 'filters.js' %}"></script>
|
<script defer type='text/javascript' src="{% i18n_static 'filters.js' %}"></script>
|
||||||
<script type='text/javascript' src="{% i18n_static 'forms.js' %}"></script>
|
<script defer type='text/javascript' src="{% i18n_static 'forms.js' %}"></script>
|
||||||
<script type='text/javascript' src="{% i18n_static 'helpers.js' %}"></script>
|
<script defer type='text/javascript' src="{% i18n_static 'helpers.js' %}"></script>
|
||||||
<script type='text/javascript' src="{% i18n_static 'label.js' %}"></script>
|
<script defer type='text/javascript' src="{% i18n_static 'label.js' %}"></script>
|
||||||
<script type='text/javascript' src="{% i18n_static 'modals.js' %}"></script>
|
<script defer type='text/javascript' src="{% i18n_static 'modals.js' %}"></script>
|
||||||
<script type='text/javascript' src="{% i18n_static 'model_renderers.js' %}"></script>
|
<script defer type='text/javascript' src="{% i18n_static 'model_renderers.js' %}"></script>
|
||||||
<script type='text/javascript' src="{% i18n_static 'order.js' %}"></script>
|
<script defer type='text/javascript' src="{% i18n_static 'order.js' %}"></script>
|
||||||
<script type='text/javascript' src="{% i18n_static 'part.js' %}"></script>
|
<script defer type='text/javascript' src="{% i18n_static 'part.js' %}"></script>
|
||||||
<script type='text/javascript' src="{% i18n_static 'report.js' %}"></script>
|
<script defer type='text/javascript' src="{% i18n_static 'report.js' %}"></script>
|
||||||
<script type='text/javascript' src="{% i18n_static 'search.js' %}"></script>
|
<script defer type='text/javascript' src="{% i18n_static 'search.js' %}"></script>
|
||||||
<script type='text/javascript' src="{% i18n_static 'stock.js' %}"></script>
|
<script defer type='text/javascript' src="{% i18n_static 'stock.js' %}"></script>
|
||||||
<script type='text/javascript' src="{% i18n_static 'plugin.js' %}"></script>
|
<script defer type='text/javascript' src="{% i18n_static 'plugin.js' %}"></script>
|
||||||
<script type='text/javascript' src="{% i18n_static 'tables.js' %}"></script>
|
<script defer type='text/javascript' src="{% i18n_static 'tables.js' %}"></script>
|
||||||
<script type='text/javascript' src="{% i18n_static 'table_filters.js' %}"></script>
|
<script defer type='text/javascript' src="{% i18n_static 'table_filters.js' %}"></script>
|
||||||
<script type='text/javascript' src="{% i18n_static 'notification.js' %}"></script>
|
<script defer type='text/javascript' src="{% i18n_static 'notification.js' %}"></script>
|
||||||
|
|
||||||
<script type='text/javascript' src="{% static 'fontawesome/js/solid.min.js' %}"></script>
|
|
||||||
<script type='text/javascript' src="{% static 'fontawesome/js/regular.min.js' %}"></script>
|
|
||||||
<script type='text/javascript' src="{% static 'fontawesome/js/brands.min.js' %}"></script>
|
|
||||||
<script type='text/javascript' src="{% static 'fontawesome/js/fontawesome.min.js' %}"></script>
|
|
||||||
|
|
||||||
{% block js_load %}
|
{% block js_load %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
<script type='text/javascript'>
|
<script defer type='text/javascript'>
|
||||||
|
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
|
|
||||||
|
|||||||
@@ -2540,7 +2540,7 @@ function loadBuildTable(table, options) {
|
|||||||
if (value) {
|
if (value) {
|
||||||
return row.responsible_detail.name;
|
return row.responsible_detail.name;
|
||||||
} else {
|
} else {
|
||||||
return '{% trans "No information" %}';
|
return '-';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
<div class='card'>
|
<div class='card'>
|
||||||
{% block details_left %}
|
{% block details_left %}
|
||||||
<div class='row'>
|
<div class='row'>
|
||||||
<div class='col' style='max-width: 220px;'>
|
<div class='col' style='max-width: 280px;'>
|
||||||
{% block thumbnail %}
|
{% block thumbnail %}
|
||||||
{% endblock thumbnail %}
|
{% endblock thumbnail %}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{% load static %}
|
{% load static %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
{% load inventree_extras %}
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
@@ -65,15 +66,7 @@
|
|||||||
{% block body_scripts_general %}
|
{% block body_scripts_general %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{% include "third_party_js.html" %}
|
||||||
<!-- 3rd party general js -->
|
|
||||||
<script type="text/javascript" src="{% static 'fullcalendar/main.js' %}"></script>
|
|
||||||
<script type="text/javascript" src="{% static 'fullcalendar/locales-all.js' %}"></script>
|
|
||||||
<script type="text/javascript" src="{% static 'select2/js/select2.full.js' %}"></script>
|
|
||||||
<script type='text/javascript' src="{% static 'script/moment.js' %}"></script>
|
|
||||||
<script type='text/javascript' src="{% static 'script/chart.min.js' %}"></script>
|
|
||||||
<script type='text/javascript' src="{% static 'script/clipboard.min.js' %}"></script>
|
|
||||||
<script type='text/javascript' src="{% static 'script/randomColor.min.js' %}"></script>
|
|
||||||
|
|
||||||
<!-- general JS -->
|
<!-- general JS -->
|
||||||
<script type='text/javascript' src="{% static 'script/inventree/inventree.js' %}"></script>
|
<script type='text/javascript' src="{% static 'script/inventree/inventree.js' %}"></script>
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
{% load static %}
|
||||||
|
|
||||||
|
<!-- jquery -->
|
||||||
|
<script type="text/javascript" src="{% static 'script/jquery_3.3.1_jquery.min.js' %}"></script>
|
||||||
|
<script type='text/javascript' src="{% static 'script/jquery.form.min.js' %}"></script>
|
||||||
|
<script type='text/javascript' src="{% static 'script/jquery-ui/jquery-ui.min.js' %}"></script>
|
||||||
|
|
||||||
|
<!-- Bootstrap-->
|
||||||
|
<script type="text/javascript" src="{% static 'bootstrap/js/bootstrap.bundle.min.js' %}"></script>
|
||||||
|
|
||||||
|
<!-- Bootstrap Table -->
|
||||||
|
<script defer type='text/javascript' src="{% static 'script/bootstrap/bootstrap-treeview.js' %}"></script>
|
||||||
|
<script defer type='text/javascript' src='{% static "treegrid/js/jquery.treegrid.js" %}'></script>
|
||||||
|
<script defer type='text/javascript' src='{% static "treegrid/js/jquery.treegrid.bootstrap3.js" %}'></script>
|
||||||
|
<script defer type='text/javascript' src="{% static 'bootstrap-table/bootstrap-table.min.js' %}"></script>
|
||||||
|
<script defer type='text/javascript' src='{% static "bootstrap-table/extensions/group-by-v2/bootstrap-table-group-by.min.js" %}'></script>
|
||||||
|
<script defer type='text/javascript' src='{% static "bootstrap-table/extensions/filter-control/bootstrap-table-filter-control.min.js" %}'></script>
|
||||||
|
<script defer type='text/javascript' src='{% static "bootstrap-table/extensions/treegrid/bootstrap-table-treegrid.min.js" %}'></script>
|
||||||
|
<script defer type='text/javascript' src='{% static "bootstrap-table/extensions/custom-view/bootstrap-table-custom-view.min.js" %}'></script>
|
||||||
|
|
||||||
|
<!-- fontawesome -->
|
||||||
|
<script defer type='text/javascript' src="{% static 'fontawesome/js/solid.min.js' %}"></script>
|
||||||
|
<script defer type='text/javascript' src="{% static 'fontawesome/js/regular.min.js' %}"></script>
|
||||||
|
<script defer type='text/javascript' src="{% static 'fontawesome/js/brands.min.js' %}"></script>
|
||||||
|
<script defer type='text/javascript' src="{% static 'fontawesome/js/fontawesome.min.js' %}"></script>
|
||||||
|
|
||||||
|
<!-- 3rd party general js -->
|
||||||
|
<script defer type="text/javascript" src="{% static 'fullcalendar/main.min.js' %}"></script>
|
||||||
|
<script defer type="text/javascript" src="{% static 'fullcalendar/locales-all.min.js' %}"></script>
|
||||||
|
<script defer type="text/javascript" src="{% static 'select2/js/select2.full.min.js' %}"></script>
|
||||||
|
<script defer type='text/javascript' src="{% static 'script/moment.js' %}"></script>
|
||||||
|
<script defer type='text/javascript' src="{% static 'script/chart.js' %}"></script>
|
||||||
|
<script defer type='text/javascript' src="{% static 'script/chartjs-adapter-moment.js' %}"></script>
|
||||||
|
<script defer type='text/javascript' src="{% static 'script/clipboard.min.js' %}"></script>
|
||||||
|
<script defer type='text/javascript' src="{% static 'easymde/easymde.min.js' %}"></script>
|
||||||
|
<script defer type='text/javascript' src="{% static 'script/randomColor.min.js' %}"></script>
|
||||||
|
<script defer type='text/javascript' src="{% static 'script/qr-scanner.umd.min.js' %}"></script>
|
||||||
+53
-11
@@ -6,6 +6,7 @@ from django.contrib.auth import get_user_model
|
|||||||
from django.contrib.auth.models import Group, Permission
|
from django.contrib.auth.models import Group, Permission
|
||||||
from django.contrib.contenttypes.fields import GenericForeignKey
|
from django.contrib.contenttypes.fields import GenericForeignKey
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
from django.core.cache import cache
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import Q, UniqueConstraint
|
from django.db.models import Q, UniqueConstraint
|
||||||
from django.db.models.signals import post_delete, post_save
|
from django.db.models.signals import post_delete, post_save
|
||||||
@@ -474,13 +475,19 @@ def update_group_roles(group, debug=False):
|
|||||||
logger.info(f"Adding permission {child_perm} to group {group.name}")
|
logger.info(f"Adding permission {child_perm} to group {group.name}")
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_save, sender=Group, dispatch_uid='create_missing_rule_sets')
|
def clear_user_role_cache(user):
|
||||||
def create_missing_rule_sets(sender, instance, **kwargs):
|
"""Remove user role permission information from the cache.
|
||||||
"""Called *after* a Group object is saved.
|
|
||||||
|
|
||||||
As the linked RuleSet instances are saved *before* the Group, then we can now use these RuleSet values to update the group permissions.
|
- This function is called whenever the user / group is updated
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user: The User object to be expunged from the cache
|
||||||
"""
|
"""
|
||||||
update_group_roles(instance)
|
|
||||||
|
for role in RuleSet.RULESET_MODELS.keys():
|
||||||
|
for perm in ['add', 'change', 'view', 'delete']:
|
||||||
|
key = f"role_{user}_{role}_{perm}"
|
||||||
|
cache.delete(key)
|
||||||
|
|
||||||
|
|
||||||
def check_user_role(user, role, permission):
|
def check_user_role(user, role, permission):
|
||||||
@@ -491,6 +498,17 @@ def check_user_role(user, role, permission):
|
|||||||
if user.is_superuser:
|
if user.is_superuser:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
# First, check the cache
|
||||||
|
key = f"role_{user}_{role}_{permission}"
|
||||||
|
|
||||||
|
result = cache.get(key)
|
||||||
|
|
||||||
|
if result is not None:
|
||||||
|
return result
|
||||||
|
|
||||||
|
# Default for no match
|
||||||
|
result = False
|
||||||
|
|
||||||
for group in user.groups.all():
|
for group in user.groups.all():
|
||||||
|
|
||||||
for rule in group.rule_sets.all():
|
for rule in group.rule_sets.all():
|
||||||
@@ -498,19 +516,24 @@ def check_user_role(user, role, permission):
|
|||||||
if rule.name == role:
|
if rule.name == role:
|
||||||
|
|
||||||
if permission == 'add' and rule.can_add:
|
if permission == 'add' and rule.can_add:
|
||||||
return True
|
result = True
|
||||||
|
break
|
||||||
|
|
||||||
if permission == 'change' and rule.can_change:
|
if permission == 'change' and rule.can_change:
|
||||||
return True
|
result = True
|
||||||
|
break
|
||||||
|
|
||||||
if permission == 'view' and rule.can_view:
|
if permission == 'view' and rule.can_view:
|
||||||
return True
|
result = True
|
||||||
|
break
|
||||||
|
|
||||||
if permission == 'delete' and rule.can_delete:
|
if permission == 'delete' and rule.can_delete:
|
||||||
return True
|
result = True
|
||||||
|
break
|
||||||
|
|
||||||
# No matching permissions found
|
# Save result to cache
|
||||||
return False
|
cache.set(key, result, timeout=3600)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
class Owner(models.Model):
|
class Owner(models.Model):
|
||||||
@@ -659,3 +682,22 @@ def delete_owner(sender, instance, **kwargs):
|
|||||||
"""Callback function to delete an owner instance after either a new group or user instance is deleted."""
|
"""Callback function to delete an owner instance after either a new group or user instance is deleted."""
|
||||||
owner = Owner.get_owner(instance)
|
owner = Owner.get_owner(instance)
|
||||||
owner.delete()
|
owner.delete()
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(post_save, sender=get_user_model(), dispatch_uid='clear_user_cache')
|
||||||
|
def clear_user_cache(sender, instance, **kwargs):
|
||||||
|
"""Callback function when a user object is saved"""
|
||||||
|
|
||||||
|
clear_user_role_cache(instance)
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(post_save, sender=Group, dispatch_uid='create_missing_rule_sets')
|
||||||
|
def create_missing_rule_sets(sender, instance, **kwargs):
|
||||||
|
"""Called *after* a Group object is saved.
|
||||||
|
|
||||||
|
As the linked RuleSet instances are saved *before* the Group, then we can now use these RuleSet values to update the group permissions.
|
||||||
|
"""
|
||||||
|
update_group_roles(instance)
|
||||||
|
|
||||||
|
for user in get_user_model().objects.filter(groups__name=instance.name):
|
||||||
|
clear_user_role_cache(user)
|
||||||
|
|||||||
Reference in New Issue
Block a user