Basic email template for notifications #96
1
.gitmodules
vendored
1
.gitmodules
vendored
@ -1,3 +1,4 @@
|
||||
[submodule "assets_shared"]
|
||||
path = assets_shared
|
||||
url = https://projects.blender.org/infrastructure/web-assets.git
|
||||
branch = v2
|
||||
|
@ -24,7 +24,7 @@
|
||||
<div class="ext-detail-tagline">
|
||||
<a href="{{ extension.get_absolute_url }}">{{ extension.name }}</a>
|
||||
</div>
|
||||
<div class="ext-detail-authors ml-3">
|
||||
<div class="ext-detail-authors ms-3">
|
||||
<a href="{% url 'extensions:by-type' type_slug=extension.type_slug %}">
|
||||
{{ extension.get_type_display }}
|
||||
</a>
|
||||
@ -44,7 +44,7 @@
|
||||
|
||||
{% block hero_tabs %}
|
||||
<nav class="hero-tabs">
|
||||
<span class="ml-auto"></span>
|
||||
<span class="ms-auto"></span>
|
||||
|
||||
<div class="btn-row mb-1">
|
||||
{% if request.user.is_staff %}
|
||||
@ -88,7 +88,7 @@
|
||||
<div class="dl-row">
|
||||
<div class="dl-col">
|
||||
<dt>Status</dt>
|
||||
<dd>{% include "common/components/status.html" with class="d-block" %}</dd>
|
||||
<dd>{% include "common/components/status.html" %}</dd>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dl-row">
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 9d428a82a5b51c1eec99639f3baebeac3b1f93f9
|
||||
Subproject commit af61a962e1a30898279b4efdbb07a2dcb230a257
|
@ -5,7 +5,7 @@ function galleriaCloneFirstItem() {
|
||||
let firstGalleriaItem = galleriaCarrousel.firstElementChild.cloneNode(true);
|
||||
firstGalleriaItem.classList.remove('js-galleria-item-preview', 'is-active');
|
||||
firstGalleriaItem.classList.add('js-expand-on-click');
|
||||
firstGalleriaItem.id = 'galleria-item-large';
|
||||
firstGalleriaItem.id = 'galleria-item-lg';
|
||||
|
||||
document.getElementById("galleria-container").prepend(firstGalleriaItem);
|
||||
}
|
||||
@ -13,7 +13,7 @@ function galleriaCloneFirstItem() {
|
||||
|
||||
function galleriaSetLargePreview(item) {
|
||||
let previewsContainer = document.getElementById('galleria-items');
|
||||
let previewLarge = document.getElementById('galleria-item-large');
|
||||
let previewLarge = document.getElementById('galleria-item-lg');
|
||||
let thumbnails = document.getElementsByClassName("js-galleria-item-preview");
|
||||
[].forEach.call(thumbnails, function(el) {
|
||||
el.classList.remove("is-active");
|
||||
|
@ -4,7 +4,7 @@
|
||||
z-index: 0
|
||||
|
||||
> li
|
||||
--border-color: var(--box-background-color)
|
||||
--border-color: var(--box-bg-color)
|
||||
position: relative
|
||||
|
||||
&:first-child
|
||||
@ -16,7 +16,7 @@
|
||||
&:last-child
|
||||
/* Remove bottom half of the vertical line for last item. */
|
||||
.comment-card:before
|
||||
height: calc(50% - 1rem)
|
||||
height: calc(50% - var(--spacer))
|
||||
.activity-status-change:before
|
||||
height: calc(50% + var(--border-width))
|
||||
|
||||
@ -50,21 +50,25 @@
|
||||
left: var(--border-width)
|
||||
position: absolute
|
||||
top: 50%
|
||||
width: 2rem
|
||||
width: calc(var(--spacer) * 2)
|
||||
z-index: -1
|
||||
|
||||
.activity-icon
|
||||
top: 1.2rem
|
||||
|
||||
.profile-avatar
|
||||
border: var(--border-width) solid var(--border-color)
|
||||
background-color: var(--border-color)
|
||||
|
||||
.comment-card
|
||||
&:after
|
||||
top: 2rem
|
||||
top: 3.2rem
|
||||
|
||||
.activity-icon
|
||||
top: 1.25rem
|
||||
top: 2.2rem
|
||||
|
||||
.activity-status-change
|
||||
color: var(--text-color-tertiary)
|
||||
color: var(--color-text-tertiary)
|
||||
|
||||
.profile-avatar
|
||||
+margin(3, right)
|
||||
@ -73,7 +77,7 @@
|
||||
left: 0
|
||||
|
||||
strong
|
||||
color: var(--text-color-secondary)
|
||||
color: var(--color-text-secondary)
|
||||
|
||||
.badge
|
||||
border: none
|
||||
@ -83,22 +87,22 @@
|
||||
&.activity-status-approved
|
||||
.activity-icon
|
||||
border-color: var(--color-success)
|
||||
box-shadow: 0 0 1rem var(--color-success-bg)
|
||||
box-shadow: 0 0 var(--spacer) var(--color-success-bg)
|
||||
color: var(--color-success-text)
|
||||
|
||||
.activity-icon
|
||||
align-items: center
|
||||
background-color: var(--background-color)
|
||||
background-color: var(--color-bg)
|
||||
border-radius: 100%
|
||||
border: var(--border-width) solid var(--border-color)
|
||||
color: var(--text-color-tertiary)
|
||||
color: var(--color-text-tertiary)
|
||||
display: flex
|
||||
font-size: var(--font-size-small)
|
||||
height: 1.5rem
|
||||
font-size: var(--fs-sm)
|
||||
height: var(--spacer-4)
|
||||
justify-content: center
|
||||
left: -.66rem
|
||||
position: absolute
|
||||
width: 1.5rem
|
||||
width: var(--spacer-4)
|
||||
|
||||
/* Comment form */
|
||||
.comment-form
|
||||
@ -112,9 +116,6 @@
|
||||
select
|
||||
width: auto
|
||||
|
||||
button[type="submit"]
|
||||
min-width: 50%
|
||||
|
||||
textarea
|
||||
height: calc(var(--spacer) * 8)
|
||||
max-height: 0
|
||||
|
@ -1,17 +1,24 @@
|
||||
.badge-card
|
||||
+border-radius(lg)
|
||||
border-bottom-left-radius: 0
|
||||
border-bottom-right-radius: 0
|
||||
display: flex
|
||||
+padding(2, y)
|
||||
|
||||
a.badge-tag
|
||||
--badge-color: var(--text-color-secondary)
|
||||
--badge-bg: var(--text-color-tertiary)
|
||||
--badge-color: var(--color-text-secondary)
|
||||
--badge-bg: var(--color-text-tertiary)
|
||||
|
||||
background-color: transparent
|
||||
text-decoration: none !important
|
||||
|
||||
&:hover
|
||||
background-color: transparent
|
||||
border-color: var(--text-color)
|
||||
color: var(--text-color)
|
||||
border-color: var(--color-text)
|
||||
color: var(--color-text)
|
||||
|
||||
.badge-tag
|
||||
font-size: var(--font-size-extra-small)
|
||||
font-size: var(--fs-xs)
|
||||
|
||||
.badge-status
|
||||
&-approved
|
||||
@ -24,10 +31,3 @@ a.badge-tag
|
||||
&-disabled-by-staff,
|
||||
&-disabled-by-author
|
||||
@extend .badge-secondary
|
||||
|
||||
.card-badge
|
||||
+border-radius(lg)
|
||||
border-bottom-left-radius: 0
|
||||
border-bottom-right-radius: 0
|
||||
display: flex
|
||||
+padding(2, y)
|
||||
|
29
common/static/common/styles/_cards.sass
Normal file
29
common/static/common/styles/_cards.sass
Normal file
@ -0,0 +1,29 @@
|
||||
.card
|
||||
@extend .box
|
||||
|
||||
+media-sm
|
||||
--cards-items-per-row: 2
|
||||
|
||||
+media-md
|
||||
--cards-items-per-row: 3
|
||||
|
||||
+media-lg
|
||||
--cards-items-per-row: 4
|
||||
|
||||
.cards-item-content
|
||||
overflow: hidden
|
||||
|
||||
.crads-item-excerpt
|
||||
line-height: calc(24 / 18)
|
||||
|
||||
.cards-item-extra
|
||||
text-transform: none
|
||||
|
||||
.cards-item-extra-rating-stars
|
||||
margin-bottom: .2rem
|
||||
|
||||
.stars
|
||||
font-size: 1.4rem
|
||||
|
||||
.cards-item-title
|
||||
+padding(0, y)
|
@ -11,33 +11,36 @@
|
||||
z-index: 0
|
||||
|
||||
&:before
|
||||
background-color: var(--box-background-color)
|
||||
border-radius: .25rem
|
||||
background-color: var(--box-bg-color)
|
||||
border-radius: .4rem
|
||||
content: ''
|
||||
display: block
|
||||
height: 1rem
|
||||
height: var(--spacer)
|
||||
left: -.33rem
|
||||
position: absolute
|
||||
rotate: 45deg
|
||||
top: 1rem
|
||||
width: 1rem
|
||||
top: var(--spacer)
|
||||
width: var(--spacer)
|
||||
z-index: -1
|
||||
|
||||
p:last-child
|
||||
margin-bottom: 0
|
||||
|
||||
header
|
||||
color: var(--text-color-secondary)
|
||||
font-size: var(--font-size-small)
|
||||
color: var(--color-text-secondary)
|
||||
font-size: var(--fs-sm)
|
||||
+margin(2, bottom)
|
||||
|
||||
ul
|
||||
align-items: center
|
||||
display: flex
|
||||
+list-unstyled
|
||||
gap: 1rem
|
||||
gap: var(--spacer)
|
||||
margin: 0
|
||||
|
||||
li
|
||||
line-height: var(--lh-sm)
|
||||
|
||||
aside
|
||||
+margin(2, top)
|
||||
|
||||
|
@ -1,14 +1,17 @@
|
||||
\:root
|
||||
--lh-sm: 2.4rem
|
||||
|
||||
.hero.extension-detail
|
||||
--hero-max-height: 0
|
||||
--hero-min-height: 240px
|
||||
--font-size-hero-title: clamp(3rem, 4vw + 1rem, 48px)
|
||||
--font-size-large: 18px
|
||||
--border-width: 2px
|
||||
--hero-background-color: hsl(213, 10%, 14%)
|
||||
--hero-min-height: 24.0rem
|
||||
--fs-hero-title: clamp(4.8rem, 4vw + 1.6rem, 4.8rem)
|
||||
--fs-lg: 1.8rem
|
||||
--border-width: .2rem
|
||||
--hero-bg-color: hsl(213, 10%, 14%)
|
||||
|
||||
background-color: var(--hero-background-color)
|
||||
background-color: var(--hero-bg-color)
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='40' height='40' viewBox='0 0 40 40'%3E%3Cg fill-rule='evenodd'%3E%3Cg fill='%233e4248' fill-opacity='0.21'%3E%3Cpath d='M0 38.59l2.83-2.83 1.41 1.41L1.41 40H0v-1.41zM0 1.4l2.83 2.83 1.41-1.41L1.41 0H0v1.41zM38.59 40l-2.83-2.83 1.41-1.41L40 38.59V40h-1.41zM40 1.41l-2.83 2.83-1.41-1.41L38.59 0H40v1.41zM20 18.6l2.83-2.83 1.41 1.41L21.41 20l2.83 2.83-1.41 1.41L20 21.41l-2.83 2.83-1.41-1.41L18.59 20l-2.83-2.83 1.41-1.41L20 18.59z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E")
|
||||
background-size: 40px
|
||||
background-size: 4.0rem
|
||||
flex-direction: column
|
||||
overflow: initial
|
||||
text-shadow: none
|
||||
@ -24,10 +27,10 @@
|
||||
|
||||
.hero-overlay
|
||||
background-color: transparent
|
||||
background-image: linear-gradient(0deg, var(--background-color), hsla(213, 10%, 14%, 0))
|
||||
background-image: linear-gradient(0deg, var(--color-bg), hsla(213, 10%, 14%, 0))
|
||||
|
||||
&.extension-review
|
||||
--hero-min-height: 210px
|
||||
--hero-min-height: 21.0rem
|
||||
|
||||
.ext-detail-download-danger
|
||||
background-color: var(--color-danger-bg)
|
||||
@ -42,8 +45,8 @@
|
||||
@extend .alert
|
||||
@extend .alert-danger
|
||||
border-radius: 0
|
||||
font-size: var(--font-size-small)
|
||||
+font-weight-bold
|
||||
font-size: var(--fs-sm)
|
||||
+fw-bold
|
||||
+padding(1, y)
|
||||
text-align: center
|
||||
|
||||
@ -54,17 +57,17 @@
|
||||
color: var(--color-warning-text);
|
||||
|
||||
.hero-breadcrumbs
|
||||
font-size: var(--font-size-small)
|
||||
font-size: var(--fs-sm)
|
||||
|
||||
a
|
||||
color: var(--text-color-secondary)
|
||||
color: var(--color-text-secondary)
|
||||
display: inline-block
|
||||
+padding(2)
|
||||
|
||||
.ext-detail-name
|
||||
font-size: var(--font-size-title-massive)
|
||||
+font-weight-title
|
||||
line-height: var(--font-size-title-massive)
|
||||
font-size: var(--fs-title-massive)
|
||||
+fw-title
|
||||
line-height: var(--fs-title-massive)
|
||||
margin-bottom: 0
|
||||
|
||||
.ext-detail-info-authors
|
||||
@ -72,7 +75,7 @@
|
||||
flex-wrap: wrap
|
||||
|
||||
.ext-detail-authors
|
||||
color: var(--text-color-secondary)
|
||||
color: var(--color-text-secondary)
|
||||
|
||||
.ext-detail-tagline
|
||||
+margin(2, bottom)
|
||||
@ -81,9 +84,12 @@
|
||||
+padding(4)
|
||||
+style-rich-text
|
||||
|
||||
pre
|
||||
+margin(3, bottom)
|
||||
|
||||
.ext-detail-info
|
||||
dd
|
||||
color: var(--text-color)
|
||||
color: var(--color-text)
|
||||
overflow: hidden
|
||||
text-overflow: ellipsis
|
||||
white-space: nowrap
|
||||
@ -93,8 +99,9 @@
|
||||
margin-bottom: 0
|
||||
|
||||
dt
|
||||
color: var(--text-color-secondary)
|
||||
font-size: var(--font-size-small)
|
||||
color: var(--color-text-secondary)
|
||||
font-size: var(--fs-sm)
|
||||
line-height: calc(24 / 14)
|
||||
|
||||
dd
|
||||
font-family: var(--font-family-body)
|
||||
@ -108,7 +115,7 @@
|
||||
white-space: nowrap
|
||||
|
||||
&:hover
|
||||
color: var(--text-color-primary)
|
||||
color: var(--color-text-primary)
|
||||
|
||||
.dl-col
|
||||
overflow: hidden
|
||||
@ -134,10 +141,10 @@
|
||||
padding: 0
|
||||
|
||||
strong
|
||||
font-size: var(--font-size-large)
|
||||
font-size: var(--fs-lg)
|
||||
|
||||
i
|
||||
font-size: var(--font-size-large)
|
||||
font-size: var(--fs-lg)
|
||||
+margin(3, right)
|
||||
|
||||
.ext-detail-download
|
||||
@ -145,7 +152,7 @@
|
||||
+padding(2, y)
|
||||
|
||||
.btn-accent
|
||||
box-shadow: 2px 5px 5px rgba(0,82,255,.102), 1px 10px 15px rgba(0,82,255,.102), 2px 10px 30px rgba(0,82,255,.349)
|
||||
box-shadow: .2rem .8rem .8rem rgba(0,82,255,.102), 1.6rem 1.0rem 1.8rem rgba(0,82,255,.102), 3.2rem 1.0rem 3.2rem rgba(0,82,255,.349)
|
||||
|
||||
.btn-install-drag,
|
||||
.btn-install-drag:active
|
||||
@ -160,134 +167,21 @@
|
||||
summary
|
||||
.date
|
||||
+margin(2, left)
|
||||
color: var(--text-color-secondary)
|
||||
+font-weight-normal
|
||||
|
||||
.cards-list
|
||||
+media-sm
|
||||
--cards-list-items-per-row: 2
|
||||
+media-md
|
||||
--cards-list-items-per-row: 3
|
||||
+media-lg
|
||||
--cards-list-items-per-row: 4
|
||||
|
||||
.ext-card
|
||||
+box-card
|
||||
display: flex
|
||||
flex-direction: column
|
||||
height: 100%
|
||||
overflow: hidden
|
||||
transition: box-shadow ease-in-out 1s
|
||||
|
||||
&:hover
|
||||
box-shadow: 10px 10px 20px 0px rgba(0, 0, 0, .04), -10px 0 20px 0px rgba(0, 0, 0, .04)
|
||||
|
||||
&.is-background-blur
|
||||
background-color: hsl(213, 10%, 21%)
|
||||
border: thin solid hsl(213, 10%, 20%)
|
||||
position: relative
|
||||
|
||||
.ext-card-body
|
||||
--text-color-secondary: hsla(213, 40%, 90%, .6)
|
||||
|
||||
border-bottom-left-radius: var(--border-radius-lg)
|
||||
border-bottom-right-radius: var(--border-radius-lg)
|
||||
+padding(1, top)
|
||||
mix-blend-mode: screen
|
||||
position: relative
|
||||
z-index: 1
|
||||
|
||||
&:has(.ext-card-admin)
|
||||
.ext-card-body
|
||||
border-radius: 0
|
||||
|
||||
.ext-card-thumbnail-img
|
||||
-webkit-mask-image: -webkit-gradient(linear, left 60%, left bottom, from(rgba(0,0,0,1)), to(rgba(0,0,0,0)))
|
||||
|
||||
.ext-card-thumbnail:hover
|
||||
&+.ext-card-body .ext-card-title
|
||||
color: var(--text-color-primary)
|
||||
|
||||
&.ext-card-row
|
||||
flex-direction: row
|
||||
+margin(3, bottom)
|
||||
|
||||
.ext-card-thumbnail
|
||||
--card-thumbnail-width: 240px
|
||||
border-top-right-radius: 0
|
||||
border-bottom-left-radius: var(--border-radius-lg)
|
||||
height: 100%
|
||||
|
||||
img
|
||||
border-top-right-radius: 0
|
||||
border-bottom-left-radius: var(--border-radius-lg)
|
||||
|
||||
.ext-blender-version
|
||||
display: inline-block
|
||||
|
||||
.ext-card-thumbnail-blur
|
||||
bottom: 0
|
||||
filter: blur(50px)
|
||||
left: 0
|
||||
position: absolute
|
||||
right: 0
|
||||
transform: scale(1.25)
|
||||
top: 0
|
||||
z-index: 0
|
||||
opacity: .5
|
||||
|
||||
.ext-card-thumbnail
|
||||
--card-thumbnail-width: 100%
|
||||
|
||||
align-items: center
|
||||
border-top-left-radius: var(--border-radius-lg)
|
||||
border-top-right-radius: var(--border-radius-lg)
|
||||
display: block
|
||||
justify-content: center
|
||||
max-width: var(--card-thumbnail-width)
|
||||
overflow: hidden
|
||||
|
||||
.ext-card-thumbnail-img
|
||||
background-position: center
|
||||
background-size: cover
|
||||
+make-aspect-ratio('16x9')
|
||||
transition: transform ease-out var(--transition-speed)
|
||||
|
||||
.ext-card-body
|
||||
display: flex
|
||||
flex: 1
|
||||
flex-direction: column
|
||||
justify-content: space-between
|
||||
+padding(3)
|
||||
|
||||
p
|
||||
line-height: 1.2
|
||||
|
||||
.ext-card-title
|
||||
font-size: var(--font-size-large)
|
||||
+margin(3, bottom)
|
||||
transition: color var(--transition-speed)
|
||||
|
||||
a
|
||||
text-decoration: none
|
||||
color: var(--color-text-secondary)
|
||||
+fw-normal
|
||||
|
||||
.ext-list-details
|
||||
@extend .list-inline
|
||||
|
||||
align-items: center
|
||||
color: var(--text-color-secondary)
|
||||
font-size: var(--font-size-small)
|
||||
color: var(--color-text-secondary)
|
||||
font-size: var(--fs-sm)
|
||||
line-height: var(--lh-sm)
|
||||
margin: auto 0 0 0
|
||||
|
||||
&+.ext-list-details
|
||||
+margin(2, top)
|
||||
|
||||
.ext-card-tags
|
||||
display: flex
|
||||
flex-wrap: wrap
|
||||
gap: .25rem
|
||||
justify-content: flex-start
|
||||
|
||||
/* Show only on row list view.*/
|
||||
.ext-blender-version
|
||||
display: none
|
||||
@ -295,19 +189,6 @@
|
||||
.ext-edit-field-row
|
||||
+margin(2, top)
|
||||
|
||||
.ext-card-admin
|
||||
align-items: center
|
||||
background-color: hsla(213, 80%, 1%, .33)
|
||||
border-bottom-left-radius: var(--border-radius-lg)
|
||||
border-bottom-right-radius: var(--border-radius-lg)
|
||||
border-top: var(--border-width) solid var(--border-color)
|
||||
display: flex
|
||||
justify-content: space-between
|
||||
z-index: 1
|
||||
|
||||
dd
|
||||
font-family: var(--font-body)
|
||||
|
||||
.previews-upload
|
||||
+box-card
|
||||
+padding(3)
|
||||
@ -316,27 +197,29 @@
|
||||
.previews-list
|
||||
display: flex
|
||||
flex-direction: column
|
||||
gap: .5rem
|
||||
gap: .8rem
|
||||
|
||||
.previews-list-item
|
||||
--preview-thumbnail-max-size: 180px
|
||||
--preview-thumbnail-max-size: calc(12.4rem * 16 / 9)
|
||||
|
||||
align-items: center
|
||||
align-items: start
|
||||
background-color:
|
||||
border-radius: var(--border-radius-lg)
|
||||
border: var(--border-width) solid var(--border-color)
|
||||
display: flex
|
||||
+padding(1, y)
|
||||
+padding(2, y)
|
||||
|
||||
.previews-list-item-thumbnail
|
||||
margin: 0
|
||||
+margin(2, y)
|
||||
width: var(--preview-thumbnail-max-size)
|
||||
|
||||
.previews-list-item-thumbnail-img
|
||||
background-color: var(--background-color)
|
||||
background-color: var(--color-bg)
|
||||
background-position: center
|
||||
background-size: cover
|
||||
border-radius: var(--border-radius)
|
||||
height: 12.4rem
|
||||
+make-aspect-ratio('16x9')
|
||||
|
||||
.details
|
||||
@ -344,7 +227,8 @@
|
||||
flex: 1
|
||||
|
||||
label
|
||||
font-size: var(--font-size-small)
|
||||
font-size: var(--fs-sm)
|
||||
line-height: var(--lh-sm)
|
||||
|
||||
ul
|
||||
+list-unstyled
|
||||
@ -365,7 +249,7 @@
|
||||
|
||||
.form-control
|
||||
&[type="file"]
|
||||
font-size: var(--font-size-extra-small)
|
||||
font-size: var(--fs-xs)
|
||||
max-width: 50%
|
||||
|
||||
.ext-version-history
|
||||
@ -374,49 +258,52 @@
|
||||
|
||||
ul
|
||||
@extend .list-inline
|
||||
color: var(--text-color-secondary)
|
||||
+font-weight-normal
|
||||
gap: 0 1rem
|
||||
color: var(--color-text-secondary)
|
||||
+fw-normal
|
||||
gap: 0 1.6rem
|
||||
margin: 0
|
||||
+margin(3, right)
|
||||
|
||||
.blender-version
|
||||
color: var(--text-color-secondary)
|
||||
+font-weight-normal
|
||||
color: var(--color-text-secondary)
|
||||
+fw-normal
|
||||
+margin(3, left)
|
||||
|
||||
details[open]
|
||||
details
|
||||
padding: 0
|
||||
|
||||
&[open]
|
||||
.show-on-collapse
|
||||
display: none
|
||||
|
||||
.ext-detail-info
|
||||
.ext-detail-permissions
|
||||
strong
|
||||
font-size: var(--font-size-normal)
|
||||
font-size: var(--fs-normal)
|
||||
|
||||
small
|
||||
display: block
|
||||
|
||||
i
|
||||
font-size: var(--font-size-normal)
|
||||
font-size: var(--fs-normal)
|
||||
+margin(2, right)
|
||||
|
||||
/* Settings */
|
||||
.settings
|
||||
.form-control
|
||||
&[disabled]
|
||||
--input-bg-color: var(--background-color)
|
||||
--input-color-bg: var(--color-bg)
|
||||
|
||||
background-color: var(--input-bg-color)
|
||||
color: var(--text-color-secondary)
|
||||
background-color: var(--input-color-bg)
|
||||
color: var(--color-text-secondary)
|
||||
|
||||
&:hover
|
||||
--input-bg-color-hover: var(--input-bg-color)
|
||||
--input-color-bg-hover: var(--input-color-bg)
|
||||
|
||||
cursor: not-allowed
|
||||
|
||||
& + i.i-lock
|
||||
color: var(--text-color-secondary)
|
||||
color: var(--color-text-secondary)
|
||||
position: absolute
|
||||
right: var(--spacer)
|
||||
|
||||
@ -430,7 +317,7 @@
|
||||
+margin(2, right)
|
||||
|
||||
.ext-review-list
|
||||
color: var(--text-color-secondary)
|
||||
color: var(--color-text-secondary)
|
||||
|
||||
th
|
||||
+padding(3, x)
|
||||
@ -440,7 +327,7 @@
|
||||
transition: background-color var(--transition-speed-fast)
|
||||
|
||||
a
|
||||
color: var(--text-color)
|
||||
color: var(--color-text)
|
||||
+padding(1, y)
|
||||
padding-inline: 0 !important
|
||||
|
||||
@ -456,3 +343,36 @@
|
||||
.ext-review-list-activity
|
||||
display: flex
|
||||
+padding(0, x)
|
||||
|
||||
.rating-form
|
||||
select
|
||||
color: var(--color-warning)
|
||||
|
||||
&:active,
|
||||
&:hover,
|
||||
&:focus
|
||||
color: var(--color-warning)
|
||||
|
||||
// TODO: consider adding component boxed nav generic to web-assets, and make variants on top of that
|
||||
.nav-pills
|
||||
@extend .dropdown-menu
|
||||
|
||||
box-shadow: none
|
||||
display: block
|
||||
position: relative
|
||||
|
||||
.nav-pills-item
|
||||
@extend .dropdown-item
|
||||
|
||||
+margin(1, bottom)
|
||||
|
||||
&.active
|
||||
background-color: var(--color-accent-bg)
|
||||
|
||||
&:last-child
|
||||
+margin(0, bottom)
|
||||
|
||||
.nav-pills-divider
|
||||
@extend .dropdown-divider
|
||||
|
||||
+margin(0, top)
|
||||
|
@ -1,3 +1,18 @@
|
||||
.form-check-input,
|
||||
.form-check-label
|
||||
&:hover
|
||||
cursor: pointer
|
||||
|
||||
.form-check-input
|
||||
height: var(--spacer-4)
|
||||
|
||||
.form-check-label
|
||||
+margin(2, left)
|
||||
|
||||
.form-control
|
||||
&[type="file"]
|
||||
height: calc(var(--spacer) * 2.5)
|
||||
|
||||
/* Override Tagger's styling. */
|
||||
.was-validated .form-control:invalid,
|
||||
.form-control.is-invalid
|
||||
|
@ -1,7 +1,7 @@
|
||||
.galleria-container
|
||||
--extension-thumbnail-width: 140px
|
||||
--extension-thumbnail-width: 14.0rem
|
||||
|
||||
background-color: var(--background-color-secondary)
|
||||
background-color: var(--color-bg-secondary)
|
||||
border-radius: var(--border-radius-lg)
|
||||
+padding(2)
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
|
||||
.galleria-items
|
||||
display: flex
|
||||
gap: .5rem
|
||||
gap: var(--spacer-2)
|
||||
overflow-x: auto
|
||||
+padding(2, top)
|
||||
scroll-behavior: smooth
|
||||
@ -25,7 +25,7 @@
|
||||
display: none
|
||||
|
||||
&::-webkit-scrollbar
|
||||
height: 10px
|
||||
height: 1.0rem
|
||||
width: 100%
|
||||
|
||||
&::-webkit-scrollbar-thumb
|
||||
@ -33,7 +33,7 @@
|
||||
border-radius: 999em
|
||||
|
||||
&::-webkit-scrollbar-track
|
||||
background-color: hsl(var(--background-color-h), var(--background-color-s), 80%)
|
||||
background-color: hsl(var(--color-bg-h), var(--color-bg-s), 80%)
|
||||
|
||||
.galleria-item
|
||||
cursor: pointer
|
||||
@ -43,7 +43,7 @@
|
||||
|
||||
.galleria-item-type-video
|
||||
&::after
|
||||
font-size: 2rem
|
||||
font-size: calc(var(--spacer) * 2)
|
||||
|
||||
.galleria-item
|
||||
+border-radius
|
||||
@ -69,14 +69,14 @@
|
||||
transform: translate(-50%, -50%)
|
||||
width: initial
|
||||
height: initial
|
||||
gap: 1rem
|
||||
gap: var(--spacer)
|
||||
|
||||
|
||||
&.is-active
|
||||
background-color: var(--color-primary)
|
||||
background-color: var(--color-accent)
|
||||
|
||||
img
|
||||
clip-path: inset(0.2rem 0.2rem 0.2rem 0.2rem)
|
||||
clip-path: inset(.2rem .2rem .2rem .2rem)
|
||||
|
||||
img
|
||||
clip-path: inset(0 0 0 0)
|
||||
@ -92,7 +92,7 @@
|
||||
color: white
|
||||
content: '\e83e'
|
||||
font-family: 'fontutti'
|
||||
font-size: 4rem
|
||||
font-size: 5.6rem
|
||||
left: 50%
|
||||
top: 50%
|
||||
pointer-events: none
|
||||
@ -120,7 +120,7 @@
|
||||
background: transparent
|
||||
border: none
|
||||
cursor: pointer
|
||||
font-size: 4rem
|
||||
font-size: 5.6rem
|
||||
height: 100vh
|
||||
max-width: 200px
|
||||
opacity: .6
|
||||
@ -143,7 +143,7 @@
|
||||
|
||||
&.btn-close
|
||||
fill: white
|
||||
font-size: 2rem
|
||||
font-size: 3.2rem
|
||||
height: 20vh
|
||||
max-height: 80px
|
||||
max-width: 80px
|
||||
@ -174,9 +174,9 @@
|
||||
|
||||
.indicator
|
||||
background-color: rgba(black, .5)
|
||||
bottom: 1rem
|
||||
bottom: var(--spacer)
|
||||
color: white
|
||||
+font-weight-bold
|
||||
+fw-bold
|
||||
min-width: 3ch
|
||||
+padding(2, x)
|
||||
position: absolute
|
||||
@ -184,10 +184,10 @@
|
||||
text-align: right
|
||||
|
||||
.caption
|
||||
backdrop-filter: blur(25px)
|
||||
backdrop-filter: blur(2.8rem)
|
||||
background-color: rgba(black, .5)
|
||||
border-radius: var(--border-radius)
|
||||
bottom: 1rem
|
||||
bottom: var(--spacer)
|
||||
color: white
|
||||
+font-weight(500)
|
||||
line-height: 1.5
|
||||
@ -195,7 +195,7 @@
|
||||
+padding(2, x)
|
||||
position: absolute
|
||||
text-align: center
|
||||
text-shadow: 1px 1px 0 black, 2px 2px 3px rgba(black, .5)
|
||||
text-shadow: .1rem .1rem 0 black, .2rem .2rem rgba(black, .5)
|
||||
|
||||
body.is-galleria-active
|
||||
overflow: hidden
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
&.is-flatpage
|
||||
--hero-max-height: 0
|
||||
--hero-min-height: 240px
|
||||
--hero-min-height: 24.0rem
|
||||
background: transparent
|
||||
|
||||
.hero-content
|
||||
@ -23,7 +23,7 @@
|
||||
> a:not(.btn)
|
||||
background-color: transparent
|
||||
border-radius: 0
|
||||
color: var(--text-color-secondary)
|
||||
color: var(--color-text-secondary)
|
||||
display: inline-block
|
||||
+padding(4, x)
|
||||
+padding(2, y)
|
||||
@ -32,7 +32,7 @@
|
||||
|
||||
&::after
|
||||
background-color: currentColor
|
||||
bottom: -1px
|
||||
bottom: -.1rem
|
||||
content: ''
|
||||
height: var(--border-width)
|
||||
left: 0
|
||||
@ -48,7 +48,7 @@
|
||||
opacity: 1
|
||||
|
||||
&.is-active
|
||||
+font-weight-bold
|
||||
+fw-bold
|
||||
color: white
|
||||
|
||||
&::after
|
||||
|
@ -1,14 +1,23 @@
|
||||
.dl-col
|
||||
margin-bottom: -.1rem // Compensate border-bottom height
|
||||
|
||||
.dl-col-2
|
||||
flex-grow: 2
|
||||
|
||||
.dl-row
|
||||
+padding(2, bottom)
|
||||
|
||||
&:first-child
|
||||
+padding(0, top)
|
||||
|
||||
.list-filters
|
||||
+box-card
|
||||
background-color: var(--background-color-tertiary)
|
||||
background-color: var(--color-bg-tertiary)
|
||||
+padding(3)
|
||||
|
||||
h3
|
||||
border-bottom: var(--border-width) solid var(--border-color)
|
||||
color: var(--text-color-secondary)
|
||||
color: var(--color-text-secondary)
|
||||
+padding(2, bottom)
|
||||
|
||||
ul
|
||||
@ -17,12 +26,12 @@
|
||||
|
||||
li
|
||||
&.is-active
|
||||
color: var(--text-color-primary)
|
||||
+font-weight-bold
|
||||
color: var(--color-text-primary)
|
||||
+fw-bold
|
||||
|
||||
a
|
||||
display: block
|
||||
|
||||
&:hover
|
||||
color: var(--text-color-primary)
|
||||
color: var(--color-text-primary)
|
||||
text-decoration: none
|
||||
|
@ -7,7 +7,8 @@
|
||||
h4,
|
||||
h5,
|
||||
h6
|
||||
+margin(4, top)
|
||||
+margin(3, bottom)
|
||||
+padding(3, top)
|
||||
|
||||
img
|
||||
+border-radius(lg)
|
||||
@ -19,9 +20,4 @@
|
||||
|
||||
& >
|
||||
h1:first-of-type,
|
||||
h2:first-of-type,
|
||||
h3:first-of-type,
|
||||
h4:first-of-type,
|
||||
h5:first-of-type,
|
||||
h6:first-of-type
|
||||
+margin(0, top)
|
||||
+padding(0, top)
|
||||
|
17
common/static/common/styles/_navigation_global.sass
Normal file
17
common/static/common/styles/_navigation_global.sass
Normal file
@ -0,0 +1,17 @@
|
||||
.nav-global
|
||||
--nav-global-border-radius: var(--border-radius)
|
||||
--nav-global-border-radius-lg: var(--border-radius-lg)
|
||||
--nav-global-button-height: calc(var(--spacer) * 2.5)
|
||||
--nav-global-font-size: var(--fs-sm)
|
||||
--nav-global-link-padding-y: var(--nav-global-spacer-xs);
|
||||
--nav-global-navbar-height: var(--navbar-primary-height, var(--spacer-6));
|
||||
--nav-global-spacer: var(--spacer)
|
||||
--nav-global-spacer-sm: var(--spacer-2)
|
||||
--nav-global-spacer-xs: var(--spacer-1)
|
||||
|
||||
.btn-primary
|
||||
color: var(--color-accent) !important
|
||||
|
||||
input,
|
||||
.form-control
|
||||
height: var(--nav-global-button-height)
|
@ -1,22 +1,23 @@
|
||||
.background-color
|
||||
background-color: var(--background-color)
|
||||
background-color: var(--color-bg)
|
||||
|
||||
.background-color-primary
|
||||
background-color: var(--background-color-primary)
|
||||
background-color: var(--color-bg-primary)
|
||||
|
||||
.background-color-secondary
|
||||
background-color: var(--background-color-secondary)
|
||||
background-color: var(--color-bg-secondary)
|
||||
|
||||
.background-color-tertiary
|
||||
background-color: var(--background-color-tertiary)
|
||||
background-color: var(--color-bg-tertiary)
|
||||
|
||||
.border-bottom-tertiary
|
||||
border-bottom: thin solid var(--background-color-tertiary)
|
||||
border-bottom: thin solid var(--color-bg-tertiary)
|
||||
|
||||
.cursor-move
|
||||
&:hover
|
||||
cursor: move !important
|
||||
|
||||
// TODO: move utilities 'fade' and 'show' to web-assets
|
||||
.fade
|
||||
opacity: 0
|
||||
// TODO: make variable 'transition-speed-slow' work
|
||||
@ -36,6 +37,13 @@
|
||||
.show
|
||||
opacity: 1
|
||||
|
||||
.text-accent
|
||||
color: var(--color-accent)
|
||||
|
||||
a.text-accent
|
||||
&:hover
|
||||
color: var(--color-accent)
|
||||
|
||||
.text-underline
|
||||
text-decoration: underline !important
|
||||
|
||||
|
@ -2,41 +2,13 @@
|
||||
$font-path: '/static/fonts'
|
||||
|
||||
/* Import variables.*/
|
||||
$grid-breakpoints: (xs: 0,sm: 768px,md: 1020px,lg: 1220px,xl: 1380px,xxl: 1680px) !default
|
||||
$grid-breakpoints: (xs: 0,sm: 768px,md: 1020px,lg: 1220px,xl: 1380px,xxl: 1680px)
|
||||
|
||||
$container-max-widths: (sm: 760px, md: 1020px, lg: 1070px, xl: 1320px, xxl: 1600px)
|
||||
$container-width: map-get($container-max-widths, 'xl')
|
||||
|
||||
@import '../../../../assets_shared/src/styles/_media_queries.sass'
|
||||
@import '../../../../assets_shared/src/styles/_mixins.sass'
|
||||
@import '../../../../assets_shared/src/styles/_variables.sass'
|
||||
|
||||
/* Import Bootstrap. */
|
||||
@import '../../../../assets_shared/src/styles/bootstrap/bootstrap.scss'
|
||||
|
||||
@import '../../../../assets_shared/src/styles/_utilities.sass'
|
||||
@import '../../../../assets_shared/src/styles/_fonts.sass'
|
||||
|
||||
@import '../../../../assets_shared/src/styles/_bootstrap_overrides.sass'
|
||||
|
||||
@import '../../../../assets_shared/src/styles/_alert.sass'
|
||||
@import '../../../../assets_shared/src/styles/_badge.sass'
|
||||
@import '../../../../assets_shared/src/styles/_base.sass'
|
||||
@import '../../../../assets_shared/src/styles/_box.sass'
|
||||
@import '../../../../assets_shared/src/styles/_button.sass'
|
||||
@import '../../../../assets_shared/src/styles/_cards.sass'
|
||||
@import '../../../../assets_shared/src/styles/_code.sass'
|
||||
@import '../../../../assets_shared/src/styles/_details.sass'
|
||||
@import '../../../../assets_shared/src/styles/_footer.sass'
|
||||
@import '../../../../assets_shared/src/styles/_forms.sass'
|
||||
@import '../../../../assets_shared/src/styles/_hero.sass'
|
||||
@import '../../../../assets_shared/src/styles/_list.sass'
|
||||
@import '../../../../assets_shared/src/styles/_navigation.sass'
|
||||
@import '../../../../assets_shared/src/styles/_navigation_global.scss'
|
||||
@import '../../../../assets_shared/src/styles/_pagination.sass'
|
||||
@import '../../../../assets_shared/src/styles/_sidebar.sass'
|
||||
@import '../../../../assets_shared/src/styles/_table.sass'
|
||||
@import '../../../../assets_shared/src/styles/_type.sass'
|
||||
/* Web Assets. */
|
||||
@import '../../../../assets_shared/src/styles/main.sass'
|
||||
|
||||
/* Extension Platform specific styling. */
|
||||
@import '_mixins.sass'
|
||||
@ -46,6 +18,7 @@ $container-width: map-get($container-max-widths, 'xl')
|
||||
@import '_alert.sass'
|
||||
@import '_badge.sass'
|
||||
@import '_box.sass'
|
||||
@import '_cards.sass'
|
||||
@import '_code.sass'
|
||||
@import '_comments.sass'
|
||||
@import '_extension.sass'
|
||||
@ -54,6 +27,7 @@ $container-width: map-get($container-max-widths, 'xl')
|
||||
@import '_galleria.sass'
|
||||
@import '_hero.sass'
|
||||
@import '_list.sass'
|
||||
@import '_navigation_global.sass'
|
||||
@import '_table.sass'
|
||||
@import 'ratings/static/ratings/styles/_review.sass'
|
||||
@import 'ratings/static/ratings/styles/_stars.sass'
|
||||
@ -66,7 +40,7 @@ $container-width: map-get($container-max-widths, 'xl')
|
||||
+media-xs
|
||||
width: 60px
|
||||
|
||||
/* Temporarily here until it can be moved to web-assets v2. */
|
||||
/* TODO: temporarily here until it can be moved to web-assets v2. */
|
||||
.nav-global-links-right
|
||||
gap: 0 var(--spacer-2)
|
||||
.navbar-search
|
||||
@ -77,11 +51,11 @@ $container-width: map-get($container-max-widths, 'xl')
|
||||
|
||||
.profile-avatar
|
||||
border-radius: 50%
|
||||
height: var(--spacer-4)
|
||||
pointer-events: none
|
||||
width: 26px
|
||||
|
||||
.search-highlight
|
||||
background-color: var(--btn-bg-color)
|
||||
background-color: var(--btn-color-bg)
|
||||
border-radius: var(--border-radius)
|
||||
color: var(--btn-color)
|
||||
font-style: normal
|
||||
@ -97,13 +71,13 @@ $container-width: map-get($container-max-widths, 'xl')
|
||||
border-radius: var(--border-radius)
|
||||
color: hsl(0, 100%, 90%) !important
|
||||
display: flex
|
||||
+font-weight-bold
|
||||
font-size: var(--font-size-extra-small)
|
||||
+fw-bold
|
||||
font-size: var(--fs-xs)
|
||||
justify-content: center
|
||||
padding-block: .1rem
|
||||
padding-inline: .4rem
|
||||
padding-inline: var(--spacer-1)
|
||||
position: absolute
|
||||
top: -.4rem
|
||||
top: calc(var(--spacer-2) * -1)
|
||||
transition: background-color var(--transition-speed), box-shadow 500ms, color var(--transition-speed)
|
||||
right: -.5rem
|
||||
|
||||
|
@ -40,12 +40,12 @@
|
||||
.tagger > ul > li:not(.tagger-new) a:visited,
|
||||
.tagger-new ul a,
|
||||
.tagger-new ul a:visited {
|
||||
color: var(--text-color);
|
||||
color: var(--color-text);
|
||||
}
|
||||
.tagger > ul > li:not(.tagger-new) > a,
|
||||
.tagger li:not(.tagger-new) > span,
|
||||
.tagger .tagger-new ul {
|
||||
background: var(--btn-bg-color);
|
||||
background: var(--btn-color-bg);
|
||||
border-radius: var(--border-radius);
|
||||
padding: 4px 4px 4px 8px;
|
||||
|
||||
|
@ -125,8 +125,8 @@
|
||||
</li>
|
||||
|
||||
{% block nav-upload %}
|
||||
<li>
|
||||
<a href="{% url 'extensions:submit' %}" class="btn btn-primary text-primary">
|
||||
<li class="me-2">
|
||||
<a href="{% url 'extensions:submit' %}" class="btn btn-primary">
|
||||
<i class="i-upload"></i>
|
||||
<span>Upload Extension</span>
|
||||
</a>
|
||||
|
@ -1,3 +1,4 @@
|
||||
{# TODO: check if template is used and needed #}
|
||||
<li class="nav-item {% include "common/components/_nav_item_active" %}">
|
||||
{% include "common/components/nav_link.html" %}
|
||||
</li>
|
||||
|
@ -1,5 +1,5 @@
|
||||
{% if name %}
|
||||
<a class="nav-link {% include "common/components/_nav_item_active" %} {% if classes %}{{ classes }}{% endif %}" href="{% url name %}">{{ title }}</a>
|
||||
<a class="nav-pills-item {% include "common/components/_nav_item_active" %} {% if classes %}{{ classes }}{% endif %}" href="{% url name %}">{{ title }}</a>
|
||||
{% elif path %}
|
||||
<a class="nav-link {% include "common/components/_nav_item_active" %} {% if classes %}{{ classes }}{% endif %}" href="{{ path }}">{{ title }}</a>
|
||||
<a class="nav-pills-item {% include "common/components/_nav_item_active" %} {% if classes %}{{ classes }}{% endif %}" href="{{ path }}">{{ title }}</a>
|
||||
{% endif %}
|
||||
|
@ -14,7 +14,7 @@
|
||||
{% endblock hero %}
|
||||
|
||||
{% block content %}
|
||||
<div class="box p-5 my-3 is-flatpage">
|
||||
<div class="box my-3 is-flatpage">
|
||||
{{ flatpage.content|markdown }}
|
||||
</div>
|
||||
{% endblock content %}
|
||||
|
@ -10,6 +10,7 @@ class Verb:
|
||||
REPORTED_RATING = 'reported rating'
|
||||
REQUESTED_CHANGES = 'requested changes'
|
||||
REQUESTED_REVIEW = 'requested review'
|
||||
UPLOADED_NEW_VERSION = 'uploaded new version'
|
||||
|
||||
|
||||
class Flag:
|
||||
|
@ -8,6 +8,7 @@ from django.db.models.signals import m2m_changed, pre_save, post_save, pre_delet
|
||||
from django.dispatch import receiver
|
||||
|
||||
from constants.activity import Flag
|
||||
from reviewers.models import ApprovalActivity
|
||||
import extensions.models
|
||||
import files.models
|
||||
|
||||
@ -165,3 +166,26 @@ def _auto_approve_subsequent_uploads(
|
||||
args = {'f_id': file.pk, 'pk': instance.pk, 'sender': sender, 's': file.source.name}
|
||||
logger.info('Auto-approving file pk=%(f_id)s of %(sender)s pk=%(pk)s source=%(s)s', args)
|
||||
file.save(update_fields={'status', 'date_modified'})
|
||||
|
||||
|
||||
@receiver(post_save, sender=extensions.models.Version)
|
||||
def _create_approval_activity_for_new_version_if_listed(
|
||||
sender: object,
|
||||
instance: extensions.models.Version,
|
||||
created: bool,
|
||||
raw: bool,
|
||||
**kwargs: object,
|
||||
):
|
||||
if raw:
|
||||
return
|
||||
if not created:
|
||||
return
|
||||
extension = instance.extension
|
||||
if not extension.is_listed or not instance.file:
|
||||
return
|
||||
ApprovalActivity(
|
||||
type=ApprovalActivity.ActivityType.UPLOADED_NEW_VERSION,
|
||||
user=instance.file.user,
|
||||
extension=instance.extension,
|
||||
message=f'uploaded new version: {instance.version}',
|
||||
).save()
|
||||
|
@ -1,8 +1,8 @@
|
||||
// TODO: improve and refactor variable namings
|
||||
|
||||
const formsetContainer = document.getElementById('add-image-container');
|
||||
const formsetContainer = document.getElementById('add-img-container');
|
||||
const form = document.getElementById('update-extension-form');
|
||||
const btnAddImage = document.getElementById('btn-add-image');
|
||||
const btnAddImage = document.getElementById('btn-add-img');
|
||||
const formsetPrefix = 'form';
|
||||
const inputTotalForms = document.getElementById(`id_${formsetPrefix}-TOTAL_FORMS`);
|
||||
const tagInput = document.getElementById('id_tags');
|
||||
@ -28,7 +28,7 @@ function appendImageUploadForm() {
|
||||
const formRow = document.createElement('div');
|
||||
const newFormHTML = `
|
||||
<div class="previews-list-item">
|
||||
<div class="align-items-center d-flex previews-list-item-thumbnail pl-3">
|
||||
<div class="align-items-center d-flex previews-list-item-thumbnail ps-3">
|
||||
<div class="js-input-img-thumbnail previews-list-item-thumbnail-img" title="Preview">
|
||||
<div class="align-items-center d-flex js-input-img-thumbnail-icon justify-content-center">
|
||||
<i class="i-image"></i>
|
||||
@ -44,10 +44,10 @@ function appendImageUploadForm() {
|
||||
<input accept="image/jpg,image/jpeg,image/png,image/webp,video/mp4" class="form-control js-input-img" id="id_${formsetPrefix}-${i}-source" type="file" name="${formsetPrefix}-${i}-source">
|
||||
<ul class="pt-0">
|
||||
<li>
|
||||
<button class="btn btn-link btn-sm js-btn-reset-img-upload-form pl-2 pr-0"><i class="i-refresh"></i> Reset</button>
|
||||
<button class="btn btn-link btn-sm js-btn-reset-img-upload-form ps-2 pe-0"><i class="i-refresh"></i> Reset</button>
|
||||
</li>
|
||||
<li>
|
||||
<button class="btn btn-link btn-sm js-btn-remove-img-upload-form pl-2 pr-0"><i class="i-trash"></i> Delete</button>
|
||||
<button class="btn btn-link btn-sm js-btn-remove-img-upload-form ps-2 pe-0"><i class="i-trash"></i> Delete</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -71,7 +71,7 @@
|
||||
{% trans "Version History" %}
|
||||
</a>
|
||||
|
||||
<span class="ml-auto"></span>
|
||||
<span class="ms-auto"></span>
|
||||
|
||||
<div class="btn-row">
|
||||
{% if is_maintainer %}
|
||||
|
@ -1,5 +1,5 @@
|
||||
<a href="{% url "extensions:by-support" support_slug=slug %}" title="Support: {{ name }}"
|
||||
class="badge text-decoration-none align-middle {% if not small %}px-3 py-2 my-1{% endif %} badge-dark{#% if slug == 'official' %}primary{% elif slug == 'community' %}success{% else %}warning{% endif % #}"
|
||||
style="{% if not small %}font-size: var(--font-size-base);{% endif %}">
|
||||
style="{% if not small %}font-size: var(--fs-base);{% endif %}">
|
||||
<b>{{ name }}</b>
|
||||
</a>
|
||||
|
@ -1,25 +1,23 @@
|
||||
{% load common filters %}
|
||||
{% with latest=extension.latest_version thumbnail_360p_url=extension.get_previews.0.thumbnail_360p_url %}
|
||||
|
||||
<div class="ext-card {% if blur %}is-background-blur{% endif %}">
|
||||
{% if blur %}
|
||||
<div class="ext-card-thumbnail-blur" style="background-image: url({{ thumbnail_360p_url }});"></div>
|
||||
{% endif %}
|
||||
|
||||
<a class="ext-card-thumbnail" href="{{ extension.get_absolute_url }}">
|
||||
<div class="ext-card-thumbnail-img" style="background-image: url({{ thumbnail_360p_url }});" title="{{ extension.name }}"></div>
|
||||
{% with latest=extension.latest_version thumbnail_360p_url=extension.previews.listed.first.thumbnail_360p_url %}
|
||||
<div class="cards-item">
|
||||
<div class="cards-item-content">
|
||||
<a href="{{ extension.get_absolute_url }}">
|
||||
<div class="cards-item-thumbnail">
|
||||
<img alt="{{ extension.name }}" src="{{ thumbnail_360p_url }}" title="{{ extension.name }}">
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<div class="ext-card-body">
|
||||
<h3 class="ext-card-title">
|
||||
<h3 class="cards-item-title">
|
||||
<a href="{{ extension.get_absolute_url }}">{{ extension.name }}</a>
|
||||
</h3>
|
||||
<div class="cards-item-excerpt">
|
||||
<p>
|
||||
{{ latest.tagline }}
|
||||
</p>
|
||||
|
||||
<ul class="ext-list-details">
|
||||
<li class="ext-card-author">
|
||||
</div>
|
||||
<div class="cards-item-extra">
|
||||
<ul>
|
||||
<li>
|
||||
{% if extension.team %}
|
||||
{% with team=extension.team %}
|
||||
<a href="{{ team.get_absolute_url }}" title="{{ team.name }}">{{ team.name }}</a>
|
||||
@ -30,10 +28,10 @@
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul class="ext-list-details mt-1">
|
||||
<ul class="cards-item-extra-rating-stars">
|
||||
{% if extension.average_score %}
|
||||
<li>
|
||||
<a href="{{ extension.get_ratings_url }}">
|
||||
<a class="align-items-center d-flex" href="{{ extension.get_ratings_url }}">
|
||||
{% include "ratings/components/average.html" with score=extension.average_score %}
|
||||
({{ extension.text_ratings_count|int_compact }})
|
||||
</a>
|
||||
@ -47,22 +45,25 @@
|
||||
{% endif %}
|
||||
|
||||
{% if show_type %}
|
||||
<li class="ml-auto">
|
||||
<li class="ms-auto">
|
||||
{{ extension.get_type_display }}
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
|
||||
{% if latest.tags.count %}
|
||||
<ul class="ext-list-details ext-card-tags">
|
||||
<li class="ext-card-tags">
|
||||
{% include "extensions/components/tags.html" with small=True version=latest %}
|
||||
<ul>
|
||||
{% for tag in latest.tags.all %}
|
||||
<li>
|
||||
{% include "extensions/components/badge_tag.html" with small=True version=latest %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{# Author/admin tools can be added here in an extending template #}
|
||||
{% block admin %}{% endblock admin %}
|
||||
</div>
|
||||
</div>
|
||||
{% endwith %}
|
||||
|
@ -2,9 +2,9 @@
|
||||
|
||||
{# Info Summary #}
|
||||
<section class="ext-detail-info">
|
||||
<div class="card">
|
||||
<div class="card p-0">
|
||||
{% if is_initial %}
|
||||
<div class="badge badge-info card-badge">
|
||||
<div class="badge badge-card badge-info">
|
||||
Information retrieved from manifest
|
||||
</div>
|
||||
{% else %}
|
||||
|
@ -19,11 +19,13 @@
|
||||
|
||||
{# Description #}
|
||||
{% block extension_description %}
|
||||
{% if extension.description %}
|
||||
<section id="about" class="mt-3">
|
||||
<div class="box ext-detail-description">
|
||||
{{ extension.description|markdown }}
|
||||
</div>
|
||||
</section>
|
||||
{% endif %}
|
||||
{% endblock extension_description %}
|
||||
|
||||
{# What's New #}
|
||||
@ -82,7 +84,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="mb-0"><i class="i-check mr-0"></i> This extension does not require special permissions.</p>
|
||||
<p class="mb-0"><i class="i-check me-0"></i> This extension does not require special permissions.</p>
|
||||
{% endif %}
|
||||
</section>
|
||||
{% endif %}
|
||||
@ -125,7 +127,7 @@
|
||||
<dt>{% trans 'Rating' %}</dt>
|
||||
<dd>
|
||||
{% if extension.average_score %}
|
||||
<a href="{{ extension.get_ratings_url }}" class="text-decoration-none">
|
||||
<a href="{{ extension.get_ratings_url }}" class="align-items-center d-flex stars-helper-detail text-decoration-none">
|
||||
{% include "ratings/components/average.html" with score=extension.average_score %}
|
||||
({{ extension.ratings.listed.count }})
|
||||
</a>
|
||||
@ -274,7 +276,7 @@
|
||||
{% trans 'Reviews' %}
|
||||
</a>
|
||||
</h2>
|
||||
<a href="{{ extension.get_ratings_url }}" class="ml-auto">See all</a>
|
||||
<a href="{{ extension.get_ratings_url }}" class="ms-auto">See all</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -82,7 +82,7 @@
|
||||
|
||||
<section class="card p-3 mt-3">
|
||||
<div class="btn-col">
|
||||
<button type="submit" name="save_draft" class="btn btn-primary btn-warning">
|
||||
<button type="submit" name="save_draft" class="btn btn-warning">
|
||||
<i class="i-check"></i>
|
||||
<span>{% trans 'Save Draft' %}</span>
|
||||
</button>
|
||||
|
@ -25,7 +25,7 @@
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="hero-background" style="background-image: url(https://www.blender.org/wp-content/uploads/2022/08/piotr-krynski-scanislands-blender-33lts-crop.jpg); background-position-y: 50%"></div>
|
||||
<div class="hero-bg" style="background-image: url(https://www.blender.org/wp-content/uploads/2022/08/piotr-krynski-scanislands-blender-33lts-crop.jpg); background-position-y: 50%"></div>
|
||||
<div class="hero-overlay"></div>
|
||||
<div class="hero-credits"></div>
|
||||
</div>
|
||||
@ -38,10 +38,10 @@
|
||||
<h2>
|
||||
<a href="{% url 'extensions:by-type' type_slug='add-ons' %}">Add-ons</a>
|
||||
</h2>
|
||||
<a href="{% url 'extensions:by-type' type_slug='add-ons' %}" class="ml-auto">See all</a>
|
||||
<a href="{% url 'extensions:by-type' type_slug='add-ons' %}" class="ms-auto">See all</a>
|
||||
</div>
|
||||
<p>Extend Blender capabilities with these add-ons by the community.</p>
|
||||
<div class="cards-list mt-3">
|
||||
<div class="cards cards-lg-4 cards-md-3 cards-sm-2 mt-3">
|
||||
{% for extension in addons %}
|
||||
{% include "extensions/components/card.html" %}
|
||||
{% endfor %}
|
||||
@ -53,12 +53,12 @@
|
||||
<h2>
|
||||
<a href="{% url 'extensions:by-type' type_slug='themes' %}">Themes</a>
|
||||
</h2>
|
||||
<a href="{% url 'extensions:by-type' type_slug='themes' %}" class="ml-auto fw-normal">
|
||||
<a href="{% url 'extensions:by-type' type_slug='themes' %}" class="ms-auto fw-normal">
|
||||
See all
|
||||
</a>
|
||||
</div>
|
||||
<p>Blender themes to your liking. Dark, light, flat, colorful, and everything in between.</p>
|
||||
<div class="cards-list mt-3">
|
||||
<div class="cards cards-lg-4 cards-md-3 cards-sm-2 mt-3">
|
||||
{% for extension in themes %}
|
||||
{% include "extensions/components/card.html" %}
|
||||
{% endfor %}
|
||||
@ -66,7 +66,7 @@
|
||||
|
||||
<div class="my-5 text-center">
|
||||
Got an add-on or theme to share with the community?
|
||||
<a href="{% url 'extensions:submit' %}" class="text-primary ml-2">
|
||||
<a href="{% url 'extensions:submit' %}" class="text-accent ms-2">
|
||||
Upload
|
||||
<i class="i-chevron-right"></i>
|
||||
</a>
|
||||
|
@ -33,7 +33,7 @@
|
||||
{% endif %}
|
||||
{% if tag %}
|
||||
<h2 class="d-flex align-items-center">
|
||||
<span class="mr-3">{% blocktranslate %}Extensions with the tag{% endblocktranslate %}</span>
|
||||
<span class="me-3">{% blocktranslate %}Extensions with the tag{% endblocktranslate %}</span>
|
||||
{% include "extensions/components/badge_tag.html" %}
|
||||
</h2>
|
||||
{% endif %}
|
||||
@ -47,7 +47,7 @@
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
{% if object_list %}
|
||||
<div class="cards-list card-layout-horizontal cards-3">
|
||||
<div class="cards cards-3">
|
||||
{% for extension in object_list %}
|
||||
{% include "extensions/components/card.html" with show_type=False %}
|
||||
{% endfor %}
|
||||
|
@ -1,15 +1,14 @@
|
||||
{% load common %}
|
||||
{# Upload new preview images #}
|
||||
{% load i18n %}
|
||||
<div class="previews-upload">
|
||||
<div id="add-image-container" class="previews-list">
|
||||
<div id="add-img-container" class="previews-list">
|
||||
{{ add_preview_formset.management_form }}
|
||||
{{ add_preview_formset.non_form_errors }}
|
||||
{% for newform in add_preview_formset %}
|
||||
{% with inlineform=newform|add_form_classes %}
|
||||
<div class="ext-edit-field-row js-ext-edit-field-row">
|
||||
<div class="previews-list-item">
|
||||
<div class="align-items-center d-flex previews-list-item-thumbnail pl-3">
|
||||
<div class="d-flex previews-list-item-thumbnail ps-3">
|
||||
<div class="js-input-img-thumbnail previews-list-item-thumbnail-img" title="Preview">
|
||||
<div class="align-items-center d-flex js-input-img-thumbnail-icon justify-content-center">
|
||||
<i class="i-image"></i>
|
||||
@ -24,7 +23,7 @@
|
||||
{% include "common/components/field.html" with field=inlineform.source label='File' %}
|
||||
<ul class="pt-0">
|
||||
<li>
|
||||
<button class="btn btn-link btn-sm js-btn-reset-img-upload-form pl-2 pr-0"><i class="i-refresh"></i> Reset</button>
|
||||
<button class="btn btn-link btn-sm js-btn-reset-img-upload-form ps-2 pe-0"><i class="i-refresh"></i> Reset</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@ -35,10 +34,9 @@
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col text-right mt-3">
|
||||
<a id="btn-add-image" class="btn">
|
||||
<a id="btn-add-img" class="btn">
|
||||
<i class="i-plus"></i>
|
||||
<span>{% trans 'Add Preview' %}</span>
|
||||
</a>
|
||||
|
@ -2,16 +2,17 @@
|
||||
{% load i18n %}
|
||||
|
||||
{% block admin %}
|
||||
<div class="ext-card-admin p-3">
|
||||
<div>
|
||||
<div class="bg-secondary cards-item-extra pt-3">
|
||||
<ul class="w-100">
|
||||
<li class="d-flex justify-content-between me-0 w-100">
|
||||
<a href="{{ extension.get_manage_url }}" class="btn btn-sm">
|
||||
<i class="i-edit"></i>
|
||||
<span>{% trans 'Edit' %}</span>
|
||||
</a>
|
||||
<div class="align-items-center d-flex">
|
||||
{% include "common/components/status.html" with object=extension class="badge-tag" %}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{% include "common/components/status.html" with object=extension %}
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
{% endblock admin %}
|
||||
|
@ -25,7 +25,7 @@
|
||||
<div class="row mt-4">
|
||||
<div class="col">
|
||||
{% if object_list %}
|
||||
<div class="cards-list">
|
||||
<div class="cards">
|
||||
{% for extension in object_list %}
|
||||
{% include "extensions/manage/components/card.html" with show_type=True %}
|
||||
{% endfor %}
|
||||
|
@ -68,7 +68,7 @@
|
||||
<small>Source File</small>
|
||||
</a>
|
||||
</li>
|
||||
<li class="ml-auto">
|
||||
<li class="ms-auto">
|
||||
{% include "common/components/field.html" with field=inlineform.DELETE %}
|
||||
</li>
|
||||
<li>
|
||||
@ -153,7 +153,7 @@
|
||||
const previewDragContainer = document.querySelector('.js-previews-drag-container');
|
||||
const previewDragClass = 'js-preview-drag';
|
||||
|
||||
{% comment %} dragula([document.querySelector('.js-preview-drag'), document.querySelector('.cards-list')]); {% endcomment %}
|
||||
{% comment %} dragula([document.querySelector('.js-preview-drag'), document.querySelector('.cards')]); {% endcomment %}
|
||||
dragula([previewDragContainer, previewDragContainer], {
|
||||
moves: function (el, container, handle) {
|
||||
return handle.className.includes(previewDragClass);
|
||||
|
@ -29,7 +29,7 @@
|
||||
<span class="show-on-collapse blender-version">
|
||||
{% include "extensions/components/blender_version.html" with version=version %}
|
||||
</span>
|
||||
<ul class="ml-auto">
|
||||
<ul class="ms-auto">
|
||||
<li class="show-on-collapse">{{ version.file.size_bytes|filesizeformat }}</li>
|
||||
<li class="show-on-collapse"><i class="i-download"></i> {{ version.download_count }}</li>
|
||||
<li>
|
||||
|
@ -10,6 +10,7 @@ from common.tests.factories.users import UserFactory
|
||||
from common.tests.utils import _get_all_form_errors
|
||||
from extensions.models import Extension, Version
|
||||
from files.models import File
|
||||
from reviewers.models import ApprovalActivity
|
||||
import utils
|
||||
|
||||
|
||||
@ -425,6 +426,14 @@ class NewVersionTest(TestCase):
|
||||
f'/add-ons/{self.extension.slug}/manage/versions/new/{file.pk}/',
|
||||
)
|
||||
self.assertEqual(self.extension.versions.count(), 1)
|
||||
self.extension.approve()
|
||||
self.assertEqual(
|
||||
ApprovalActivity.objects.filter(
|
||||
extension=self.extension,
|
||||
type=ApprovalActivity.ActivityType.UPLOADED_NEW_VERSION,
|
||||
).count(),
|
||||
0,
|
||||
)
|
||||
|
||||
# Check step 2: finalise new version and send to review
|
||||
url = response['Location']
|
||||
@ -444,3 +453,10 @@ class NewVersionTest(TestCase):
|
||||
self.assertEqual(new_version.schema_version, '1.0.0')
|
||||
self.assertEqual(new_version.release_notes, 'new version')
|
||||
self.assertEqual(new_version.file.get_status_display(), 'Approved')
|
||||
self.assertEqual(
|
||||
ApprovalActivity.objects.filter(
|
||||
extension=self.extension,
|
||||
type=ApprovalActivity.ActivityType.UPLOADED_NEW_VERSION,
|
||||
).count(),
|
||||
1,
|
||||
)
|
||||
|
@ -18,6 +18,7 @@ VERB2FLAGS = {
|
||||
Verb.REPORTED_RATING: [Flag.MODERATOR],
|
||||
Verb.REQUESTED_CHANGES: [Flag.AUTHOR, Flag.REVIEWER],
|
||||
Verb.REQUESTED_REVIEW: [Flag.MODERATOR, Flag.REVIEWER],
|
||||
Verb.UPLOADED_NEW_VERSION: [],
|
||||
}
|
||||
|
||||
|
||||
@ -41,7 +42,7 @@ def _create_notifications(
|
||||
notifications = []
|
||||
|
||||
flags = VERB2FLAGS.get(instance.verb, None)
|
||||
if not flags:
|
||||
if flags is None:
|
||||
logger.warning(f'no follower flags for verb={instance.verb}, nobody will be notified')
|
||||
return
|
||||
|
||||
|
@ -20,7 +20,7 @@ and will most likely fail due to differences in configuration paths and so on.
|
||||
To avoid adding more dependencies to the project itself, `ansible` uses its own `virtualenv`.
|
||||
To set it up use the following commands:
|
||||
|
||||
virtualenv .venv -p python
|
||||
python3.10 -m venv .venv
|
||||
source .venv/bin/activate
|
||||
pip install -r requirements.txt
|
||||
|
||||
|
@ -32,7 +32,7 @@
|
||||
h1 {
|
||||
background: linear-gradient(to right, #0cc, violet);
|
||||
background-clip: text;
|
||||
-webkit-background-clip: text;
|
||||
-webkit-bg-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
font-weight: 300;
|
||||
font-size: 1.6em;
|
||||
|
@ -51,6 +51,7 @@
|
||||
-webkit-mask-size: var(--star-size) var(--star-size)
|
||||
mask-size: var(--star-size) var(--star-size)
|
||||
text-align: left
|
||||
transform: translateY(-.2rem)
|
||||
width: var(--stars-number)
|
||||
|
||||
span
|
||||
@ -62,6 +63,11 @@
|
||||
--star-size: 1.6em
|
||||
width: 8em
|
||||
|
||||
// TODO: refactor stars-helper
|
||||
.stars-helper
|
||||
max-height: 1.4rem
|
||||
transform: translateY(-.1rem)
|
||||
|
||||
.ratings-summary
|
||||
display: flex
|
||||
flex-direction: column
|
||||
@ -87,9 +93,9 @@
|
||||
text-decoration: none
|
||||
|
||||
span
|
||||
color: var(--text-color-secondary)
|
||||
color: var(--color-text-secondary)
|
||||
display: block
|
||||
font-size: var(--font-size-base)
|
||||
font-size: var(--fs-base)
|
||||
|
||||
.stars
|
||||
+margin(auto, x)
|
||||
|
@ -2,6 +2,6 @@
|
||||
|
||||
{% blocktranslate asvar title with score=score %}Rated {{ score }} out of 5{% endblocktranslate %}
|
||||
|
||||
<span class="stars{% if size %} {{ size }}{% endif %}" title="{{ title }}">
|
||||
<span class="stars me-1 {% if size %} {{ size }}{% endif %}" title="{{ title }}">
|
||||
<span style="width: {% widthratio score 5 100 %}%"></span>
|
||||
</span>
|
||||
|
@ -14,9 +14,9 @@
|
||||
{{ rating.user }}
|
||||
</a>
|
||||
</li>
|
||||
<li class="mr-auto">
|
||||
<li class="align-items-center d-flex me-auto">
|
||||
{% with score_percentage=rating.score %}
|
||||
<a href="{{ extension.get_ratings_url }}?score={{ rating.score }}">
|
||||
<a class="stars-helper" href="{{ extension.get_ratings_url }}?score={{ rating.score }}">
|
||||
{% include "ratings/components/average.html" with score=rating.score %}
|
||||
</a>
|
||||
{% endwith %}
|
||||
|
@ -4,7 +4,7 @@
|
||||
{% block page_title %}Rate {{ extension.name }}{% endblock page_title %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container">
|
||||
<div class="container rating-form">
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
{% with form=form|add_form_classes %}
|
||||
|
@ -13,7 +13,7 @@
|
||||
{% endif %}
|
||||
</h2>
|
||||
{% if score %}
|
||||
<div class="ml-auto">
|
||||
<div class="ms-auto">
|
||||
<a href="{{ extension.get_ratings_url }}" class="text-muted">See all</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
18
reviewers/migrations/0009_alter_approvalactivity_type.py
Normal file
18
reviewers/migrations/0009_alter_approvalactivity_type.py
Normal file
@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.11 on 2024-04-29 17:33
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('reviewers', '0008_alter_approvalactivity_message'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='approvalactivity',
|
||||
name='type',
|
||||
field=models.CharField(choices=[('COM', 'Comment'), ('APR', 'Approved'), ('AWC', 'Awaiting Changes'), ('AWR', 'Awaiting Review'), ('UNV', 'Uploaded New Version')], default='COM', max_length=3),
|
||||
),
|
||||
]
|
@ -80,6 +80,7 @@ class ApprovalActivity(CreatedModifiedMixin, RecordDeletionMixin, models.Model):
|
||||
APPROVED = "APR", _("Approved")
|
||||
AWAITING_CHANGES = "AWC", _("Awaiting Changes")
|
||||
AWAITING_REVIEW = "AWR", _("Awaiting Review")
|
||||
UPLOADED_NEW_VERSION = "UNV", _("Uploaded New Version")
|
||||
|
||||
user = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, null=True)
|
||||
extension = models.ForeignKey(
|
||||
|
@ -30,6 +30,7 @@ def _create_action_from_review_and_follow(
|
||||
ApprovalActivity.ActivityType.AWAITING_CHANGES: Verb.REQUESTED_CHANGES,
|
||||
ApprovalActivity.ActivityType.AWAITING_REVIEW: Verb.REQUESTED_REVIEW,
|
||||
ApprovalActivity.ActivityType.COMMENT: Verb.COMMENTED,
|
||||
ApprovalActivity.ActivityType.UPLOADED_NEW_VERSION: Verb.UPLOADED_NEW_VERSION,
|
||||
}
|
||||
action.send(
|
||||
instance.user,
|
||||
|
@ -6,27 +6,25 @@
|
||||
{{ extension.name }}
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
{% if extension.authors.count %}
|
||||
{% include "extensions/components/authors.html" %}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{% include "extensions/components/authors.html" %}</td>
|
||||
<td title="{{ extension.date_created }}">{{ extension.date_created|naturaltime_compact }}</td>
|
||||
<td class="d-flex">
|
||||
<a href="{{ extension.get_review_url }}#activity">
|
||||
<span>{{ extension.review_activity.all|length }}</span>
|
||||
<span>{{ stats.count }}</span>
|
||||
</a>
|
||||
|
||||
{% if extension.review_activity.all %}
|
||||
<a href="{{ extension.get_review_url }}#activity-{{ extension.review_activity.all.last.id }}" class="ml-3">
|
||||
<span>{{ extension.review_activity.all.last.date_created|naturaltime_compact }}</span>
|
||||
<a href="{{ extension.get_review_url }}#activity-{{ stats.last_activity.id }}" class="ms-3">
|
||||
<span>{{ stats.last_activity.date_created|naturaltime_compact }}</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% include "files/components/scan_details_flag.html" with suspicious_files=extension.suspicious_files %}
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ extension.get_review_url }}" class="text-decoration-none">
|
||||
{% include "common/components/status.html" with object=extension class="d-block" %}
|
||||
{% with last_type=stats.last_type_display|default:"Awaiting Review" %}
|
||||
<div class="d-block badge badge-status-{{ last_type|slugify }}">
|
||||
<i class="i-eye"></i>
|
||||
<span>{{ last_type }}</span>
|
||||
</div>
|
||||
{% endwith %}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -24,7 +24,7 @@
|
||||
{% trans "Version History" %}
|
||||
</a>
|
||||
|
||||
<span class="ml-auto"></span>
|
||||
<span class="ms-auto"></span>
|
||||
|
||||
<div class="btn-row">
|
||||
{% if is_maintainer %}
|
||||
@ -101,8 +101,7 @@
|
||||
{% for activity in extension.review_activity.all %}
|
||||
<li id="activity-{{ activity.id }}">
|
||||
|
||||
{# All activities except comments. #}
|
||||
{% if activity.type != 'COM' %}
|
||||
{% if activity.type in status_change_types %}
|
||||
<div class="activity-item activity-status-change activity-status-{{ activity.get_type_display|slugify }}">
|
||||
<i class="activity-icon i-activity-{{ activity.get_type_display|slugify }}"></i>
|
||||
|
||||
@ -139,7 +138,7 @@
|
||||
{{ activity.user }}
|
||||
</a>
|
||||
</li>
|
||||
<li class="ml-auto">
|
||||
<li class="ms-auto">
|
||||
<a href="#activity-{{ activity.id }}" title="{{ activity.date_created }}">
|
||||
{{ activity.date_created|naturaltime_compact }}
|
||||
</a>
|
||||
@ -167,8 +166,11 @@
|
||||
{% include "common/components/field.html" with field=form.message %}
|
||||
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="btn-row ml-3 w-100 justify-content-end">
|
||||
<div class="btn-row ms-3 w-100 justify-content-end">
|
||||
{% if is_maintainer or request.user.is_moderator %}
|
||||
{% include "common/components/field.html" with field=form.type %}
|
||||
{% endif %}
|
||||
|
||||
<button type="submit" id="activity-submit" class="btn btn-primary">
|
||||
<span>{% trans "Comment" %}</span>
|
||||
</button>
|
||||
|
@ -34,12 +34,10 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for extension in object_list %}
|
||||
{% if user.is_moderator %}
|
||||
{% include 'reviewers/components/review_list_item.html' %}
|
||||
{% elif extension.status_slug == 'awaiting-review' %}
|
||||
{% include 'reviewers/components/review_list_item.html' %}
|
||||
{% endif %}
|
||||
{% for stats in object_list %}
|
||||
{% with extension=stats.extension %}
|
||||
{% include 'reviewers/components/review_list_item.html' with extension=extension stats=stats %}
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
@ -3,13 +3,21 @@ from django.shortcuts import reverse
|
||||
|
||||
from common.tests.factories.extensions import create_version
|
||||
from files.models import File
|
||||
from reviewers.models import ApprovalActivity
|
||||
|
||||
|
||||
class CommentsViewTest(TestCase):
|
||||
fixtures = ['licenses']
|
||||
|
||||
def setUp(self):
|
||||
self.default_version = create_version(file__status=File.STATUSES.AWAITING_REVIEW)
|
||||
version = create_version(file__status=File.STATUSES.AWAITING_REVIEW)
|
||||
self.default_version = version
|
||||
ApprovalActivity(
|
||||
type=ApprovalActivity.ActivityType.COMMENT,
|
||||
user=version.file.user,
|
||||
extension=version.extension,
|
||||
message='test comment',
|
||||
).save()
|
||||
|
||||
# List of extensions under review does not require authentication
|
||||
def test_list_visibility(self):
|
||||
|
@ -13,15 +13,51 @@ from reviewers.models import ApprovalActivity
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
STATUS_CHANGE_TYPES = [
|
||||
ApprovalActivity.ActivityType.APPROVED,
|
||||
ApprovalActivity.ActivityType.AWAITING_CHANGES,
|
||||
ApprovalActivity.ActivityType.AWAITING_REVIEW,
|
||||
]
|
||||
|
||||
|
||||
class ApprovalQueueView(ListView):
|
||||
model = Extension
|
||||
paginate_by = 100
|
||||
|
||||
def get_queryset(self):
|
||||
return Extension.objects.exclude(status=Extension.STATUSES.APPROVED).order_by(
|
||||
'-date_created'
|
||||
qs = (
|
||||
ApprovalActivity.objects.prefetch_related(
|
||||
'extension',
|
||||
'extension__authors',
|
||||
'extension__versions',
|
||||
'extension__versions__file',
|
||||
'extension__versions__file__validation',
|
||||
)
|
||||
.order_by('-date_created')
|
||||
.all()
|
||||
)
|
||||
by_extension = {}
|
||||
result = []
|
||||
for item in qs:
|
||||
extension = item.extension
|
||||
stats = by_extension.get(extension, None)
|
||||
if not stats:
|
||||
# this check guarantees that we add a record only once per extension,
|
||||
# and iterating over qs we get result also ordered by item.date_created
|
||||
stats = {
|
||||
'count': 0,
|
||||
'extension': extension,
|
||||
'last_activity': None,
|
||||
'last_type_display': None,
|
||||
}
|
||||
by_extension[extension] = stats
|
||||
result.append(stats)
|
||||
stats['count'] += 1
|
||||
if not stats.get('last_activity', None):
|
||||
stats['last_activity'] = item
|
||||
if not stats.get('last_type_display', None) and item.type in STATUS_CHANGE_TYPES:
|
||||
stats['last_type_display'] = item.get_type_display
|
||||
return result
|
||||
|
||||
template_name = 'reviewers/extensions_review_list.html'
|
||||
|
||||
@ -36,32 +72,30 @@ class ExtensionsApprovalDetailView(DetailView):
|
||||
ctx['pending_previews'] = self.object.preview_set.exclude(
|
||||
file__status=File.STATUSES.APPROVED
|
||||
)
|
||||
ctx['status_change_types'] = STATUS_CHANGE_TYPES
|
||||
|
||||
if self.request.user.is_authenticated:
|
||||
form = ctx['comment_form'] = CommentForm()
|
||||
# Remove 'Approved' status from dropdown it not moderator
|
||||
filtered_activity_types = ApprovalActivity.ActivityType.choices
|
||||
# anyone can comment
|
||||
filtered_activity_types = {ApprovalActivity.ActivityType.COMMENT}
|
||||
user = self.request.user
|
||||
if not (user.is_moderator or user.is_superuser):
|
||||
filtered_activity_types = [
|
||||
t
|
||||
for t in ApprovalActivity.ActivityType.choices
|
||||
if t[0]
|
||||
not in [
|
||||
if self.object.has_maintainer(user):
|
||||
filtered_activity_types.add(ApprovalActivity.ActivityType.AWAITING_REVIEW)
|
||||
if user.is_moderator or user.is_superuser:
|
||||
filtered_activity_types.update(
|
||||
[
|
||||
ApprovalActivity.ActivityType.APPROVED,
|
||||
ApprovalActivity.ActivityType.AWAITING_CHANGES,
|
||||
]
|
||||
]
|
||||
if not self.object.has_maintainer(user):
|
||||
# Other accounts can only comment
|
||||
filtered_activity_types = [
|
||||
t
|
||||
for t in ApprovalActivity.ActivityType.choices
|
||||
if t[0] == ApprovalActivity.ActivityType.COMMENT
|
||||
]
|
||||
form.fields['type'].choices = filtered_activity_types
|
||||
form.fields['type'].widget.choices = filtered_activity_types
|
||||
if len(filtered_activity_types) == 1:
|
||||
)
|
||||
choices = list(
|
||||
filter(
|
||||
lambda c: c[0] in filtered_activity_types, ApprovalActivity.ActivityType.choices
|
||||
)
|
||||
)
|
||||
form.fields['type'].choices = choices
|
||||
form.fields['type'].widget.choices = choices
|
||||
if len(choices) == 1:
|
||||
form.fields['type'].widget = django.forms.HiddenInput()
|
||||
return ctx
|
||||
|
||||
|
@ -1,3 +1,3 @@
|
||||
{% for _slug, badge in badges.items %}
|
||||
<img class="mr-2" width="{{ width }}" src="{{ badge.image }}" title="{{ badge.description }}" label="{{ badge.label }}" />
|
||||
<img class="me-2" width="{{ width }}" src="{{ badge.image }}" title="{{ badge.description }}" label="{{ badge.label }}" />
|
||||
{% endfor %}
|
||||
|
@ -1,7 +1,7 @@
|
||||
{% load static %}
|
||||
<img src="{% if user.image %}{{ user.image.url }}{% else %}{% static 'common/images/blank-profile-pic.png' %}{% endif %}" class="profile-avatar {{ classes }}">
|
||||
{% if show_name %}
|
||||
<span class="ml-2">
|
||||
<span class="ms-2">
|
||||
{% firstof user.full_name user.username %}
|
||||
</span>
|
||||
{% endif %}
|
||||
|
@ -12,7 +12,7 @@
|
||||
<div class="row">
|
||||
<div class="d-none d-md-block col-md-3">
|
||||
<div class="is-sticky pt-4">
|
||||
<nav class="box nav-drawer-nested">
|
||||
<nav class="box nav-drawer-nested p-3">
|
||||
<div class="nav-drawer-body fw-bold">
|
||||
{% include 'users/settings/tabs.html' %}
|
||||
</div>
|
||||
|
@ -27,12 +27,12 @@
|
||||
</div>
|
||||
<div class="col-md-6 mb-4">
|
||||
<label class="mb-2 h3" for="email">
|
||||
<span class="mr-1">Email</span>
|
||||
<span class="me-1">Email</span>
|
||||
|
||||
{% if user.confirmed_email_at %}
|
||||
<span class="align-middle badge badge-sm badge-success"><i class="i-check"></i>Confirmed</span>
|
||||
<span class="align-middle badge badge-success fs-xs"><i class="i-check"></i>Confirmed</span>
|
||||
{% else %}
|
||||
<span class="align-middle badge badge-sm badge-warning"><i class="i-alert-triangle"></i>Not yet confirmed</span>
|
||||
<span class="align-middle badge badge-warning fs-xs"><i class="i-alert-triangle"></i>Not yet confirmed</span>
|
||||
{% endif %}
|
||||
</label>
|
||||
<div class="align-items-center d-flex position-relative">
|
||||
|
@ -3,9 +3,11 @@
|
||||
{% include "common/components/nav_link.html" with name="users:my-profile" title="Profile" classes="i-home py-2" %}
|
||||
|
||||
{% if user.teams.count %}
|
||||
{% include "common/components/nav_link.html" with name="teams:list" title="Teams" classes="i-people py-2" %}
|
||||
{% include "common/components/nav_link.html" with name="teams:list" title="Teams" classes="i-users py-2" %}
|
||||
{% endif %}
|
||||
|
||||
<div class="nav-pills-divider"></div>
|
||||
|
||||
{% include "common/components/nav_link.html" with name="users:my-profile-delete" title="Delete account" classes="i-trash py-2" %}
|
||||
</div>
|
||||
{% endspaceless %}
|
||||
|
Loading…
Reference in New Issue
Block a user