diff --git a/internal_packages/attachments/lib/image-attachment-component.cjsx b/internal_packages/attachments/lib/image-attachment-component.cjsx index aaca8b951..a6ec1d330 100644 --- a/internal_packages/attachments/lib/image-attachment-component.cjsx +++ b/internal_packages/attachments/lib/image-attachment-component.cjsx @@ -14,12 +14,13 @@ class ImageAttachmentComponent extends AttachmentComponent
- {@_fileActions()} + {@_renderFileActions()}
-
-
{@props.file.filename}
+
+
{@props.file.filename}
+
{@_imgOrLoader()}
diff --git a/internal_packages/attachments/stylesheets/attachments.less b/internal_packages/attachments/stylesheets/attachments.less index 102c8e685..fc08bcbd5 100644 --- a/internal_packages/attachments/stylesheets/attachments.less +++ b/internal_packages/attachments/stylesheets/attachments.less @@ -79,8 +79,11 @@ } } -.image-file-upload, .image-attachment-file-wrap, .attachment-file-wrap, +.image-file-upload, +.image-attachment-file-wrap, +.attachment-file-wrap, .attachment-inner-wrap { + .attachment-download-bar-wrap { display: none; } @@ -128,10 +131,15 @@ } } -.image-attachment-file-wrap, .image-file-upload { +.image-attachment-file-wrap, +.image-file-upload { + position: relative; - margin: 0 0 8px 0; text-align: center; + display:inline-block; + vertical-align: top; + margin-bottom: @spacing-standard; + margin-right: @spacing-standard; .attachment-download-progress, .attachment-upload-progress { @@ -147,11 +155,11 @@ } &:hover { - .attachment-file-actions, .attachment-name-bg, .attachment-name { + .attachment-file-actions, .attachment-name-container, .attachment-name { display: block; } } - .attachment-file-actions, .attachment-name-bg, .attachment-name { + .attachment-file-actions, .attachment-name-container, .attachment-name { display: none; } @@ -167,30 +175,35 @@ .attachment-preview { position: relative; z-index: 1; + overflow: hidden; - .attachment-name-bg { + .attachment-name-container { position: absolute; bottom: 0; top: 0; z-index: 2; width: 100%; - background: linear-gradient(to top, rgba(0,0,0,0.75) 0%,rgba(0,0,0,0) 23%) - } - .attachment-name { - color: @white; - left: 15px; - bottom: 13px; - position: absolute; - z-index: 3; + height:100%; + min-height:300px; + background: linear-gradient(to top, rgba(0,0,0,0.75) 0%,rgba(0,0,0,0) 23%); + vertical-align:bottom; + + .attachment-name { + color: @white; + left: @spacing-standard; + bottom: @spacing-standard; + position: absolute; + z-index: 3; + } } img { position: relative; z-index: 1; max-width: 100%; - background: @background-secondary; + background: url(../static/images/attachments/transparency-background.png) top left repeat; + background-size:8px; } } } - diff --git a/internal_packages/composer/lib/image-file-upload.cjsx b/internal_packages/composer/lib/image-file-upload.cjsx index 0a957f926..1cbaf76a4 100644 --- a/internal_packages/composer/lib/image-file-upload.cjsx +++ b/internal_packages/composer/lib/image-file-upload.cjsx @@ -18,8 +18,9 @@ class ImageFileUpload extends FileUpload
-
-
{@props.uploadData.fileName}
+
+
{@props.uploadData.fileName}
+
diff --git a/internal_packages/developer-bar/stylesheets/developer-bar.less b/internal_packages/developer-bar/stylesheets/developer-bar.less index 13f1423c6..268259dcd 100755 --- a/internal_packages/developer-bar/stylesheets/developer-bar.less +++ b/internal_packages/developer-bar/stylesheets/developer-bar.less @@ -9,7 +9,7 @@ order:1000; display:flex; flex-direction:column; - + .resizable { display: flex; width:100%; @@ -49,12 +49,12 @@ font-size: 13px; line-height: 15px; height: 25px; - background-color: #999; + background: rgba(60,60,60,1); color: white; } .btn:hover { - background-color: #AAA; + background: rgba(40,40,40,1); } .fa-caret-square-o-down, @@ -146,7 +146,7 @@ color: white; } } - + &.long-polling { .item { @@ -214,5 +214,3 @@ } } - - diff --git a/internal_packages/thread-list/lib/thread-list-icon.cjsx b/internal_packages/thread-list/lib/thread-list-icon.cjsx index e06f1f70d..bcf4f07d4 100644 --- a/internal_packages/thread-list/lib/thread-list-icon.cjsx +++ b/internal_packages/thread-list/lib/thread-list-icon.cjsx @@ -12,7 +12,8 @@ class ThreadListIcon extends React.Component thread: React.PropTypes.object _iconType: => - myEmail = NamespaceStore.current()?.emailAddress + if !@props.thread + return 'thread-icon-star-on-hover' if @props.thread.hasTagId('starred') return 'thread-icon-star' @@ -23,6 +24,7 @@ class ThreadListIcon extends React.Component msgs = @_nonDraftMessages() last = msgs[msgs.length - 1] + myEmail = NamespaceStore.current()?.emailAddress if msgs.length > 1 and last.from[0]?.email is myEmail if Utils.isForwardedMessage(last) return 'thread-icon-forwarded thread-icon-star-on-hover' diff --git a/src/flux/models/query.coffee b/src/flux/models/query.coffee index deeb363fa..59f46f52b 100644 --- a/src/flux/models/query.coffee +++ b/src/flux/models/query.coffee @@ -159,13 +159,19 @@ class ModelQuery Query Execution ### - # Public: Starts query execution and returns a Promise. + # Public: Short-hand syntax that calls run().then(fn) with the provided function. # # Returns a {Promise} that resolves with the Models returned by the # query, or rejects with an error from the Database layer. # then: (next) -> - @_database.run(@).then(next) + @run(@).then(next) + + # Public: Returns a {Promise} that resolves with the Models returned by the + # query, or rejects with an error from the Database layer. + # + run: -> + @_database.run(@) formatResult: (result) -> return null unless result diff --git a/src/flux/stores/database-view.coffee b/src/flux/stores/database-view.coffee index fcfa7223e..5222b2dfc 100644 --- a/src/flux/stores/database-view.coffee +++ b/src/flux/stores/database-view.coffee @@ -6,6 +6,36 @@ EventEmitter = require('events').EventEmitter verbose = true +# A small helper class that prevents the DatabaseView from making too many +# queries. It tracks the number of jobs in flight via `increment` and allows +# a callback to run "when there are fewer then N ongoing queries". +# Sort of like _.throttle, but with a work threshold rather than a time threshold. +class TaskThrottler + constructor: (@_maxConcurrent) -> + @_inflight = 0 + @_whenReady = null + + whenReady: (fn) -> + if @_inflight < @_maxConcurrent + fn() + else + @_whenReady = fn + + increment: -> + decremented = false + @_inflight += 1 + + # Returns a function that can be called once and only once to + # decrement the counter. + return => + if not decremented + @_inflight -= 1 + if @_whenReady and @_inflight < @_maxConcurrent + @_whenReady() + @_whenReady = null + decremented = true + + # Public: DatabaseView abstracts away the process of paginating a query # and loading ranges of data. It's very smart about deciding when # results need to be refreshed. There are a few core concepts that @@ -34,13 +64,15 @@ class DatabaseView extends ModelView constructor: (@klass, config = {}, @_metadataProvider) -> super @_pageSize = 100 + @_throttler = new TaskThrottler(2) + @_matchers = config.matchers ? [] @_includes = config.includes ? [] @_orders = config.orders ? [] @_count = -1 @invalidateCount() - @invalidateRetainedRangeImmediate() + @invalidateRetainedRange() @ log: -> @@ -251,18 +283,16 @@ class DatabaseView extends ModelView @_count = count @_emitter.emit('trigger') - invalidateRetainedRange: _.debounce -> - @invalidateRetainedRangeImmediate() - ,10 - - invalidateRetainedRangeImmediate: -> - for idx in @pagesRetained() - @retrievePage(idx) + invalidateRetainedRange: -> + @_throttler.whenReady => + for idx in @pagesRetained() + @retrievePage(idx) retrieveDirtyInRetainedRange: -> - for idx in @pagesRetained() - if not @_pages[idx] or @_pages[idx].lastTouchTime > @_pages[idx].lastLoadTime - @retrievePage(idx) + @_throttler.whenReady => + for idx in @pagesRetained() + if not @_pages[idx] or @_pages[idx].lastTouchTime > @_pages[idx].lastLoadTime + @retrievePage(idx) retrievePage: (idx) -> page = @_pages[idx] ? { @@ -284,7 +314,8 @@ class DatabaseView extends ModelView query.include(attr) for attr in @_includes query.order(@_orders) if @_orders.length > 0 - query.then (items) => + decrement = @_throttler.increment() + query.run().finally(decrement).then (items) => # If the page is no longer in the cache at all, it may have fallen out of the # retained range and been cleaned up. return unless @_pages[idx] @@ -323,7 +354,8 @@ class DatabaseView extends ModelView if idsMissingMetadata.length > 0 and @_metadataProvider metadataPromise = @_metadataProvider(idsMissingMetadata) - metadataPromise.then (results) => + decrement = @_throttler.increment() + metadataPromise.finally(decrement).then (results) => # If we've started reloading since we made our query, don't do any more work if page.lastTouchTime >= touchTime @log("Metadata version #{touchTime} fetched, but out of date (current is #{page.lastTouchTime})") diff --git a/static/images/attachments/icon-attachment-download-@1x.png b/static/images/attachments/icon-attachment-download@1x.png similarity index 100% rename from static/images/attachments/icon-attachment-download-@1x.png rename to static/images/attachments/icon-attachment-download@1x.png diff --git a/static/images/attachments/icon-attachment-download-@2x.png b/static/images/attachments/icon-attachment-download@2x.png similarity index 100% rename from static/images/attachments/icon-attachment-download-@2x.png rename to static/images/attachments/icon-attachment-download@2x.png diff --git a/static/images/attachments/transparency-background.png b/static/images/attachments/transparency-background.png new file mode 100644 index 000000000..7aa8018aa Binary files /dev/null and b/static/images/attachments/transparency-background.png differ